diff --git a/eclipse-code-format.xml b/eclipse-code-format.xml
index c3795f5b8d..4ab5b45712 100644
--- a/eclipse-code-format.xml
+++ b/eclipse-code-format.xml
@@ -1,291 +1,313 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/integration-android/src/de/schildbach/wallet/integration/android/BitcoinIntegration.java b/integration-android/src/de/schildbach/wallet/integration/android/BitcoinIntegration.java
index 3fba9de4f1..3d9200a0f1 100644
--- a/integration-android/src/de/schildbach/wallet/integration/android/BitcoinIntegration.java
+++ b/integration-android/src/de/schildbach/wallet/integration/android/BitcoinIntegration.java
@@ -26,259 +26,251 @@
/**
* @author Andreas Schildbach
*/
-public final class BitcoinIntegration
-{
- private static final String INTENT_EXTRA_PAYMENTREQUEST = "paymentrequest";
- private static final String INTENT_EXTRA_PAYMENT = "payment";
- private static final String INTENT_EXTRA_TRANSACTION_HASH = "transaction_hash";
-
- private static final String MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest"; // BIP 71
-
- /**
- * Request any amount of Bitcoins (probably a donation) from user, without feedback from the app.
- *
- * @param context
- * Android context
- * @param address
- * Bitcoin address
- */
- public static void request(final Context context, final String address)
- {
- final Intent intent = makeBitcoinUriIntent(address, null);
-
- start(context, intent);
- }
-
- /**
- * Request specific amount of Bitcoins from user, without feedback from the app.
- *
- * @param context
- * Android context
- * @param address
- * Bitcoin address
- * @param amount
- * Bitcoin amount in satoshis
- */
- public static void request(final Context context, final String address, final long amount)
- {
- final Intent intent = makeBitcoinUriIntent(address, amount);
-
- start(context, intent);
- }
-
- /**
- * Request payment from user, without feedback from the app.
- *
- * @param context
- * Android context
- * @param paymentRequest
- * BIP70 formatted payment request
- */
- public static void request(final Context context, final byte[] paymentRequest)
- {
- final Intent intent = makePaymentRequestIntent(paymentRequest);
-
- start(context, intent);
- }
-
- /**
- * Request any amount of Bitcoins (probably a donation) from user, with feedback from the app. Result intent can be
- * received by overriding {@link android.app.Activity#onActivityResult()}. Result indicates either
- * {@link Activity#RESULT_OK} or {@link Activity#RESULT_CANCELED}. In the success case, use
- * {@link #transactionHashFromResult(Intent)} to read the transaction hash from the intent.
- *
- * Warning: A success indication is no guarantee! To be on the safe side, you must drive your own Bitcoin
- * infrastructure and validate the transaction.
- *
- * @param activity
- * Calling Android activity
- * @param requestCode
- * Code identifying the call when {@link android.app.Activity#onActivityResult()} is called back
- * @param address
- * Bitcoin address
- */
- public static void requestForResult(final Activity activity, final int requestCode, final String address)
- {
- final Intent intent = makeBitcoinUriIntent(address, null);
-
- startForResult(activity, requestCode, intent);
- }
-
- /**
- * Request specific amount of Bitcoins from user, with feedback from the app. Result intent can be received by
- * overriding {@link android.app.Activity#onActivityResult()}. Result indicates either {@link Activity#RESULT_OK} or
- * {@link Activity#RESULT_CANCELED}. In the success case, use {@link #transactionHashFromResult(Intent)} to read the
- * transaction hash from the intent.
- *
- * Warning: A success indication is no guarantee! To be on the safe side, you must drive your own Bitcoin
- * infrastructure and validate the transaction.
- *
- * @param activity
- * Calling Android activity
- * @param requestCode
- * Code identifying the call when {@link android.app.Activity#onActivityResult()} is called back
- * @param address
- * Bitcoin address
- */
- public static void requestForResult(final Activity activity, final int requestCode, final String address, final long amount)
- {
- final Intent intent = makeBitcoinUriIntent(address, amount);
-
- startForResult(activity, requestCode, intent);
- }
-
- /**
- * Request payment from user, with feedback from the app. Result intent can be received by overriding
- * {@link android.app.Activity#onActivityResult()}. Result indicates either {@link Activity#RESULT_OK} or
- * {@link Activity#RESULT_CANCELED}. In the success case, use {@link #transactionHashFromResult(Intent)} to read the
- * transaction hash from the intent.
- *
- * Warning: A success indication is no guarantee! To be on the safe side, you must drive your own Bitcoin
- * infrastructure and validate the transaction.
- *
- * @param activity
- * Calling Android activity
- * @param requestCode
- * Code identifying the call when {@link android.app.Activity#onActivityResult()} is called back
- * @param paymentRequest
- * BIP70 formatted payment request
- */
- public static void requestForResult(final Activity activity, final int requestCode, final byte[] paymentRequest)
- {
- final Intent intent = makePaymentRequestIntent(paymentRequest);
-
- startForResult(activity, requestCode, intent);
- }
-
- /**
- * Get payment request from intent. Meant for usage by applications accepting payment requests.
- *
- * @param intent
- * intent
- * @return payment request or null
- */
- public static byte[] paymentRequestFromIntent(final Intent intent)
- {
- final byte[] paymentRequest = intent.getByteArrayExtra(INTENT_EXTRA_PAYMENTREQUEST);
-
- return paymentRequest;
- }
-
- /**
- * Put BIP70 payment message into result intent. Meant for usage by Bitcoin wallet applications.
- *
- * @param result
- * result intent
- * @param payment
- * payment message
- */
- public static void paymentToResult(final Intent result, final byte[] payment)
- {
- result.putExtra(INTENT_EXTRA_PAYMENT, payment);
- }
-
- /**
- * Get BIP70 payment message from result intent. Meant for usage by applications initiating a Bitcoin payment.
- *
- * You can use the transactions contained in the payment to validate the payment. For this, you need your own
- * Bitcoin infrastructure though. There is no guarantee that the payment will ever confirm.
- *
- * @param result
- * result intent
- * @return payment message
- */
- public static byte[] paymentFromResult(final Intent result)
- {
- final byte[] payment = result.getByteArrayExtra(INTENT_EXTRA_PAYMENT);
-
- return payment;
- }
-
- /**
- * Put transaction hash into result intent. Meant for usage by Bitcoin wallet applications.
- *
- * @param result
- * result intent
- * @param txHash
- * transaction hash
- */
- public static void transactionHashToResult(final Intent result, final String txHash)
- {
- result.putExtra(INTENT_EXTRA_TRANSACTION_HASH, txHash);
- }
-
- /**
- * Get transaction hash from result intent. Meant for usage by applications initiating a Bitcoin payment.
- *
- * You can use this hash to request the transaction from the Bitcoin network, in order to validate. For this, you
- * need your own Bitcoin infrastructure though. There is no guarantee that the transaction has ever been broadcasted
- * to the Bitcoin network.
- *
- * @param result
- * result intent
- * @return transaction hash
- */
- public static String transactionHashFromResult(final Intent result)
- {
- final String txHash = result.getStringExtra(INTENT_EXTRA_TRANSACTION_HASH);
-
- return txHash;
- }
-
- private static final int SATOSHIS_PER_COIN = 100000000;
-
- private static Intent makeBitcoinUriIntent(final String address, final Long amount)
- {
- final StringBuilder uri = new StringBuilder("bitcoin:");
- if (address != null)
- uri.append(address);
- if (amount != null)
- uri.append("?amount=").append(String.format("%d.%08d", amount / SATOSHIS_PER_COIN, amount % SATOSHIS_PER_COIN));
-
- final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri.toString()));
-
- return intent;
- }
-
- private static Intent makePaymentRequestIntent(final byte[] paymentRequest)
- {
- final Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setType(MIMETYPE_PAYMENTREQUEST);
- intent.putExtra(INTENT_EXTRA_PAYMENTREQUEST, paymentRequest);
-
- return intent;
- }
-
- private static void start(final Context context, final Intent intent)
- {
- final PackageManager pm = context.getPackageManager();
- if (pm.resolveActivity(intent, 0) != null)
- context.startActivity(intent);
- else
- redirectToDownload(context);
- }
-
- private static void startForResult(final Activity activity, final int requestCode, final Intent intent)
- {
- final PackageManager pm = activity.getPackageManager();
- if (pm.resolveActivity(intent, 0) != null)
- activity.startActivityForResult(intent, requestCode);
- else
- redirectToDownload(activity);
- }
-
- private static void redirectToDownload(final Context context)
- {
- Toast.makeText(context, "No Bitcoin application found.\nPlease install Bitcoin Wallet.", Toast.LENGTH_LONG).show();
-
- final Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=de.schildbach.wallet"));
- final Intent binaryIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/bitcoin-wallet/bitcoin-wallet/releases"));
-
- final PackageManager pm = context.getPackageManager();
- if (pm.resolveActivity(marketIntent, 0) != null)
- context.startActivity(marketIntent);
- else if (pm.resolveActivity(binaryIntent, 0) != null)
- context.startActivity(binaryIntent);
- // else out of luck
- }
+public final class BitcoinIntegration {
+ private static final String INTENT_EXTRA_PAYMENTREQUEST = "paymentrequest";
+ private static final String INTENT_EXTRA_PAYMENT = "payment";
+ private static final String INTENT_EXTRA_TRANSACTION_HASH = "transaction_hash";
+
+ private static final String MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest"; // BIP 71
+
+ /**
+ * Request any amount of Bitcoins (probably a donation) from user, without feedback from the app.
+ *
+ * @param context
+ * Android context
+ * @param address
+ * Bitcoin address
+ */
+ public static void request(final Context context, final String address) {
+ final Intent intent = makeBitcoinUriIntent(address, null);
+
+ start(context, intent);
+ }
+
+ /**
+ * Request specific amount of Bitcoins from user, without feedback from the app.
+ *
+ * @param context
+ * Android context
+ * @param address
+ * Bitcoin address
+ * @param amount
+ * Bitcoin amount in satoshis
+ */
+ public static void request(final Context context, final String address, final long amount) {
+ final Intent intent = makeBitcoinUriIntent(address, amount);
+
+ start(context, intent);
+ }
+
+ /**
+ * Request payment from user, without feedback from the app.
+ *
+ * @param context
+ * Android context
+ * @param paymentRequest
+ * BIP70 formatted payment request
+ */
+ public static void request(final Context context, final byte[] paymentRequest) {
+ final Intent intent = makePaymentRequestIntent(paymentRequest);
+
+ start(context, intent);
+ }
+
+ /**
+ * Request any amount of Bitcoins (probably a donation) from user, with feedback from the app. Result
+ * intent can be received by overriding {@link android.app.Activity#onActivityResult()}. Result indicates
+ * either {@link Activity#RESULT_OK} or {@link Activity#RESULT_CANCELED}. In the success case, use
+ * {@link #transactionHashFromResult(Intent)} to read the transaction hash from the intent.
+ *
+ * Warning: A success indication is no guarantee! To be on the safe side, you must drive your own Bitcoin
+ * infrastructure and validate the transaction.
+ *
+ * @param activity
+ * Calling Android activity
+ * @param requestCode
+ * Code identifying the call when {@link android.app.Activity#onActivityResult()} is called
+ * back
+ * @param address
+ * Bitcoin address
+ */
+ public static void requestForResult(final Activity activity, final int requestCode, final String address) {
+ final Intent intent = makeBitcoinUriIntent(address, null);
+
+ startForResult(activity, requestCode, intent);
+ }
+
+ /**
+ * Request specific amount of Bitcoins from user, with feedback from the app. Result intent can be
+ * received by overriding {@link android.app.Activity#onActivityResult()}. Result indicates either
+ * {@link Activity#RESULT_OK} or {@link Activity#RESULT_CANCELED}. In the success case, use
+ * {@link #transactionHashFromResult(Intent)} to read the transaction hash from the intent.
+ *
+ * Warning: A success indication is no guarantee! To be on the safe side, you must drive your own Bitcoin
+ * infrastructure and validate the transaction.
+ *
+ * @param activity
+ * Calling Android activity
+ * @param requestCode
+ * Code identifying the call when {@link android.app.Activity#onActivityResult()} is called
+ * back
+ * @param address
+ * Bitcoin address
+ */
+ public static void requestForResult(final Activity activity, final int requestCode, final String address,
+ final long amount) {
+ final Intent intent = makeBitcoinUriIntent(address, amount);
+
+ startForResult(activity, requestCode, intent);
+ }
+
+ /**
+ * Request payment from user, with feedback from the app. Result intent can be received by overriding
+ * {@link android.app.Activity#onActivityResult()}. Result indicates either {@link Activity#RESULT_OK} or
+ * {@link Activity#RESULT_CANCELED}. In the success case, use {@link #transactionHashFromResult(Intent)}
+ * to read the transaction hash from the intent.
+ *
+ * Warning: A success indication is no guarantee! To be on the safe side, you must drive your own Bitcoin
+ * infrastructure and validate the transaction.
+ *
+ * @param activity
+ * Calling Android activity
+ * @param requestCode
+ * Code identifying the call when {@link android.app.Activity#onActivityResult()} is called
+ * back
+ * @param paymentRequest
+ * BIP70 formatted payment request
+ */
+ public static void requestForResult(final Activity activity, final int requestCode, final byte[] paymentRequest) {
+ final Intent intent = makePaymentRequestIntent(paymentRequest);
+
+ startForResult(activity, requestCode, intent);
+ }
+
+ /**
+ * Get payment request from intent. Meant for usage by applications accepting payment requests.
+ *
+ * @param intent
+ * intent
+ * @return payment request or null
+ */
+ public static byte[] paymentRequestFromIntent(final Intent intent) {
+ final byte[] paymentRequest = intent.getByteArrayExtra(INTENT_EXTRA_PAYMENTREQUEST);
+
+ return paymentRequest;
+ }
+
+ /**
+ * Put BIP70 payment message into result intent. Meant for usage by Bitcoin wallet applications.
+ *
+ * @param result
+ * result intent
+ * @param payment
+ * payment message
+ */
+ public static void paymentToResult(final Intent result, final byte[] payment) {
+ result.putExtra(INTENT_EXTRA_PAYMENT, payment);
+ }
+
+ /**
+ * Get BIP70 payment message from result intent. Meant for usage by applications initiating a Bitcoin
+ * payment.
+ *
+ * You can use the transactions contained in the payment to validate the payment. For this, you need your
+ * own Bitcoin infrastructure though. There is no guarantee that the payment will ever confirm.
+ *
+ * @param result
+ * result intent
+ * @return payment message
+ */
+ public static byte[] paymentFromResult(final Intent result) {
+ final byte[] payment = result.getByteArrayExtra(INTENT_EXTRA_PAYMENT);
+
+ return payment;
+ }
+
+ /**
+ * Put transaction hash into result intent. Meant for usage by Bitcoin wallet applications.
+ *
+ * @param result
+ * result intent
+ * @param txHash
+ * transaction hash
+ */
+ public static void transactionHashToResult(final Intent result, final String txHash) {
+ result.putExtra(INTENT_EXTRA_TRANSACTION_HASH, txHash);
+ }
+
+ /**
+ * Get transaction hash from result intent. Meant for usage by applications initiating a Bitcoin payment.
+ *
+ * You can use this hash to request the transaction from the Bitcoin network, in order to validate. For
+ * this, you need your own Bitcoin infrastructure though. There is no guarantee that the transaction has
+ * ever been broadcasted to the Bitcoin network.
+ *
+ * @param result
+ * result intent
+ * @return transaction hash
+ */
+ public static String transactionHashFromResult(final Intent result) {
+ final String txHash = result.getStringExtra(INTENT_EXTRA_TRANSACTION_HASH);
+
+ return txHash;
+ }
+
+ private static final int SATOSHIS_PER_COIN = 100000000;
+
+ private static Intent makeBitcoinUriIntent(final String address, final Long amount) {
+ final StringBuilder uri = new StringBuilder("bitcoin:");
+ if (address != null)
+ uri.append(address);
+ if (amount != null)
+ uri.append("?amount=")
+ .append(String.format("%d.%08d", amount / SATOSHIS_PER_COIN, amount % SATOSHIS_PER_COIN));
+
+ final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri.toString()));
+
+ return intent;
+ }
+
+ private static Intent makePaymentRequestIntent(final byte[] paymentRequest) {
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setType(MIMETYPE_PAYMENTREQUEST);
+ intent.putExtra(INTENT_EXTRA_PAYMENTREQUEST, paymentRequest);
+
+ return intent;
+ }
+
+ private static void start(final Context context, final Intent intent) {
+ final PackageManager pm = context.getPackageManager();
+ if (pm.resolveActivity(intent, 0) != null)
+ context.startActivity(intent);
+ else
+ redirectToDownload(context);
+ }
+
+ private static void startForResult(final Activity activity, final int requestCode, final Intent intent) {
+ final PackageManager pm = activity.getPackageManager();
+ if (pm.resolveActivity(intent, 0) != null)
+ activity.startActivityForResult(intent, requestCode);
+ else
+ redirectToDownload(activity);
+ }
+
+ private static void redirectToDownload(final Context context) {
+ Toast.makeText(context, "No Bitcoin application found.\nPlease install Bitcoin Wallet.", Toast.LENGTH_LONG)
+ .show();
+
+ final Intent marketIntent = new Intent(Intent.ACTION_VIEW,
+ Uri.parse("market://details?id=de.schildbach.wallet"));
+ final Intent binaryIntent = new Intent(Intent.ACTION_VIEW,
+ Uri.parse("https://github.com/bitcoin-wallet/bitcoin-wallet/releases"));
+
+ final PackageManager pm = context.getPackageManager();
+ if (pm.resolveActivity(marketIntent, 0) != null)
+ context.startActivity(marketIntent);
+ else if (pm.resolveActivity(binaryIntent, 0) != null)
+ context.startActivity(binaryIntent);
+ // else out of luck
+ }
}
diff --git a/sample-integration-android/AndroidManifest.xml b/sample-integration-android/AndroidManifest.xml
index 623eba52e4..30e60b184b 100644
--- a/sample-integration-android/AndroidManifest.xml
+++ b/sample-integration-android/AndroidManifest.xml
@@ -1,31 +1,31 @@
+ package="de.schildbach.wallet.integration.sample"
+ android:versionCode="1"
+ android:versionName="1.0" >
-
+
-
+
-
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/sample-integration-android/res/layout/sample_activity.xml b/sample-integration-android/res/layout/sample_activity.xml
index 1a3d2c3309..44465e4d58 100644
--- a/sample-integration-android/res/layout/sample_activity.xml
+++ b/sample-integration-android/res/layout/sample_activity.xml
@@ -1,93 +1,93 @@
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
-
+
+
\ No newline at end of file
diff --git a/sample-integration-android/src/de/schildbach/wallet/integration/sample/SampleActivity.java b/sample-integration-android/src/de/schildbach/wallet/integration/sample/SampleActivity.java
index 7231f5e5ba..fe09652f14 100644
--- a/sample-integration-android/src/de/schildbach/wallet/integration/sample/SampleActivity.java
+++ b/sample-integration-android/src/de/schildbach/wallet/integration/sample/SampleActivity.java
@@ -42,124 +42,109 @@
/**
* @author Andreas Schildbach
*/
-public class SampleActivity extends Activity
-{
- private static final long AMOUNT = 500000;
- private static final String[] DONATION_ADDRESSES_MAINNET = { "18CK5k1gajRKKSC7yVSTXT9LUzbheh1XY4", "1PZmMahjbfsTy6DsaRyfStzoWTPppWwDnZ" };
- private static final String[] DONATION_ADDRESSES_TESTNET = { "mkCLjaXncyw8eSWJBcBtnTgviU85z5PfwS", "mwEacn7pYszzxfgcNaVUzYvzL6ypRJzB6A" };
- private static final String MEMO = "Sample donation";
- private static final int REQUEST_CODE = 0;
-
- private Button donateButton, requestButton;
- private TextView donateMessage;
-
- @Override
- protected void onCreate(final Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.sample_activity);
-
- donateButton = (Button) findViewById(R.id.sample_donate_button);
- donateButton.setOnClickListener(new OnClickListener()
- {
- public void onClick(final View v)
- {
- handleDonate();
- }
- });
-
- requestButton = (Button) findViewById(R.id.sample_request_button);
- requestButton.setOnClickListener(new OnClickListener()
- {
- public void onClick(final View v)
- {
- handleRequest();
- }
- });
-
- donateMessage = (TextView) findViewById(R.id.sample_donate_message);
- }
-
- private String[] donationAddresses()
- {
- final boolean isMainnet = ((RadioButton) findViewById(R.id.sample_network_mainnet)).isChecked();
-
- return isMainnet ? DONATION_ADDRESSES_MAINNET : DONATION_ADDRESSES_TESTNET;
- }
-
- private void handleDonate()
- {
- final String[] addresses = donationAddresses();
-
- BitcoinIntegration.requestForResult(SampleActivity.this, REQUEST_CODE, addresses[0]);
- }
-
- private void handleRequest()
- {
- try
- {
- final String[] addresses = donationAddresses();
- final NetworkParameters params = Address.getParametersFromAddress(addresses[0]);
-
- final Protos.Output.Builder output1 = Protos.Output.newBuilder();
- output1.setAmount(AMOUNT);
- output1.setScript(ByteString.copyFrom(ScriptBuilder.createOutputScript(new Address(params, addresses[0])).getProgram()));
-
- final Protos.Output.Builder output2 = Protos.Output.newBuilder();
- output2.setAmount(AMOUNT);
- output2.setScript(ByteString.copyFrom(ScriptBuilder.createOutputScript(new Address(params, addresses[1])).getProgram()));
-
- final Protos.PaymentDetails.Builder paymentDetails = Protos.PaymentDetails.newBuilder();
- paymentDetails.setNetwork(params.getPaymentProtocolId());
- paymentDetails.addOutputs(output1);
- paymentDetails.addOutputs(output2);
- paymentDetails.setMemo(MEMO);
- paymentDetails.setTime(System.currentTimeMillis());
-
- final Protos.PaymentRequest.Builder paymentRequest = Protos.PaymentRequest.newBuilder();
- paymentRequest.setSerializedPaymentDetails(paymentDetails.build().toByteString());
-
- BitcoinIntegration.requestForResult(SampleActivity.this, REQUEST_CODE, paymentRequest.build().toByteArray());
- }
- catch (final AddressFormatException x)
- {
- throw new RuntimeException(x);
- }
- }
-
- @Override
- protected void onActivityResult(final int requestCode, final int resultCode, final Intent data)
- {
- if (requestCode == REQUEST_CODE)
- {
- if (resultCode == Activity.RESULT_OK)
- {
- final String txHash = BitcoinIntegration.transactionHashFromResult(data);
- if (txHash != null)
- {
- final SpannableStringBuilder messageBuilder = new SpannableStringBuilder("Transaction hash:\n");
- messageBuilder.append(txHash);
- messageBuilder.setSpan(new TypefaceSpan("monospace"), messageBuilder.length() - txHash.length(), messageBuilder.length(),
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-
- if (BitcoinIntegration.paymentFromResult(data) != null)
- messageBuilder.append("\n(also a BIP70 payment message was received)");
-
- donateMessage.setText(messageBuilder);
- donateMessage.setVisibility(View.VISIBLE);
- }
-
- Toast.makeText(this, "Thank you!", Toast.LENGTH_LONG).show();
- }
- else if (resultCode == Activity.RESULT_CANCELED)
- {
- Toast.makeText(this, "Cancelled.", Toast.LENGTH_LONG).show();
- }
- else
- {
- Toast.makeText(this, "Unknown result.", Toast.LENGTH_LONG).show();
- }
- }
- }
+public class SampleActivity extends Activity {
+ private static final long AMOUNT = 500000;
+ private static final String[] DONATION_ADDRESSES_MAINNET = { "18CK5k1gajRKKSC7yVSTXT9LUzbheh1XY4",
+ "1PZmMahjbfsTy6DsaRyfStzoWTPppWwDnZ" };
+ private static final String[] DONATION_ADDRESSES_TESTNET = { "mkCLjaXncyw8eSWJBcBtnTgviU85z5PfwS",
+ "mwEacn7pYszzxfgcNaVUzYvzL6ypRJzB6A" };
+ private static final String MEMO = "Sample donation";
+ private static final int REQUEST_CODE = 0;
+
+ private Button donateButton, requestButton;
+ private TextView donateMessage;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.sample_activity);
+
+ donateButton = (Button) findViewById(R.id.sample_donate_button);
+ donateButton.setOnClickListener(new OnClickListener() {
+ public void onClick(final View v) {
+ handleDonate();
+ }
+ });
+
+ requestButton = (Button) findViewById(R.id.sample_request_button);
+ requestButton.setOnClickListener(new OnClickListener() {
+ public void onClick(final View v) {
+ handleRequest();
+ }
+ });
+
+ donateMessage = (TextView) findViewById(R.id.sample_donate_message);
+ }
+
+ private String[] donationAddresses() {
+ final boolean isMainnet = ((RadioButton) findViewById(R.id.sample_network_mainnet)).isChecked();
+
+ return isMainnet ? DONATION_ADDRESSES_MAINNET : DONATION_ADDRESSES_TESTNET;
+ }
+
+ private void handleDonate() {
+ final String[] addresses = donationAddresses();
+
+ BitcoinIntegration.requestForResult(SampleActivity.this, REQUEST_CODE, addresses[0]);
+ }
+
+ private void handleRequest() {
+ try {
+ final String[] addresses = donationAddresses();
+ final NetworkParameters params = Address.getParametersFromAddress(addresses[0]);
+
+ final Protos.Output.Builder output1 = Protos.Output.newBuilder();
+ output1.setAmount(AMOUNT);
+ output1.setScript(ByteString
+ .copyFrom(ScriptBuilder.createOutputScript(new Address(params, addresses[0])).getProgram()));
+
+ final Protos.Output.Builder output2 = Protos.Output.newBuilder();
+ output2.setAmount(AMOUNT);
+ output2.setScript(ByteString
+ .copyFrom(ScriptBuilder.createOutputScript(new Address(params, addresses[1])).getProgram()));
+
+ final Protos.PaymentDetails.Builder paymentDetails = Protos.PaymentDetails.newBuilder();
+ paymentDetails.setNetwork(params.getPaymentProtocolId());
+ paymentDetails.addOutputs(output1);
+ paymentDetails.addOutputs(output2);
+ paymentDetails.setMemo(MEMO);
+ paymentDetails.setTime(System.currentTimeMillis());
+
+ final Protos.PaymentRequest.Builder paymentRequest = Protos.PaymentRequest.newBuilder();
+ paymentRequest.setSerializedPaymentDetails(paymentDetails.build().toByteString());
+
+ BitcoinIntegration.requestForResult(SampleActivity.this, REQUEST_CODE,
+ paymentRequest.build().toByteArray());
+ } catch (final AddressFormatException x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
+ if (requestCode == REQUEST_CODE) {
+ if (resultCode == Activity.RESULT_OK) {
+ final String txHash = BitcoinIntegration.transactionHashFromResult(data);
+ if (txHash != null) {
+ final SpannableStringBuilder messageBuilder = new SpannableStringBuilder("Transaction hash:\n");
+ messageBuilder.append(txHash);
+ messageBuilder.setSpan(new TypefaceSpan("monospace"), messageBuilder.length() - txHash.length(),
+ messageBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ if (BitcoinIntegration.paymentFromResult(data) != null)
+ messageBuilder.append("\n(also a BIP70 payment message was received)");
+
+ donateMessage.setText(messageBuilder);
+ donateMessage.setVisibility(View.VISIBLE);
+ }
+
+ Toast.makeText(this, "Thank you!", Toast.LENGTH_LONG).show();
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ Toast.makeText(this, "Cancelled.", Toast.LENGTH_LONG).show();
+ } else {
+ Toast.makeText(this, "Unknown result.", Toast.LENGTH_LONG).show();
+ }
+ }
+ }
}
diff --git a/wallet/AndroidManifest.xml b/wallet/AndroidManifest.xml
index d540c85121..0829ffa6a8 100644
--- a/wallet/AndroidManifest.xml
+++ b/wallet/AndroidManifest.xml
@@ -1,244 +1,243 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns:tools="http://schemas.android.com/tools"
+ package="de.schildbach.wallet_test"
+ android:installLocation="internalOnly"
+ android:versionCode="281"
+ android:versionName="5.01-test" >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/README b/wallet/README
index 9cbefe3670..70beb7d38e 100644
--- a/wallet/README
+++ b/wallet/README
@@ -3,24 +3,24 @@ FILES
Your wallet contains your private keys and various transaction related metadata. It is stored in app-private
storage:
- Mainnet: /data/data/de.schildbach.wallet/files/wallet-protobuf
+ Mainnet: /data/data/de.schildbach.wallet/files/wallet-protobuf
- Testnet: /data/data/de.schildbach.wallet_test/files/wallet-protobuf-testnet
+ Testnet: /data/data/de.schildbach.wallet_test/files/wallet-protobuf-testnet
The wallet file format is not compatible to wallet.dat (Satoshi client). Rather, it uses a custom protobuf format
which should be compatible between clients using bitcoinj.
Certain actions cause automatic rolling backups of your wallet to app-private storage:
- Mainnet: /data/data/de.schildbach.wallet/files/key-backup-protobuf
+ Mainnet: /data/data/de.schildbach.wallet/files/key-backup-protobuf
- Testnet: /data/data/de.schildbach.wallet_test/files/key-backup-protobuf-testnet
+ Testnet: /data/data/de.schildbach.wallet_test/files/key-backup-protobuf-testnet
Your wallet can be manually backed up to and restored from external storage:
- Mainnet: /sdcard/Download/bitcoin-wallet-backup-
+ Mainnet: /sdcard/Download/bitcoin-wallet-backup-
- Testnet: /sdcard/Download/bitcoin-wallet-backup-testnet-
+ Testnet: /sdcard/Download/bitcoin-wallet-backup-testnet-
If you want to recover coins from manual backups and for whatever reason you cannot use the app
itself to restore from the backup, see the separate README.recover guide.
@@ -30,11 +30,11 @@ DEBUGGING
Wallet file for Testnet can be pulled from an (even un-rooted) device using
- adb pull /data/data/de.schildbach.wallet_test/files/wallet-protobuf-testnet
+ adb pull /data/data/de.schildbach.wallet_test/files/wallet-protobuf-testnet
Log messages can be viewed by
- adb logcat
+ adb logcat
The app can send extensive debug information. Use Options > Settings > Report Issue and follow the dialog.
In the generated e-mail, replace the support address with yours.
@@ -50,27 +50,27 @@ You can probably skip some steps, especially if you built Android apps before.
You'll need git, a Java SDK 6 (or later) and Gradle 2.10 (or later) for this. I'll assume Ubuntu Xenial Linux
for the package installs, which comes with slightly more recent versions.
- # first time only
- sudo apt install git gradle openjdk-8-jdk libstdc++6:i386 zlib1g:i386
+ # first time only
+ sudo apt install git gradle openjdk-8-jdk libstdc++6:i386 zlib1g:i386
Get the Android SDK (Tools only) from
- http://developer.android.com/sdk/
+ http://developer.android.com/sdk/
and unpack it to your workspace directory. Point your ANDROID_HOME variable to the unpacked Android SDK directory
and switch to it. Use
- # make sure tools are at the newest version
- tools/android update sdk --no-ui --force --filter tools
+ # make sure tools are at the newest version
+ tools/android update sdk --no-ui --force --filter tools
- # fetch required android dependencies
- tools/android update sdk --no-ui --force --filter build-tools-24,android-15,android-23,extra-android-m2repository
+ # fetch required android dependencies
+ tools/android update sdk --no-ui --force --filter build-tools-24,android-15,android-23,extra-android-m2repository
to download the necessary API level.
Get the Android NDK from
- https://developer.android.com/ndk
+ https://developer.android.com/ndk
and unpack it to your workspace directory. Point your ANDROID_NDK_HOME variable to the unpacked Android NDK
directory.
@@ -78,21 +78,21 @@ directory.
Finally, you can build Bitcoin Wallet and sign it with your development key. Again in your workspace,
use
- # first time only
- git clone -b master https://github.com/bitcoin-wallet/bitcoin-wallet.git bitcoin-wallet
+ # first time only
+ git clone -b master https://github.com/bitcoin-wallet/bitcoin-wallet.git bitcoin-wallet
- # each time
- cd bitcoin-wallet
- git pull
- gradle clean :native-scrypt:copy test build
+ # each time
+ cd bitcoin-wallet
+ git pull
+ gradle clean :native-scrypt:copy test build
To install the app on your Android device, use
- # first time only
- sudo apt install android-tools-adb
+ # first time only
+ sudo apt install android-tools-adb
- # each time
- adb install wallet/build/outputs/apk/bitcoin-wallet-debug.apk
+ # each time
+ adb install wallet/build/outputs/apk/bitcoin-wallet-debug.apk
If installing fails, make sure "Developer options" and "USB debugging" are enabled on your Android device, and an ADB
connection is established.
@@ -108,11 +108,11 @@ The productive version uses Mainnet, is built non-debuggable, space-optimized wi
wallet file is protected against access from non-root users. In the code repository, it lives in a
separate 'prod' branch that gets rebased against master with each released version.
- # each time
- cd bitcoin-wallet
- git fetch origin
- git checkout origin/prod
- gradle clean :native-scrypt:copy test build
+ # each time
+ cd bitcoin-wallet
+ git fetch origin
+ git checkout origin/prod
+ gradle clean :native-scrypt:copy test build
SETTING UP FOR DEVELOPMENT
@@ -124,26 +124,26 @@ TRANSLATIONS
The source language is English. Translations for all languages except German happen on Transifex:
- https://www.transifex.com/bitcoin-wallet/bitcoin-wallet/
+ https://www.transifex.com/bitcoin-wallet/bitcoin-wallet/
The english resources are pushed to Transifex. Changes are pulled and committed to the git
repository from time to time. It can be done by manually downloading the files, but using the "tx"
command line client is more convenient:
- # first time only
- sudo apt install transifex-client
+ # first time only
+ sudo apt install transifex-client
If strings resources are added or changed, the source language files need to be pushed to
Transifex. This step will probably only be executed by the maintainer of the project, as special
permission is needed:
- # push source files to Transifex
- tx push -s
+ # push source files to Transifex
+ tx push -s
As soon as a translation is ready, it can be pulled:
- # pull translation from Transifex
- tx pull -f -l
+ # pull translation from Transifex
+ tx pull -f -l
Note that after pulling, any bugs introduced by either translators or Transifex itself need to be
corrected manually.
@@ -179,14 +179,14 @@ BITCOINJ
Bitcoin Wallet uses bitcoinj for Bitcoin specific logic:
- https://bitcoinj.github.io/
+ https://bitcoinj.github.io/
EXCHANGE RATES
Bitcoin Wallet reads this feed from "BitcoinAverage" for getting exchange rates:
- https://api.bitcoinaverage.com/custom/abw
+ https://api.bitcoinaverage.com/custom/abw
I chose this feed because it is not dependent on a single exchange. However, you should keep in
mind it's always a 24h average (falling back to 7d or even 30d if no trade occurred for a long
@@ -198,4 +198,4 @@ SWEEPING WALLETS
For sweeping wallets, Bitcoin Wallet uses an API by biteasy to query for unspent transaction
outputs:
- https://api.biteasy.com/v2/btc/mainnet/outputs
+ https://api.biteasy.com/v2/btc/mainnet/outputs
diff --git a/wallet/README.recover b/wallet/README.recover
index b1671aaf25..fe03c9a6a4 100644
--- a/wallet/README.recover
+++ b/wallet/README.recover
@@ -33,7 +33,7 @@ PREPARATION
On your PC, install the following Ubuntu packages:
- sudo apt install android-tools-adb openssl git maven
+ sudo apt install android-tools-adb openssl git maven
On your Android device, go to Settings > Developer options and enable "USB debugging". On most
recent devices you need to go to Settings > About first and tap on "Build number" multiple times
@@ -52,11 +52,11 @@ paragraph directly to DECRYPTING.
You cannot find your backup? If you're still using the device you made the backup with, there is
a good chance the backup is on-device. Use
- adb shell ls -l /sdcard/Download/bitcoin-wallet-*
+ adb shell ls -l /sdcard/Download/bitcoin-wallet-*
It will list any backup files present. Pick one and use
- adb pull /sdcard/Download/bitcoin-wallet-backup-testnet-2014-11-01
+ adb pull /sdcard/Download/bitcoin-wallet-backup-testnet-2014-11-01
to copy the file to your PC.
@@ -65,7 +65,7 @@ DECRYPTING
You now have your backup file on your PC. Wallet backups are encrypted. Let's decrypt it using:
- openssl enc -d -aes-256-cbc -a -in bitcoin-wallet-backup-testnet-2014-11-01 > bitcoin-wallet-decrypted-backup
+ openssl enc -d -aes-256-cbc -a -in bitcoin-wallet-backup-testnet-2014-11-01 > bitcoin-wallet-decrypted-backup
It will ask you for a decryption password, which is your backup password. If it prints
"bad password" you've got the wrong password, but if it doesn't print anything your password might
@@ -73,7 +73,7 @@ still be wrong. We can only be sure by looking at the decrypted data.
Historically there is two backup formats. Let's look at the first printable characters in the file:
- cat bitcoin-wallet-decrypted-backup | tr -cd "[:print:]" | awk '{print $1}'
+ cat bitcoin-wallet-decrypted-backup | tr -cd "[:print:]" | awk '{print $1}'
If it prints "org.bitcoin.production", you got the right password and the backup file uses the
bitcoinj protobuf format. This backup format was introduced in v3.47 (May 2014). Skip to
@@ -91,27 +91,27 @@ RECOVERING FROM PROTOBUF WALLET FORMAT
We need wallet-tool from bitcoinj. First, in a working directory, let's get bitcoinj:
- git clone -b release-0.14 https://github.com/bitcoinj/bitcoinj.git
+ git clone -b release-0.14 https://github.com/bitcoinj/bitcoinj.git
Make sure everything is compiled and ready to go by using once:
- cd bitcoinj/tools
- ./wallet-tool
+ cd bitcoinj/tools
+ ./wallet-tool
Now use wallet-tool to sync the wallet from your backup:
- ./wallet-tool reset --wallet=/tmp/bitcoin-wallet-decrypted-backup
- ./wallet-tool sync --wallet=/tmp/bitcoin-wallet-decrypted-backup --debuglog
+ ./wallet-tool reset --wallet=/tmp/bitcoin-wallet-decrypted-backup
+ ./wallet-tool sync --wallet=/tmp/bitcoin-wallet-decrypted-backup --debuglog
The sync process will take anywhere from a few minutes to hours. Wallet-tool will return to the
shell prompt if its finished synching. Have a look at the wallet:
- ./wallet-tool dump --wallet=/tmp/bitcoin-wallet-decrypted-backup
+ ./wallet-tool dump --wallet=/tmp/bitcoin-wallet-decrypted-backup
Does the balance look right? You can see all transactions that ever touched your wallet. Now empty
your entire wallet to the desired destination wallet:
- ./wallet-tool send --wallet=/tmp/bitcoin-wallet-decrypted-backup --output=:ALL
+ ./wallet-tool send --wallet=/tmp/bitcoin-wallet-decrypted-backup --output=:ALL
If your wallet was protected by a spending PIN, you need to supply that PIN using the
--password= option. Be extra careful with this command to get all parameters right. If it
@@ -124,7 +124,7 @@ RECOVERING FROM BASE58 KEY FORMAT
Have a deeper look at the backup file:
- cat bitcoin-wallet-decrypted-backup
+ cat bitcoin-wallet-decrypted-backup
You'll see each line contains a key in WIF (wallet import format), technically Base58. The
datetime string after each key is the birthdate of that key which you can ignore for the purpose
@@ -136,7 +136,7 @@ https://multibit.org/ and restore from inside that application.
Another option is importing each individual key into Electrum or bitcoin-qt/bitcoind. You can
install Electrum with
- sudo apt install electrum
+ sudo apt install electrum
As soon as you see your whole balance again, empty your entire wallet to the desired destination
wallet. Please do not continue to use the imported wallet. Remember you just operated on
diff --git a/wallet/graphics/drawable/stat_notify_received-xhdpi.svg b/wallet/graphics/drawable/stat_notify_received-xhdpi.svg
index 0b4f84c481..94f0a89276 100644
--- a/wallet/graphics/drawable/stat_notify_received-xhdpi.svg
+++ b/wallet/graphics/drawable/stat_notify_received-xhdpi.svg
@@ -2,8 +2,8 @@
diff --git a/wallet/graphics/mipmap/ic_app_color_48dp-mdpi.svg b/wallet/graphics/mipmap/ic_app_color_48dp-mdpi.svg
index 3a9903fbb5..c4ce245caf 100644
--- a/wallet/graphics/mipmap/ic_app_color_48dp-mdpi.svg
+++ b/wallet/graphics/mipmap/ic_app_color_48dp-mdpi.svg
@@ -1,36 +1,36 @@
diff --git a/wallet/res/anim/slide_in_bottom.xml b/wallet/res/anim/slide_in_bottom.xml
index 9c1533f7bc..730fe6b271 100644
--- a/wallet/res/anim/slide_in_bottom.xml
+++ b/wallet/res/anim/slide_in_bottom.xml
@@ -1,5 +1,15 @@
-
-
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/anim/transaction_layout_anim.xml b/wallet/res/anim/transaction_layout_anim.xml
index 80f6412718..a5ddf5f5d3 100644
--- a/wallet/res/anim/transaction_layout_anim.xml
+++ b/wallet/res/anim/transaction_layout_anim.xml
@@ -1,3 +1,3 @@
+ android:animation="@anim/slide_in_bottom" />
diff --git a/wallet/res/color/fg_network.xml b/wallet/res/color/fg_network.xml
index 234e9a8ede..0c411d2224 100644
--- a/wallet/res/color/fg_network.xml
+++ b/wallet/res/color/fg_network.xml
@@ -1,7 +1,7 @@
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/drawable/action_bar_up_indicator.xml b/wallet/res/drawable/action_bar_up_indicator.xml
index f0e175d3c5..1a01ab7322 100644
--- a/wallet/res/drawable/action_bar_up_indicator.xml
+++ b/wallet/res/drawable/action_bar_up_indicator.xml
@@ -1,10 +1,10 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/wallet/res/drawable/action_mode_background.xml b/wallet/res/drawable/action_mode_background.xml
index 425f1c346d..64fd9514e8 100644
--- a/wallet/res/drawable/action_mode_background.xml
+++ b/wallet/res/drawable/action_mode_background.xml
@@ -1,9 +1,9 @@
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/appwidget_button_center.xml b/wallet/res/drawable/appwidget_button_center.xml
index 137488ec0d..ef741de166 100644
--- a/wallet/res/drawable/appwidget_button_center.xml
+++ b/wallet/res/drawable/appwidget_button_center.xml
@@ -1,8 +1,8 @@
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/appwidget_button_left.xml b/wallet/res/drawable/appwidget_button_left.xml
index 775d1aac86..5e8b2ddcbc 100644
--- a/wallet/res/drawable/appwidget_button_left.xml
+++ b/wallet/res/drawable/appwidget_button_left.xml
@@ -1,8 +1,8 @@
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/appwidget_button_right.xml b/wallet/res/drawable/appwidget_button_right.xml
index b7ae74ee80..8133915696 100644
--- a/wallet/res/drawable/appwidget_button_right.xml
+++ b/wallet/res/drawable/appwidget_button_right.xml
@@ -1,8 +1,8 @@
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/appwidget_dark_bg_clickable.xml b/wallet/res/drawable/appwidget_dark_bg_clickable.xml
index 621ba83a3e..2a366dec5e 100644
--- a/wallet/res/drawable/appwidget_dark_bg_clickable.xml
+++ b/wallet/res/drawable/appwidget_dark_bg_clickable.xml
@@ -1,8 +1,8 @@
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/appwidget_divider.xml b/wallet/res/drawable/appwidget_divider.xml
index 3e44f818fa..b74d4817fe 100644
--- a/wallet/res/drawable/appwidget_divider.xml
+++ b/wallet/res/drawable/appwidget_divider.xml
@@ -1,8 +1,10 @@
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/button_bar_background.xml b/wallet/res/drawable/button_bar_background.xml
index 27bf3c28d5..3ee340b883 100644
--- a/wallet/res/drawable/button_bar_background.xml
+++ b/wallet/res/drawable/button_bar_background.xml
@@ -1,8 +1,8 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/wallet/res/drawable/divider_currency.xml b/wallet/res/drawable/divider_currency.xml
index bc3b4daa9a..340fe36e66 100644
--- a/wallet/res/drawable/divider_currency.xml
+++ b/wallet/res/drawable/divider_currency.xml
@@ -1,10 +1,10 @@
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/divider_dark.xml b/wallet/res/drawable/divider_dark.xml
index fbd0d2edec..6e85adbc0d 100644
--- a/wallet/res/drawable/divider_dark.xml
+++ b/wallet/res/drawable/divider_dark.xml
@@ -1,8 +1,10 @@
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/divider_field.xml b/wallet/res/drawable/divider_field.xml
index 6d5335723d..7c0153d34e 100644
--- a/wallet/res/drawable/divider_field.xml
+++ b/wallet/res/drawable/divider_field.xml
@@ -1,10 +1,10 @@
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/stat_sys_peers.xml b/wallet/res/drawable/stat_sys_peers.xml
index d1dc15f11f..ed8c707807 100644
--- a/wallet/res/drawable/stat_sys_peers.xml
+++ b/wallet/res/drawable/stat_sys_peers.xml
@@ -1,20 +1,20 @@
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/drawable/view_shadow_bottom.xml b/wallet/res/drawable/view_shadow_bottom.xml
index 2a25f6276e..043796c70a 100644
--- a/wallet/res/drawable/view_shadow_bottom.xml
+++ b/wallet/res/drawable/view_shadow_bottom.xml
@@ -1,12 +1,12 @@
-
-
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/view_shadow_left.xml b/wallet/res/drawable/view_shadow_left.xml
index dffa897165..7c206616c0 100644
--- a/wallet/res/drawable/view_shadow_left.xml
+++ b/wallet/res/drawable/view_shadow_left.xml
@@ -1,12 +1,12 @@
-
-
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/view_shadow_right.xml b/wallet/res/drawable/view_shadow_right.xml
index 5ba7ed02b2..ae7cbf314f 100644
--- a/wallet/res/drawable/view_shadow_right.xml
+++ b/wallet/res/drawable/view_shadow_right.xml
@@ -1,12 +1,12 @@
-
-
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/drawable/view_shadow_top.xml b/wallet/res/drawable/view_shadow_top.xml
index 586a14a86b..14a21615bd 100644
--- a/wallet/res/drawable/view_shadow_top.xml
+++ b/wallet/res/drawable/view_shadow_top.xml
@@ -1,12 +1,12 @@
-
-
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout-land/request_coins_fragment.xml b/wallet/res/layout-land/request_coins_fragment.xml
index a29a215596..7c56e4e9cf 100644
--- a/wallet/res/layout-land/request_coins_fragment.xml
+++ b/wallet/res/layout-land/request_coins_fragment.xml
@@ -1,61 +1,61 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns:tools="http://schemas.android.com/tools"
+ android:baselineAligned="false"
+ android:orientation="horizontal"
+ tools:ignore="RequiredSize" >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/address_book_onepane.xml b/wallet/res/layout/address_book_onepane.xml
index 3c813699dc..860a527cea 100644
--- a/wallet/res/layout/address_book_onepane.xml
+++ b/wallet/res/layout/address_book_onepane.xml
@@ -1,22 +1,22 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/address_book_row.xml b/wallet/res/layout/address_book_row.xml
index 8eb3cbf55a..3c29b05a48 100644
--- a/wallet/res/layout/address_book_row.xml
+++ b/wallet/res/layout/address_book_row.xml
@@ -1,46 +1,46 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/bg_list"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/list_entry_padding_vertical"
+ android:paddingLeft="@dimen/list_entry_padding_horizontal"
+ android:paddingRight="@dimen/list_entry_padding_horizontal"
+ android:paddingTop="@dimen/list_entry_padding_vertical" >
-
+
-
+
-
-
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/address_book_twopanes.xml b/wallet/res/layout/address_book_twopanes.xml
index 85f0c50a7f..b63491e22b 100644
--- a/wallet/res/layout/address_book_twopanes.xml
+++ b/wallet/res/layout/address_book_twopanes.xml
@@ -1,80 +1,80 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal" >
-
+
-
+
-
+
-
-
-
+
+
+
-
+
-
+
-
+
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/backup_wallet_dialog.xml b/wallet/res/layout/backup_wallet_dialog.xml
index 6f603b9079..941a66a953 100644
--- a/wallet/res/layout/backup_wallet_dialog.xml
+++ b/wallet/res/layout/backup_wallet_dialog.xml
@@ -1,95 +1,95 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/bitmap_dialog.xml b/wallet/res/layout/bitmap_dialog.xml
index 000a2c52f4..cb94df3f3d 100644
--- a/wallet/res/layout/bitmap_dialog.xml
+++ b/wallet/res/layout/bitmap_dialog.xml
@@ -1,34 +1,34 @@
+ android:id="@+id/bitmap_dialog_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
-
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/block_explorer_content.xml b/wallet/res/layout/block_explorer_content.xml
index aa5424437e..8b4ac55809 100644
--- a/wallet/res/layout/block_explorer_content.xml
+++ b/wallet/res/layout/block_explorer_content.xml
@@ -1,6 +1,6 @@
+ android:id="@+id/peer_list_fragment"
+ android:name="de.schildbach.wallet.ui.BlockListFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
diff --git a/wallet/res/layout/block_list_fragment.xml b/wallet/res/layout/block_list_fragment.xml
index 9a88dddde7..2f8b001edb 100644
--- a/wallet/res/layout/block_list_fragment.xml
+++ b/wallet/res/layout/block_list_fragment.xml
@@ -1,17 +1,17 @@
+ android:id="@+id/block_list_group"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/block_row.xml b/wallet/res/layout/block_row.xml
index 478100fcfc..0a5b7e63d9 100644
--- a/wallet/res/layout/block_row.xml
+++ b/wallet/res/layout/block_row.xml
@@ -1,88 +1,88 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/bg_list"
+ android:orientation="vertical" >
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/block_row_transaction.xml b/wallet/res/layout/block_row_transaction.xml
index 91f395644c..878baa40f0 100644
--- a/wallet/res/layout/block_row_transaction.xml
+++ b/wallet/res/layout/block_row_transaction.xml
@@ -1,33 +1,33 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/bg_list"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:paddingBottom="2dp"
+ android:paddingTop="2dp" >
-
+
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/dialog_title.xml b/wallet/res/layout/dialog_title.xml
index 035261dab1..f89390f0e6 100644
--- a/wallet/res/layout/dialog_title.xml
+++ b/wallet/res/layout/dialog_title.xml
@@ -1,31 +1,31 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/bg_dialog_title"
+ android:orientation="horizontal"
+ android:paddingBottom="8dp"
+ android:paddingLeft="@dimen/list_entry_padding_horizontal_lax"
+ android:paddingRight="@dimen/list_entry_padding_horizontal_lax"
+ android:paddingTop="16dp" >
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/edit_address_book_entry_dialog.xml b/wallet/res/layout/edit_address_book_entry_dialog.xml
index 37eb31df41..5a5f0dbfcf 100644
--- a/wallet/res/layout/edit_address_book_entry_dialog.xml
+++ b/wallet/res/layout/edit_address_book_entry_dialog.xml
@@ -1,57 +1,57 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
-
+
-
+
-
+
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/encrypt_keys_dialog.xml b/wallet/res/layout/encrypt_keys_dialog.xml
index 89d811c22a..5cf090e0a4 100644
--- a/wallet/res/layout/encrypt_keys_dialog.xml
+++ b/wallet/res/layout/encrypt_keys_dialog.xml
@@ -1,95 +1,95 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/exchange_rate_row.xml b/wallet/res/layout/exchange_rate_row.xml
index 0f8e7d8d9d..f500f715fd 100644
--- a/wallet/res/layout/exchange_rate_row.xml
+++ b/wallet/res/layout/exchange_rate_row.xml
@@ -1,90 +1,90 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/bg_list"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/list_entry_padding_vertical"
+ android:paddingLeft="@dimen/list_entry_padding_horizontal"
+ android:paddingRight="@dimen/list_entry_padding_horizontal"
+ android:paddingTop="@dimen/list_entry_padding_vertical" >
-
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/exchange_rates_content.xml b/wallet/res/layout/exchange_rates_content.xml
index 7fe187db30..c1743a4854 100644
--- a/wallet/res/layout/exchange_rates_content.xml
+++ b/wallet/res/layout/exchange_rates_content.xml
@@ -1,6 +1,6 @@
+ android:id="@+id/exchange_rates_fragment"
+ android:name="de.schildbach.wallet.ui.ExchangeRatesFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
diff --git a/wallet/res/layout/extended_public_key_dialog.xml b/wallet/res/layout/extended_public_key_dialog.xml
index fd21a899ff..7a9d9b30b7 100644
--- a/wallet/res/layout/extended_public_key_dialog.xml
+++ b/wallet/res/layout/extended_public_key_dialog.xml
@@ -1,19 +1,19 @@
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@color/bg_less_bright" >
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/fancy_list_content.xml b/wallet/res/layout/fancy_list_content.xml
index 57f1cd4e88..9ece964c1f 100644
--- a/wallet/res/layout/fancy_list_content.xml
+++ b/wallet/res/layout/fancy_list_content.xml
@@ -1,21 +1,21 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/maintenance_dialog.xml b/wallet/res/layout/maintenance_dialog.xml
index 675bfa9df6..58144ad9d3 100644
--- a/wallet/res/layout/maintenance_dialog.xml
+++ b/wallet/res/layout/maintenance_dialog.xml
@@ -1,54 +1,54 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
-
+
-
+
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/network_monitor_onepane.xml b/wallet/res/layout/network_monitor_onepane.xml
index e586bf98cd..7032be9cec 100644
--- a/wallet/res/layout/network_monitor_onepane.xml
+++ b/wallet/res/layout/network_monitor_onepane.xml
@@ -1,22 +1,22 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/network_monitor_twopanes.xml b/wallet/res/layout/network_monitor_twopanes.xml
index 9e466ce710..74bfd10026 100644
--- a/wallet/res/layout/network_monitor_twopanes.xml
+++ b/wallet/res/layout/network_monitor_twopanes.xml
@@ -1,82 +1,82 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal" >
-
+
-
+
-
+
-
-
-
+
+
+
-
+
-
+
-
+
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/peer_list_fragment.xml b/wallet/res/layout/peer_list_fragment.xml
index 4f9502a6b8..482ff1f567 100644
--- a/wallet/res/layout/peer_list_fragment.xml
+++ b/wallet/res/layout/peer_list_fragment.xml
@@ -1,25 +1,25 @@
+ android:id="@+id/peer_list_group"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
-
+
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/peer_list_row.xml b/wallet/res/layout/peer_list_row.xml
index c425b7273e..2efb3148d9 100644
--- a/wallet/res/layout/peer_list_row.xml
+++ b/wallet/res/layout/peer_list_row.xml
@@ -1,52 +1,52 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/bg_list"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/list_entry_padding_vertical"
+ android:paddingLeft="@dimen/list_entry_padding_horizontal"
+ android:paddingRight="@dimen/list_entry_padding_horizontal"
+ android:paddingTop="@dimen/list_entry_padding_vertical" >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/peer_monitor_content.xml b/wallet/res/layout/peer_monitor_content.xml
index 13ba85c3c4..35b09c0cc4 100644
--- a/wallet/res/layout/peer_monitor_content.xml
+++ b/wallet/res/layout/peer_monitor_content.xml
@@ -1,6 +1,6 @@
+ android:id="@+id/peer_list_fragment"
+ android:name="de.schildbach.wallet.ui.PeerListFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
diff --git a/wallet/res/layout/raise_fee_dialog.xml b/wallet/res/layout/raise_fee_dialog.xml
index 4e326e699f..aa69ec0fa9 100644
--- a/wallet/res/layout/raise_fee_dialog.xml
+++ b/wallet/res/layout/raise_fee_dialog.xml
@@ -1,54 +1,54 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
-
+
-
+
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/report_issue_dialog.xml b/wallet/res/layout/report_issue_dialog.xml
index 594e0d4a00..c408eeeb78 100644
--- a/wallet/res/layout/report_issue_dialog.xml
+++ b/wallet/res/layout/report_issue_dialog.xml
@@ -1,68 +1,68 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/request_coins_content.xml b/wallet/res/layout/request_coins_content.xml
index bc550f3a8b..9f39e22d07 100644
--- a/wallet/res/layout/request_coins_content.xml
+++ b/wallet/res/layout/request_coins_content.xml
@@ -1,15 +1,15 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/bg_form"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/request_coins_form_include.xml b/wallet/res/layout/request_coins_form_include.xml
index 719e383504..4071a6e137 100644
--- a/wallet/res/layout/request_coins_form_include.xml
+++ b/wallet/res/layout/request_coins_form_include.xml
@@ -1,67 +1,67 @@
+ xmlns:tools="http://schemas.android.com/tools"
+ android:background="@color/bg_form"
+ android:orientation="vertical" >
-
+
-
+
-
+
-
-
+
+
-
+
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/request_coins_fragment.xml b/wallet/res/layout/request_coins_fragment.xml
index 7f3349f6d8..e7e54b7a34 100644
--- a/wallet/res/layout/request_coins_fragment.xml
+++ b/wallet/res/layout/request_coins_fragment.xml
@@ -1,65 +1,65 @@
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ tools:ignore="RequiredSize" >
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/restore_wallet_dialog.xml b/wallet/res/layout/restore_wallet_dialog.xml
index 39db720931..49ef0035e5 100644
--- a/wallet/res/layout/restore_wallet_dialog.xml
+++ b/wallet/res/layout/restore_wallet_dialog.xml
@@ -1,68 +1,68 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/restore_wallet_file_row.xml b/wallet/res/layout/restore_wallet_file_row.xml
index d83c3d0e89..95a25e4095 100644
--- a/wallet/res/layout/restore_wallet_file_row.xml
+++ b/wallet/res/layout/restore_wallet_file_row.xml
@@ -1,30 +1,30 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/list_entry_padding_vertical"
+ android:paddingLeft="@dimen/list_entry_padding_horizontal"
+ android:paddingRight="@dimen/list_entry_padding_horizontal"
+ android:paddingTop="@dimen/list_entry_padding_vertical" >
-
+
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/restore_wallet_from_external_dialog.xml b/wallet/res/layout/restore_wallet_from_external_dialog.xml
index 25d16bc35f..6bfce0cbdd 100644
--- a/wallet/res/layout/restore_wallet_from_external_dialog.xml
+++ b/wallet/res/layout/restore_wallet_from_external_dialog.xml
@@ -1,52 +1,52 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
-
+
-
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/row_separator.xml b/wallet/res/layout/row_separator.xml
index 06719d850a..b518063940 100644
--- a/wallet/res/layout/row_separator.xml
+++ b/wallet/res/layout/row_separator.xml
@@ -1,11 +1,11 @@
+ android:id="@android:id/text1"
+ android:background="@color/bg_less_bright"
+ android:paddingBottom="3dp"
+ android:paddingLeft="@dimen/list_entry_padding_horizontal"
+ android:paddingRight="@dimen/list_entry_padding_horizontal"
+ android:paddingTop="3dp"
+ android:textColor="@color/fg_less_significant"
+ android:textSize="@dimen/font_size_small"
+ android:textStyle="bold" />
diff --git a/wallet/res/layout/scan_activity.xml b/wallet/res/layout/scan_activity.xml
index 147e74cf60..0232e4629e 100755
--- a/wallet/res/layout/scan_activity.xml
+++ b/wallet/res/layout/scan_activity.xml
@@ -1,17 +1,17 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
-
+
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/send_coins_buttons_include.xml b/wallet/res/layout/send_coins_buttons_include.xml
index 202d05d058..1e40f5c8e7 100644
--- a/wallet/res/layout/send_coins_buttons_include.xml
+++ b/wallet/res/layout/send_coins_buttons_include.xml
@@ -1,37 +1,37 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:divider="?android:attr/dividerHorizontal"
+ android:dividerPadding="0dp"
+ android:orientation="vertical"
+ android:showDividers="beginning" >
-
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/send_coins_content.xml b/wallet/res/layout/send_coins_content.xml
index db4e0d57ea..2eee6d7dcc 100644
--- a/wallet/res/layout/send_coins_content.xml
+++ b/wallet/res/layout/send_coins_content.xml
@@ -1,15 +1,15 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/bg_form"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/send_coins_fragment.xml b/wallet/res/layout/send_coins_fragment.xml
index da1f2832fa..c2afeae610 100644
--- a/wallet/res/layout/send_coins_fragment.xml
+++ b/wallet/res/layout/send_coins_fragment.xml
@@ -1,213 +1,213 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ tools:ignore="RequiredSize" >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/spinner_item.xml b/wallet/res/layout/spinner_item.xml
index 230fb28c47..601e93d39d 100644
--- a/wallet/res/layout/spinner_item.xml
+++ b/wallet/res/layout/spinner_item.xml
@@ -1,7 +1,7 @@
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="4dp"
+ android:paddingRight="4dp" />
diff --git a/wallet/res/layout/sweep_wallet_content.xml b/wallet/res/layout/sweep_wallet_content.xml
index f3b53c19dd..7dca4c8bc3 100644
--- a/wallet/res/layout/sweep_wallet_content.xml
+++ b/wallet/res/layout/sweep_wallet_content.xml
@@ -1,15 +1,15 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/bg_form"
+ android:fillViewport="true"
+ android:scrollbars="none" >
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/sweep_wallet_fragment.xml b/wallet/res/layout/sweep_wallet_fragment.xml
index 1d7a1fe760..e49a0f9494 100644
--- a/wallet/res/layout/sweep_wallet_fragment.xml
+++ b/wallet/res/layout/sweep_wallet_fragment.xml
@@ -1,93 +1,93 @@
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/transaction_row.xml b/wallet/res/layout/transaction_row.xml
index 87129002d4..f9cfed0270 100644
--- a/wallet/res/layout/transaction_row.xml
+++ b/wallet/res/layout/transaction_row.xml
@@ -1,175 +1,175 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/transaction_row_card.xml b/wallet/res/layout/transaction_row_card.xml
index b9e9957e4a..e4f8a7d1db 100644
--- a/wallet/res/layout/transaction_row_card.xml
+++ b/wallet/res/layout/transaction_row_card.xml
@@ -1,14 +1,14 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/card_padding_vertical"
+ android:layout_marginLeft="@dimen/card_padding_horizontal"
+ android:layout_marginRight="@dimen/card_padding_horizontal"
+ android:layout_marginTop="@dimen/card_padding_vertical"
+ android:focusable="true"
+ android:foreground="?android:attr/selectableItemBackground" >
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/transaction_row_warning.xml b/wallet/res/layout/transaction_row_warning.xml
index 2ade76827e..aca36350d4 100644
--- a/wallet/res/layout/transaction_row_warning.xml
+++ b/wallet/res/layout/transaction_row_warning.xml
@@ -1,14 +1,14 @@
+ android:id="@+id/transaction_row_warning_message"
+ style="@android:style/Widget.Holo.Button.Borderless"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:drawablePadding="@dimen/list_entry_padding_vertical_lax"
+ android:gravity="left|center_vertical"
+ android:paddingBottom="@dimen/list_entry_padding_vertical_lax"
+ android:paddingLeft="@dimen/list_entry_padding_horizontal_lax"
+ android:paddingRight="@dimen/list_entry_padding_horizontal_lax"
+ android:paddingTop="@dimen/list_entry_padding_vertical_lax"
+ android:textColor="@color/fg_less_significant"
+ android:textSize="@dimen/font_size_small" />
diff --git a/wallet/res/layout/wallet_actions_fragment.xml b/wallet/res/layout/wallet_actions_fragment.xml
index 8bcfad75d9..a81ea3ca64 100644
--- a/wallet/res/layout/wallet_actions_fragment.xml
+++ b/wallet/res/layout/wallet_actions_fragment.xml
@@ -1,48 +1,48 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:divider="@drawable/divider_dark"
+ android:dividerPadding="8dp"
+ android:measureWithLargestChild="true"
+ android:orientation="horizontal" >
-
+
-
+
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/wallet_activity_bottom_include.xml b/wallet/res/layout/wallet_activity_bottom_include.xml
index 87d2f2bcd7..6271412cb4 100644
--- a/wallet/res/layout/wallet_activity_bottom_include.xml
+++ b/wallet/res/layout/wallet_activity_bottom_include.xml
@@ -1,22 +1,22 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/bg_action_bar"
+ android:divider="@drawable/divider_dark"
+ android:orientation="vertical"
+ android:showDividers="middle" >
-
+
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/wallet_activity_onepane_horizontal.xml b/wallet/res/layout/wallet_activity_onepane_horizontal.xml
index 6e31ed7123..c63de74b79 100644
--- a/wallet/res/layout/wallet_activity_onepane_horizontal.xml
+++ b/wallet/res/layout/wallet_activity_onepane_horizontal.xml
@@ -1,69 +1,69 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/wallet_activity_onepane_vertical.xml b/wallet/res/layout/wallet_activity_onepane_vertical.xml
index 3438c4de4a..52fba658f5 100644
--- a/wallet/res/layout/wallet_activity_onepane_vertical.xml
+++ b/wallet/res/layout/wallet_activity_onepane_vertical.xml
@@ -1,55 +1,55 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/wallet_activity_twopanes.xml b/wallet/res/layout/wallet_activity_twopanes.xml
index 2213ea6ddf..65d9aca7eb 100644
--- a/wallet/res/layout/wallet_activity_twopanes.xml
+++ b/wallet/res/layout/wallet_activity_twopanes.xml
@@ -1,82 +1,82 @@
+ android:id="@+id/wallet_main_twopanes"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/wallet_address_dialog.xml b/wallet/res/layout/wallet_address_dialog.xml
index 9d75e1ef29..00a8d99ae2 100644
--- a/wallet/res/layout/wallet_address_dialog.xml
+++ b/wallet/res/layout/wallet_address_dialog.xml
@@ -1,48 +1,48 @@
+ android:id="@+id/wallet_address_dialog_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
-
+
-
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/layout/wallet_address_fragment.xml b/wallet/res/layout/wallet_address_fragment.xml
index 7912516dd1..4cce9fe4fa 100644
--- a/wallet/res/layout/wallet_address_fragment.xml
+++ b/wallet/res/layout/wallet_address_fragment.xml
@@ -1,18 +1,18 @@
+ android:id="@+id/bitcoin_address_qr_card"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:foreground="?android:attr/selectableItemBackground" >
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/wallet_balance_fragment.xml b/wallet/res/layout/wallet_balance_fragment.xml
index 2b0ba9aae2..bf6708981d 100644
--- a/wallet/res/layout/wallet_balance_fragment.xml
+++ b/wallet/res/layout/wallet_balance_fragment.xml
@@ -1,52 +1,52 @@
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_height="wrap_content" >
-
+
-
+
-
+
-
-
+
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/wallet_balance_widget_content.xml b/wallet/res/layout/wallet_balance_widget_content.xml
index 1d961c983a..794b14fedc 100644
--- a/wallet/res/layout/wallet_balance_widget_content.xml
+++ b/wallet/res/layout/wallet_balance_widget_content.xml
@@ -1,96 +1,96 @@
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/appwidget_dark_bg_clickable"
+ android:divider="@drawable/appwidget_divider"
+ android:orientation="horizontal"
+ android:showDividers="middle" >
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/layout/wallet_disclaimer_fragment.xml b/wallet/res/layout/wallet_disclaimer_fragment.xml
index ca48b6765a..8487f8b6ec 100644
--- a/wallet/res/layout/wallet_disclaimer_fragment.xml
+++ b/wallet/res/layout/wallet_disclaimer_fragment.xml
@@ -1,7 +1,7 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:padding="4dp"
+ android:textColor="@color/fg_network_significant"
+ android:textSize="@dimen/font_size_tiny" />
diff --git a/wallet/res/layout/wallet_transactions_fragment.xml b/wallet/res/layout/wallet_transactions_fragment.xml
index ef4ae024c2..f67700c27b 100644
--- a/wallet/res/layout/wallet_transactions_fragment.xml
+++ b/wallet/res/layout/wallet_transactions_fragment.xml
@@ -1,26 +1,26 @@
+ android:id="@+id/wallet_transactions_group"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
-
+
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/menu/blocks_context.xml b/wallet/res/menu/blocks_context.xml
index 8d56dfce1d..301595d7cf 100644
--- a/wallet/res/menu/blocks_context.xml
+++ b/wallet/res/menu/blocks_context.xml
@@ -1,9 +1,9 @@
\ No newline at end of file
diff --git a/wallet/res/menu/exchange_rates_context.xml b/wallet/res/menu/exchange_rates_context.xml
index aa7ccb0636..a1b0104830 100644
--- a/wallet/res/menu/exchange_rates_context.xml
+++ b/wallet/res/menu/exchange_rates_context.xml
@@ -1,11 +1,11 @@
\ No newline at end of file
diff --git a/wallet/res/menu/exchange_rates_fragment_options.xml b/wallet/res/menu/exchange_rates_fragment_options.xml
index 70dc777b8a..a2ef043602 100644
--- a/wallet/res/menu/exchange_rates_fragment_options.xml
+++ b/wallet/res/menu/exchange_rates_fragment_options.xml
@@ -1,11 +1,11 @@
\ No newline at end of file
diff --git a/wallet/res/menu/request_coins_activity_options.xml b/wallet/res/menu/request_coins_activity_options.xml
index 334c62cc02..c925096f8a 100644
--- a/wallet/res/menu/request_coins_activity_options.xml
+++ b/wallet/res/menu/request_coins_activity_options.xml
@@ -1,9 +1,9 @@
\ No newline at end of file
diff --git a/wallet/res/menu/request_coins_fragment_options.xml b/wallet/res/menu/request_coins_fragment_options.xml
index a8d89e2e6b..cb2212a60a 100644
--- a/wallet/res/menu/request_coins_fragment_options.xml
+++ b/wallet/res/menu/request_coins_fragment_options.xml
@@ -1,19 +1,19 @@
\ No newline at end of file
diff --git a/wallet/res/menu/send_coins_activity_options.xml b/wallet/res/menu/send_coins_activity_options.xml
index 4f61ebc9ab..f924cab3ec 100644
--- a/wallet/res/menu/send_coins_activity_options.xml
+++ b/wallet/res/menu/send_coins_activity_options.xml
@@ -1,9 +1,9 @@
\ No newline at end of file
diff --git a/wallet/res/menu/send_coins_fragment_options.xml b/wallet/res/menu/send_coins_fragment_options.xml
index 45dcfeef39..505bc46349 100644
--- a/wallet/res/menu/send_coins_fragment_options.xml
+++ b/wallet/res/menu/send_coins_fragment_options.xml
@@ -1,32 +1,32 @@
\ No newline at end of file
diff --git a/wallet/res/menu/sending_addresses_context.xml b/wallet/res/menu/sending_addresses_context.xml
index c4b733b8da..afec044144 100644
--- a/wallet/res/menu/sending_addresses_context.xml
+++ b/wallet/res/menu/sending_addresses_context.xml
@@ -1,34 +1,34 @@
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/menu/sending_addresses_fragment_options.xml b/wallet/res/menu/sending_addresses_fragment_options.xml
index 4e29855295..47a2265040 100644
--- a/wallet/res/menu/sending_addresses_fragment_options.xml
+++ b/wallet/res/menu/sending_addresses_fragment_options.xml
@@ -1,16 +1,16 @@
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/menu/sweep_wallet_fragment_options.xml b/wallet/res/menu/sweep_wallet_fragment_options.xml
index 051e133504..baf7134f6a 100644
--- a/wallet/res/menu/sweep_wallet_fragment_options.xml
+++ b/wallet/res/menu/sweep_wallet_fragment_options.xml
@@ -1,15 +1,15 @@
-
-
+
+
\ No newline at end of file
diff --git a/wallet/res/menu/wallet_addresses_context.xml b/wallet/res/menu/wallet_addresses_context.xml
index 4430d2732b..6c295ed003 100644
--- a/wallet/res/menu/wallet_addresses_context.xml
+++ b/wallet/res/menu/wallet_addresses_context.xml
@@ -1,26 +1,26 @@
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/menu/wallet_balance_fragment_options.xml b/wallet/res/menu/wallet_balance_fragment_options.xml
index 7e6b130fb1..95952cdd3e 100644
--- a/wallet/res/menu/wallet_balance_fragment_options.xml
+++ b/wallet/res/menu/wallet_balance_fragment_options.xml
@@ -1,9 +1,9 @@
-
+
\ No newline at end of file
diff --git a/wallet/res/menu/wallet_options.xml b/wallet/res/menu/wallet_options.xml
index 394606ef0e..8f8cbc67f8 100644
--- a/wallet/res/menu/wallet_options.xml
+++ b/wallet/res/menu/wallet_options.xml
@@ -1,73 +1,73 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/menu/wallet_transactions_context.xml b/wallet/res/menu/wallet_transactions_context.xml
index 9aa0a99761..db81dad975 100644
--- a/wallet/res/menu/wallet_transactions_context.xml
+++ b/wallet/res/menu/wallet_transactions_context.xml
@@ -1,24 +1,24 @@
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/menu/wallet_transactions_fragment_options.xml b/wallet/res/menu/wallet_transactions_fragment_options.xml
index 1a0e11b60f..3881747b30 100644
--- a/wallet/res/menu/wallet_transactions_fragment_options.xml
+++ b/wallet/res/menu/wallet_transactions_fragment_options.xml
@@ -1,24 +1,24 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/values-de/strings.xml b/wallet/res/values-de/strings.xml
index 9930390d67..b08d92eb07 100644
--- a/wallet/res/values-de/strings.xml
+++ b/wallet/res/values-de/strings.xml
@@ -1,365 +1,341 @@
-
- Wallet wurde zurückgesetzt,\nwird einige Zeit benötigen
-
- Nutzung auf eigene Gefahr. Lies die <u>Sicherheitshinweise</u>.
- Bitte <u>sichere deine Wallet</u>!
- %1$s, hinkt %2$d Stunden hinterher
- %1$s, hinkt %2$d Tage hinterher
- %1$s, hinkt %2$d Wochen hinterher
- %1$s, hinkt %2$d Monate hinterher
- Synchronisiere mit Netzwerk
- Synchronisation blockiert
- Synchronisation: Speicherplatz-Problem
- Synchronisation: Netzwerk-Problem
- Bitcoin-Adresse ins Clipboard kopiert
- Um deine Privatsphäre zu schützen, ändert sich deine Adresse sobald sie eine Zahlung empfängt.
- Dieser Wert ist recht hoch, um in der Tasche getragen zu werden. Bitte verschiebe etwas an einen sichereren Ort.
- Guthaben ist während des Replays nicht verfügbar.
- Wechselkurse
- Kann Wechselkurse nicht laden.
- Kann Wechselkurs nicht finden.
- (Standard)
- Kurs
- Guthaben
- Kurs von %s
- Wechselkurs suchen
- Als Standard-Fremdwährung setzen
- Noch keine Bitcoins empfangen.
- Noch keine Bitcoins gesendet.
- Wie komme ich an Bitcoins?\n\nHandle gegen traditionelles Geld,\nverkaufe Güter oder Dienstleistungen oder\nverdiene durch Arbeit.
- Gratulation, du hast deine erste Zahlung erhalten! Hast du deine Wallet bereits <u>gesichert</u>, um dich gegen Verlust zu schützen?
- Tipp: Um die Sicherheit deiner Wallet zu erhöhen, kannst du dein <u>Gerät verschlüsseln</u>. Das schützt auch die Daten anderer Apps.
- geschürft
- intern
- Filter
- Alle Zahlungen
- Empfangene Zahlungen
- Gesendete Zahlungen
- Sicherheit
- Ausgabe-PIN setzen
- Ausgabe-PIN ändern
- Sicherheitshinweise
- Spenden
- Spende für Bitcoin Wallet
- Interner Speicher wird knapp!
- Bitcoin Wallet nutzt internen Speicher um sich Transaktionen und Blöcke zu merken. Wenn der
+ Wallet wurde zurückgesetzt,\nwird einige Zeit benötigen
+ Nutzung auf eigene Gefahr. Lies die <u>Sicherheitshinweise</u>.
+ Bitte <u>sichere deine Wallet</u>!
+ %1$s, hinkt %2$d Stunden hinterher
+ %1$s, hinkt %2$d Tage hinterher
+ %1$s, hinkt %2$d Wochen hinterher
+ %1$s, hinkt %2$d Monate hinterher
+ Synchronisiere mit Netzwerk
+ Synchronisation blockiert
+ Synchronisation: Speicherplatz-Problem
+ Synchronisation: Netzwerk-Problem
+ Bitcoin-Adresse ins Clipboard kopiert
+ Um deine Privatsphäre zu schützen, ändert sich deine Adresse sobald sie eine Zahlung empfängt.
+ Dieser Wert ist recht hoch, um in der Tasche getragen zu werden. Bitte verschiebe etwas an einen sichereren Ort.
+ Guthaben ist während des Replays nicht verfügbar.
+ Wechselkurse
+ Kann Wechselkurse nicht laden.
+ Kann Wechselkurs nicht finden.
+ (Standard)
+ Kurs
+ Guthaben
+ Kurs von %s
+ Wechselkurs suchen
+ Als Standard-Fremdwährung setzen
+ Noch keine Bitcoins empfangen.
+ Noch keine Bitcoins gesendet.
+ Wie komme ich an Bitcoins?\n\nHandle gegen traditionelles Geld,\nverkaufe Güter oder Dienstleistungen oder\nverdiene durch Arbeit.
+ Gratulation, du hast deine erste Zahlung erhalten! Hast du deine Wallet bereits <u>gesichert</u>, um dich gegen Verlust zu schützen?
+ Tipp: Um die Sicherheit deiner Wallet zu erhöhen, kannst du dein <u>Gerät verschlüsseln</u>. Das schützt auch die Daten anderer Apps.
+ geschürft
+ intern
+ Filter
+ Alle Zahlungen
+ Empfangene Zahlungen
+ Gesendete Zahlungen
+ Sicherheit
+ Ausgabe-PIN setzen
+ Ausgabe-PIN ändern
+ Sicherheitshinweise
+ Spenden
+ Spende für Bitcoin Wallet
+ Interner Speicher wird knapp!
+ Bitcoin Wallet nutzt internen Speicher um sich Transaktionen und Blöcke zu merken. Wenn der
Speicher vollläuft, wird es nicht mehr funktionieren und deine Bitcoins sind in Gefahr!\n\nMöchtest Du die
App-Verwaltung öffnen, um ungenutzte Apps zu deinstallieren?
- App-Verwaltung
- Überprüfe Datums & Uhrzeit-Einstellungen
- Deine Gerätezeit geht um %d Minuten falsch. Deswegen kannst Du möglicherweise keine Bitcoins senden oder empfangen.\n\nDu solltest deine Datums, Zeit- und Zeitzoneneinstellungen überprüfen und ggf. korrigieren.
- Eine neue Version ist verfügbar!
- Diese Version behebt wichtige Fehler. Die Einzelheiten stehen in der Liste der Änderungen auf Google Play.
- Wenn du kein Update siehst, heißt das vermutlich daß deine Android-Version nicht mehr unterstützt wird.
- Google Play
- Herunterladen
- Android ist veraltet
- Es ist möglich, daß eine der nächsten Versionen von Bitcoin Wallet dein Gerät nicht mehr unterstützt. In manchen Fällen kann es schwierig werden, Zahlungen zu tätigen.\n\nEs wird empfohlen, die enthaltenen Bitcoins bald zu verschieben, außer du weisst was du tust.
-
- Bitcoins senden
- Rufe Signatur von %s ab…
- Abrufen der Signatur fehlgeschlagen
- Falsche Signatur!
- verifiziert durch: %s
- unbekannt
- Empfänger
- Adresse oder Namen
- Ungültige Bitcoin-Adresse!
- Du bist dabei, an dich selbst zu schicken!
- komplexe\nAdresse
- (%s warten auf Bestätigung)
- Betrag
- Eine geringe Netzwerk-Gebühr von %s wird gezahlt.
- Der Betrag ist zu klein zum Senden.
- Nicht genug verfügbare Bitcoins. Dir fehlen %s.
- Die Summe an winzigen Zahlungen in deiner Wallet ist zu klein, um verschickt zu werden.
- Zahlung auch direkt senden
- Die Zahlung wurde erfolgreich direkt gesendet.
- Die Zahlung wurde über die direkte Verbindung abgelehnt.
- Direkte Zahlung fehlgeschlagen
- Deine Zahlung wird trotzdem über das P2P-Netzwerk übertragen.
- Senden
- Zurück
- Nicht genug verfügbare Bitcoins
- Dir fehlen %s.
- Möchtest du mit allem zahlen was du hast?
- Entleerung der Wallet fehlgeschlagen
- Entschlüsselung…
- Signierung…
- Versenden…
- Versendet!
- Fehlgeschlagen!
- Problem beim Versenden der Bitcoins!
- Netzwerk-Gebühr
- Kostengünstig
- Normal
- Express
- Wallet entleeren
-
- Netzwerk-Gebühr erhöhen
- Willst du die Netzwerk-Gebühr für diese Zahlung um %s anheben? Das beschleunigt die Bestätigung der Zahlung.
- Entschlüsselung…
- Fertig.
- Erhöhen
-
- Paper-Wallet leeren
- Du bist dabei eine Paper-Wallet oder Coupon zu leeren. Dies wird alle Bitcoins von diesem Papier in deine Wallet auf diesem Gerät verschieben. Sobald die Transaktion bestätigt ist, wird das Papier wertlos und sollte aus Sicherheitsgründen nicht wiederverwendet werden.
- Paper-Wallets werden meist für Cold Storage genutzt. Einige Geldautomaten drucken sie auf das Quittungspapier, anstatt die Bitcoins direkt an das mobile Gerät zu versenden. Manchmal werden vorgeladene Paper-Wallets als Zahlungsmittel verwendet (nicht empfohlen).
- Beginne, indem Du den privaten Schlüssel eines Paper-Wallets scannst. Benutze dafür die Kamera-Schaltfläche.
- Dieser private Schlüssel ist mit einem Passwort geschützt.
- Passwort
- falsches Passwort!
- Zu leerendes Guthaben
- Entschlüsseln
- Leeren
- Entschlüsselung…\nDauert bis zu 2 Minuten.
- Aktualisiere Guthaben…
- Guthabenanforderung fehlgeschlagen
- Nicht genug Bitcoins
- Das zu leerende Guthaben ist zu gering zum Entleeren.
- Guthaben aktualisieren
-
- Wartung empfohlen
- Du hast %1$s auf unsicheren Adressen erhalten. Möchtest du diese Bitcoins auf sichere Adressen verschieben? Eine geringe Netzwerk-Gebühr von %2$s wird gezahlt.
- Entschlüsselung…
- Fertig.
- Verschieben
-
- Bitcoins anfordern
- Angeforderter Betrag (optional)
- Zahlung zur zuverlässigeren Abwicklung per Bluetooth akzeptieren
- Laß diesen Code vom Sender scannen.
- Oder berühr\'s mit einem NFC-fähigen Gerät.
- Anforderung aufs Clipboard kopiert
- Anforderung veröffentlichen…
- Keine andere Bitcoin-App gefunden
- Von lokaler App anfordern
-
- Adressbuch
- Deine Adressen
- Alte Adressen
- Sendeadressen
- Keine Einträge im Adressbuch
- Bitcoins an Adresse senden
- Adresse ändern
- Adresse entfernen
- Ins Clipboard kopieren
- Aus dem Clipboard einfügen
- Clipboard ist leer
- Die Daten auf dem Clipboard sind nicht entzifferbar
- Die Adresse auf dem Clipboard ist eine deiner eigenen.
- Adresse scannen
- Gescannte Daten sind nicht entzifferbar
- Die gescannte Adresse ist eine deiner eigenen.
- Diese Adresse ist vielleicht kompromittiert. Du solltest sie nicht mehr zum Empfang von Bitcoins nutzen.
-
- Sendeadresse hinzufügen
- Name von Sendeadresse ändern
- Name zu eigener Adresse hinzufügen
- Name von eigener Adresse ändern
- Adresse
- Name
- Speichern
-
- Netzwerk-Gebühr
- Diese Transaktion stärkt deine Wallet gegen Diebstahl. <u>Mehr Information.</u>
- Diese Transaktion erhöht die Netzwerk-Gebühr für eine vorherige Zahlung.
- Diese Zahlung ist noch nicht übertragen.
- Diese Zahlung wurde direkt empfangen. Es besteht das Risiko, daß sie niemals verfügbar wird.
- Die Bestätigung dieser Zahlung ist verspätet, wahrscheinlich aufgrund einer Überlastung des Bitcoin-Netzes.
- Diese Zahlung sollte in ein paar Minuten verfügbar werden.
- Diese Zahlung hat ein erhöhtes Risiko daß sie vom Sender rückgängig gemacht wird! Warte wenn möglich auf Bestätigung.
- Diese Zahlung wurde vom Sender rückgängig gemacht.
- Dieser kleine Betrag kann vermutlich nie wirtschaftlich ausgegeben werden.
- Diese Zahlung ging an viele Wallets (neben deiner), was die App mit der Zeit verlangsamt. Versuche wenn möglich Zahlungen zu empfangen, die nur an dich gerichtet sind.
- Diese Zahlung wurde verzögert, weil der Sender eine unsichere Transaktionsform verwendet hat.
-
- Netzwerk-Monitor
- Peers
- Blöcke
- Anpassung der Mining-Difficulty
- Halbierung des Mining-Reward
- gerade eben
-
- Keine Peers verbunden
- ⇆ %d ms
-
- Lese-Berechtigung fehlt
- Um auf deinem externen Speicher nach Wallet-Sicherungen zu suchen, musst du die Berechtigung zum Lesen erteilen.
- Wallet wiederherstellen
- Wähle eine Sicherungsdatei vom externen Speicher (%s) aus:
- Du bist dabei, deine aktuelle Wallet zu ersetzen. Alle Bitcoins in der aktuellen Wallet gehen dabei verloren, außer du hast diese separat gesichert.
- Wichtig: Lade keine privaten Schlüssel aus dubiosen Quellen! Andere Personen können die Kontrolle über deine Bitcoins bekommen, wenn du das tust.
- mit Passwort verschlüsselt
- unverschlüsselt
- externer Speicher
- app-privater Speicher
- automatisch gesichert %s
- manuell gesichert %s
- Wiederherstellen
- Wallet wurde wiederhergestellt.
- Deine Wallet wurde erfolgreich wiederhergestellt. Jetzt wird das Guthaben ermittelt. Das wird einige Zeit dauern.
- Die Wallet konnte nicht wieder hergestellt werden:\n\n%s\n\nFalsches Passwort?
-
- Schreib-Berechtigung fehlt
- Um deine Wallet auf den externen Speicher zu sichern, musst du die Berechtigung zum Schreiben erteilen.
- Wallet sichern
- Dein Backup wird mit dem gewählten Passwort verschlüsselt und auf den externen Speicher gesichert.
- Deine Wallet ist mit einer Ausgabe-PIN geschützt. Stelle sicher, daß du die PIN nicht vergisst (neben dem Backup-Passwort)!
- Exportieren
- Deine Wallet wurde nach %s gesichert.
Wenn die SD-Karte deines Geräts wechselbar ist, sollte deine Sicherung auf dieser Karte sein. Entferne und bewahre sie an einem sicheren Ort auf. Wenn die Karte nicht wechselbar ist, mußt du deine Sicherung an einem anderen Ort als dein Gerät archivieren.
Wenn der einzige Ort, an dem dein Backup existiert, dein Gerät bleibt, läufst du in Gefahr beide zusammen zu verlieren!
Verwahre in jedem Fall auch dein Backup-Passwort sicher. Möchtest du deine Wallet jetzt archivieren?
]]>
- Deine Wallet konnte nicht gesichert werden:\n%s
- Archivieren
- Bitcoin Wallet Sicherung
- Die verschlüsselte Datei im Anhang enthält private Bitcoin-Schlüssel und sollte sicher verwahrt werden. Vergiss das Verschlüsselungs-Passwort nicht!
- Wallet archivieren mit…
- Archivieren der Wallet fehlgeschlagen.
- Passwort
- Wiederholung
- Diskrepanz!
- Passwort zeigen
- Fehler
- Wallet wiederherstellen
-
- Ausgabe-PIN
- Ausgaben von deiner Wallet werden durch die gewählte PIN geschützt.
- Wichtig: Vergiss deine PIN nicht! Nutze keine oft verwendete Nummern (z.B. Geburtstage).
- Alte PIN
- schwach
- mittel
- gut
- stark
- PIN zeigen
- Verschlüsselung…
- Entschlüsselung…
- Fertig.
-
- Sorry
- Die Kamera hat ein Problem. Evtl. musst du dein Gerät neu starten.
- Kamera-Berechtigung
- Um QR-Codes zu scannen, musst du die Berechtigung zur Nutzung der Kamera erteilen.
-
- Kann Daten nicht lesen:\n%s
- Eingabe nicht erkannt:\n%s
- Ungültige Bitcoin-URI:\n%s
- Ungültige Bitcoin-Adresse gelesen!\n(Versuchst Du Mainnet/Testnet zu mischen?)
- Kann Zahlungsanforderung nicht verifizieren:\n%s
- Ungültige Zahlungsanforderung:\n%s
- Ungültige Transaktion:\n%s
-
- Einstellungen
- Diagnose
- Labor
- Stückelung und Genauigkeit
- Maßeinheit für die Anzeige von Werten. Dies beeinflußt keine Berechnungen.
- BTC, 8 Dezimalen
- BTC, 6 Dezimalen
- BTC, 4 Dezimalen
- mBTC, 2 Dezimalen
- µBTC, keine Dezimalen
- Eigener Name
- Dein eigener Name, der zu Zahlungsanforderungen hinzugefügt wird. Versuch ihn kurz zu halten.
- Senden-Dialog automatisch schließen
- Wenn die Zahlung gesendet ist, wird der Senden-Dialog automatisch geschlossen.
- Konnektivitäts-Anzeige
- Zeigt die aktuelle Anzahl von verbundenen Peers im Notifizierungsbereich an.
- Vertrauenswürdiger Peer
- IP oder Hostname eines einzelnen Peers, der verbunden wird.
- Namensauflösung läuft…
- Unbekannter Hostname!
- Reguläre Peers übergehen
- Verhindert Verbindungen zu Peers außer dem vertrauenswürdigen Peer.
- Block-Explorer
- Externer Block-Explorer, der für die Anzeige von Transaktionen, Adressen und Blocks verwendet wird.
- Datenverbrauch
- Zeigt Optionen, um die mobile Datennutzung einzuschränken.
- Erinnerung an Guthaben
- Nach einigen Wochen Nicht-Nutzung wird die App daran erinnern wenn sich noch Bitcoins in der Wallet befinden.
- Problem melden
- Sammelt Informationen über dein Problem und schickt den Bericht per e-Mail an die Entwickler.
- Blockchain zurücksetzen
- Blockchain, Transaktionen und Guthaben werden zurückgesetzt. Das Wiedereinspielen wird eine Weile dauern.
- Möchtest du die Blockchain zurücksetzen und wiedereinspielen?\n\nDies wird verübergehend dein Guthaben ausblenden und deine Transaktionen leeren. Beides wird sich während des Vorgangs erholen.
- Zurücksetzen
- Xpub anzeigen
- Zeigt den Extended Public Key deiner Wallet, so daß er in andere Apps oder Dienste importiert werden kann. Pass aber auf, denn das wird deine finanziellen Umstände gegenüber der App offenlegen.
-
- Teilen…
- Extended Public Key
- Xpub teilen…
-
- Problem melden
- Absturz erkannt
- Bitte beschreibe dein Problem genau, so daß es nachvollzogen werden kann.
- Möchtest du einen Fehlerbericht senden, um bei der Fehlerbehebung zu helfen?
- Problembeschreibung
- Senden
- Geräte-Informationen anhängen
- Liste von installierten Paketen anhängen
- Applikations-Logfile anhängen
- Dump der Wallet anhängen
- Bericht senden mit…
- Senden des Berichts fehlgeschlagen.
-
- Über
- Version
- Urheberrecht
- Lizenz
- Quellcode
- Diese App nutzt…
- bitcoinj %s, eine Bitcoin-Protokoll-Implementierung
- ZXing, eine QR-Code-Bibliothek
- Scrypt, implementiert von Will Glozer und Colin Percival
- Google+ Community
- Diskussionen über die App
- Eintrag bei Google Play
- Rezensionen und Bewertungen
-
- %s empfangen
- %d Peers verbunden
- Du hast noch Bitcoins auf diesem Gerät!
- Denk daran: Dein Guthaben von %s wird verloren sein, wenn du die Bitcoin Wallet App de-installierst ohne es vorher an eine andere Wallet hin zu senden.
- Wenn dir die Bitcoins egal sind, könntest du sie auch dem Bitcoin Wallet Projekt spenden.
- Später erinnern
- Nicht erinnern
-
- Bitcoin-Guthaben
-
-
- Ok
- Schließen
- Abbrechen
- Wiederholen
- Hilfe
- Hinzufügen
- Löschen
- Setzen
- Entfernen
- Ändern
- Kopieren
- Einfügen
- Teilen
- Als Standard setzen
- Anfordern
- Senden
- Scannen
- Einstellungen
+ App-Verwaltung
+ Überprüfe Datums & Uhrzeit-Einstellungen
+ Deine Gerätezeit geht um %d Minuten falsch. Deswegen kannst Du möglicherweise keine Bitcoins senden oder empfangen.\n\nDu solltest deine Datums, Zeit- und Zeitzoneneinstellungen überprüfen und ggf. korrigieren.
+ Eine neue Version ist verfügbar!
+ Diese Version behebt wichtige Fehler. Die Einzelheiten stehen in der Liste der Änderungen auf Google Play.
+ Wenn du kein Update siehst, heißt das vermutlich daß deine Android-Version nicht mehr unterstützt wird.
+ Google Play
+ Herunterladen
+ Android ist veraltet
+ Es ist möglich, daß eine der nächsten Versionen von Bitcoin Wallet dein Gerät nicht mehr unterstützt. In manchen Fällen kann es schwierig werden, Zahlungen zu tätigen.\n\nEs wird empfohlen, die enthaltenen Bitcoins bald zu verschieben, außer du weisst was du tust.
+ Bitcoins senden
+ Rufe Signatur von %s ab…
+ Abrufen der Signatur fehlgeschlagen
+ Falsche Signatur!
+ verifiziert durch: %s
+ unbekannt
+ Empfänger
+ Adresse oder Namen
+ Ungültige Bitcoin-Adresse!
+ Du bist dabei, an dich selbst zu schicken!
+ komplexe\nAdresse
+ (%s warten auf Bestätigung)
+ Betrag
+ Eine geringe Netzwerk-Gebühr von %s wird gezahlt.
+ Der Betrag ist zu klein zum Senden.
+ Nicht genug verfügbare Bitcoins. Dir fehlen %s.
+ Die Summe an winzigen Zahlungen in deiner Wallet ist zu klein, um verschickt zu werden.
+ Zahlung auch direkt senden
+ Die Zahlung wurde erfolgreich direkt gesendet.
+ Die Zahlung wurde über die direkte Verbindung abgelehnt.
+ Direkte Zahlung fehlgeschlagen
+ Deine Zahlung wird trotzdem über das P2P-Netzwerk übertragen.
+ Senden
+ Zurück
+ Nicht genug verfügbare Bitcoins
+ Dir fehlen %s.
+ Möchtest du mit allem zahlen was du hast?
+ Entleerung der Wallet fehlgeschlagen
+ Entschlüsselung…
+ Signierung…
+ Versenden…
+ Versendet!
+ Fehlgeschlagen!
+ Problem beim Versenden der Bitcoins!
+ Netzwerk-Gebühr
+ Kostengünstig
+ Normal
+ Express
+ Wallet entleeren
+ Netzwerk-Gebühr erhöhen
+ Willst du die Netzwerk-Gebühr für diese Zahlung um %s anheben? Das beschleunigt die Bestätigung der Zahlung.
+ Entschlüsselung…
+ Fertig.
+ Erhöhen
+ Paper-Wallet leeren
+ Du bist dabei eine Paper-Wallet oder Coupon zu leeren. Dies wird alle Bitcoins von diesem Papier in deine Wallet auf diesem Gerät verschieben. Sobald die Transaktion bestätigt ist, wird das Papier wertlos und sollte aus Sicherheitsgründen nicht wiederverwendet werden.
+ Paper-Wallets werden meist für Cold Storage genutzt. Einige Geldautomaten drucken sie auf das Quittungspapier, anstatt die Bitcoins direkt an das mobile Gerät zu versenden. Manchmal werden vorgeladene Paper-Wallets als Zahlungsmittel verwendet (nicht empfohlen).
+ Beginne, indem Du den privaten Schlüssel eines Paper-Wallets scannst. Benutze dafür die Kamera-Schaltfläche.
+ Dieser private Schlüssel ist mit einem Passwort geschützt.
+ Passwort
+ falsches Passwort!
+ Zu leerendes Guthaben
+ Entschlüsseln
+ Leeren
+ Entschlüsselung…\nDauert bis zu 2 Minuten.
+ Aktualisiere Guthaben…
+ Guthabenanforderung fehlgeschlagen
+ Nicht genug Bitcoins
+ Das zu leerende Guthaben ist zu gering zum Entleeren.
+ Guthaben aktualisieren
+ Wartung empfohlen
+ Du hast %1$s auf unsicheren Adressen erhalten. Möchtest du diese Bitcoins auf sichere Adressen verschieben? Eine geringe Netzwerk-Gebühr von %2$s wird gezahlt.
+ Entschlüsselung…
+ Fertig.
+ Verschieben
+ Bitcoins anfordern
+ Angeforderter Betrag (optional)
+ Zahlung zur zuverlässigeren Abwicklung per Bluetooth akzeptieren
+ Laß diesen Code vom Sender scannen.
+ Oder berühr\'s mit einem NFC-fähigen Gerät.
+ Anforderung aufs Clipboard kopiert
+ Anforderung veröffentlichen…
+ Keine andere Bitcoin-App gefunden
+ Von lokaler App anfordern
+ Adressbuch
+ Deine Adressen
+ Alte Adressen
+ Sendeadressen
+ Keine Einträge im Adressbuch
+ Bitcoins an Adresse senden
+ Adresse ändern
+ Adresse entfernen
+ Ins Clipboard kopieren
+ Aus dem Clipboard einfügen
+ Clipboard ist leer
+ Die Daten auf dem Clipboard sind nicht entzifferbar
+ Die Adresse auf dem Clipboard ist eine deiner eigenen.
+ Adresse scannen
+ Gescannte Daten sind nicht entzifferbar
+ Die gescannte Adresse ist eine deiner eigenen.
+ Diese Adresse ist vielleicht kompromittiert. Du solltest sie nicht mehr zum Empfang von Bitcoins nutzen.
+ Sendeadresse hinzufügen
+ Name von Sendeadresse ändern
+ Name zu eigener Adresse hinzufügen
+ Name von eigener Adresse ändern
+ Adresse
+ Name
+ Speichern
+ Netzwerk-Gebühr
+ Diese Transaktion stärkt deine Wallet gegen Diebstahl. <u>Mehr Information.</u>
+ Diese Transaktion erhöht die Netzwerk-Gebühr für eine vorherige Zahlung.
+ Diese Zahlung ist noch nicht übertragen.
+ Diese Zahlung wurde direkt empfangen. Es besteht das Risiko, daß sie niemals verfügbar wird.
+ Die Bestätigung dieser Zahlung ist verspätet, wahrscheinlich aufgrund einer Überlastung des Bitcoin-Netzes.
+ Diese Zahlung sollte in ein paar Minuten verfügbar werden.
+ Diese Zahlung hat ein erhöhtes Risiko daß sie vom Sender rückgängig gemacht wird! Warte wenn möglich auf Bestätigung.
+ Diese Zahlung wurde vom Sender rückgängig gemacht.
+ Dieser kleine Betrag kann vermutlich nie wirtschaftlich ausgegeben werden.
+ Diese Zahlung ging an viele Wallets (neben deiner), was die App mit der Zeit verlangsamt. Versuche wenn möglich Zahlungen zu empfangen, die nur an dich gerichtet sind.
+ Diese Zahlung wurde verzögert, weil der Sender eine unsichere Transaktionsform verwendet hat.
+ Netzwerk-Monitor
+ Peers
+ Blöcke
+ Anpassung der Mining-Difficulty
+ Halbierung des Mining-Reward
+ gerade eben
+ Keine Peers verbunden
+ ⇆ %d ms
+ Lese-Berechtigung fehlt
+ Um auf deinem externen Speicher nach Wallet-Sicherungen zu suchen, musst du die Berechtigung zum Lesen erteilen.
+ Wallet wiederherstellen
+ Wähle eine Sicherungsdatei vom externen Speicher (%s) aus:
+ Du bist dabei, deine aktuelle Wallet zu ersetzen. Alle Bitcoins in der aktuellen Wallet gehen dabei verloren, außer du hast diese separat gesichert.
+ Wichtig: Lade keine privaten Schlüssel aus dubiosen Quellen! Andere Personen können die Kontrolle über deine Bitcoins bekommen, wenn du das tust.
+ mit Passwort verschlüsselt
+ unverschlüsselt
+ externer Speicher
+ app-privater Speicher
+ automatisch gesichert %s
+ manuell gesichert %s
+ Wiederherstellen
+ Wallet wurde wiederhergestellt.
+ Deine Wallet wurde erfolgreich wiederhergestellt. Jetzt wird das Guthaben ermittelt. Das wird einige Zeit dauern.
+ Die Wallet konnte nicht wieder hergestellt werden:\n\n%s\n\nFalsches Passwort?
+ Schreib-Berechtigung fehlt
+ Um deine Wallet auf den externen Speicher zu sichern, musst du die Berechtigung zum Schreiben erteilen.
+ Wallet sichern
+ Dein Backup wird mit dem gewählten Passwort verschlüsselt und auf den externen Speicher gesichert.
+ Deine Wallet ist mit einer Ausgabe-PIN geschützt. Stelle sicher, daß du die PIN nicht vergisst (neben dem Backup-Passwort)!
+ Exportieren
+ Deine Wallet wurde nach %s gesichert.
Wenn die SD-Karte deines Geräts wechselbar ist, sollte deine Sicherung auf dieser Karte sein. Entferne und bewahre sie an einem sicheren Ort auf. Wenn die Karte nicht wechselbar ist, mußt du deine Sicherung an einem anderen Ort als dein Gerät archivieren.
Wenn der einzige Ort, an dem dein Backup existiert, dein Gerät bleibt, läufst du in Gefahr beide zusammen zu verlieren!
Verwahre in jedem Fall auch dein Backup-Passwort sicher. Möchtest du deine Wallet jetzt archivieren?
]]>
+ Deine Wallet konnte nicht gesichert werden:\n%s
+ Archivieren
+ Bitcoin Wallet Sicherung
+ Die verschlüsselte Datei im Anhang enthält private Bitcoin-Schlüssel und sollte sicher verwahrt werden. Vergiss das Verschlüsselungs-Passwort nicht!
+ Wallet archivieren mit…
+ Archivieren der Wallet fehlgeschlagen.
+ Passwort
+ Wiederholung
+ Diskrepanz!
+ Passwort zeigen
+ Fehler
+ Wallet wiederherstellen
+ Ausgabe-PIN
+ Ausgaben von deiner Wallet werden durch die gewählte PIN geschützt.
+ Wichtig: Vergiss deine PIN nicht! Nutze keine oft verwendete Nummern (z.B. Geburtstage).
+ Alte PIN
+ schwach
+ mittel
+ gut
+ stark
+ PIN zeigen
+ Verschlüsselung…
+ Entschlüsselung…
+ Fertig.
+ Sorry
+ Die Kamera hat ein Problem. Evtl. musst du dein Gerät neu starten.
+ Kamera-Berechtigung
+ Um QR-Codes zu scannen, musst du die Berechtigung zur Nutzung der Kamera erteilen.
+ Kann Daten nicht lesen:\n%s
+ Eingabe nicht erkannt:\n%s
+ Ungültige Bitcoin-URI:\n%s
+ Ungültige Bitcoin-Adresse gelesen!\n(Versuchst Du Mainnet/Testnet zu mischen?)
+ Kann Zahlungsanforderung nicht verifizieren:\n%s
+ Ungültige Zahlungsanforderung:\n%s
+ Ungültige Transaktion:\n%s
+ Einstellungen
+ Diagnose
+ Labor
+ Stückelung und Genauigkeit
+ Maßeinheit für die Anzeige von Werten. Dies beeinflußt keine Berechnungen.
+ BTC, 8 Dezimalen
+ BTC, 6 Dezimalen
+ BTC, 4 Dezimalen
+ mBTC, 2 Dezimalen
+ µBTC, keine Dezimalen
+ Eigener Name
+ Dein eigener Name, der zu Zahlungsanforderungen hinzugefügt wird. Versuch ihn kurz zu halten.
+ Senden-Dialog automatisch schließen
+ Wenn die Zahlung gesendet ist, wird der Senden-Dialog automatisch geschlossen.
+ Konnektivitäts-Anzeige
+ Zeigt die aktuelle Anzahl von verbundenen Peers im Notifizierungsbereich an.
+ Vertrauenswürdiger Peer
+ IP oder Hostname eines einzelnen Peers, der verbunden wird.
+ Namensauflösung läuft…
+ Unbekannter Hostname!
+ Reguläre Peers übergehen
+ Verhindert Verbindungen zu Peers außer dem vertrauenswürdigen Peer.
+ Block-Explorer
+ Externer Block-Explorer, der für die Anzeige von Transaktionen, Adressen und Blocks verwendet wird.
+ Datenverbrauch
+ Zeigt Optionen, um die mobile Datennutzung einzuschränken.
+ Erinnerung an Guthaben
+ Nach einigen Wochen Nicht-Nutzung wird die App daran erinnern wenn sich noch Bitcoins in der Wallet befinden.
+ Problem melden
+ Sammelt Informationen über dein Problem und schickt den Bericht per e-Mail an die Entwickler.
+ Blockchain zurücksetzen
+ Blockchain, Transaktionen und Guthaben werden zurückgesetzt. Das Wiedereinspielen wird eine Weile dauern.
+ Möchtest du die Blockchain zurücksetzen und wiedereinspielen?\n\nDies wird verübergehend dein Guthaben ausblenden und deine Transaktionen leeren. Beides wird sich während des Vorgangs erholen.
+ Zurücksetzen
+ Xpub anzeigen
+ Zeigt den Extended Public Key deiner Wallet, so daß er in andere Apps oder Dienste importiert werden kann. Pass aber auf, denn das wird deine finanziellen Umstände gegenüber der App offenlegen.
+ Teilen…
+ Extended Public Key
+ Xpub teilen…
+ Problem melden
+ Absturz erkannt
+ Bitte beschreibe dein Problem genau, so daß es nachvollzogen werden kann.
+ Möchtest du einen Fehlerbericht senden, um bei der Fehlerbehebung zu helfen?
+ Problembeschreibung
+ Senden
+ Geräte-Informationen anhängen
+ Liste von installierten Paketen anhängen
+ Applikations-Logfile anhängen
+ Dump der Wallet anhängen
+ Bericht senden mit…
+ Senden des Berichts fehlgeschlagen.
+ Über
+ Version
+ Urheberrecht
+ Lizenz
+ Quellcode
+ Diese App nutzt…
+ bitcoinj %s, eine Bitcoin-Protokoll-Implementierung
+ ZXing, eine QR-Code-Bibliothek
+ Scrypt, implementiert von Will Glozer und Colin Percival
+ Google+ Community
+ Diskussionen über die App
+ Eintrag bei Google Play
+ Rezensionen und Bewertungen
+ %s empfangen
+ %d Peers verbunden
+ Du hast noch Bitcoins auf diesem Gerät!
+ Denk daran: Dein Guthaben von %s wird verloren sein, wenn du die Bitcoin Wallet App de-installierst ohne es vorher an eine andere Wallet hin zu senden.
+ Wenn dir die Bitcoins egal sind, könntest du sie auch dem Bitcoin Wallet Projekt spenden.
+ Später erinnern
+ Nicht erinnern
+ Bitcoin-Guthaben
- QR-Code zeigen
- Im Browser öffnen
+
+ Ok
+ Schließen
+ Abbrechen
+ Wiederholen
+ Hilfe
+ Hinzufügen
+ Löschen
+ Setzen
+ Entfernen
+ Ändern
+ Kopieren
+ Einfügen
+ Teilen
+ Als Standard setzen
+ Anfordern
+ Senden
+ Scannen
+ Einstellungen
+ QR-Code zeigen
+ Im Browser öffnen
-
- heute
- (unbenannt)
- PIN
- falsche PIN!
+
+ heute
+ (unbenannt)
+ PIN
+ falsche PIN!
-
- I/O-Fehler: %s
- HTTP-Fehler %1$s:\n%2$s
- Bluetooth-Fehler: %1$s
+
+ I/O-Fehler: %s
+ HTTP-Fehler %1$s:\n%2$s
+ Bluetooth-Fehler: %1$s
-
+
\ No newline at end of file
diff --git a/wallet/res/values-de/strings_help.xml b/wallet/res/values-de/strings_help.xml
index 4c17385cb6..5c66e93bff 100644
--- a/wallet/res/values-de/strings_help.xml
+++ b/wallet/res/values-de/strings_help.xml
@@ -1,7 +1,7 @@
-
+
Im linken oberen Teil des Bildschirms wird dein aktuelles Guthaben in Bitcoin und einer ausgewählten Währung angezeigt.
@@ -21,8 +21,8 @@
Im Optionsmenü sind weitere Aktionen versteckt.
]]>
-
-
+
+
In diesem Dialogfeld kann eine Zahlung von einem anderen Teilnehmer angefordert werden, der dafür Bitcoin Wallet auf seinem Gerät installiert haben sollte.
@@ -40,8 +40,8 @@
Wenn alle Angaben korrekt sind, kann die Zahlung kann durch eine einfache Bestätigung ausgeführt werden.
]]>
-
-
+
+
Dieses Dialogfeld wird geöffnet, wenn der Zahlungsprozess initiiert wurde.
@@ -70,8 +70,8 @@
Die Empfängeradresse sollte deswegen vor Bestätigung der Zahlung unbedingt auf Richtigkeit überprüft werden.
]]>
-
-
+
+ Wichtige Sicherheitshinweise:
@@ -104,6 +104,6 @@
Speichere nur Beträge für den täglichen Gebrauch.
]]>
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/values-h400dp/layouts.xml b/wallet/res/values-h400dp/layouts.xml
index fe40f5b522..cbf5ba6c51 100644
--- a/wallet/res/values-h400dp/layouts.xml
+++ b/wallet/res/values-h400dp/layouts.xml
@@ -1,6 +1,6 @@
- true
+ true
\ No newline at end of file
diff --git a/wallet/res/values-large-land/layouts.xml b/wallet/res/values-large-land/layouts.xml
index a01fbf720f..51adf8d81f 100644
--- a/wallet/res/values-large-land/layouts.xml
+++ b/wallet/res/values-large-land/layouts.xml
@@ -1,8 +1,8 @@
- @layout/wallet_activity_twopanes
- @layout/address_book_twopanes
- false
+ @layout/wallet_activity_twopanes
+ @layout/address_book_twopanes
+ false
\ No newline at end of file
diff --git a/wallet/res/values-large/dimens.xml b/wallet/res/values-large/dimens.xml
index eda7f1feb5..5cacae98bf 100644
--- a/wallet/res/values-large/dimens.xml
+++ b/wallet/res/values-large/dimens.xml
@@ -1,15 +1,15 @@
- 13sp
- 16sp
- 20sp
- 26sp
- 31sp
- 42sp
- 17sp
- 112dp
- 160dp
- 288dp
+ 13sp
+ 16sp
+ 20sp
+ 26sp
+ 31sp
+ 42sp
+ 17sp
+ 112dp
+ 160dp
+ 288dp
\ No newline at end of file
diff --git a/wallet/res/values-large/layouts.xml b/wallet/res/values-large/layouts.xml
index d03e56b4a7..65fe999af9 100644
--- a/wallet/res/values-large/layouts.xml
+++ b/wallet/res/values-large/layouts.xml
@@ -1,12 +1,12 @@
- true
- @layout/wallet_activity_onepane_vertical
- @layout/address_book_onepane
- @layout/network_monitor_twopanes
- true
- true
- true
+ true
+ @layout/wallet_activity_onepane_vertical
+ @layout/address_book_onepane
+ @layout/network_monitor_twopanes
+ true
+ true
+ true
\ No newline at end of file
diff --git a/wallet/res/values-normal-land/layouts.xml b/wallet/res/values-normal-land/layouts.xml
index 4d1ee67670..eb52c29348 100644
--- a/wallet/res/values-normal-land/layouts.xml
+++ b/wallet/res/values-normal-land/layouts.xml
@@ -1,10 +1,10 @@
- @layout/wallet_activity_onepane_horizontal
- @layout/address_book_twopanes
- @layout/network_monitor_twopanes
- false
- false
+ @layout/wallet_activity_onepane_horizontal
+ @layout/address_book_twopanes
+ @layout/network_monitor_twopanes
+ false
+ false
\ No newline at end of file
diff --git a/wallet/res/values-normal/layouts.xml b/wallet/res/values-normal/layouts.xml
index 64c456eed0..035480895c 100644
--- a/wallet/res/values-normal/layouts.xml
+++ b/wallet/res/values-normal/layouts.xml
@@ -1,12 +1,12 @@
- false
- @layout/wallet_activity_onepane_vertical
- @layout/address_book_onepane
- @layout/network_monitor_onepane
- true
- true
- true
+ false
+ @layout/wallet_activity_onepane_vertical
+ @layout/address_book_onepane
+ @layout/network_monitor_onepane
+ true
+ true
+ true
\ No newline at end of file
diff --git a/wallet/res/values-small-land/layouts.xml b/wallet/res/values-small-land/layouts.xml
index be3af299bd..5e54e630d8 100644
--- a/wallet/res/values-small-land/layouts.xml
+++ b/wallet/res/values-small-land/layouts.xml
@@ -1,6 +1,6 @@
- @layout/wallet_activity_onepane_horizontal
+ @layout/wallet_activity_onepane_horizontal
\ No newline at end of file
diff --git a/wallet/res/values-small/dimens.xml b/wallet/res/values-small/dimens.xml
index 963bae2b6c..4ba17dceed 100644
--- a/wallet/res/values-small/dimens.xml
+++ b/wallet/res/values-small/dimens.xml
@@ -1,13 +1,13 @@
- 11sp
- 14sp
- 16sp
- 20sp
- 25sp
- 30sp
- 14sp
- 72dp
+ 11sp
+ 14sp
+ 16sp
+ 20sp
+ 25sp
+ 30sp
+ 14sp
+ 72dp
\ No newline at end of file
diff --git a/wallet/res/values-small/layouts.xml b/wallet/res/values-small/layouts.xml
index aa6f8135c1..c056b6051a 100644
--- a/wallet/res/values-small/layouts.xml
+++ b/wallet/res/values-small/layouts.xml
@@ -1,12 +1,12 @@
- true
- @layout/wallet_activity_onepane_vertical
- @layout/address_book_onepane
- @layout/network_monitor_onepane
- true
- false
- false
+ true
+ @layout/wallet_activity_onepane_vertical
+ @layout/address_book_onepane
+ @layout/network_monitor_onepane
+ true
+ false
+ false
\ No newline at end of file
diff --git a/wallet/res/values-w1000dp/dimens.xml b/wallet/res/values-w1000dp/dimens.xml
index cff7701356..a150aa2bff 100644
--- a/wallet/res/values-w1000dp/dimens.xml
+++ b/wallet/res/values-w1000dp/dimens.xml
@@ -1,7 +1,7 @@
- 24dp
- 448dp
+ 24dp
+ 448dp
\ No newline at end of file
diff --git a/wallet/res/values-w400dp/dimens.xml b/wallet/res/values-w400dp/dimens.xml
index 77291b8023..acefdb09dc 100644
--- a/wallet/res/values-w400dp/dimens.xml
+++ b/wallet/res/values-w400dp/dimens.xml
@@ -1,6 +1,6 @@
- 12dp
+ 12dp
\ No newline at end of file
diff --git a/wallet/res/values-xlarge/dimens.xml b/wallet/res/values-xlarge/dimens.xml
index 13d4b99e8c..b46c2c850a 100644
--- a/wallet/res/values-xlarge/dimens.xml
+++ b/wallet/res/values-xlarge/dimens.xml
@@ -1,22 +1,22 @@
- 14sp
- 18sp
- 22sp
- 30sp
- 34sp
- 50sp
- 19sp
- 8dp
- 16dp
- 25dp
- 6dp
- 12dp
- 18dp
- 16dp
- 128dp
- 192dp
- 320dp
+ 14sp
+ 18sp
+ 22sp
+ 30sp
+ 34sp
+ 50sp
+ 19sp
+ 8dp
+ 16dp
+ 25dp
+ 6dp
+ 12dp
+ 18dp
+ 16dp
+ 128dp
+ 192dp
+ 320dp
\ No newline at end of file
diff --git a/wallet/res/values-xlarge/layouts.xml b/wallet/res/values-xlarge/layouts.xml
index 807412a379..8e41882a77 100644
--- a/wallet/res/values-xlarge/layouts.xml
+++ b/wallet/res/values-xlarge/layouts.xml
@@ -1,12 +1,12 @@
- true
- @layout/wallet_activity_twopanes
- @layout/address_book_twopanes
- @layout/network_monitor_twopanes
- false
- true
- true
+ true
+ @layout/wallet_activity_twopanes
+ @layout/address_book_twopanes
+ @layout/network_monitor_twopanes
+ false
+ true
+ true
\ No newline at end of file
diff --git a/wallet/res/values/colors.xml b/wallet/res/values/colors.xml
index 07c3e4edc8..3499a3a8ea 100644
--- a/wallet/res/values/colors.xml
+++ b/wallet/res/values/colors.xml
@@ -1,36 +1,36 @@
-
- #ff000000
- #ff666666
- #ffbbbbbb
- #ff008000
- #ff990000
- #ffff0000
- #ffffffff
- #ffa0a0a0
+
+ #ff000000
+ #ff666666
+ #ffbbbbbb
+ #ff008000
+ #ff990000
+ #ffff0000
+ #ffffffff
+ #ffa0a0a0
-
- #ffffffff
- #ffe8e8f0
- #ff222222
- #fff2f2f8
- @android:color/white
- #40ffffff
- #40808090
- @android:color/transparent
+
+ #ffffffff
+ #ffe8e8f0
+ #ff222222
+ #fff2f2f8
+ @android:color/white
+ #40ffffff
+ #40808090
+ @android:color/transparent
-
- #ff0000
- #c06000
- #00a000
+
+ #ff0000
+ #c06000
+ #00a000
-
- #60000000
- #cc0000
- #ff6600
- #b0000000
- #c099cc00
+
+ #60000000
+ #cc0000
+ #ff6600
+ #b0000000
+ #c099cc00
-
+
\ No newline at end of file
diff --git a/wallet/res/values/dimens.xml b/wallet/res/values/dimens.xml
index da8ad7ef6e..0cce1511c7 100644
--- a/wallet/res/values/dimens.xml
+++ b/wallet/res/values/dimens.xml
@@ -1,27 +1,27 @@
- 12sp
- 15sp
- 18sp
- 24sp
- 28sp
- 34sp
- 15sp
- 6dp
- 12dp
- 20dp
- 3dp
- 6dp
- 10dp
- 6dp
- 2dp
- 352sp
- 0dp
- 80dp
- 128dp
- 224dp
- 4dp
- 8dp
+ 12sp
+ 15sp
+ 18sp
+ 24sp
+ 28sp
+ 34sp
+ 15sp
+ 6dp
+ 12dp
+ 20dp
+ 3dp
+ 6dp
+ 10dp
+ 6dp
+ 2dp
+ 352sp
+ 0dp
+ 80dp
+ 128dp
+ 224dp
+ 4dp
+ 8dp
\ No newline at end of file
diff --git a/wallet/res/values/ids.xml b/wallet/res/values/ids.xml
index 909346866c..88ff6622d7 100644
--- a/wallet/res/values/ids.xml
+++ b/wallet/res/values/ids.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/wallet/res/values/layouts.xml b/wallet/res/values/layouts.xml
index 1268cabb3a..260456e06d 100644
--- a/wallet/res/values/layouts.xml
+++ b/wallet/res/values/layouts.xml
@@ -1,6 +1,6 @@
- false
+ false
\ No newline at end of file
diff --git a/wallet/res/values/strings.xml b/wallet/res/values/strings.xml
index a3307a9731..7c386bf14e 100644
--- a/wallet/res/values/strings.xml
+++ b/wallet/res/values/strings.xml
@@ -1,345 +1,340 @@
- Your wallet was reset!\nIt will take some time to recover.
- Use at your own risk. Read the <u>safety notes</u>.
- You need to <u>back up your wallet</u>!
- %1$s, %2$d hours behind
- %1$s, %2$d days behind
- %1$s, %2$d weeks behind
- %1$s, %2$d months behind
- Synchronizing with network
- Synchronization stalled
- Synchronizing: Storage problem
- Synchronizing: Network problem
- Bitcoin address copied to clipboard
- To protect your privacy, your address will change once it receives a payment.
- This amount is quite high for carrying in your pocket. Please move some to a safer place.
- Balance is unavailable during replay.
- Exchange rates
- Could not load exchange rates.
- Could not find exchange rate.
- (default)
- rate
- balance
- Price from %s
- Search exchange rate
- Set as default foreign currency
- No Bitcoins received so far.
- No Bitcoins sent so far.
- How to get Bitcoins?\n\nTrade for traditional money,\nsell goods or services or\nearn by working.
- Congratulations, you received your first payment! Have you already <u>backed up your wallet</u>, to protect against loss?
- Hint: to increase the safety of your wallet, you can <u>encrypt your device</u>. This also protects data of other apps.
- mined
- internal
- Filter
- All payments
- Received payments
- Sent payments
- Safety
- Set spending PIN
- Change spending PIN
- Safety notes
- Tip / donate
- Donation for Bitcoin Wallet
- Internal device storage space low!
- Bitcoin Wallet uses internal storage for remembering transactions and blocks. If it runs out of space, it will stop working and your Bitcoins will be at risk!\n\nDo you want to open the Application Manager to uninstall unneeded apps?
- Manage apps
- Check date & time settings
- Your device time is off by %d minutes. You probably cannot send or receive Bitcoins due to this problem.\n\nYou should check and if necessary correct your date, time and timezone settings.
- A new version is available!
- This version fixes important bugs. For details, see the change log on Google Play.
- If you don\'t see an update, this probably means your version of Android isn\'t supported any more.
- Google Play
- Download
- Android version is out of date
- Chances are that one of the next releases of Bitcoin Wallet will not support your device any more. In some cases, it can get difficult to spend coins on this device.\n\nUnless you know what you are doing, it is recommended to move out your coins soon.
- Send Bitcoins
- Fetching signature from %s…
- Fetching signature failed
- Wrong signature!
- verified by: %s
- unknown
- Pay to
- type address or name
- Invalid Bitcoin address!
- You\'re about to send to yourself!
- complex\naddress
- (%s waiting for confirmation)
- Amount to pay
- A small network fee of %s will be paid.
- The amount is too small to send.
- Not enough available coins. You\'re missing %s.
- The amount of tiny payments in your wallet doesn\'t add up to a sendable value.
- Send payment directly to the payee.
- Your payment was successfully sent directly.
- Your payment was rejected via direct connection.
- Direct payment failed
- Your payment will still be broadcasted via the P2P network.
- Send
- Back
- Not enough available coins
- You\'re missing %s.
- Do you want to pay with all you have?
- Emptying of wallet failed
- Decrypting…
- Signing…
- Sending…
- Sent!
- Failed!
- Problem sending coins!
- Fee
- Economic
- Normal
- Priority
- Empty wallet
- Raise network fee
- Do you want to raise the fee of this payment by %s? It will make the payment confirm quicker.
- Decrypting…
- Done.
- Raise
- Sweep paper wallet
- You are about to sweep a paper wallet or coupon. This will move all coins from that paper to your wallet on this device. When the transaction is confirmed, the paper will be worthless and should not be re-used for safety reasons.
- Paper wallets are most commonly used for cold storage. Some ATMs print them on their paper slip rather than sending the coins to your mobile device directly. People sometimes use pre-charged paper wallets to pass value around (not recommended).
- Start by scanning the private key of a paper wallet. Use the camera action button.
- This private key is protected with a password.
- password
- bad password!
- Balance to sweep
- Decrypt
- Sweep
- Decrypting…\nTakes up to 2 minutes.
- Loading balance…
- Loading wallet balance failed
- Not enough coins
- The amount of coins in the wallet is too small for sweeping.
- Reload balance
- Maintenance recommended
- You received %1$s to unsecure addresses. Would you like to move these coins to secure addresses? A small network fee of %2$s will be paid.
- Decrypting…
- Done.
- Move
- Request Bitcoins
- Requested amount (optional)
- Accept payment via Bluetooth for more reliable processing
- Have this code scanned by the sender.
- Or tap an NFC enabled device.
- Bitcoin request copied to clipboard
- Share request for Bitcoins…
- No other Bitcoin app found
- Request from local app
- Address book
- Your addresses
- Old addresses
- Sending addresses
- No entries in address book
- Send Bitcoins to address
- Edit address
- Remove address
- Copy to clipboard
- Paste from clipboard
- Clipboard is empty
- Data from clipboard is unrecognizable
- The address on the clipboard is your own.
- Scan address
- Scanned data is unrecognizable
- The scanned address is your own.
- This address might be compromised. You should not use it any more for receiving coins.
- Add sending address
- Edit label of sending address
- Add label to your address
- Edit label of your address
- Address
- Label
- Save
- Network fee
- This transaction strengthens your wallet against theft. <u>More info.</u>
- This transaction raises the network fee for a previous payment.
- This payment has not been transmitted yet.
- This payment has been received directly. There is a risk it might never become spendable.
- The confirmation of this payment is delayed, likely due to an overload of the Bitcoin network.
- This payment should become spendable in a few minutes.
- This payment has an increased risk of being reversed by the sender! If you can, wait for confirmation.
- This payment has been reversed by the sender.
- This small amount can probably never be spent economically.
- This payment pays to many wallets besides yours, which makes the app slow down over time. If you can, try receiving payments which pay only to you.
- This payment was delayed because the sender used an insecure transaction type.
- Network monitor
- Peers
- Blocks
- Mining difficulty adjustment
- Mining reward halving
- just now
- No peers connected
- ⇆ %d ms
+ Your wallet was reset!\nIt will take some time to recover.
+ Use at your own risk. Read the <u>safety notes</u>.
+ You need to <u>back up your wallet</u>!
+ %1$s, %2$d hours behind
+ %1$s, %2$d days behind
+ %1$s, %2$d weeks behind
+ %1$s, %2$d months behind
+ Synchronizing with network
+ Synchronization stalled
+ Synchronizing: Storage problem
+ Synchronizing: Network problem
+ Bitcoin address copied to clipboard
+ To protect your privacy, your address will change once it receives a payment.
+ This amount is quite high for carrying in your pocket. Please move some to a safer place.
+ Balance is unavailable during replay.
+ Exchange rates
+ Could not load exchange rates.
+ Could not find exchange rate.
+ (default)
+ rate
+ balance
+ Price from %s
+ Search exchange rate
+ Set as default foreign currency
+ No Bitcoins received so far.
+ No Bitcoins sent so far.
+ How to get Bitcoins?\n\nTrade for traditional money,\nsell goods or services or\nearn by working.
+ Congratulations, you received your first payment! Have you already <u>backed up your wallet</u>, to protect against loss?
+ Hint: to increase the safety of your wallet, you can <u>encrypt your device</u>. This also protects data of other apps.
+ mined
+ internal
+ Filter
+ All payments
+ Received payments
+ Sent payments
+ Safety
+ Set spending PIN
+ Change spending PIN
+ Safety notes
+ Tip / donate
+ Donation for Bitcoin Wallet
+ Internal device storage space low!
+ Bitcoin Wallet uses internal storage for remembering transactions and blocks. If it runs out of space, it will stop working and your Bitcoins will be at risk!\n\nDo you want to open the Application Manager to uninstall unneeded apps?
+ Manage apps
+ Check date & time settings
+ Your device time is off by %d minutes. You probably cannot send or receive Bitcoins due to this problem.\n\nYou should check and if necessary correct your date, time and timezone settings.
+ A new version is available!
+ This version fixes important bugs. For details, see the change log on Google Play.
+ If you don\'t see an update, this probably means your version of Android isn\'t supported any more.
+ Google Play
+ Download
+ Android version is out of date
+ Chances are that one of the next releases of Bitcoin Wallet will not support your device any more. In some cases, it can get difficult to spend coins on this device.\n\nUnless you know what you are doing, it is recommended to move out your coins soon.
+ Send Bitcoins
+ Fetching signature from %s…
+ Fetching signature failed
+ Wrong signature!
+ verified by: %s
+ unknown
+ Pay to
+ type address or name
+ Invalid Bitcoin address!
+ You\'re about to send to yourself!
+ complex\naddress
+ (%s waiting for confirmation)
+ Amount to pay
+ A small network fee of %s will be paid.
+ The amount is too small to send.
+ Not enough available coins. You\'re missing %s.
+ The amount of tiny payments in your wallet doesn\'t add up to a sendable value.
+ Send payment directly to the payee.
+ Your payment was successfully sent directly.
+ Your payment was rejected via direct connection.
+ Direct payment failed
+ Your payment will still be broadcasted via the P2P network.
+ Send
+ Back
+ Not enough available coins
+ You\'re missing %s.
+ Do you want to pay with all you have?
+ Emptying of wallet failed
+ Decrypting…
+ Signing…
+ Sending…
+ Sent!
+ Failed!
+ Problem sending coins!
+ Fee
+ Economic
+ Normal
+ Priority
+ Empty wallet
+ Raise network fee
+ Do you want to raise the fee of this payment by %s? It will make the payment confirm quicker.
+ Decrypting…
+ Done.
+ Raise
+ Sweep paper wallet
+ You are about to sweep a paper wallet or coupon. This will move all coins from that paper to your wallet on this device. When the transaction is confirmed, the paper will be worthless and should not be re-used for safety reasons.
+ Paper wallets are most commonly used for cold storage. Some ATMs print them on their paper slip rather than sending the coins to your mobile device directly. People sometimes use pre-charged paper wallets to pass value around (not recommended).
+ Start by scanning the private key of a paper wallet. Use the camera action button.
+ This private key is protected with a password.
+ password
+ bad password!
+ Balance to sweep
+ Decrypt
+ Sweep
+ Decrypting…\nTakes up to 2 minutes.
+ Loading balance…
+ Loading wallet balance failed
+ Not enough coins
+ The amount of coins in the wallet is too small for sweeping.
+ Reload balance
+ Maintenance recommended
+ You received %1$s to unsecure addresses. Would you like to move these coins to secure addresses? A small network fee of %2$s will be paid.
+ Decrypting…
+ Done.
+ Move
+ Request Bitcoins
+ Requested amount (optional)
+ Accept payment via Bluetooth for more reliable processing
+ Have this code scanned by the sender.
+ Or tap an NFC enabled device.
+ Bitcoin request copied to clipboard
+ Share request for Bitcoins…
+ No other Bitcoin app found
+ Request from local app
+ Address book
+ Your addresses
+ Old addresses
+ Sending addresses
+ No entries in address book
+ Send Bitcoins to address
+ Edit address
+ Remove address
+ Copy to clipboard
+ Paste from clipboard
+ Clipboard is empty
+ Data from clipboard is unrecognizable
+ The address on the clipboard is your own.
+ Scan address
+ Scanned data is unrecognizable
+ The scanned address is your own.
+ This address might be compromised. You should not use it any more for receiving coins.
+ Add sending address
+ Edit label of sending address
+ Add label to your address
+ Edit label of your address
+ Address
+ Label
+ Save
+ Network fee
+ This transaction strengthens your wallet against theft. <u>More info.</u>
+ This transaction raises the network fee for a previous payment.
+ This payment has not been transmitted yet.
+ This payment has been received directly. There is a risk it might never become spendable.
+ The confirmation of this payment is delayed, likely due to an overload of the Bitcoin network.
+ This payment should become spendable in a few minutes.
+ This payment has an increased risk of being reversed by the sender! If you can, wait for confirmation.
+ This payment has been reversed by the sender.
+ This small amount can probably never be spent economically.
+ This payment pays to many wallets besides yours, which makes the app slow down over time. If you can, try receiving payments which pay only to you.
+ This payment was delayed because the sender used an insecure transaction type.
+ Network monitor
+ Peers
+ Blocks
+ Mining difficulty adjustment
+ Mining reward halving
+ just now
+ No peers connected
+ ⇆ %d ms
+ Read permission missing
+ In order to search for wallet backups on your external storage, you need to grant read permission.
+ Restore wallet
+ Pick a wallet backup file from external storage (%s):
+ You are about to replace your current wallet. Any coins in the current wallet will be lost unless you\'ve got a separate backup of that.
+ Important: Do not load private keys from dubious sources! Others can gain control over your funds if you do.
+ password encrypted
+ unencrypted
+ external storage
+ app-private storage
+ automatic backup %s
+ manually backed up %s
+ Restore
+ Wallet was restored.
+ Your wallet was successfully restored. Its balance will be determined next. This will take some time.
+ Wallet could not be restored:\n\n%s\n\nBad password?
+ Write permission missing
+ In order to backup your wallet to external storage, you need to grant write permission.
+ Back up wallet
+ Your backup will be encrypted with the chosen password and written to external storage.
+ Your wallet is protected by a spending PIN. Make sure you remember the PIN in addition to the backup password!
+ Back up
+ Your wallet has been backed up to %s
If your device has a removable SD card, your backup should be on that card. Remove it and keep it at a safe place. If the card is not removable, you need to archive your backup to some other place than your device.
If the only place your backup exists is on your device, you run the risk of losing both at the same time!
In any case, make sure you remember your backup password. Do you want to archive your wallet now?
]]>
+ Your wallet could not be backed up:\n%s
+ Archive
+ Bitcoin Wallet backup
+ The attached encrypted file contains Bitcoin private keys and should be kept safe at all times. Don\'t forget the encryption password!
+ Archive wallet using…
+ Archiving wallet failed.
+ password
+ again
+ mismatch!
+ Show password
+ Error
+ Restore wallet
+ Spending PIN
+ Spending from your wallet will be protected with the chosen PIN.
+ Important: You need to remember your PIN! Do not use common numbers (like birthdates).
+ Old PIN
+ weak
+ fair
+ good
+ strong
+ Show PIN
+ Encrypting…
+ Decrypting…
+ Done.
+ Sorry
+ The camera has a problem. You probably need to restart the device.
+ Camera permission
+ In order to scan QR codes, you need to grant permission to use the camera.
+ Cannot read data:\n%s
+ Cannot recognize input:\n%s
+ Invalid Bitcoin URI:\n%s
+ Got invalid bitcoin address!\n(Mixing up mainnet/testnet?)
+ Cannot verify payment request:\n%s
+ Invalid payment request:\n%s
+ Invalid transaction:\n%s
+ Settings
+ Diagnostics
+ Labs
+ Denomination and precision
+ Unit to show amounts in. This does not affect computations.
+ BTC, 8 decimal places
+ BTC, 6 decimal places
+ BTC, 4 decimal places
+ mBTC, 2 decimal places
+ µBTC, no decimal places
+ Own name
+ Name of yourself, to be added to payment requests. Try to keep it short.
+ Auto-close send coins dialog
+ When the payment is made, the send dialog will close automatically.
+ Connectivity indicator
+ Show current number of connected peers in the notification area.
+ Trusted peer
+ IP or hostname of single peer to connect to.
+ Resolving…
+ Unknown hostname!
+ Skip regular peer discovery
+ Prevents connecting to any peers besides the trusted peer.
+ Block explorer
+ External block explorer to use for browsing transactions, addresses and blocks.
+ Data usage
+ Show options to restrict data usage on mobile networks.
+ Balance reminder
+ After a couple of weeks of not being used, the app will notify if there are still coins in the wallet.
+ Report issue
+ Collect information about your issue and email your report to the developers.
+ Reset block chain
+ Reset block chain, transactions and wallet balance. Replay will take a while.
+ Would you like to reset and replay the block chain?\n\nThis will temporarily hide your wallet balance and remove transactions. Both will recover as block chain sync progresses.
+ Reset
+ Show xpub
+ View the extended public key of your wallet, so it can be imported into other apps and services. Be careful: doing so will disclose your monetary privacy to that app.
+ Share…
+ Extended Public Key
+ Share xpub…
+ Report issue
+ Previous crash detected
+ Please describe your issue precisely enough to be reproduced.
+ Would you like to send a crash report, helping to fix this issue in the future?
+ issue description
+ Report
+ Append device information
+ Append list of installed packages
+ Append application log
+ Append wallet dump
+ Send report using…
+ Sending report failed.
+ About
+ Version
+ Copyright
+ License
+ Source code
+ This app is using…
+ bitcoinj %s, a Bitcoin protocol implementation
+ ZXing, a QR-code processing library
+ Scrypt, implemented by Will Glozer and Colin Percival
+ Google+ community
+ Discussions about the app
+ Google Play page
+ Review or rate the app
+ Received %s
+ %d peers connected
+ You\'ve still got Bitcoins on this device!
+ Remember your balance of %s will be lost if you uninstall the Bitcoin Wallet app without sending it away first.
+ If you don\'t care about your coins, you could also donate them to the Bitcoin Wallet project.
+ Remind me later
+ Don\'t remind me
+ Bitcoin balance
- Read permission missing
- In order to search for wallet backups on your external storage, you need to grant read permission.
- Restore wallet
- Pick a wallet backup file from external storage (%s):
- You are about to replace your current wallet. Any coins in the current wallet will be lost unless you\'ve got a separate backup of that.
- Important: Do not load private keys from dubious sources! Others can gain control over your funds if you do.
- password encrypted
- unencrypted
- external storage
- app-private storage
- automatic backup %s
- manually backed up %s
- Restore
- Wallet was restored.
- Your wallet was successfully restored. Its balance will be determined next. This will take some time.
- Wallet could not be restored:\n\n%s\n\nBad password?
+
+ OK
+ Dismiss
+ Cancel
+ Retry
+ Help
+ Add
+ Delete
+ Set
+ Remove
+ Edit
+ Copy
+ Paste
+ Share
+ Set as default
+ Request coins
+ Send coins
+ Scan
+ Settings
+ Show QR code
+ Browse
- Write permission missing
- In order to backup your wallet to external storage, you need to grant write permission.
- Back up wallet
- Your backup will be encrypted with the chosen password and written to external storage.
- Your wallet is protected by a spending PIN. Make sure you remember the PIN in addition to the backup password!
- Back up
- Your wallet has been backed up to %s
If your device has a removable SD card, your backup should be on that card. Remove it and keep it at a safe place. If the card is not removable, you need to archive your backup to some other place than your device.
If the only place your backup exists is on your device, you run the risk of losing both at the same time!
In any case, make sure you remember your backup password. Do you want to archive your wallet now?
]]>
- Your wallet could not be backed up:\n%s
- Archive
- Bitcoin Wallet backup
- The attached encrypted file contains Bitcoin private keys and should be kept safe at all times. Don\'t forget the encryption password!
- Archive wallet using…
- Archiving wallet failed.
- password
- again
- mismatch!
- Show password
- Error
- Restore wallet
- Spending PIN
- Spending from your wallet will be protected with the chosen PIN.
- Important: You need to remember your PIN! Do not use common numbers (like birthdates).
- Old PIN
- weak
- fair
- good
- strong
- Show PIN
- Encrypting…
- Decrypting…
- Done.
- Sorry
- The camera has a problem. You probably need to restart the device.
- Camera permission
- In order to scan QR codes, you need to grant permission to use the camera.
- Cannot read data:\n%s
- Cannot recognize input:\n%s
- Invalid Bitcoin URI:\n%s
- Got invalid bitcoin address!\n(Mixing up mainnet/testnet?)
- Cannot verify payment request:\n%s
- Invalid payment request:\n%s
- Invalid transaction:\n%s
- Settings
- Diagnostics
- Labs
- Denomination and precision
- Unit to show amounts in. This does not affect computations.
- BTC, 8 decimal places
- BTC, 6 decimal places
- BTC, 4 decimal places
- mBTC, 2 decimal places
- µBTC, no decimal places
- Own name
- Name of yourself, to be added to payment requests. Try to keep it short.
- Auto-close send coins dialog
- When the payment is made, the send dialog will close automatically.
- Connectivity indicator
- Show current number of connected peers in the notification area.
- Trusted peer
- IP or hostname of single peer to connect to.
- Resolving…
- Unknown hostname!
- Skip regular peer discovery
- Prevents connecting to any peers besides the trusted peer.
- Block explorer
- External block explorer to use for browsing transactions, addresses and blocks.
- Data usage
- Show options to restrict data usage on mobile networks.
- Balance reminder
- After a couple of weeks of not being used, the app will notify if there are still coins in the wallet.
- Report issue
- Collect information about your issue and email your report to the developers.
- Reset block chain
- Reset block chain, transactions and wallet balance. Replay will take a while.
- Would you like to reset and replay the block chain?\n\nThis will temporarily hide your wallet balance and remove transactions. Both will recover as block chain sync progresses.
- Reset
- Show xpub
- View the extended public key of your wallet, so it can be imported into other apps and services. Be careful: doing so will disclose your monetary privacy to that app.
- Share…
- Extended Public Key
- Share xpub…
- Report issue
- Previous crash detected
- Please describe your issue precisely enough to be reproduced.
- Would you like to send a crash report, helping to fix this issue in the future?
- issue description
- Report
- Append device information
- Append list of installed packages
- Append application log
- Append wallet dump
- Send report using…
- Sending report failed.
+
+ today
+ (unlabeled)
+ PIN
+ bad PIN!
- About
- Version
- Copyright
- License
- Source code
- This app is using…
- bitcoinj %s, a Bitcoin protocol implementation
- ZXing, a QR-code processing library
- Scrypt, implemented by Will Glozer and Colin Percival
- Google+ community
- Discussions about the app
- Google Play page
- Review or rate the app
+
+ I/O error: %s
+ Parse error: %s
+ HTTP error %1$s:\n%2$s
+ Bluetooth error: %1$s
- Received %s
- %d peers connected
- You\'ve still got Bitcoins on this device!
- Remember your balance of %s will be lost if you uninstall the Bitcoin Wallet app without sending it away first.
- If you don\'t care about your coins, you could also donate them to the Bitcoin Wallet project.
- Remind me later
- Don\'t remind me
-
- Bitcoin balance
-
-
- OK
- Dismiss
- Cancel
- Retry
- Help
- Add
- Delete
- Set
- Remove
- Edit
- Copy
- Paste
- Share
- Set as default
- Request coins
- Send coins
- Scan
- Settings
- Show QR code
- Browse
-
-
- today
- (unlabeled)
- PIN
- bad PIN!
-
-
- I/O error: %s
- Parse error: %s
- HTTP error %1$s:\n%2$s
- Bluetooth error: %1$s
-
-
+
\ No newline at end of file
diff --git a/wallet/res/values/strings_help.xml b/wallet/res/values/strings_help.xml
index d1b12d0e39..5f3b9b6add 100644
--- a/wallet/res/values/strings_help.xml
+++ b/wallet/res/values/strings_help.xml
@@ -1,7 +1,7 @@
-
+
The upper left part of the screen displays your balance in Bitcoins and one selected national currency.
@@ -21,8 +21,8 @@
More options are available in the options menu.
]]>
-
-
+
+
Using this dialog, you can request coins from another person (who should already have installed Bitcoin Wallet).
@@ -40,8 +40,8 @@
If she accepts, all she needs to do is sending the payment.
]]>
-
-
+
+
You have initiated the process of sending coins.
@@ -70,8 +70,8 @@
Always check the receiving address.
]]>
-
-
+
+ Important safety notes:
@@ -104,6 +104,6 @@
Only use with small amounts for day use.
]]>
-
+
-
+
\ No newline at end of file
diff --git a/wallet/res/values/styles.xml b/wallet/res/values/styles.xml
index e58919c246..52f1ed6cf6 100644
--- a/wallet/res/values/styles.xml
+++ b/wallet/res/values/styles.xml
@@ -1,118 +1,118 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/values/values.xml b/wallet/res/values/values.xml
index 15f4e4dea0..c0901e26e4 100644
--- a/wallet/res/values/values.xml
+++ b/wallet/res/values/values.xml
@@ -1,33 +1,33 @@
- →
- ←
- ⇄
- Bitcoin Wallet [testnet3]
- Testnet3
+ →
+ ←
+ ⇄
+ Bitcoin Wallet [testnet3]
+ Testnet3
-
- 8
- 6
- 4
- 2/3
- 0/6
-
-
- @string/preferences_precision_labels_8
- @string/preferences_precision_labels_6
- @string/preferences_precision_labels_4
- @string/preferences_precision_labels_2_3
- @string/preferences_precision_labels_0_6
-
-
- https://testnet.blockexplorer.com/
- https://www.biteasy.com/testnet/
-
-
- blockexplorer.com
- BitEasy
-
+
+ 8
+ 6
+ 4
+ 2/3
+ 0/6
+
+
+ @string/preferences_precision_labels_8
+ @string/preferences_precision_labels_6
+ @string/preferences_precision_labels_4
+ @string/preferences_precision_labels_2_3
+ @string/preferences_precision_labels_0_6
+
+
+ https://testnet.blockexplorer.com/
+ https://www.biteasy.com/testnet/
+
+
+ blockexplorer.com
+ BitEasy
+
\ No newline at end of file
diff --git a/wallet/res/xml-v16/wallet_balance_widget.xml b/wallet/res/xml-v16/wallet_balance_widget.xml
index d625c3ae68..3e749aad9e 100644
--- a/wallet/res/xml-v16/wallet_balance_widget.xml
+++ b/wallet/res/xml-v16/wallet_balance_widget.xml
@@ -1,9 +1,9 @@
+ android:initialLayout="@layout/wallet_balance_widget_content"
+ android:minHeight="60dp"
+ android:minResizeWidth="132dp"
+ android:minWidth="294dp"
+ android:previewImage="@drawable/widget_preview"
+ android:resizeMode="horizontal"
+ android:updatePeriodMillis="1800000" />
diff --git a/wallet/res/xml/preference_about.xml b/wallet/res/xml/preference_about.xml
index 7f984f56c3..e07ad57135 100644
--- a/wallet/res/xml/preference_about.xml
+++ b/wallet/res/xml/preference_about.xml
@@ -1,73 +1,73 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/xml/preference_diagnostics.xml b/wallet/res/xml/preference_diagnostics.xml
index 3f68467b06..217e52d388 100644
--- a/wallet/res/xml/preference_diagnostics.xml
+++ b/wallet/res/xml/preference_diagnostics.xml
@@ -1,17 +1,17 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/wallet/res/xml/preference_headers.xml b/wallet/res/xml/preference_headers.xml
index 056198824e..f63b7b948e 100644
--- a/wallet/res/xml/preference_headers.xml
+++ b/wallet/res/xml/preference_headers.xml
@@ -1,14 +1,14 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/wallet/res/xml/preference_settings.xml b/wallet/res/xml/preference_settings.xml
index 7414ecc101..cf4665747c 100644
--- a/wallet/res/xml/preference_settings.xml
+++ b/wallet/res/xml/preference_settings.xml
@@ -1,84 +1,84 @@
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
-
+
+
+
-
+
-
-
+
+
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/wallet/res/xml/wallet_balance_widget.xml b/wallet/res/xml/wallet_balance_widget.xml
index 6e7bc5a8f9..555ab75384 100644
--- a/wallet/res/xml/wallet_balance_widget.xml
+++ b/wallet/res/xml/wallet_balance_widget.xml
@@ -1,7 +1,7 @@
+ android:initialLayout="@layout/wallet_balance_widget_content"
+ android:minHeight="60dp"
+ android:minWidth="294dp"
+ android:previewImage="@drawable/widget_preview"
+ android:updatePeriodMillis="1800000" />
diff --git a/wallet/src/de/schildbach/wallet/AddressBookProvider.java b/wallet/src/de/schildbach/wallet/AddressBookProvider.java
index 1e56752343..9eb0dd29c6 100644
--- a/wallet/src/de/schildbach/wallet/AddressBookProvider.java
+++ b/wallet/src/de/schildbach/wallet/AddressBookProvider.java
@@ -31,216 +31,190 @@
/**
* @author Andreas Schildbach
*/
-public class AddressBookProvider extends ContentProvider
-{
- private static final String DATABASE_TABLE = "address_book";
+public class AddressBookProvider extends ContentProvider {
+ private static final String DATABASE_TABLE = "address_book";
- public static final String KEY_ROWID = "_id";
- public static final String KEY_ADDRESS = "address";
- public static final String KEY_LABEL = "label";
+ public static final String KEY_ROWID = "_id";
+ public static final String KEY_ADDRESS = "address";
+ public static final String KEY_LABEL = "label";
- public static final String SELECTION_QUERY = "q";
- public static final String SELECTION_IN = "in";
- public static final String SELECTION_NOTIN = "notin";
+ public static final String SELECTION_QUERY = "q";
+ public static final String SELECTION_IN = "in";
+ public static final String SELECTION_NOTIN = "notin";
- public static Uri contentUri(final String packageName)
- {
- return Uri.parse("content://" + packageName + '.' + DATABASE_TABLE);
- }
+ public static Uri contentUri(final String packageName) {
+ return Uri.parse("content://" + packageName + '.' + DATABASE_TABLE);
+ }
- public static String resolveLabel(final Context context, final String address)
- {
- String label = null;
+ public static String resolveLabel(final Context context, final String address) {
+ String label = null;
- final Uri uri = contentUri(context.getPackageName()).buildUpon().appendPath(address).build();
- final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
+ final Uri uri = contentUri(context.getPackageName()).buildUpon().appendPath(address).build();
+ final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
- if (cursor != null)
- {
- if (cursor.moveToFirst())
- label = cursor.getString(cursor.getColumnIndexOrThrow(AddressBookProvider.KEY_LABEL));
+ if (cursor != null) {
+ if (cursor.moveToFirst())
+ label = cursor.getString(cursor.getColumnIndexOrThrow(AddressBookProvider.KEY_LABEL));
- cursor.close();
- }
+ cursor.close();
+ }
- return label;
- }
+ return label;
+ }
- private Helper helper;
+ private Helper helper;
- @Override
- public boolean onCreate()
- {
- helper = new Helper(getContext());
- return true;
- }
-
- @Override
- public String getType(final Uri uri)
- {
- throw new UnsupportedOperationException();
- }
+ @Override
+ public boolean onCreate() {
+ helper = new Helper(getContext());
+ return true;
+ }
- @Override
- public Uri insert(final Uri uri, final ContentValues values)
- {
- if (uri.getPathSegments().size() != 1)
- throw new IllegalArgumentException(uri.toString());
-
- final String address = uri.getLastPathSegment();
- values.put(KEY_ADDRESS, address);
-
- long rowId = helper.getWritableDatabase().insertOrThrow(DATABASE_TABLE, null, values);
-
- final Uri rowUri = contentUri(getContext().getPackageName()).buildUpon().appendPath(address).appendPath(Long.toString(rowId)).build();
-
- getContext().getContentResolver().notifyChange(rowUri, null);
-
- return rowUri;
- }
-
- @Override
- public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs)
- {
- if (uri.getPathSegments().size() != 1)
- throw new IllegalArgumentException(uri.toString());
-
- final String address = uri.getLastPathSegment();
-
- final int count = helper.getWritableDatabase().update(DATABASE_TABLE, values, KEY_ADDRESS + "=?", new String[] { address });
-
- if (count > 0)
- getContext().getContentResolver().notifyChange(uri, null);
-
- return count;
- }
-
- @Override
- public int delete(final Uri uri, final String selection, final String[] selectionArgs)
- {
- final List pathSegments = uri.getPathSegments();
- if (pathSegments.size() != 1)
- throw new IllegalArgumentException(uri.toString());
-
- final String address = uri.getLastPathSegment();
-
- final int count = helper.getWritableDatabase().delete(DATABASE_TABLE, KEY_ADDRESS + "=?", new String[] { address });
-
- if (count > 0)
- getContext().getContentResolver().notifyChange(uri, null);
-
- return count;
- }
-
- @Override
- public Cursor query(final Uri uri, final String[] projection, final String originalSelection, final String[] originalSelectionArgs,
- final String sortOrder)
- {
- final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(DATABASE_TABLE);
-
- final List pathSegments = uri.getPathSegments();
- if (pathSegments.size() > 1)
- throw new IllegalArgumentException(uri.toString());
-
- String selection = null;
- String[] selectionArgs = null;
-
- if (pathSegments.size() == 1)
- {
- final String address = uri.getLastPathSegment();
-
- qb.appendWhere(KEY_ADDRESS + "=");
- qb.appendWhereEscapeString(address);
- }
- else if (SELECTION_IN.equals(originalSelection))
- {
- final String[] addresses = originalSelectionArgs[0].trim().split(",");
-
- qb.appendWhere(KEY_ADDRESS + " IN (");
- appendAddresses(qb, addresses);
- qb.appendWhere(")");
- }
- else if (SELECTION_NOTIN.equals(originalSelection))
- {
- final String[] addresses = originalSelectionArgs[0].trim().split(",");
-
- qb.appendWhere(KEY_ADDRESS + " NOT IN (");
- appendAddresses(qb, addresses);
- qb.appendWhere(")");
- }
- else if (SELECTION_QUERY.equals(originalSelection))
- {
- final String query = '%' + originalSelectionArgs[0].trim() + '%';
- selection = KEY_ADDRESS + " LIKE ? OR " + KEY_LABEL + " LIKE ?";
- selectionArgs = new String[] { query, query };
- }
-
- final Cursor cursor = qb.query(helper.getReadableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
-
- cursor.setNotificationUri(getContext().getContentResolver(), uri);
-
- return cursor;
- }
-
- private static void appendAddresses(final SQLiteQueryBuilder qb, final String[] addresses)
- {
- for (final String address : addresses)
- {
- qb.appendWhereEscapeString(address.trim());
- if (!address.equals(addresses[addresses.length - 1]))
- qb.appendWhere(",");
- }
- }
-
- private static class Helper extends SQLiteOpenHelper
- {
- private static final String DATABASE_NAME = "address_book";
- private static final int DATABASE_VERSION = 1;
-
- private static final String DATABASE_CREATE = "CREATE TABLE " + DATABASE_TABLE + " (" //
- + KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " //
- + KEY_ADDRESS + " TEXT NOT NULL, " //
- + KEY_LABEL + " TEXT NULL);";
-
- public Helper(final Context context)
- {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
-
- @Override
- public void onCreate(final SQLiteDatabase db)
- {
- db.execSQL(DATABASE_CREATE);
- }
-
- @Override
- public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion)
- {
- db.beginTransaction();
- try
- {
- for (int v = oldVersion; v < newVersion; v++)
- upgrade(db, v);
-
- db.setTransactionSuccessful();
- }
- finally
- {
- db.endTransaction();
- }
- }
-
- private void upgrade(final SQLiteDatabase db, final int oldVersion)
- {
- if (oldVersion == 1)
- {
- // future
- }
- else
- {
- throw new UnsupportedOperationException("old=" + oldVersion);
- }
- }
- }
+ @Override
+ public String getType(final Uri uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Uri insert(final Uri uri, final ContentValues values) {
+ if (uri.getPathSegments().size() != 1)
+ throw new IllegalArgumentException(uri.toString());
+
+ final String address = uri.getLastPathSegment();
+ values.put(KEY_ADDRESS, address);
+
+ long rowId = helper.getWritableDatabase().insertOrThrow(DATABASE_TABLE, null, values);
+
+ final Uri rowUri = contentUri(getContext().getPackageName()).buildUpon().appendPath(address)
+ .appendPath(Long.toString(rowId)).build();
+
+ getContext().getContentResolver().notifyChange(rowUri, null);
+
+ return rowUri;
+ }
+
+ @Override
+ public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
+ if (uri.getPathSegments().size() != 1)
+ throw new IllegalArgumentException(uri.toString());
+
+ final String address = uri.getLastPathSegment();
+
+ final int count = helper.getWritableDatabase().update(DATABASE_TABLE, values, KEY_ADDRESS + "=?",
+ new String[] { address });
+
+ if (count > 0)
+ getContext().getContentResolver().notifyChange(uri, null);
+
+ return count;
+ }
+
+ @Override
+ public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
+ final List pathSegments = uri.getPathSegments();
+ if (pathSegments.size() != 1)
+ throw new IllegalArgumentException(uri.toString());
+
+ final String address = uri.getLastPathSegment();
+
+ final int count = helper.getWritableDatabase().delete(DATABASE_TABLE, KEY_ADDRESS + "=?",
+ new String[] { address });
+
+ if (count > 0)
+ getContext().getContentResolver().notifyChange(uri, null);
+
+ return count;
+ }
+
+ @Override
+ public Cursor query(final Uri uri, final String[] projection, final String originalSelection,
+ final String[] originalSelectionArgs, final String sortOrder) {
+ final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+ qb.setTables(DATABASE_TABLE);
+
+ final List pathSegments = uri.getPathSegments();
+ if (pathSegments.size() > 1)
+ throw new IllegalArgumentException(uri.toString());
+
+ String selection = null;
+ String[] selectionArgs = null;
+
+ if (pathSegments.size() == 1) {
+ final String address = uri.getLastPathSegment();
+
+ qb.appendWhere(KEY_ADDRESS + "=");
+ qb.appendWhereEscapeString(address);
+ } else if (SELECTION_IN.equals(originalSelection)) {
+ final String[] addresses = originalSelectionArgs[0].trim().split(",");
+
+ qb.appendWhere(KEY_ADDRESS + " IN (");
+ appendAddresses(qb, addresses);
+ qb.appendWhere(")");
+ } else if (SELECTION_NOTIN.equals(originalSelection)) {
+ final String[] addresses = originalSelectionArgs[0].trim().split(",");
+
+ qb.appendWhere(KEY_ADDRESS + " NOT IN (");
+ appendAddresses(qb, addresses);
+ qb.appendWhere(")");
+ } else if (SELECTION_QUERY.equals(originalSelection)) {
+ final String query = '%' + originalSelectionArgs[0].trim() + '%';
+ selection = KEY_ADDRESS + " LIKE ? OR " + KEY_LABEL + " LIKE ?";
+ selectionArgs = new String[] { query, query };
+ }
+
+ final Cursor cursor = qb.query(helper.getReadableDatabase(), projection, selection, selectionArgs, null, null,
+ sortOrder);
+
+ cursor.setNotificationUri(getContext().getContentResolver(), uri);
+
+ return cursor;
+ }
+
+ private static void appendAddresses(final SQLiteQueryBuilder qb, final String[] addresses) {
+ for (final String address : addresses) {
+ qb.appendWhereEscapeString(address.trim());
+ if (!address.equals(addresses[addresses.length - 1]))
+ qb.appendWhere(",");
+ }
+ }
+
+ private static class Helper extends SQLiteOpenHelper {
+ private static final String DATABASE_NAME = "address_book";
+ private static final int DATABASE_VERSION = 1;
+
+ private static final String DATABASE_CREATE = "CREATE TABLE " + DATABASE_TABLE + " (" //
+ + KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " //
+ + KEY_ADDRESS + " TEXT NOT NULL, " //
+ + KEY_LABEL + " TEXT NULL);";
+
+ public Helper(final Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(final SQLiteDatabase db) {
+ db.execSQL(DATABASE_CREATE);
+ }
+
+ @Override
+ public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
+ db.beginTransaction();
+ try {
+ for (int v = oldVersion; v < newVersion; v++)
+ upgrade(db, v);
+
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ private void upgrade(final SQLiteDatabase db, final int oldVersion) {
+ if (oldVersion == 1) {
+ // future
+ } else {
+ throw new UnsupportedOperationException("old=" + oldVersion);
+ }
+ }
+ }
}
diff --git a/wallet/src/de/schildbach/wallet/Configuration.java b/wallet/src/de/schildbach/wallet/Configuration.java
index 7aabba860b..75db9c9161 100644
--- a/wallet/src/de/schildbach/wallet/Configuration.java
+++ b/wallet/src/de/schildbach/wallet/Configuration.java
@@ -23,6 +23,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Strings;
+
+import de.schildbach.wallet.ExchangeRatesProvider.ExchangeRate;
+import de.schildbach.wallet_test.R;
+
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
@@ -30,300 +35,259 @@
import android.net.Uri;
import android.text.format.DateUtils;
-import com.google.common.base.Strings;
-
-import de.schildbach.wallet.ExchangeRatesProvider.ExchangeRate;
-import de.schildbach.wallet_test.R;
-
/**
* @author Andreas Schildbach
*/
-public class Configuration
-{
- public final int lastVersionCode;
-
- private final SharedPreferences prefs;
- private final Resources res;
-
- public static final String PREFS_KEY_BTC_PRECISION = "btc_precision";
- public static final String PREFS_KEY_OWN_NAME = "own_name";
- public static final String PREFS_KEY_SEND_COINS_AUTOCLOSE = "send_coins_autoclose";
- public static final String PREFS_KEY_CONNECTIVITY_NOTIFICATION = "connectivity_notification";
- public static final String PREFS_KEY_EXCHANGE_CURRENCY = "exchange_currency";
- public static final String PREFS_KEY_TRUSTED_PEER = "trusted_peer";
- public static final String PREFS_KEY_TRUSTED_PEER_ONLY = "trusted_peer_only";
- public static final String PREFS_KEY_BLOCK_EXPLORER = "block_explorer";
- public static final String PREFS_KEY_DATA_USAGE = "data_usage";
- public static final String PREFS_KEY_REMIND_BALANCE = "remind_balance";
- public static final String PREFS_KEY_DISCLAIMER = "disclaimer";
- private static final String PREFS_KEY_LABS_QR_PAYMENT_REQUEST = "labs_qr_payment_request";
- private static final String PREFS_KEY_LOOK_UP_WALLET_NAMES = "look_up_wallet_names";
-
- private static final String PREFS_KEY_LAST_VERSION = "last_version";
- private static final String PREFS_KEY_LAST_USED = "last_used";
- private static final String PREFS_KEY_BEST_CHAIN_HEIGHT_EVER = "best_chain_height_ever";
- private static final String PREFS_KEY_CACHED_EXCHANGE_CURRENCY = "cached_exchange_currency";
- private static final String PREFS_KEY_CACHED_EXCHANGE_RATE_COIN = "cached_exchange_rate_coin";
- private static final String PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT = "cached_exchange_rate_fiat";
- private static final String PREFS_KEY_LAST_EXCHANGE_DIRECTION = "last_exchange_direction";
- private static final String PREFS_KEY_CHANGE_LOG_VERSION = "change_log_version";
- public static final String PREFS_KEY_REMIND_BACKUP = "remind_backup";
- private static final String PREFS_KEY_LAST_BACKUP = "last_backup";
-
- private static final int PREFS_DEFAULT_BTC_SHIFT = 3;
- private static final int PREFS_DEFAULT_BTC_PRECISION = 2;
-
- private static final Logger log = LoggerFactory.getLogger(Configuration.class);
-
- public Configuration(final SharedPreferences prefs, final Resources res)
- {
- this.prefs = prefs;
- this.res = res;
-
- this.lastVersionCode = prefs.getInt(PREFS_KEY_LAST_VERSION, 0);
- }
-
- private int getBtcPrecision()
- {
- final String precision = prefs.getString(PREFS_KEY_BTC_PRECISION, null);
- if (precision != null)
- return precision.charAt(0) - '0';
- else
- return PREFS_DEFAULT_BTC_PRECISION;
- }
-
- public int getBtcShift()
- {
- final String precision = prefs.getString(PREFS_KEY_BTC_PRECISION, null);
- if (precision != null)
- return precision.length() == 3 ? precision.charAt(2) - '0' : 0;
- else
- return PREFS_DEFAULT_BTC_SHIFT;
- }
-
- public Coin getBtcBase()
- {
- final int shift = getBtcShift();
- if (shift == 0)
- return Coin.COIN;
- else if (shift == 3)
- return Coin.MILLICOIN;
- else if (shift == 6)
- return Coin.MICROCOIN;
- else
- throw new IllegalStateException("cannot handle shift: " + shift);
- }
-
- public MonetaryFormat getFormat()
- {
- final int shift = getBtcShift();
- final int minPrecision = shift <= 3 ? 2 : 0;
- final int decimalRepetitions = (getBtcPrecision() - minPrecision) / 2;
- return new MonetaryFormat().shift(shift).minDecimals(minPrecision).repeatOptionalDecimals(2, decimalRepetitions);
- }
-
- public MonetaryFormat getMaxPrecisionFormat()
- {
- final int shift = getBtcShift();
- if (shift == 0)
- return new MonetaryFormat().shift(0).minDecimals(2).optionalDecimals(2, 2, 2);
- else if (shift == 3)
- return new MonetaryFormat().shift(3).minDecimals(2).optionalDecimals(2, 1);
- else
- return new MonetaryFormat().shift(6).minDecimals(0).optionalDecimals(2);
- }
-
- public String getOwnName()
- {
- return Strings.emptyToNull(prefs.getString(PREFS_KEY_OWN_NAME, "").trim());
- }
-
- public boolean getSendCoinsAutoclose()
- {
- return prefs.getBoolean(PREFS_KEY_SEND_COINS_AUTOCLOSE, true);
- }
-
- public boolean getConnectivityNotificationEnabled()
- {
- return prefs.getBoolean(PREFS_KEY_CONNECTIVITY_NOTIFICATION, false);
- }
-
- public String getTrustedPeerHost()
- {
- return Strings.emptyToNull(prefs.getString(PREFS_KEY_TRUSTED_PEER, "").trim());
- }
-
- public boolean getTrustedPeerOnly()
- {
- return prefs.getBoolean(PREFS_KEY_TRUSTED_PEER_ONLY, false);
- }
-
- public Uri getBlockExplorer()
- {
- return Uri.parse(prefs.getString(PREFS_KEY_BLOCK_EXPLORER, res.getStringArray(R.array.preferences_block_explorer_values)[0]));
- }
-
- public boolean remindBalance()
- {
- return prefs.getBoolean(PREFS_KEY_REMIND_BALANCE, true);
- }
-
- public void setRemindBalance(final boolean remindBalance)
- {
- prefs.edit().putBoolean(PREFS_KEY_REMIND_BALANCE, remindBalance).apply();
- }
-
- public boolean remindBackup()
- {
- return prefs.getBoolean(PREFS_KEY_REMIND_BACKUP, true);
- }
-
- public long getLastBackupTime()
- {
- return prefs.getLong(PREFS_KEY_LAST_BACKUP, 0);
- }
-
- public void armBackupReminder()
- {
- prefs.edit().putBoolean(PREFS_KEY_REMIND_BACKUP, true).apply();
- }
-
- public void disarmBackupReminder()
- {
- prefs.edit().putBoolean(PREFS_KEY_REMIND_BACKUP, false).putLong(PREFS_KEY_LAST_BACKUP, System.currentTimeMillis()).apply();
- }
-
- public boolean getDisclaimerEnabled()
- {
- return prefs.getBoolean(PREFS_KEY_DISCLAIMER, true);
- }
-
- public String getExchangeCurrencyCode()
- {
- return prefs.getString(PREFS_KEY_EXCHANGE_CURRENCY, null);
- }
-
- public void setExchangeCurrencyCode(final String exchangeCurrencyCode)
- {
- prefs.edit().putString(PREFS_KEY_EXCHANGE_CURRENCY, exchangeCurrencyCode).apply();
- }
-
- public boolean getQrPaymentRequestEnabled()
- {
- return prefs.getBoolean(PREFS_KEY_LABS_QR_PAYMENT_REQUEST, false);
- }
-
- public boolean getLookUpWalletNames()
- {
- return prefs.getBoolean(PREFS_KEY_LOOK_UP_WALLET_NAMES, false);
- }
-
- public boolean versionCodeCrossed(final int currentVersionCode, final int triggeringVersionCode)
- {
- final boolean wasBelow = lastVersionCode < triggeringVersionCode;
- final boolean wasUsedBefore = lastVersionCode > 0;
- final boolean isNowAbove = currentVersionCode >= triggeringVersionCode;
-
- return wasUsedBefore && wasBelow && isNowAbove;
- }
-
- public void updateLastVersionCode(final int currentVersionCode)
- {
- prefs.edit().putInt(PREFS_KEY_LAST_VERSION, currentVersionCode).apply();
-
- if (currentVersionCode > lastVersionCode)
- log.info("detected app upgrade: " + lastVersionCode + " -> " + currentVersionCode);
- else if (currentVersionCode < lastVersionCode)
- log.warn("detected app downgrade: " + lastVersionCode + " -> " + currentVersionCode);
- }
-
- public boolean hasBeenUsed()
- {
- return prefs.contains(PREFS_KEY_LAST_USED);
- }
-
- public long getLastUsedAgo()
- {
- final long now = System.currentTimeMillis();
-
- return now - prefs.getLong(PREFS_KEY_LAST_USED, 0);
- }
-
- public void touchLastUsed()
- {
- final long prefsLastUsed = prefs.getLong(PREFS_KEY_LAST_USED, 0);
- final long now = System.currentTimeMillis();
- prefs.edit().putLong(PREFS_KEY_LAST_USED, now).apply();
-
- log.info("just being used - last used {} minutes ago", (now - prefsLastUsed) / DateUtils.MINUTE_IN_MILLIS);
- }
-
- public int getBestChainHeightEver()
- {
- return prefs.getInt(PREFS_KEY_BEST_CHAIN_HEIGHT_EVER, 0);
- }
-
- public void maybeIncrementBestChainHeightEver(final int bestChainHeightEver)
- {
- if (bestChainHeightEver > getBestChainHeightEver())
- prefs.edit().putInt(PREFS_KEY_BEST_CHAIN_HEIGHT_EVER, bestChainHeightEver).apply();
- }
-
- public ExchangeRate getCachedExchangeRate()
- {
- if (prefs.contains(PREFS_KEY_CACHED_EXCHANGE_CURRENCY) && prefs.contains(PREFS_KEY_CACHED_EXCHANGE_RATE_COIN)
- && prefs.contains(PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT))
- {
- final String cachedExchangeCurrency = prefs.getString(PREFS_KEY_CACHED_EXCHANGE_CURRENCY, null);
- final Coin cachedExchangeRateCoin = Coin.valueOf(prefs.getLong(PREFS_KEY_CACHED_EXCHANGE_RATE_COIN, 0));
- final Fiat cachedExchangeRateFiat = Fiat.valueOf(cachedExchangeCurrency, prefs.getLong(PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT, 0));
- return new ExchangeRate(new org.bitcoinj.utils.ExchangeRate(cachedExchangeRateCoin, cachedExchangeRateFiat), null);
- }
- else
- {
- return null;
- }
- }
-
- public void setCachedExchangeRate(final ExchangeRate cachedExchangeRate)
- {
- final Editor edit = prefs.edit();
- edit.putString(PREFS_KEY_CACHED_EXCHANGE_CURRENCY, cachedExchangeRate.getCurrencyCode());
- edit.putLong(PREFS_KEY_CACHED_EXCHANGE_RATE_COIN, cachedExchangeRate.rate.coin.value);
- edit.putLong(PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT, cachedExchangeRate.rate.fiat.value);
- edit.apply();
- }
-
- public boolean getLastExchangeDirection()
- {
- return prefs.getBoolean(PREFS_KEY_LAST_EXCHANGE_DIRECTION, true);
- }
-
- public void setLastExchangeDirection(final boolean exchangeDirection)
- {
- prefs.edit().putBoolean(PREFS_KEY_LAST_EXCHANGE_DIRECTION, exchangeDirection).apply();
- }
-
- public boolean changeLogVersionCodeCrossed(final int currentVersionCode, final int triggeringVersionCode)
- {
- final int changeLogVersion = prefs.getInt(PREFS_KEY_CHANGE_LOG_VERSION, 0);
-
- final boolean wasBelow = changeLogVersion < triggeringVersionCode;
- final boolean wasUsedBefore = changeLogVersion > 0;
- final boolean isNowAbove = currentVersionCode >= triggeringVersionCode;
-
- prefs.edit().putInt(PREFS_KEY_CHANGE_LOG_VERSION, currentVersionCode).apply();
-
- return /* wasUsedBefore && */wasBelow && isNowAbove;
- }
-
- public void registerOnSharedPreferenceChangeListener(final OnSharedPreferenceChangeListener listener)
- {
- prefs.registerOnSharedPreferenceChangeListener(listener);
- }
-
- public void unregisterOnSharedPreferenceChangeListener(final OnSharedPreferenceChangeListener listener)
- {
- prefs.unregisterOnSharedPreferenceChangeListener(listener);
- }
+public class Configuration {
+ public final int lastVersionCode;
+
+ private final SharedPreferences prefs;
+ private final Resources res;
+
+ public static final String PREFS_KEY_BTC_PRECISION = "btc_precision";
+ public static final String PREFS_KEY_OWN_NAME = "own_name";
+ public static final String PREFS_KEY_SEND_COINS_AUTOCLOSE = "send_coins_autoclose";
+ public static final String PREFS_KEY_CONNECTIVITY_NOTIFICATION = "connectivity_notification";
+ public static final String PREFS_KEY_EXCHANGE_CURRENCY = "exchange_currency";
+ public static final String PREFS_KEY_TRUSTED_PEER = "trusted_peer";
+ public static final String PREFS_KEY_TRUSTED_PEER_ONLY = "trusted_peer_only";
+ public static final String PREFS_KEY_BLOCK_EXPLORER = "block_explorer";
+ public static final String PREFS_KEY_DATA_USAGE = "data_usage";
+ public static final String PREFS_KEY_REMIND_BALANCE = "remind_balance";
+ public static final String PREFS_KEY_DISCLAIMER = "disclaimer";
+ private static final String PREFS_KEY_LABS_QR_PAYMENT_REQUEST = "labs_qr_payment_request";
+ private static final String PREFS_KEY_LOOK_UP_WALLET_NAMES = "look_up_wallet_names";
+
+ private static final String PREFS_KEY_LAST_VERSION = "last_version";
+ private static final String PREFS_KEY_LAST_USED = "last_used";
+ private static final String PREFS_KEY_BEST_CHAIN_HEIGHT_EVER = "best_chain_height_ever";
+ private static final String PREFS_KEY_CACHED_EXCHANGE_CURRENCY = "cached_exchange_currency";
+ private static final String PREFS_KEY_CACHED_EXCHANGE_RATE_COIN = "cached_exchange_rate_coin";
+ private static final String PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT = "cached_exchange_rate_fiat";
+ private static final String PREFS_KEY_LAST_EXCHANGE_DIRECTION = "last_exchange_direction";
+ private static final String PREFS_KEY_CHANGE_LOG_VERSION = "change_log_version";
+ public static final String PREFS_KEY_REMIND_BACKUP = "remind_backup";
+ private static final String PREFS_KEY_LAST_BACKUP = "last_backup";
+
+ private static final int PREFS_DEFAULT_BTC_SHIFT = 3;
+ private static final int PREFS_DEFAULT_BTC_PRECISION = 2;
+
+ private static final Logger log = LoggerFactory.getLogger(Configuration.class);
+
+ public Configuration(final SharedPreferences prefs, final Resources res) {
+ this.prefs = prefs;
+ this.res = res;
+
+ this.lastVersionCode = prefs.getInt(PREFS_KEY_LAST_VERSION, 0);
+ }
+
+ private int getBtcPrecision() {
+ final String precision = prefs.getString(PREFS_KEY_BTC_PRECISION, null);
+ if (precision != null)
+ return precision.charAt(0) - '0';
+ else
+ return PREFS_DEFAULT_BTC_PRECISION;
+ }
+
+ public int getBtcShift() {
+ final String precision = prefs.getString(PREFS_KEY_BTC_PRECISION, null);
+ if (precision != null)
+ return precision.length() == 3 ? precision.charAt(2) - '0' : 0;
+ else
+ return PREFS_DEFAULT_BTC_SHIFT;
+ }
+
+ public Coin getBtcBase() {
+ final int shift = getBtcShift();
+ if (shift == 0)
+ return Coin.COIN;
+ else if (shift == 3)
+ return Coin.MILLICOIN;
+ else if (shift == 6)
+ return Coin.MICROCOIN;
+ else
+ throw new IllegalStateException("cannot handle shift: " + shift);
+ }
+
+ public MonetaryFormat getFormat() {
+ final int shift = getBtcShift();
+ final int minPrecision = shift <= 3 ? 2 : 0;
+ final int decimalRepetitions = (getBtcPrecision() - minPrecision) / 2;
+ return new MonetaryFormat().shift(shift).minDecimals(minPrecision).repeatOptionalDecimals(2,
+ decimalRepetitions);
+ }
+
+ public MonetaryFormat getMaxPrecisionFormat() {
+ final int shift = getBtcShift();
+ if (shift == 0)
+ return new MonetaryFormat().shift(0).minDecimals(2).optionalDecimals(2, 2, 2);
+ else if (shift == 3)
+ return new MonetaryFormat().shift(3).minDecimals(2).optionalDecimals(2, 1);
+ else
+ return new MonetaryFormat().shift(6).minDecimals(0).optionalDecimals(2);
+ }
+
+ public String getOwnName() {
+ return Strings.emptyToNull(prefs.getString(PREFS_KEY_OWN_NAME, "").trim());
+ }
+
+ public boolean getSendCoinsAutoclose() {
+ return prefs.getBoolean(PREFS_KEY_SEND_COINS_AUTOCLOSE, true);
+ }
+
+ public boolean getConnectivityNotificationEnabled() {
+ return prefs.getBoolean(PREFS_KEY_CONNECTIVITY_NOTIFICATION, false);
+ }
+
+ public String getTrustedPeerHost() {
+ return Strings.emptyToNull(prefs.getString(PREFS_KEY_TRUSTED_PEER, "").trim());
+ }
+
+ public boolean getTrustedPeerOnly() {
+ return prefs.getBoolean(PREFS_KEY_TRUSTED_PEER_ONLY, false);
+ }
+
+ public Uri getBlockExplorer() {
+ return Uri.parse(prefs.getString(PREFS_KEY_BLOCK_EXPLORER,
+ res.getStringArray(R.array.preferences_block_explorer_values)[0]));
+ }
+
+ public boolean remindBalance() {
+ return prefs.getBoolean(PREFS_KEY_REMIND_BALANCE, true);
+ }
+
+ public void setRemindBalance(final boolean remindBalance) {
+ prefs.edit().putBoolean(PREFS_KEY_REMIND_BALANCE, remindBalance).apply();
+ }
+
+ public boolean remindBackup() {
+ return prefs.getBoolean(PREFS_KEY_REMIND_BACKUP, true);
+ }
+
+ public long getLastBackupTime() {
+ return prefs.getLong(PREFS_KEY_LAST_BACKUP, 0);
+ }
+
+ public void armBackupReminder() {
+ prefs.edit().putBoolean(PREFS_KEY_REMIND_BACKUP, true).apply();
+ }
+
+ public void disarmBackupReminder() {
+ prefs.edit().putBoolean(PREFS_KEY_REMIND_BACKUP, false)
+ .putLong(PREFS_KEY_LAST_BACKUP, System.currentTimeMillis()).apply();
+ }
+
+ public boolean getDisclaimerEnabled() {
+ return prefs.getBoolean(PREFS_KEY_DISCLAIMER, true);
+ }
+
+ public String getExchangeCurrencyCode() {
+ return prefs.getString(PREFS_KEY_EXCHANGE_CURRENCY, null);
+ }
+
+ public void setExchangeCurrencyCode(final String exchangeCurrencyCode) {
+ prefs.edit().putString(PREFS_KEY_EXCHANGE_CURRENCY, exchangeCurrencyCode).apply();
+ }
+
+ public boolean getQrPaymentRequestEnabled() {
+ return prefs.getBoolean(PREFS_KEY_LABS_QR_PAYMENT_REQUEST, false);
+ }
+
+ public boolean getLookUpWalletNames() {
+ return prefs.getBoolean(PREFS_KEY_LOOK_UP_WALLET_NAMES, false);
+ }
+
+ public boolean versionCodeCrossed(final int currentVersionCode, final int triggeringVersionCode) {
+ final boolean wasBelow = lastVersionCode < triggeringVersionCode;
+ final boolean wasUsedBefore = lastVersionCode > 0;
+ final boolean isNowAbove = currentVersionCode >= triggeringVersionCode;
+
+ return wasUsedBefore && wasBelow && isNowAbove;
+ }
+
+ public void updateLastVersionCode(final int currentVersionCode) {
+ prefs.edit().putInt(PREFS_KEY_LAST_VERSION, currentVersionCode).apply();
+
+ if (currentVersionCode > lastVersionCode)
+ log.info("detected app upgrade: " + lastVersionCode + " -> " + currentVersionCode);
+ else if (currentVersionCode < lastVersionCode)
+ log.warn("detected app downgrade: " + lastVersionCode + " -> " + currentVersionCode);
+ }
+
+ public boolean hasBeenUsed() {
+ return prefs.contains(PREFS_KEY_LAST_USED);
+ }
+
+ public long getLastUsedAgo() {
+ final long now = System.currentTimeMillis();
+
+ return now - prefs.getLong(PREFS_KEY_LAST_USED, 0);
+ }
+
+ public void touchLastUsed() {
+ final long prefsLastUsed = prefs.getLong(PREFS_KEY_LAST_USED, 0);
+ final long now = System.currentTimeMillis();
+ prefs.edit().putLong(PREFS_KEY_LAST_USED, now).apply();
+
+ log.info("just being used - last used {} minutes ago", (now - prefsLastUsed) / DateUtils.MINUTE_IN_MILLIS);
+ }
+
+ public int getBestChainHeightEver() {
+ return prefs.getInt(PREFS_KEY_BEST_CHAIN_HEIGHT_EVER, 0);
+ }
+
+ public void maybeIncrementBestChainHeightEver(final int bestChainHeightEver) {
+ if (bestChainHeightEver > getBestChainHeightEver())
+ prefs.edit().putInt(PREFS_KEY_BEST_CHAIN_HEIGHT_EVER, bestChainHeightEver).apply();
+ }
+
+ public ExchangeRate getCachedExchangeRate() {
+ if (prefs.contains(PREFS_KEY_CACHED_EXCHANGE_CURRENCY) && prefs.contains(PREFS_KEY_CACHED_EXCHANGE_RATE_COIN)
+ && prefs.contains(PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT)) {
+ final String cachedExchangeCurrency = prefs.getString(PREFS_KEY_CACHED_EXCHANGE_CURRENCY, null);
+ final Coin cachedExchangeRateCoin = Coin.valueOf(prefs.getLong(PREFS_KEY_CACHED_EXCHANGE_RATE_COIN, 0));
+ final Fiat cachedExchangeRateFiat = Fiat.valueOf(cachedExchangeCurrency,
+ prefs.getLong(PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT, 0));
+ return new ExchangeRate(new org.bitcoinj.utils.ExchangeRate(cachedExchangeRateCoin, cachedExchangeRateFiat),
+ null);
+ } else {
+ return null;
+ }
+ }
+
+ public void setCachedExchangeRate(final ExchangeRate cachedExchangeRate) {
+ final Editor edit = prefs.edit();
+ edit.putString(PREFS_KEY_CACHED_EXCHANGE_CURRENCY, cachedExchangeRate.getCurrencyCode());
+ edit.putLong(PREFS_KEY_CACHED_EXCHANGE_RATE_COIN, cachedExchangeRate.rate.coin.value);
+ edit.putLong(PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT, cachedExchangeRate.rate.fiat.value);
+ edit.apply();
+ }
+
+ public boolean getLastExchangeDirection() {
+ return prefs.getBoolean(PREFS_KEY_LAST_EXCHANGE_DIRECTION, true);
+ }
+
+ public void setLastExchangeDirection(final boolean exchangeDirection) {
+ prefs.edit().putBoolean(PREFS_KEY_LAST_EXCHANGE_DIRECTION, exchangeDirection).apply();
+ }
+
+ public boolean changeLogVersionCodeCrossed(final int currentVersionCode, final int triggeringVersionCode) {
+ final int changeLogVersion = prefs.getInt(PREFS_KEY_CHANGE_LOG_VERSION, 0);
+
+ final boolean wasBelow = changeLogVersion < triggeringVersionCode;
+ final boolean wasUsedBefore = changeLogVersion > 0;
+ final boolean isNowAbove = currentVersionCode >= triggeringVersionCode;
+
+ prefs.edit().putInt(PREFS_KEY_CHANGE_LOG_VERSION, currentVersionCode).apply();
+
+ return /* wasUsedBefore && */wasBelow && isNowAbove;
+ }
+
+ public void registerOnSharedPreferenceChangeListener(final OnSharedPreferenceChangeListener listener) {
+ prefs.registerOnSharedPreferenceChangeListener(listener);
+ }
+
+ public void unregisterOnSharedPreferenceChangeListener(final OnSharedPreferenceChangeListener listener) {
+ prefs.unregisterOnSharedPreferenceChangeListener(listener);
+ }
}
diff --git a/wallet/src/de/schildbach/wallet/Constants.java b/wallet/src/de/schildbach/wallet/Constants.java
index 4558c52b13..bce8cc258d 100644
--- a/wallet/src/de/schildbach/wallet/Constants.java
+++ b/wallet/src/de/schildbach/wallet/Constants.java
@@ -26,154 +26,155 @@
import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.utils.MonetaryFormat;
-import android.os.Build;
-import android.os.Environment;
-import android.text.format.DateUtils;
-
import com.google.common.io.BaseEncoding;
import com.squareup.okhttp.OkHttpClient;
import de.schildbach.wallet_test.R;
+import android.os.Build;
+import android.os.Environment;
+import android.text.format.DateUtils;
+
/**
* @author Andreas Schildbach
*/
-public final class Constants
-{
- public static final boolean TEST = R.class.getPackage().getName().contains("_test");
+public final class Constants {
+ public static final boolean TEST = R.class.getPackage().getName().contains("_test");
- /** Network this wallet is on (e.g. testnet or mainnet). */
- public static final NetworkParameters NETWORK_PARAMETERS = TEST ? TestNet3Params.get() : MainNetParams.get();
+ /** Network this wallet is on (e.g. testnet or mainnet). */
+ public static final NetworkParameters NETWORK_PARAMETERS = TEST ? TestNet3Params.get() : MainNetParams.get();
- /** Bitcoinj global context. */
- public static final Context CONTEXT = new Context(NETWORK_PARAMETERS);
+ /** Bitcoinj global context. */
+ public static final Context CONTEXT = new Context(NETWORK_PARAMETERS);
- public final static class Files
- {
- private static final String FILENAME_NETWORK_SUFFIX = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET) ? "" : "-testnet";
+ public final static class Files {
+ private static final String FILENAME_NETWORK_SUFFIX = NETWORK_PARAMETERS.getId()
+ .equals(NetworkParameters.ID_MAINNET) ? "" : "-testnet";
- /** Filename of the wallet. */
- public static final String WALLET_FILENAME_PROTOBUF = "wallet-protobuf" + FILENAME_NETWORK_SUFFIX;
+ /** Filename of the wallet. */
+ public static final String WALLET_FILENAME_PROTOBUF = "wallet-protobuf" + FILENAME_NETWORK_SUFFIX;
- /** How often the wallet is autosaved. */
- public static final long WALLET_AUTOSAVE_DELAY_MS = 5 * DateUtils.SECOND_IN_MILLIS;
+ /** How often the wallet is autosaved. */
+ public static final long WALLET_AUTOSAVE_DELAY_MS = 5 * DateUtils.SECOND_IN_MILLIS;
- /** Filename of the automatic key backup (old format, can only be read). */
- public static final String WALLET_KEY_BACKUP_BASE58 = "key-backup-base58" + FILENAME_NETWORK_SUFFIX;
+ /** Filename of the automatic key backup (old format, can only be read). */
+ public static final String WALLET_KEY_BACKUP_BASE58 = "key-backup-base58" + FILENAME_NETWORK_SUFFIX;
- /** Filename of the automatic wallet backup. */
- public static final String WALLET_KEY_BACKUP_PROTOBUF = "key-backup-protobuf" + FILENAME_NETWORK_SUFFIX;
+ /** Filename of the automatic wallet backup. */
+ public static final String WALLET_KEY_BACKUP_PROTOBUF = "key-backup-protobuf" + FILENAME_NETWORK_SUFFIX;
- /** Path to external storage */
- public static final File EXTERNAL_STORAGE_DIR = Environment.getExternalStorageDirectory();
+ /** Path to external storage */
+ public static final File EXTERNAL_STORAGE_DIR = Environment.getExternalStorageDirectory();
- /** Manual backups go here. */
- public static final File EXTERNAL_WALLET_BACKUP_DIR = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ /** Manual backups go here. */
+ public static final File EXTERNAL_WALLET_BACKUP_DIR = Environment
+ .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
- /** Filename of the manual key backup (old format, can only be read). */
- public static final String EXTERNAL_WALLET_KEY_BACKUP = "bitcoin-wallet-keys" + FILENAME_NETWORK_SUFFIX;
+ /** Filename of the manual key backup (old format, can only be read). */
+ public static final String EXTERNAL_WALLET_KEY_BACKUP = "bitcoin-wallet-keys" + FILENAME_NETWORK_SUFFIX;
- /** Filename of the manual wallet backup. */
- public static final String EXTERNAL_WALLET_BACKUP = "bitcoin-wallet-backup" + FILENAME_NETWORK_SUFFIX;
+ /** Filename of the manual wallet backup. */
+ public static final String EXTERNAL_WALLET_BACKUP = "bitcoin-wallet-backup" + FILENAME_NETWORK_SUFFIX;
- /** Filename of the block store for storing the chain. */
- public static final String BLOCKCHAIN_FILENAME = "blockchain" + FILENAME_NETWORK_SUFFIX;
+ /** Filename of the block store for storing the chain. */
+ public static final String BLOCKCHAIN_FILENAME = "blockchain" + FILENAME_NETWORK_SUFFIX;
- /** Filename of the block checkpoints file. */
- public static final String CHECKPOINTS_FILENAME = "checkpoints" + FILENAME_NETWORK_SUFFIX + ".txt";
- }
+ /** Filename of the block checkpoints file. */
+ public static final String CHECKPOINTS_FILENAME = "checkpoints" + FILENAME_NETWORK_SUFFIX + ".txt";
+ }
- /** Maximum size of backups. Files larger will be rejected. */
- public static final long BACKUP_MAX_CHARS = 10000000;
+ /** Maximum size of backups. Files larger will be rejected. */
+ public static final long BACKUP_MAX_CHARS = 10000000;
- private static final String BITEASY_API_URL_PROD = "https://api.biteasy.com/v2/btc/mainnet/";
- private static final String BITEASY_API_URL_TEST = "https://api.biteasy.com/v2/btc/testnet/";
- /** Base URL for blockchain API. */
- public static final String BITEASY_API_URL = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET) ? BITEASY_API_URL_PROD
- : BITEASY_API_URL_TEST;
+ private static final String BITEASY_API_URL_PROD = "https://api.biteasy.com/v2/btc/mainnet/";
+ private static final String BITEASY_API_URL_TEST = "https://api.biteasy.com/v2/btc/testnet/";
+ /** Base URL for blockchain API. */
+ public static final String BITEASY_API_URL = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET)
+ ? BITEASY_API_URL_PROD : BITEASY_API_URL_TEST;
- /** Currency code for the wallet name resolver. */
- public static final String WALLET_NAME_CURRENCY_CODE = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET) ? "btc" : "tbtc";
+ /** Currency code for the wallet name resolver. */
+ public static final String WALLET_NAME_CURRENCY_CODE = NETWORK_PARAMETERS.getId()
+ .equals(NetworkParameters.ID_MAINNET) ? "btc" : "tbtc";
- /** URL to fetch version alerts from. */
- public static final String VERSION_URL = "https://wallet.schildbach.de/version";
+ /** URL to fetch version alerts from. */
+ public static final String VERSION_URL = "https://wallet.schildbach.de/version";
- /** MIME type used for transmitting single transactions. */
- public static final String MIMETYPE_TRANSACTION = "application/x-btctx";
+ /** MIME type used for transmitting single transactions. */
+ public static final String MIMETYPE_TRANSACTION = "application/x-btctx";
- /** MIME type used for transmitting wallet backups. */
- public static final String MIMETYPE_WALLET_BACKUP = "application/x-bitcoin-wallet-backup";
+ /** MIME type used for transmitting wallet backups. */
+ public static final String MIMETYPE_WALLET_BACKUP = "application/x-bitcoin-wallet-backup";
- /** Number of confirmations until a transaction is fully confirmed. */
- public static final int MAX_NUM_CONFIRMATIONS = 7;
+ /** Number of confirmations until a transaction is fully confirmed. */
+ public static final int MAX_NUM_CONFIRMATIONS = 7;
- /** User-agent to use for network access. */
- public static final String USER_AGENT = "Bitcoin Wallet";
+ /** User-agent to use for network access. */
+ public static final String USER_AGENT = "Bitcoin Wallet";
- /** Default currency to use if all default mechanisms fail. */
- public static final String DEFAULT_EXCHANGE_CURRENCY = "USD";
+ /** Default currency to use if all default mechanisms fail. */
+ public static final String DEFAULT_EXCHANGE_CURRENCY = "USD";
- /** Donation address for tip/donate action. */
- public static final String DONATION_ADDRESS = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET)
- ? "1Hf8g3XZnDKdCy6FDQt1DrcWz3GeiYLDRS" : null;
+ /** Donation address for tip/donate action. */
+ public static final String DONATION_ADDRESS = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET)
+ ? "1Hf8g3XZnDKdCy6FDQt1DrcWz3GeiYLDRS" : null;
- /** Recipient e-mail address for reports. */
- public static final String REPORT_EMAIL = "bitcoin.wallet.developers@gmail.com";
+ /** Recipient e-mail address for reports. */
+ public static final String REPORT_EMAIL = "bitcoin.wallet.developers@gmail.com";
- /** Subject line for manually reported issues. */
- public static final String REPORT_SUBJECT_ISSUE = "Reported issue";
+ /** Subject line for manually reported issues. */
+ public static final String REPORT_SUBJECT_ISSUE = "Reported issue";
- /** Subject line for crash reports. */
- public static final String REPORT_SUBJECT_CRASH = "Crash report";
+ /** Subject line for crash reports. */
+ public static final String REPORT_SUBJECT_CRASH = "Crash report";
- public static final char CHAR_HAIR_SPACE = '\u200a';
- public static final char CHAR_THIN_SPACE = '\u2009';
- public static final char CHAR_ALMOST_EQUAL_TO = '\u2248';
- public static final char CHAR_CHECKMARK = '\u2713';
- public static final char CURRENCY_PLUS_SIGN = '\uff0b';
- public static final char CURRENCY_MINUS_SIGN = '\uff0d';
- public static final String PREFIX_ALMOST_EQUAL_TO = Character.toString(CHAR_ALMOST_EQUAL_TO) + CHAR_THIN_SPACE;
- public static final int ADDRESS_FORMAT_GROUP_SIZE = 4;
- public static final int ADDRESS_FORMAT_LINE_SIZE = 12;
+ public static final char CHAR_HAIR_SPACE = '\u200a';
+ public static final char CHAR_THIN_SPACE = '\u2009';
+ public static final char CHAR_ALMOST_EQUAL_TO = '\u2248';
+ public static final char CHAR_CHECKMARK = '\u2713';
+ public static final char CURRENCY_PLUS_SIGN = '\uff0b';
+ public static final char CURRENCY_MINUS_SIGN = '\uff0d';
+ public static final String PREFIX_ALMOST_EQUAL_TO = Character.toString(CHAR_ALMOST_EQUAL_TO) + CHAR_THIN_SPACE;
+ public static final int ADDRESS_FORMAT_GROUP_SIZE = 4;
+ public static final int ADDRESS_FORMAT_LINE_SIZE = 12;
- public static final MonetaryFormat LOCAL_FORMAT = new MonetaryFormat().noCode().minDecimals(2).optionalDecimals();
+ public static final MonetaryFormat LOCAL_FORMAT = new MonetaryFormat().noCode().minDecimals(2).optionalDecimals();
- public static final BaseEncoding HEX = BaseEncoding.base16().lowerCase();
+ public static final BaseEncoding HEX = BaseEncoding.base16().lowerCase();
- public static final String SOURCE_URL = "https://github.com/bitcoin-wallet/bitcoin-wallet";
- public static final String BINARY_URL = "https://github.com/bitcoin-wallet/bitcoin-wallet/releases";
- public static final String MARKET_APP_URL = "market://details?id=%s";
- public static final String WEBMARKET_APP_URL = "https://play.google.com/store/apps/details?id=%s";
+ public static final String SOURCE_URL = "https://github.com/bitcoin-wallet/bitcoin-wallet";
+ public static final String BINARY_URL = "https://github.com/bitcoin-wallet/bitcoin-wallet/releases";
+ public static final String MARKET_APP_URL = "market://details?id=%s";
+ public static final String WEBMARKET_APP_URL = "https://play.google.com/store/apps/details?id=%s";
- public static final int PEER_DISCOVERY_TIMEOUT_MS = 10 * (int) DateUtils.SECOND_IN_MILLIS;
- public static final int PEER_TIMEOUT_MS = 15 * (int) DateUtils.SECOND_IN_MILLIS;
+ public static final int PEER_DISCOVERY_TIMEOUT_MS = 10 * (int) DateUtils.SECOND_IN_MILLIS;
+ public static final int PEER_TIMEOUT_MS = 15 * (int) DateUtils.SECOND_IN_MILLIS;
- public static final long LAST_USAGE_THRESHOLD_JUST_MS = DateUtils.HOUR_IN_MILLIS;
- public static final long LAST_USAGE_THRESHOLD_RECENTLY_MS = 2 * DateUtils.DAY_IN_MILLIS;
- public static final long LAST_USAGE_THRESHOLD_INACTIVE_MS = 4 * DateUtils.WEEK_IN_MILLIS;
+ public static final long LAST_USAGE_THRESHOLD_JUST_MS = DateUtils.HOUR_IN_MILLIS;
+ public static final long LAST_USAGE_THRESHOLD_RECENTLY_MS = 2 * DateUtils.DAY_IN_MILLIS;
+ public static final long LAST_USAGE_THRESHOLD_INACTIVE_MS = 4 * DateUtils.WEEK_IN_MILLIS;
- public static final long DELAYED_TRANSACTION_THRESHOLD_MS = 2 * DateUtils.HOUR_IN_MILLIS;
+ public static final long DELAYED_TRANSACTION_THRESHOLD_MS = 2 * DateUtils.HOUR_IN_MILLIS;
- public static final int SDK_DEPRECATED_BELOW = Build.VERSION_CODES.JELLY_BEAN;
+ public static final int SDK_DEPRECATED_BELOW = Build.VERSION_CODES.JELLY_BEAN;
- public static final boolean BUG_OPENSSL_HEARTBLEED = Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN
- && Build.VERSION.RELEASE.startsWith("4.1.1");
+ public static final boolean BUG_OPENSSL_HEARTBLEED = Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN
+ && Build.VERSION.RELEASE.startsWith("4.1.1");
- public static final int MEMORY_CLASS_LOWEND = 48;
+ public static final int MEMORY_CLASS_LOWEND = 48;
- public static final int NOTIFICATION_ID_CONNECTED = 0;
- public static final int NOTIFICATION_ID_COINS_RECEIVED = 1;
- public static final int NOTIFICATION_ID_INACTIVITY = 2;
+ public static final int NOTIFICATION_ID_CONNECTED = 0;
+ public static final int NOTIFICATION_ID_COINS_RECEIVED = 1;
+ public static final int NOTIFICATION_ID_INACTIVITY = 2;
- /** Desired number of scrypt iterations for deriving the spending PIN */
- public static final int SCRYPT_ITERATIONS_TARGET = 65536;
+ /** Desired number of scrypt iterations for deriving the spending PIN */
+ public static final int SCRYPT_ITERATIONS_TARGET = 65536;
- /** Shared HTTP client, can reuse connections */
- public static final OkHttpClient HTTP_CLIENT = new OkHttpClient();
- static {
- HTTP_CLIENT.setFollowRedirects(false);
- HTTP_CLIENT.setFollowSslRedirects(true);
- HTTP_CLIENT.setConnectTimeout(15, TimeUnit.SECONDS);
- HTTP_CLIENT.setReadTimeout(15, TimeUnit.SECONDS);
- }
+ /** Shared HTTP client, can reuse connections */
+ public static final OkHttpClient HTTP_CLIENT = new OkHttpClient();
+ static {
+ HTTP_CLIENT.setFollowRedirects(false);
+ HTTP_CLIENT.setFollowSslRedirects(true);
+ HTTP_CLIENT.setConnectTimeout(15, TimeUnit.SECONDS);
+ HTTP_CLIENT.setReadTimeout(15, TimeUnit.SECONDS);
+ }
}
diff --git a/wallet/src/de/schildbach/wallet/ExchangeRatesProvider.java b/wallet/src/de/schildbach/wallet/ExchangeRatesProvider.java
index 5c723ec8ee..cea17889d4 100644
--- a/wallet/src/de/schildbach/wallet/ExchangeRatesProvider.java
+++ b/wallet/src/de/schildbach/wallet/ExchangeRatesProvider.java
@@ -57,290 +57,257 @@
/**
* @author Andreas Schildbach
*/
-public class ExchangeRatesProvider extends ContentProvider
-{
- public static class ExchangeRate
- {
- public ExchangeRate(final org.bitcoinj.utils.ExchangeRate rate, final String source)
- {
- checkNotNull(rate.fiat.currencyCode);
-
- this.rate = rate;
- this.source = source;
- }
-
- public final org.bitcoinj.utils.ExchangeRate rate;
- public final String source;
-
- public String getCurrencyCode()
- {
- return rate.fiat.currencyCode;
- }
-
- @Override
- public String toString()
- {
- return getClass().getSimpleName() + '[' + rate.fiat + ']';
- }
- }
-
- public static final String KEY_CURRENCY_CODE = "currency_code";
- private static final String KEY_RATE_COIN = "rate_coin";
- private static final String KEY_RATE_FIAT = "rate_fiat";
- private static final String KEY_SOURCE = "source";
-
- public static final String QUERY_PARAM_Q = "q";
- private static final String QUERY_PARAM_OFFLINE = "offline";
-
- private Configuration config;
- private String userAgent;
-
- @Nullable
- private Map exchangeRates = null;
- private long lastUpdated = 0;
-
- private static final URL BITCOINAVERAGE_URL;
- private static final String[] BITCOINAVERAGE_FIELDS = new String[] { "24h_avg", "last" };
- private static final String BITCOINAVERAGE_SOURCE = "BitcoinAverage.com";
-
- static
- {
- try
- {
- BITCOINAVERAGE_URL = new URL("https://api.bitcoinaverage.com/custom/abw");
- }
- catch (final MalformedURLException x)
- {
- throw new RuntimeException(x); // cannot happen
- }
- }
-
- private static final long UPDATE_FREQ_MS = 10 * DateUtils.MINUTE_IN_MILLIS;
-
- private static final Logger log = LoggerFactory.getLogger(ExchangeRatesProvider.class);
-
- @Override
- public boolean onCreate()
- {
- final Context context = getContext();
-
- this.config = new Configuration(PreferenceManager.getDefaultSharedPreferences(context), context.getResources());
-
- this.userAgent = WalletApplication.httpUserAgent(WalletApplication.packageInfoFromContext(context).versionName);
-
- final ExchangeRate cachedExchangeRate = config.getCachedExchangeRate();
- if (cachedExchangeRate != null)
- {
- exchangeRates = new TreeMap();
- exchangeRates.put(cachedExchangeRate.getCurrencyCode(), cachedExchangeRate);
- }
-
- return true;
- }
-
- public static Uri contentUri(final String packageName, final boolean offline)
- {
- final Uri.Builder uri = Uri.parse("content://" + packageName + '.' + "exchange_rates").buildUpon();
- if (offline)
- uri.appendQueryParameter(QUERY_PARAM_OFFLINE, "1");
- return uri.build();
- }
-
- @Override
- public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder)
- {
- final long now = System.currentTimeMillis();
-
- final boolean offline = uri.getQueryParameter(QUERY_PARAM_OFFLINE) != null;
-
- if (!offline && (lastUpdated == 0 || now - lastUpdated > UPDATE_FREQ_MS))
- {
- Map newExchangeRates = null;
- if (newExchangeRates == null)
- newExchangeRates = requestExchangeRates(BITCOINAVERAGE_URL, userAgent, BITCOINAVERAGE_SOURCE, BITCOINAVERAGE_FIELDS);
-
- if (newExchangeRates != null)
- {
- exchangeRates = newExchangeRates;
- lastUpdated = now;
-
- final ExchangeRate exchangeRateToCache = bestExchangeRate(config.getExchangeCurrencyCode());
- if (exchangeRateToCache != null)
- config.setCachedExchangeRate(exchangeRateToCache);
- }
- }
-
- if (exchangeRates == null)
- return null;
-
- final MatrixCursor cursor = new MatrixCursor(new String[] { BaseColumns._ID, KEY_CURRENCY_CODE, KEY_RATE_COIN, KEY_RATE_FIAT, KEY_SOURCE });
-
- if (selection == null)
- {
- for (final Map.Entry entry : exchangeRates.entrySet())
- {
- final ExchangeRate exchangeRate = entry.getValue();
- final org.bitcoinj.utils.ExchangeRate rate = exchangeRate.rate;
- final String currencyCode = exchangeRate.getCurrencyCode();
- cursor.newRow().add(currencyCode.hashCode()).add(currencyCode).add(rate.coin.value).add(rate.fiat.value).add(exchangeRate.source);
- }
- }
- else if (selection.equals(QUERY_PARAM_Q))
- {
- final String selectionArg = selectionArgs[0].toLowerCase(Locale.US);
- for (final Map.Entry entry : exchangeRates.entrySet())
- {
- final ExchangeRate exchangeRate = entry.getValue();
- final org.bitcoinj.utils.ExchangeRate rate = exchangeRate.rate;
- final String currencyCode = exchangeRate.getCurrencyCode();
- final String currencySymbol = GenericUtils.currencySymbol(currencyCode);
- if (currencyCode.toLowerCase(Locale.US).contains(selectionArg) || currencySymbol.toLowerCase(Locale.US).contains(selectionArg))
- cursor.newRow().add(currencyCode.hashCode()).add(currencyCode).add(rate.coin.value).add(rate.fiat.value).add(exchangeRate.source);
- }
- }
- else if (selection.equals(KEY_CURRENCY_CODE))
- {
- final String selectionArg = selectionArgs[0];
- final ExchangeRate exchangeRate = bestExchangeRate(selectionArg);
- if (exchangeRate != null)
- {
- final org.bitcoinj.utils.ExchangeRate rate = exchangeRate.rate;
- final String currencyCode = exchangeRate.getCurrencyCode();
- cursor.newRow().add(currencyCode.hashCode()).add(currencyCode).add(rate.coin.value).add(rate.fiat.value).add(exchangeRate.source);
- }
- }
-
- return cursor;
- }
-
- private ExchangeRate bestExchangeRate(final String currencyCode)
- {
- ExchangeRate rate = currencyCode != null ? exchangeRates.get(currencyCode) : null;
- if (rate != null)
- return rate;
-
- final String defaultCode = defaultCurrencyCode();
- rate = defaultCode != null ? exchangeRates.get(defaultCode) : null;
-
- if (rate != null)
- return rate;
-
- return exchangeRates.get(Constants.DEFAULT_EXCHANGE_CURRENCY);
- }
-
- private String defaultCurrencyCode()
- {
- try
- {
- return Currency.getInstance(Locale.getDefault()).getCurrencyCode();
- }
- catch (final IllegalArgumentException x)
- {
- return null;
- }
- }
-
- public static ExchangeRate getExchangeRate(final Cursor cursor)
- {
- final String currencyCode = cursor.getString(cursor.getColumnIndexOrThrow(ExchangeRatesProvider.KEY_CURRENCY_CODE));
- final Coin rateCoin = Coin.valueOf(cursor.getLong(cursor.getColumnIndexOrThrow(ExchangeRatesProvider.KEY_RATE_COIN)));
- final Fiat rateFiat = Fiat.valueOf(currencyCode, cursor.getLong(cursor.getColumnIndexOrThrow(ExchangeRatesProvider.KEY_RATE_FIAT)));
- final String source = cursor.getString(cursor.getColumnIndexOrThrow(ExchangeRatesProvider.KEY_SOURCE));
-
- return new ExchangeRate(new org.bitcoinj.utils.ExchangeRate(rateCoin, rateFiat), source);
- }
-
- @Override
- public Uri insert(final Uri uri, final ContentValues values)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int delete(final Uri uri, final String selection, final String[] selectionArgs)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getType(final Uri uri)
- {
- throw new UnsupportedOperationException();
- }
-
- private static Map requestExchangeRates(final URL url, final String userAgent, final String source, final String... fields)
- {
- final Stopwatch watch = Stopwatch.createStarted();
-
- final Request.Builder request = new Request.Builder();
- request.url(url);
- request.header("User-Agent", userAgent);
-
- final Call call = Constants.HTTP_CLIENT.newCall(request.build());
- try
- {
- final Response response = call.execute();
- if (response.isSuccessful())
- {
- final String content = response.body().string();
-
- final Map rates = new TreeMap();
-
- final JSONObject head = new JSONObject(content);
- for (final Iterator i = head.keys(); i.hasNext();)
- {
- final String currencyCode = Strings.emptyToNull(i.next());
- if (currencyCode != null && !"timestamp".equals(currencyCode) && !MonetaryFormat.CODE_BTC.equals(currencyCode)
- && !MonetaryFormat.CODE_MBTC.equals(currencyCode) && !MonetaryFormat.CODE_UBTC.equals(currencyCode))
- {
- final JSONObject o = head.getJSONObject(currencyCode);
-
- for (final String field : fields)
- {
- final String rateStr = o.optString(field, null);
-
- if (rateStr != null)
- {
- try
- {
- final Fiat rate = Fiat.parseFiat(currencyCode, rateStr);
-
- if (rate.signum() > 0)
- {
- rates.put(currencyCode, new ExchangeRate(new org.bitcoinj.utils.ExchangeRate(rate), source));
- break;
- }
- }
- catch (final NumberFormatException x)
- {
- log.warn("problem fetching {} exchange rate from {}: {}", currencyCode, url, x.getMessage());
- }
- }
- }
- }
- }
-
- watch.stop();
- log.info("fetched exchange rates from {}, {} chars, took {}", url, content.length(), watch);
-
- return rates;
- }
- else
- {
- log.warn("http status {} when fetching exchange rates from {}", response.code(), url);
- }
- }
- catch (final Exception x)
- {
- log.warn("problem fetching exchange rates from " + url, x);
- }
-
- return null;
- }
+public class ExchangeRatesProvider extends ContentProvider {
+ public static class ExchangeRate {
+ public ExchangeRate(final org.bitcoinj.utils.ExchangeRate rate, final String source) {
+ checkNotNull(rate.fiat.currencyCode);
+
+ this.rate = rate;
+ this.source = source;
+ }
+
+ public final org.bitcoinj.utils.ExchangeRate rate;
+ public final String source;
+
+ public String getCurrencyCode() {
+ return rate.fiat.currencyCode;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + '[' + rate.fiat + ']';
+ }
+ }
+
+ public static final String KEY_CURRENCY_CODE = "currency_code";
+ private static final String KEY_RATE_COIN = "rate_coin";
+ private static final String KEY_RATE_FIAT = "rate_fiat";
+ private static final String KEY_SOURCE = "source";
+
+ public static final String QUERY_PARAM_Q = "q";
+ private static final String QUERY_PARAM_OFFLINE = "offline";
+
+ private Configuration config;
+ private String userAgent;
+
+ @Nullable
+ private Map exchangeRates = null;
+ private long lastUpdated = 0;
+
+ private static final URL BITCOINAVERAGE_URL;
+ private static final String[] BITCOINAVERAGE_FIELDS = new String[] { "24h_avg", "last" };
+ private static final String BITCOINAVERAGE_SOURCE = "BitcoinAverage.com";
+
+ static {
+ try {
+ BITCOINAVERAGE_URL = new URL("https://api.bitcoinaverage.com/custom/abw");
+ } catch (final MalformedURLException x) {
+ throw new RuntimeException(x); // cannot happen
+ }
+ }
+
+ private static final long UPDATE_FREQ_MS = 10 * DateUtils.MINUTE_IN_MILLIS;
+
+ private static final Logger log = LoggerFactory.getLogger(ExchangeRatesProvider.class);
+
+ @Override
+ public boolean onCreate() {
+ final Context context = getContext();
+
+ this.config = new Configuration(PreferenceManager.getDefaultSharedPreferences(context), context.getResources());
+
+ this.userAgent = WalletApplication.httpUserAgent(WalletApplication.packageInfoFromContext(context).versionName);
+
+ final ExchangeRate cachedExchangeRate = config.getCachedExchangeRate();
+ if (cachedExchangeRate != null) {
+ exchangeRates = new TreeMap();
+ exchangeRates.put(cachedExchangeRate.getCurrencyCode(), cachedExchangeRate);
+ }
+
+ return true;
+ }
+
+ public static Uri contentUri(final String packageName, final boolean offline) {
+ final Uri.Builder uri = Uri.parse("content://" + packageName + '.' + "exchange_rates").buildUpon();
+ if (offline)
+ uri.appendQueryParameter(QUERY_PARAM_OFFLINE, "1");
+ return uri.build();
+ }
+
+ @Override
+ public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs,
+ final String sortOrder) {
+ final long now = System.currentTimeMillis();
+
+ final boolean offline = uri.getQueryParameter(QUERY_PARAM_OFFLINE) != null;
+
+ if (!offline && (lastUpdated == 0 || now - lastUpdated > UPDATE_FREQ_MS)) {
+ Map newExchangeRates = null;
+ if (newExchangeRates == null)
+ newExchangeRates = requestExchangeRates(BITCOINAVERAGE_URL, userAgent, BITCOINAVERAGE_SOURCE,
+ BITCOINAVERAGE_FIELDS);
+
+ if (newExchangeRates != null) {
+ exchangeRates = newExchangeRates;
+ lastUpdated = now;
+
+ final ExchangeRate exchangeRateToCache = bestExchangeRate(config.getExchangeCurrencyCode());
+ if (exchangeRateToCache != null)
+ config.setCachedExchangeRate(exchangeRateToCache);
+ }
+ }
+
+ if (exchangeRates == null)
+ return null;
+
+ final MatrixCursor cursor = new MatrixCursor(
+ new String[] { BaseColumns._ID, KEY_CURRENCY_CODE, KEY_RATE_COIN, KEY_RATE_FIAT, KEY_SOURCE });
+
+ if (selection == null) {
+ for (final Map.Entry entry : exchangeRates.entrySet()) {
+ final ExchangeRate exchangeRate = entry.getValue();
+ final org.bitcoinj.utils.ExchangeRate rate = exchangeRate.rate;
+ final String currencyCode = exchangeRate.getCurrencyCode();
+ cursor.newRow().add(currencyCode.hashCode()).add(currencyCode).add(rate.coin.value).add(rate.fiat.value)
+ .add(exchangeRate.source);
+ }
+ } else if (selection.equals(QUERY_PARAM_Q)) {
+ final String selectionArg = selectionArgs[0].toLowerCase(Locale.US);
+ for (final Map.Entry entry : exchangeRates.entrySet()) {
+ final ExchangeRate exchangeRate = entry.getValue();
+ final org.bitcoinj.utils.ExchangeRate rate = exchangeRate.rate;
+ final String currencyCode = exchangeRate.getCurrencyCode();
+ final String currencySymbol = GenericUtils.currencySymbol(currencyCode);
+ if (currencyCode.toLowerCase(Locale.US).contains(selectionArg)
+ || currencySymbol.toLowerCase(Locale.US).contains(selectionArg))
+ cursor.newRow().add(currencyCode.hashCode()).add(currencyCode).add(rate.coin.value)
+ .add(rate.fiat.value).add(exchangeRate.source);
+ }
+ } else if (selection.equals(KEY_CURRENCY_CODE)) {
+ final String selectionArg = selectionArgs[0];
+ final ExchangeRate exchangeRate = bestExchangeRate(selectionArg);
+ if (exchangeRate != null) {
+ final org.bitcoinj.utils.ExchangeRate rate = exchangeRate.rate;
+ final String currencyCode = exchangeRate.getCurrencyCode();
+ cursor.newRow().add(currencyCode.hashCode()).add(currencyCode).add(rate.coin.value).add(rate.fiat.value)
+ .add(exchangeRate.source);
+ }
+ }
+
+ return cursor;
+ }
+
+ private ExchangeRate bestExchangeRate(final String currencyCode) {
+ ExchangeRate rate = currencyCode != null ? exchangeRates.get(currencyCode) : null;
+ if (rate != null)
+ return rate;
+
+ final String defaultCode = defaultCurrencyCode();
+ rate = defaultCode != null ? exchangeRates.get(defaultCode) : null;
+
+ if (rate != null)
+ return rate;
+
+ return exchangeRates.get(Constants.DEFAULT_EXCHANGE_CURRENCY);
+ }
+
+ private String defaultCurrencyCode() {
+ try {
+ return Currency.getInstance(Locale.getDefault()).getCurrencyCode();
+ } catch (final IllegalArgumentException x) {
+ return null;
+ }
+ }
+
+ public static ExchangeRate getExchangeRate(final Cursor cursor) {
+ final String currencyCode = cursor
+ .getString(cursor.getColumnIndexOrThrow(ExchangeRatesProvider.KEY_CURRENCY_CODE));
+ final Coin rateCoin = Coin
+ .valueOf(cursor.getLong(cursor.getColumnIndexOrThrow(ExchangeRatesProvider.KEY_RATE_COIN)));
+ final Fiat rateFiat = Fiat.valueOf(currencyCode,
+ cursor.getLong(cursor.getColumnIndexOrThrow(ExchangeRatesProvider.KEY_RATE_FIAT)));
+ final String source = cursor.getString(cursor.getColumnIndexOrThrow(ExchangeRatesProvider.KEY_SOURCE));
+
+ return new ExchangeRate(new org.bitcoinj.utils.ExchangeRate(rateCoin, rateFiat), source);
+ }
+
+ @Override
+ public Uri insert(final Uri uri, final ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getType(final Uri uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ private static Map requestExchangeRates(final URL url, final String userAgent,
+ final String source, final String... fields) {
+ final Stopwatch watch = Stopwatch.createStarted();
+
+ final Request.Builder request = new Request.Builder();
+ request.url(url);
+ request.header("User-Agent", userAgent);
+
+ final Call call = Constants.HTTP_CLIENT.newCall(request.build());
+ try {
+ final Response response = call.execute();
+ if (response.isSuccessful()) {
+ final String content = response.body().string();
+
+ final Map rates = new TreeMap();
+
+ final JSONObject head = new JSONObject(content);
+ for (final Iterator i = head.keys(); i.hasNext();) {
+ final String currencyCode = Strings.emptyToNull(i.next());
+ if (currencyCode != null && !"timestamp".equals(currencyCode)
+ && !MonetaryFormat.CODE_BTC.equals(currencyCode)
+ && !MonetaryFormat.CODE_MBTC.equals(currencyCode)
+ && !MonetaryFormat.CODE_UBTC.equals(currencyCode)) {
+ final JSONObject o = head.getJSONObject(currencyCode);
+
+ for (final String field : fields) {
+ final String rateStr = o.optString(field, null);
+
+ if (rateStr != null) {
+ try {
+ final Fiat rate = Fiat.parseFiat(currencyCode, rateStr);
+
+ if (rate.signum() > 0) {
+ rates.put(currencyCode,
+ new ExchangeRate(new org.bitcoinj.utils.ExchangeRate(rate), source));
+ break;
+ }
+ } catch (final NumberFormatException x) {
+ log.warn("problem fetching {} exchange rate from {}: {}", currencyCode, url,
+ x.getMessage());
+ }
+ }
+ }
+ }
+ }
+
+ watch.stop();
+ log.info("fetched exchange rates from {}, {} chars, took {}", url, content.length(), watch);
+
+ return rates;
+ } else {
+ log.warn("http status {} when fetching exchange rates from {}", response.code(), url);
+ }
+ } catch (final Exception x) {
+ log.warn("problem fetching exchange rates from " + url, x);
+ }
+
+ return null;
+ }
}
diff --git a/wallet/src/de/schildbach/wallet/FileAttachmentProvider.java b/wallet/src/de/schildbach/wallet/FileAttachmentProvider.java
index a039c994b3..3801f7b8af 100644
--- a/wallet/src/de/schildbach/wallet/FileAttachmentProvider.java
+++ b/wallet/src/de/schildbach/wallet/FileAttachmentProvider.java
@@ -32,87 +32,77 @@
/**
* @author Andreas Schildbach
*/
-public final class FileAttachmentProvider extends ContentProvider
-{
- public static Uri contentUri(final String packageName, final File file)
- {
- return Uri.parse("content://" + packageName + ".file_attachment" + file.getAbsolutePath());
- }
-
- @Override
- public boolean onCreate()
- {
- return true;
- }
-
- @Override
- public String getType(final Uri uri)
- {
- final File file = new File(uri.getPath());
-
- if (!file.getAbsolutePath().startsWith(getContext().getCacheDir().getAbsolutePath()))
- return null;
-
- final String[] split = file.getName().split("\\.");
- if (split.length >= 2)
- {
- final String suffix = split[split.length - 1];
- if ("txt".equalsIgnoreCase(suffix) || "log".equalsIgnoreCase(suffix))
- return "text/plain";
- else if ("gz".equalsIgnoreCase(suffix))
- return "application/x-gzip";
- }
-
- return null;
- }
-
- @Override
- public ParcelFileDescriptor openFile(final Uri uri, final String mode) throws FileNotFoundException
- {
- return openFileHelper(uri, mode);
- }
-
- @Override
- public int delete(final Uri uri, final String selection, final String[] selectionArgs)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Uri insert(final Uri uri, final ContentValues values)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder)
- {
- final File file = new File(uri.getPath());
-
- if (!file.getAbsolutePath().startsWith(getContext().getCacheDir().getAbsolutePath()))
- throw new IllegalArgumentException("not in cache dir: " + uri);
-
- final MatrixCursor cursor = new MatrixCursor(projection);
- final RowBuilder row = cursor.newRow();
- for (int i = 0; i < projection.length; i++)
- {
- final String columnName = projection[i];
- if (columnName.equals(MediaStore.MediaColumns.DATA))
- row.add(file.getAbsolutePath());
- else if (columnName.equals(MediaStore.MediaColumns.SIZE))
- row.add(file.length());
- else if (columnName.equals(MediaStore.MediaColumns.DISPLAY_NAME))
- row.add(uri.getLastPathSegment());
- else
- throw new IllegalArgumentException("cannot handle: " + columnName);
- }
-
- return cursor;
- }
-
- @Override
- public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs)
- {
- throw new UnsupportedOperationException();
- }
+public final class FileAttachmentProvider extends ContentProvider {
+ public static Uri contentUri(final String packageName, final File file) {
+ return Uri.parse("content://" + packageName + ".file_attachment" + file.getAbsolutePath());
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public String getType(final Uri uri) {
+ final File file = new File(uri.getPath());
+
+ if (!file.getAbsolutePath().startsWith(getContext().getCacheDir().getAbsolutePath()))
+ return null;
+
+ final String[] split = file.getName().split("\\.");
+ if (split.length >= 2) {
+ final String suffix = split[split.length - 1];
+ if ("txt".equalsIgnoreCase(suffix) || "log".equalsIgnoreCase(suffix))
+ return "text/plain";
+ else if ("gz".equalsIgnoreCase(suffix))
+ return "application/x-gzip";
+ }
+
+ return null;
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(final Uri uri, final String mode) throws FileNotFoundException {
+ return openFileHelper(uri, mode);
+ }
+
+ @Override
+ public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Uri insert(final Uri uri, final ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs,
+ final String sortOrder) {
+ final File file = new File(uri.getPath());
+
+ if (!file.getAbsolutePath().startsWith(getContext().getCacheDir().getAbsolutePath()))
+ throw new IllegalArgumentException("not in cache dir: " + uri);
+
+ final MatrixCursor cursor = new MatrixCursor(projection);
+ final RowBuilder row = cursor.newRow();
+ for (int i = 0; i < projection.length; i++) {
+ final String columnName = projection[i];
+ if (columnName.equals(MediaStore.MediaColumns.DATA))
+ row.add(file.getAbsolutePath());
+ else if (columnName.equals(MediaStore.MediaColumns.SIZE))
+ row.add(file.length());
+ else if (columnName.equals(MediaStore.MediaColumns.DISPLAY_NAME))
+ row.add(uri.getLastPathSegment());
+ else
+ throw new IllegalArgumentException("cannot handle: " + columnName);
+ }
+
+ return cursor;
+ }
+
+ @Override
+ public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/wallet/src/de/schildbach/wallet/WalletApplication.java b/wallet/src/de/schildbach/wallet/WalletApplication.java
index 25520cc83d..8ba05ae9d2 100644
--- a/wallet/src/de/schildbach/wallet/WalletApplication.java
+++ b/wallet/src/de/schildbach/wallet/WalletApplication.java
@@ -40,6 +40,11 @@
import com.google.common.base.Stopwatch;
+import de.schildbach.wallet.service.BlockchainService;
+import de.schildbach.wallet.service.BlockchainServiceImpl;
+import de.schildbach.wallet.util.CrashReporter;
+import de.schildbach.wallet_test.R;
+
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.Application;
@@ -60,489 +65,421 @@
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
-import de.schildbach.wallet.service.BlockchainService;
-import de.schildbach.wallet.service.BlockchainServiceImpl;
-import de.schildbach.wallet.util.CrashReporter;
-import de.schildbach.wallet_test.R;
/**
* @author Andreas Schildbach
*/
-public class WalletApplication extends Application
-{
- private Configuration config;
- private ActivityManager activityManager;
+public class WalletApplication extends Application {
+ private Configuration config;
+ private ActivityManager activityManager;
+
+ private Intent blockchainServiceIntent;
+ private Intent blockchainServiceCancelCoinsReceivedIntent;
+ private Intent blockchainServiceResetBlockchainIntent;
+
+ private File walletFile;
+ private Wallet wallet;
+ private PackageInfo packageInfo;
+
+ public static final String ACTION_WALLET_REFERENCE_CHANGED = WalletApplication.class.getPackage().getName()
+ + ".wallet_reference_changed";
+
+ public static final int VERSION_CODE_SHOW_BACKUP_REMINDER = 205;
+
+ public static final long TIME_CREATE_APPLICATION = System.currentTimeMillis();
+
+ private static final Logger log = LoggerFactory.getLogger(WalletApplication.class);
+
+ @Override
+ public void onCreate() {
+ new LinuxSecureRandom(); // init proper random number generator
+
+ initLogging();
+
+ StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().permitDiskReads()
+ .permitDiskWrites().penaltyLog().build());
+
+ Threading.throwOnLockCycles();
+ org.bitcoinj.core.Context.enableStrictMode();
+ org.bitcoinj.core.Context.propagate(Constants.CONTEXT);
+
+ log.info("=== starting app using configuration: {}, {}", Constants.TEST ? "test" : "prod",
+ Constants.NETWORK_PARAMETERS.getId());
+
+ super.onCreate();
+
+ packageInfo = packageInfoFromContext(this);
+
+ CrashReporter.init(getCacheDir());
+
+ Threading.uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
+ @Override
+ public void uncaughtException(final Thread thread, final Throwable throwable) {
+ log.info("bitcoinj uncaught exception", throwable);
+ CrashReporter.saveBackgroundTrace(throwable, packageInfo);
+ }
+ };
- private Intent blockchainServiceIntent;
- private Intent blockchainServiceCancelCoinsReceivedIntent;
- private Intent blockchainServiceResetBlockchainIntent;
+ initMnemonicCode();
- private File walletFile;
- private Wallet wallet;
- private PackageInfo packageInfo;
+ config = new Configuration(PreferenceManager.getDefaultSharedPreferences(this), getResources());
+ activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
- public static final String ACTION_WALLET_REFERENCE_CHANGED = WalletApplication.class.getPackage().getName() + ".wallet_reference_changed";
+ blockchainServiceIntent = new Intent(this, BlockchainServiceImpl.class);
+ blockchainServiceCancelCoinsReceivedIntent = new Intent(BlockchainService.ACTION_CANCEL_COINS_RECEIVED, null,
+ this, BlockchainServiceImpl.class);
+ blockchainServiceResetBlockchainIntent = new Intent(BlockchainService.ACTION_RESET_BLOCKCHAIN, null, this,
+ BlockchainServiceImpl.class);
- public static final int VERSION_CODE_SHOW_BACKUP_REMINDER = 205;
+ walletFile = getFileStreamPath(Constants.Files.WALLET_FILENAME_PROTOBUF);
- public static final long TIME_CREATE_APPLICATION = System.currentTimeMillis();
+ loadWalletFromProtobuf();
- private static final Logger log = LoggerFactory.getLogger(WalletApplication.class);
+ if (config.versionCodeCrossed(packageInfo.versionCode, VERSION_CODE_SHOW_BACKUP_REMINDER)
+ && !wallet.getImportedKeys().isEmpty()) {
+ log.info("showing backup reminder once, because of imported keys being present");
+ config.armBackupReminder();
+ }
- @Override
- public void onCreate()
- {
- new LinuxSecureRandom(); // init proper random number generator
+ config.updateLastVersionCode(packageInfo.versionCode);
- initLogging();
+ afterLoadWallet();
- StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().permitDiskReads().permitDiskWrites().penaltyLog().build());
+ cleanupFiles();
+ }
- Threading.throwOnLockCycles();
- org.bitcoinj.core.Context.enableStrictMode();
- org.bitcoinj.core.Context.propagate(Constants.CONTEXT);
+ private void afterLoadWallet() {
+ wallet.autosaveToFile(walletFile, Constants.Files.WALLET_AUTOSAVE_DELAY_MS, TimeUnit.MILLISECONDS, null);
- log.info("=== starting app using configuration: {}, {}", Constants.TEST ? "test" : "prod", Constants.NETWORK_PARAMETERS.getId());
+ // clean up spam
+ wallet.cleanup();
- super.onCreate();
+ // make sure there is at least one recent backup
+ if (!getFileStreamPath(Constants.Files.WALLET_KEY_BACKUP_PROTOBUF).exists())
+ backupWallet();
+ }
- packageInfo = packageInfoFromContext(this);
+ private void initLogging() {
+ final File logDir = getDir("log", MODE_PRIVATE);
+ final File logFile = new File(logDir, "wallet.log");
- CrashReporter.init(getCacheDir());
+ final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
- Threading.uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler()
- {
- @Override
- public void uncaughtException(final Thread thread, final Throwable throwable)
- {
- log.info("bitcoinj uncaught exception", throwable);
- CrashReporter.saveBackgroundTrace(throwable, packageInfo);
- }
- };
+ final PatternLayoutEncoder filePattern = new PatternLayoutEncoder();
+ filePattern.setContext(context);
+ filePattern.setPattern("%d{HH:mm:ss,UTC} [%thread] %logger{0} - %msg%n");
+ filePattern.start();
- initMnemonicCode();
+ final RollingFileAppender fileAppender = new RollingFileAppender();
+ fileAppender.setContext(context);
+ fileAppender.setFile(logFile.getAbsolutePath());
- config = new Configuration(PreferenceManager.getDefaultSharedPreferences(this), getResources());
- activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ final TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy();
+ rollingPolicy.setContext(context);
+ rollingPolicy.setParent(fileAppender);
+ rollingPolicy.setFileNamePattern(logDir.getAbsolutePath() + "/wallet.%d{yyyy-MM-dd,UTC}.log.gz");
+ rollingPolicy.setMaxHistory(7);
+ rollingPolicy.start();
- blockchainServiceIntent = new Intent(this, BlockchainServiceImpl.class);
- blockchainServiceCancelCoinsReceivedIntent = new Intent(BlockchainService.ACTION_CANCEL_COINS_RECEIVED, null, this,
- BlockchainServiceImpl.class);
- blockchainServiceResetBlockchainIntent = new Intent(BlockchainService.ACTION_RESET_BLOCKCHAIN, null, this, BlockchainServiceImpl.class);
+ fileAppender.setEncoder(filePattern);
+ fileAppender.setRollingPolicy(rollingPolicy);
+ fileAppender.start();
- walletFile = getFileStreamPath(Constants.Files.WALLET_FILENAME_PROTOBUF);
+ final PatternLayoutEncoder logcatTagPattern = new PatternLayoutEncoder();
+ logcatTagPattern.setContext(context);
+ logcatTagPattern.setPattern("%logger{0}");
+ logcatTagPattern.start();
- loadWalletFromProtobuf();
+ final PatternLayoutEncoder logcatPattern = new PatternLayoutEncoder();
+ logcatPattern.setContext(context);
+ logcatPattern.setPattern("[%thread] %msg%n");
+ logcatPattern.start();
- if (config.versionCodeCrossed(packageInfo.versionCode, VERSION_CODE_SHOW_BACKUP_REMINDER) && !wallet.getImportedKeys().isEmpty())
- {
- log.info("showing backup reminder once, because of imported keys being present");
- config.armBackupReminder();
- }
-
- config.updateLastVersionCode(packageInfo.versionCode);
+ final LogcatAppender logcatAppender = new LogcatAppender();
+ logcatAppender.setContext(context);
+ logcatAppender.setTagEncoder(logcatTagPattern);
+ logcatAppender.setEncoder(logcatPattern);
+ logcatAppender.start();
- afterLoadWallet();
-
- cleanupFiles();
- }
-
- private void afterLoadWallet()
- {
- wallet.autosaveToFile(walletFile, Constants.Files.WALLET_AUTOSAVE_DELAY_MS, TimeUnit.MILLISECONDS, null);
+ final ch.qos.logback.classic.Logger log = context.getLogger(Logger.ROOT_LOGGER_NAME);
+ log.addAppender(fileAppender);
+ log.addAppender(logcatAppender);
+ log.setLevel(Level.INFO);
+ }
- // clean up spam
- wallet.cleanup();
-
- // make sure there is at least one recent backup
- if (!getFileStreamPath(Constants.Files.WALLET_KEY_BACKUP_PROTOBUF).exists())
- backupWallet();
- }
+ private static final String BIP39_WORDLIST_FILENAME = "bip39-wordlist.txt";
- private void initLogging()
- {
- final File logDir = getDir("log", MODE_PRIVATE);
- final File logFile = new File(logDir, "wallet.log");
-
- final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
-
- final PatternLayoutEncoder filePattern = new PatternLayoutEncoder();
- filePattern.setContext(context);
- filePattern.setPattern("%d{HH:mm:ss,UTC} [%thread] %logger{0} - %msg%n");
- filePattern.start();
-
- final RollingFileAppender fileAppender = new RollingFileAppender();
- fileAppender.setContext(context);
- fileAppender.setFile(logFile.getAbsolutePath());
-
- final TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy();
- rollingPolicy.setContext(context);
- rollingPolicy.setParent(fileAppender);
- rollingPolicy.setFileNamePattern(logDir.getAbsolutePath() + "/wallet.%d{yyyy-MM-dd,UTC}.log.gz");
- rollingPolicy.setMaxHistory(7);
- rollingPolicy.start();
-
- fileAppender.setEncoder(filePattern);
- fileAppender.setRollingPolicy(rollingPolicy);
- fileAppender.start();
-
- final PatternLayoutEncoder logcatTagPattern = new PatternLayoutEncoder();
- logcatTagPattern.setContext(context);
- logcatTagPattern.setPattern("%logger{0}");
- logcatTagPattern.start();
-
- final PatternLayoutEncoder logcatPattern = new PatternLayoutEncoder();
- logcatPattern.setContext(context);
- logcatPattern.setPattern("[%thread] %msg%n");
- logcatPattern.start();
-
- final LogcatAppender logcatAppender = new LogcatAppender();
- logcatAppender.setContext(context);
- logcatAppender.setTagEncoder(logcatTagPattern);
- logcatAppender.setEncoder(logcatPattern);
- logcatAppender.start();
-
- final ch.qos.logback.classic.Logger log = context.getLogger(Logger.ROOT_LOGGER_NAME);
- log.addAppender(fileAppender);
- log.addAppender(logcatAppender);
- log.setLevel(Level.INFO);
- }
-
- private static final String BIP39_WORDLIST_FILENAME = "bip39-wordlist.txt";
-
- private void initMnemonicCode()
- {
- try
- {
- final Stopwatch watch = Stopwatch.createStarted();
- MnemonicCode.INSTANCE = new MnemonicCode(getAssets().open(BIP39_WORDLIST_FILENAME), null);
- watch.stop();
- log.info("BIP39 wordlist loaded from: '{}', took {}", BIP39_WORDLIST_FILENAME, watch);
- }
- catch (final IOException x)
- {
- throw new Error(x);
- }
- }
-
- public Configuration getConfiguration()
- {
- return config;
- }
-
- public Wallet getWallet()
- {
- return wallet;
- }
-
- private void loadWalletFromProtobuf()
- {
- if (walletFile.exists())
- {
- FileInputStream walletStream = null;
-
- try
- {
- final Stopwatch watch = Stopwatch.createStarted();
- walletStream = new FileInputStream(walletFile);
- wallet = new WalletProtobufSerializer().readWallet(walletStream);
- watch.stop();
-
- if (!wallet.getParams().equals(Constants.NETWORK_PARAMETERS))
- throw new UnreadableWalletException("bad wallet network parameters: " + wallet.getParams().getId());
-
- log.info("wallet loaded from: '{}', took {}", walletFile, watch);
- }
- catch (final FileNotFoundException x)
- {
- log.error("problem loading wallet", x);
-
- Toast.makeText(WalletApplication.this, x.getClass().getName(), Toast.LENGTH_LONG).show();
-
- wallet = restoreWalletFromBackup();
- }
- catch (final UnreadableWalletException x)
- {
- log.error("problem loading wallet", x);
-
- Toast.makeText(WalletApplication.this, x.getClass().getName(), Toast.LENGTH_LONG).show();
-
- wallet = restoreWalletFromBackup();
- }
- finally
- {
- if (walletStream != null)
- {
- try
- {
- walletStream.close();
- }
- catch (final IOException x)
- {
- // swallow
- }
- }
- }
-
- if (!wallet.isConsistent())
- {
- Toast.makeText(this, "inconsistent wallet: " + walletFile, Toast.LENGTH_LONG).show();
-
- wallet = restoreWalletFromBackup();
- }
-
- if (!wallet.getParams().equals(Constants.NETWORK_PARAMETERS))
- throw new Error("bad wallet network parameters: " + wallet.getParams().getId());
- }
- else
- {
- wallet = new Wallet(Constants.NETWORK_PARAMETERS);
-
- saveWallet();
- backupWallet();
-
- config.armBackupReminder();
-
- log.info("new wallet created");
- }
- }
-
- private Wallet restoreWalletFromBackup()
- {
- InputStream is = null;
-
- try
- {
- is = openFileInput(Constants.Files.WALLET_KEY_BACKUP_PROTOBUF);
-
- final Wallet wallet = new WalletProtobufSerializer().readWallet(is, true, null);
-
- if (!wallet.isConsistent())
- throw new Error("inconsistent backup");
-
- resetBlockchain();
-
- Toast.makeText(this, R.string.toast_wallet_reset, Toast.LENGTH_LONG).show();
-
- log.info("wallet restored from backup: '" + Constants.Files.WALLET_KEY_BACKUP_PROTOBUF + "'");
-
- return wallet;
- }
- catch (final IOException x)
- {
- throw new Error("cannot read backup", x);
- }
- catch (final UnreadableWalletException x)
- {
- throw new Error("cannot read backup", x);
- }
- finally
- {
- try
- {
- is.close();
- }
- catch (final IOException x)
- {
- // swallow
- }
- }
- }
-
- public void saveWallet()
- {
- try
- {
- protobufSerializeWallet(wallet);
- }
- catch (final IOException x)
- {
- throw new RuntimeException(x);
- }
- }
-
- private void protobufSerializeWallet(final Wallet wallet) throws IOException
- {
- final Stopwatch watch = Stopwatch.createStarted();
- wallet.saveToFile(walletFile);
- watch.stop();
-
- log.info("wallet saved to: '{}', took {}", walletFile, watch);
- }
-
- public void backupWallet()
- {
- final Stopwatch watch = Stopwatch.createStarted();
- final Protos.Wallet.Builder builder = new WalletProtobufSerializer().walletToProto(wallet).toBuilder();
-
- // strip redundant
- builder.clearTransaction();
- builder.clearLastSeenBlockHash();
- builder.setLastSeenBlockHeight(-1);
- builder.clearLastSeenBlockTimeSecs();
- final Protos.Wallet walletProto = builder.build();
-
- OutputStream os = null;
-
- try
- {
- os = openFileOutput(Constants.Files.WALLET_KEY_BACKUP_PROTOBUF, Context.MODE_PRIVATE);
- walletProto.writeTo(os);
- watch.stop();
- log.info("wallet backed up to: '{}', took {}", Constants.Files.WALLET_KEY_BACKUP_PROTOBUF, watch);
- }
- catch (final IOException x)
- {
- log.error("problem writing wallet backup", x);
- }
- finally
- {
- try
- {
- os.close();
- }
- catch (final IOException x)
- {
- // swallow
- }
- }
- }
-
- private void cleanupFiles()
- {
- for (final String filename : fileList())
- {
- if (filename.startsWith(Constants.Files.WALLET_KEY_BACKUP_BASE58) || filename.startsWith(Constants.Files.WALLET_KEY_BACKUP_PROTOBUF + '.')
- || filename.endsWith(".tmp"))
- {
- final File file = new File(getFilesDir(), filename);
- log.info("removing obsolete file: '{}'", file);
- file.delete();
- }
- }
- }
-
- public void startBlockchainService(final boolean cancelCoinsReceived)
- {
- if (cancelCoinsReceived)
- startService(blockchainServiceCancelCoinsReceivedIntent);
- else
- startService(blockchainServiceIntent);
- }
-
- public void stopBlockchainService()
- {
- stopService(blockchainServiceIntent);
- }
-
- public void resetBlockchain()
- {
- // implicitly stops blockchain service
- startService(blockchainServiceResetBlockchainIntent);
- }
-
- public void replaceWallet(final Wallet newWallet)
- {
- resetBlockchain();
- wallet.shutdownAutosaveAndWait();
-
- wallet = newWallet;
- config.maybeIncrementBestChainHeightEver(newWallet.getLastBlockSeenHeight());
- afterLoadWallet();
-
- final Intent broadcast = new Intent(ACTION_WALLET_REFERENCE_CHANGED);
- broadcast.setPackage(getPackageName());
- LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
- }
-
- public void processDirectTransaction(final Transaction tx) throws VerificationException
- {
- if (wallet.isTransactionRelevant(tx))
- {
- wallet.receivePending(tx, null);
- broadcastTransaction(tx);
- }
- }
-
- public void broadcastTransaction(final Transaction tx)
- {
- final Intent intent = new Intent(BlockchainService.ACTION_BROADCAST_TRANSACTION, null, this, BlockchainServiceImpl.class);
- intent.putExtra(BlockchainService.ACTION_BROADCAST_TRANSACTION_HASH, tx.getHash().getBytes());
- startService(intent);
- }
-
- public static PackageInfo packageInfoFromContext(final Context context)
- {
- try
- {
- return context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
- }
- catch (final NameNotFoundException x)
- {
- throw new RuntimeException(x);
- }
- }
-
- public PackageInfo packageInfo()
- {
- return packageInfo;
- }
-
- public final String applicationPackageFlavor()
- {
- final String packageName = getPackageName();
- final int index = packageName.lastIndexOf('_');
-
- if (index != -1)
- return packageName.substring(index + 1);
- else
- return null;
- }
-
- public static String httpUserAgent(final String versionName)
- {
- final VersionMessage versionMessage = new VersionMessage(Constants.NETWORK_PARAMETERS, 0);
- versionMessage.appendToSubVer(Constants.USER_AGENT, versionName, null);
- return versionMessage.subVer;
- }
-
- public String httpUserAgent()
- {
- return httpUserAgent(packageInfo().versionName);
- }
-
- public int maxConnectedPeers()
- {
- final int memoryClass = activityManager.getMemoryClass();
- if (memoryClass <= Constants.MEMORY_CLASS_LOWEND)
- return 4;
- else
- return 6;
- }
-
- public static void scheduleStartBlockchainService(final Context context)
- {
- final Configuration config = new Configuration(PreferenceManager.getDefaultSharedPreferences(context), context.getResources());
- final long lastUsedAgo = config.getLastUsedAgo();
-
- // apply some backoff
- final long alarmInterval;
- if (lastUsedAgo < Constants.LAST_USAGE_THRESHOLD_JUST_MS)
- alarmInterval = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
- else if (lastUsedAgo < Constants.LAST_USAGE_THRESHOLD_RECENTLY_MS)
- alarmInterval = AlarmManager.INTERVAL_HALF_DAY;
- else
- alarmInterval = AlarmManager.INTERVAL_DAY;
-
- log.info("last used {} minutes ago, rescheduling blockchain sync in roughly {} minutes", lastUsedAgo / DateUtils.MINUTE_IN_MILLIS,
- alarmInterval / DateUtils.MINUTE_IN_MILLIS);
-
- final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- final PendingIntent alarmIntent = PendingIntent.getService(context, 0, new Intent(context, BlockchainServiceImpl.class), 0);
- alarmManager.cancel(alarmIntent);
-
- // workaround for no inexact set() before KitKat
- final long now = System.currentTimeMillis();
- alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, now + alarmInterval, AlarmManager.INTERVAL_DAY, alarmIntent);
- }
+ private void initMnemonicCode() {
+ try {
+ final Stopwatch watch = Stopwatch.createStarted();
+ MnemonicCode.INSTANCE = new MnemonicCode(getAssets().open(BIP39_WORDLIST_FILENAME), null);
+ watch.stop();
+ log.info("BIP39 wordlist loaded from: '{}', took {}", BIP39_WORDLIST_FILENAME, watch);
+ } catch (final IOException x) {
+ throw new Error(x);
+ }
+ }
+
+ public Configuration getConfiguration() {
+ return config;
+ }
+
+ public Wallet getWallet() {
+ return wallet;
+ }
+
+ private void loadWalletFromProtobuf() {
+ if (walletFile.exists()) {
+ FileInputStream walletStream = null;
+
+ try {
+ final Stopwatch watch = Stopwatch.createStarted();
+ walletStream = new FileInputStream(walletFile);
+ wallet = new WalletProtobufSerializer().readWallet(walletStream);
+ watch.stop();
+
+ if (!wallet.getParams().equals(Constants.NETWORK_PARAMETERS))
+ throw new UnreadableWalletException("bad wallet network parameters: " + wallet.getParams().getId());
+
+ log.info("wallet loaded from: '{}', took {}", walletFile, watch);
+ } catch (final FileNotFoundException x) {
+ log.error("problem loading wallet", x);
+
+ Toast.makeText(WalletApplication.this, x.getClass().getName(), Toast.LENGTH_LONG).show();
+
+ wallet = restoreWalletFromBackup();
+ } catch (final UnreadableWalletException x) {
+ log.error("problem loading wallet", x);
+
+ Toast.makeText(WalletApplication.this, x.getClass().getName(), Toast.LENGTH_LONG).show();
+
+ wallet = restoreWalletFromBackup();
+ } finally {
+ if (walletStream != null) {
+ try {
+ walletStream.close();
+ } catch (final IOException x) {
+ // swallow
+ }
+ }
+ }
+
+ if (!wallet.isConsistent()) {
+ Toast.makeText(this, "inconsistent wallet: " + walletFile, Toast.LENGTH_LONG).show();
+
+ wallet = restoreWalletFromBackup();
+ }
+
+ if (!wallet.getParams().equals(Constants.NETWORK_PARAMETERS))
+ throw new Error("bad wallet network parameters: " + wallet.getParams().getId());
+ } else {
+ wallet = new Wallet(Constants.NETWORK_PARAMETERS);
+
+ saveWallet();
+ backupWallet();
+
+ config.armBackupReminder();
+
+ log.info("new wallet created");
+ }
+ }
+
+ private Wallet restoreWalletFromBackup() {
+ InputStream is = null;
+
+ try {
+ is = openFileInput(Constants.Files.WALLET_KEY_BACKUP_PROTOBUF);
+
+ final Wallet wallet = new WalletProtobufSerializer().readWallet(is, true, null);
+
+ if (!wallet.isConsistent())
+ throw new Error("inconsistent backup");
+
+ resetBlockchain();
+
+ Toast.makeText(this, R.string.toast_wallet_reset, Toast.LENGTH_LONG).show();
+
+ log.info("wallet restored from backup: '" + Constants.Files.WALLET_KEY_BACKUP_PROTOBUF + "'");
+
+ return wallet;
+ } catch (final IOException x) {
+ throw new Error("cannot read backup", x);
+ } catch (final UnreadableWalletException x) {
+ throw new Error("cannot read backup", x);
+ } finally {
+ try {
+ is.close();
+ } catch (final IOException x) {
+ // swallow
+ }
+ }
+ }
+
+ public void saveWallet() {
+ try {
+ protobufSerializeWallet(wallet);
+ } catch (final IOException x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ private void protobufSerializeWallet(final Wallet wallet) throws IOException {
+ final Stopwatch watch = Stopwatch.createStarted();
+ wallet.saveToFile(walletFile);
+ watch.stop();
+
+ log.info("wallet saved to: '{}', took {}", walletFile, watch);
+ }
+
+ public void backupWallet() {
+ final Stopwatch watch = Stopwatch.createStarted();
+ final Protos.Wallet.Builder builder = new WalletProtobufSerializer().walletToProto(wallet).toBuilder();
+
+ // strip redundant
+ builder.clearTransaction();
+ builder.clearLastSeenBlockHash();
+ builder.setLastSeenBlockHeight(-1);
+ builder.clearLastSeenBlockTimeSecs();
+ final Protos.Wallet walletProto = builder.build();
+
+ OutputStream os = null;
+
+ try {
+ os = openFileOutput(Constants.Files.WALLET_KEY_BACKUP_PROTOBUF, Context.MODE_PRIVATE);
+ walletProto.writeTo(os);
+ watch.stop();
+ log.info("wallet backed up to: '{}', took {}", Constants.Files.WALLET_KEY_BACKUP_PROTOBUF, watch);
+ } catch (final IOException x) {
+ log.error("problem writing wallet backup", x);
+ } finally {
+ try {
+ os.close();
+ } catch (final IOException x) {
+ // swallow
+ }
+ }
+ }
+
+ private void cleanupFiles() {
+ for (final String filename : fileList()) {
+ if (filename.startsWith(Constants.Files.WALLET_KEY_BACKUP_BASE58)
+ || filename.startsWith(Constants.Files.WALLET_KEY_BACKUP_PROTOBUF + '.')
+ || filename.endsWith(".tmp")) {
+ final File file = new File(getFilesDir(), filename);
+ log.info("removing obsolete file: '{}'", file);
+ file.delete();
+ }
+ }
+ }
+
+ public void startBlockchainService(final boolean cancelCoinsReceived) {
+ if (cancelCoinsReceived)
+ startService(blockchainServiceCancelCoinsReceivedIntent);
+ else
+ startService(blockchainServiceIntent);
+ }
+
+ public void stopBlockchainService() {
+ stopService(blockchainServiceIntent);
+ }
+
+ public void resetBlockchain() {
+ // implicitly stops blockchain service
+ startService(blockchainServiceResetBlockchainIntent);
+ }
+
+ public void replaceWallet(final Wallet newWallet) {
+ resetBlockchain();
+ wallet.shutdownAutosaveAndWait();
+
+ wallet = newWallet;
+ config.maybeIncrementBestChainHeightEver(newWallet.getLastBlockSeenHeight());
+ afterLoadWallet();
+
+ final Intent broadcast = new Intent(ACTION_WALLET_REFERENCE_CHANGED);
+ broadcast.setPackage(getPackageName());
+ LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
+ }
+
+ public void processDirectTransaction(final Transaction tx) throws VerificationException {
+ if (wallet.isTransactionRelevant(tx)) {
+ wallet.receivePending(tx, null);
+ broadcastTransaction(tx);
+ }
+ }
+
+ public void broadcastTransaction(final Transaction tx) {
+ final Intent intent = new Intent(BlockchainService.ACTION_BROADCAST_TRANSACTION, null, this,
+ BlockchainServiceImpl.class);
+ intent.putExtra(BlockchainService.ACTION_BROADCAST_TRANSACTION_HASH, tx.getHash().getBytes());
+ startService(intent);
+ }
+
+ public static PackageInfo packageInfoFromContext(final Context context) {
+ try {
+ return context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+ } catch (final NameNotFoundException x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ public PackageInfo packageInfo() {
+ return packageInfo;
+ }
+
+ public final String applicationPackageFlavor() {
+ final String packageName = getPackageName();
+ final int index = packageName.lastIndexOf('_');
+
+ if (index != -1)
+ return packageName.substring(index + 1);
+ else
+ return null;
+ }
+
+ public static String httpUserAgent(final String versionName) {
+ final VersionMessage versionMessage = new VersionMessage(Constants.NETWORK_PARAMETERS, 0);
+ versionMessage.appendToSubVer(Constants.USER_AGENT, versionName, null);
+ return versionMessage.subVer;
+ }
+
+ public String httpUserAgent() {
+ return httpUserAgent(packageInfo().versionName);
+ }
+
+ public int maxConnectedPeers() {
+ final int memoryClass = activityManager.getMemoryClass();
+ if (memoryClass <= Constants.MEMORY_CLASS_LOWEND)
+ return 4;
+ else
+ return 6;
+ }
+
+ public static void scheduleStartBlockchainService(final Context context) {
+ final Configuration config = new Configuration(PreferenceManager.getDefaultSharedPreferences(context),
+ context.getResources());
+ final long lastUsedAgo = config.getLastUsedAgo();
+
+ // apply some backoff
+ final long alarmInterval;
+ if (lastUsedAgo < Constants.LAST_USAGE_THRESHOLD_JUST_MS)
+ alarmInterval = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
+ else if (lastUsedAgo < Constants.LAST_USAGE_THRESHOLD_RECENTLY_MS)
+ alarmInterval = AlarmManager.INTERVAL_HALF_DAY;
+ else
+ alarmInterval = AlarmManager.INTERVAL_DAY;
+
+ log.info("last used {} minutes ago, rescheduling blockchain sync in roughly {} minutes",
+ lastUsedAgo / DateUtils.MINUTE_IN_MILLIS, alarmInterval / DateUtils.MINUTE_IN_MILLIS);
+
+ final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ final PendingIntent alarmIntent = PendingIntent.getService(context, 0,
+ new Intent(context, BlockchainServiceImpl.class), 0);
+ alarmManager.cancel(alarmIntent);
+
+ // workaround for no inexact set() before KitKat
+ final long now = System.currentTimeMillis();
+ alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, now + alarmInterval, AlarmManager.INTERVAL_DAY,
+ alarmIntent);
+ }
}
diff --git a/wallet/src/de/schildbach/wallet/WalletBalanceWidgetProvider.java b/wallet/src/de/schildbach/wallet/WalletBalanceWidgetProvider.java
index ea1ea64885..8f7e2d207c 100644
--- a/wallet/src/de/schildbach/wallet/WalletBalanceWidgetProvider.java
+++ b/wallet/src/de/schildbach/wallet/WalletBalanceWidgetProvider.java
@@ -27,6 +27,15 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import de.schildbach.wallet.ExchangeRatesProvider.ExchangeRate;
+import de.schildbach.wallet.ui.RequestCoinsActivity;
+import de.schildbach.wallet.ui.SendCoinsQrActivity;
+import de.schildbach.wallet.ui.WalletActivity;
+import de.schildbach.wallet.ui.send.SendCoinsActivity;
+import de.schildbach.wallet.util.GenericUtils;
+import de.schildbach.wallet.util.MonetarySpannable;
+import de.schildbach.wallet_test.R;
+
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
@@ -40,155 +49,132 @@
import android.text.style.ForegroundColorSpan;
import android.view.View;
import android.widget.RemoteViews;
-import de.schildbach.wallet.ExchangeRatesProvider.ExchangeRate;
-import de.schildbach.wallet.ui.RequestCoinsActivity;
-import de.schildbach.wallet.ui.SendCoinsQrActivity;
-import de.schildbach.wallet.ui.WalletActivity;
-import de.schildbach.wallet.ui.send.SendCoinsActivity;
-import de.schildbach.wallet.util.GenericUtils;
-import de.schildbach.wallet.util.MonetarySpannable;
-import de.schildbach.wallet_test.R;
/**
* @author Andreas Schildbach
*/
-public class WalletBalanceWidgetProvider extends AppWidgetProvider
-{
- private static final Logger log = LoggerFactory.getLogger(WalletBalanceWidgetProvider.class);
-
- @Override
- public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds)
- {
- final WalletApplication application = (WalletApplication) context.getApplicationContext();
- final Coin balance = application.getWallet().getBalance(BalanceType.ESTIMATED);
-
- updateWidgets(context, appWidgetManager, appWidgetIds, balance);
- }
-
- @Override
- public void onAppWidgetOptionsChanged(final Context context, final AppWidgetManager appWidgetManager, final int appWidgetId,
- final Bundle newOptions)
- {
- if (newOptions != null)
- log.info("app widget {} options changed: minWidth={}", appWidgetId, newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH));
-
- final WalletApplication application = (WalletApplication) context.getApplicationContext();
- final Coin balance = application.getWallet().getBalance(BalanceType.ESTIMATED);
-
- updateWidget(context, appWidgetManager, appWidgetId, newOptions, balance);
- }
-
- public static void updateWidgets(final Context context, final Wallet wallet)
- {
- final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
- final ComponentName providerName = new ComponentName(context, WalletBalanceWidgetProvider.class);
-
- try
- {
- final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(providerName);
-
- if (appWidgetIds.length > 0)
- {
- final Coin balance = wallet.getBalance(BalanceType.ESTIMATED);
- WalletBalanceWidgetProvider.updateWidgets(context, appWidgetManager, appWidgetIds, balance);
- }
- }
- catch (final RuntimeException x) // system server dead?
- {
- log.warn("cannot update app widgets", x);
- }
- }
-
- private static void updateWidgets(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds, final Coin balance)
- {
- for (final int appWidgetId : appWidgetIds)
- {
- final Bundle options = getAppWidgetOptions(appWidgetManager, appWidgetId);
- updateWidget(context, appWidgetManager, appWidgetId, options, balance);
- }
- }
-
- private static void updateWidget(final Context context, final AppWidgetManager appWidgetManager, final int appWidgetId,
- final Bundle appWidgetOptions, final Coin balance)
- {
- final Configuration config = new Configuration(PreferenceManager.getDefaultSharedPreferences(context), context.getResources());
- final MonetaryFormat btcFormat = config.getFormat();
-
- final Spannable balanceStr = new MonetarySpannable(btcFormat.noCode(), balance).applyMarkup(null,
- MonetarySpannable.STANDARD_INSIGNIFICANT_SPANS);
-
- final Cursor data = context.getContentResolver().query(ExchangeRatesProvider.contentUri(context.getPackageName(), true), null,
- ExchangeRatesProvider.KEY_CURRENCY_CODE, new String[] { config.getExchangeCurrencyCode() }, null);
- final Spannable localBalanceStr;
- if (data != null)
- {
- if (data.moveToFirst())
- {
- final ExchangeRate exchangeRate = ExchangeRatesProvider.getExchangeRate(data);
- final Fiat localBalance = exchangeRate.rate.coinToFiat(balance);
- final MonetaryFormat localFormat = Constants.LOCAL_FORMAT.code(0,
- Constants.PREFIX_ALMOST_EQUAL_TO + GenericUtils.currencySymbol(exchangeRate.getCurrencyCode()));
- final Object[] prefixSpans = new Object[] { MonetarySpannable.SMALLER_SPAN,
- new ForegroundColorSpan(context.getResources().getColor(R.color.fg_less_significant)) };
- localBalanceStr = new MonetarySpannable(localFormat, localBalance).applyMarkup(prefixSpans,
- MonetarySpannable.STANDARD_INSIGNIFICANT_SPANS);
- }
- else
- {
- localBalanceStr = null;
- }
-
- data.close();
- }
- else
- {
- localBalanceStr = null;
- }
-
- final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.wallet_balance_widget_content);
-
- final String currencyCode = btcFormat.code();
- if (MonetaryFormat.CODE_BTC.equals(currencyCode))
- views.setImageViewResource(R.id.widget_wallet_prefix, R.drawable.currency_symbol_btc);
- else if (MonetaryFormat.CODE_MBTC.equals(currencyCode))
- views.setImageViewResource(R.id.widget_wallet_prefix, R.drawable.currency_symbol_mbtc);
- else if (MonetaryFormat.CODE_UBTC.equals(currencyCode))
- views.setImageViewResource(R.id.widget_wallet_prefix, R.drawable.currency_symbol_ubtc);
-
- views.setTextViewText(R.id.widget_wallet_balance_btc, balanceStr);
- views.setViewVisibility(R.id.widget_wallet_balance_local, localBalanceStr != null ? View.VISIBLE : View.GONE);
- views.setTextViewText(R.id.widget_wallet_balance_local, localBalanceStr);
-
- if (appWidgetOptions != null)
- {
- final int minWidth = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
- views.setViewVisibility(R.id.widget_app_icon, minWidth > 400 ? View.VISIBLE : View.GONE);
- views.setViewVisibility(R.id.widget_button_request, minWidth > 300 ? View.VISIBLE : View.GONE);
- views.setViewVisibility(R.id.widget_button_send, minWidth > 300 ? View.VISIBLE : View.GONE);
- views.setViewVisibility(R.id.widget_button_send_qr, minWidth > 200 ? View.VISIBLE : View.GONE);
- }
-
- views.setOnClickPendingIntent(R.id.widget_button_balance, PendingIntent.getActivity(context, 0, new Intent(context, WalletActivity.class), 0));
- views.setOnClickPendingIntent(R.id.widget_button_request,
- PendingIntent.getActivity(context, 0, new Intent(context, RequestCoinsActivity.class), 0));
- views.setOnClickPendingIntent(R.id.widget_button_send, PendingIntent.getActivity(context, 0, new Intent(context, SendCoinsActivity.class), 0));
- views.setOnClickPendingIntent(R.id.widget_button_send_qr,
- PendingIntent.getActivity(context, 0, new Intent(context, SendCoinsQrActivity.class), 0));
-
- appWidgetManager.updateAppWidget(appWidgetId, views);
- }
-
- private static Bundle getAppWidgetOptions(final AppWidgetManager appWidgetManager, final int appWidgetId)
- {
- try
- {
- final Method getAppWidgetOptions = AppWidgetManager.class.getMethod("getAppWidgetOptions", Integer.TYPE);
- final Bundle options = (Bundle) getAppWidgetOptions.invoke(appWidgetManager, appWidgetId);
- return options;
- }
- catch (final Exception x)
- {
- return null;
- }
- }
+public class WalletBalanceWidgetProvider extends AppWidgetProvider {
+ private static final Logger log = LoggerFactory.getLogger(WalletBalanceWidgetProvider.class);
+
+ @Override
+ public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
+ final WalletApplication application = (WalletApplication) context.getApplicationContext();
+ final Coin balance = application.getWallet().getBalance(BalanceType.ESTIMATED);
+
+ updateWidgets(context, appWidgetManager, appWidgetIds, balance);
+ }
+
+ @Override
+ public void onAppWidgetOptionsChanged(final Context context, final AppWidgetManager appWidgetManager,
+ final int appWidgetId, final Bundle newOptions) {
+ if (newOptions != null)
+ log.info("app widget {} options changed: minWidth={}", appWidgetId,
+ newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH));
+
+ final WalletApplication application = (WalletApplication) context.getApplicationContext();
+ final Coin balance = application.getWallet().getBalance(BalanceType.ESTIMATED);
+
+ updateWidget(context, appWidgetManager, appWidgetId, newOptions, balance);
+ }
+
+ public static void updateWidgets(final Context context, final Wallet wallet) {
+ final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
+ final ComponentName providerName = new ComponentName(context, WalletBalanceWidgetProvider.class);
+
+ try {
+ final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(providerName);
+
+ if (appWidgetIds.length > 0) {
+ final Coin balance = wallet.getBalance(BalanceType.ESTIMATED);
+ WalletBalanceWidgetProvider.updateWidgets(context, appWidgetManager, appWidgetIds, balance);
+ }
+ } catch (final RuntimeException x) // system server dead?
+ {
+ log.warn("cannot update app widgets", x);
+ }
+ }
+
+ private static void updateWidgets(final Context context, final AppWidgetManager appWidgetManager,
+ final int[] appWidgetIds, final Coin balance) {
+ for (final int appWidgetId : appWidgetIds) {
+ final Bundle options = getAppWidgetOptions(appWidgetManager, appWidgetId);
+ updateWidget(context, appWidgetManager, appWidgetId, options, balance);
+ }
+ }
+
+ private static void updateWidget(final Context context, final AppWidgetManager appWidgetManager,
+ final int appWidgetId, final Bundle appWidgetOptions, final Coin balance) {
+ final Configuration config = new Configuration(PreferenceManager.getDefaultSharedPreferences(context),
+ context.getResources());
+ final MonetaryFormat btcFormat = config.getFormat();
+
+ final Spannable balanceStr = new MonetarySpannable(btcFormat.noCode(), balance).applyMarkup(null,
+ MonetarySpannable.STANDARD_INSIGNIFICANT_SPANS);
+
+ final Cursor data = context.getContentResolver().query(
+ ExchangeRatesProvider.contentUri(context.getPackageName(), true), null,
+ ExchangeRatesProvider.KEY_CURRENCY_CODE, new String[] { config.getExchangeCurrencyCode() }, null);
+ final Spannable localBalanceStr;
+ if (data != null) {
+ if (data.moveToFirst()) {
+ final ExchangeRate exchangeRate = ExchangeRatesProvider.getExchangeRate(data);
+ final Fiat localBalance = exchangeRate.rate.coinToFiat(balance);
+ final MonetaryFormat localFormat = Constants.LOCAL_FORMAT.code(0,
+ Constants.PREFIX_ALMOST_EQUAL_TO + GenericUtils.currencySymbol(exchangeRate.getCurrencyCode()));
+ final Object[] prefixSpans = new Object[] { MonetarySpannable.SMALLER_SPAN,
+ new ForegroundColorSpan(context.getResources().getColor(R.color.fg_less_significant)) };
+ localBalanceStr = new MonetarySpannable(localFormat, localBalance).applyMarkup(prefixSpans,
+ MonetarySpannable.STANDARD_INSIGNIFICANT_SPANS);
+ } else {
+ localBalanceStr = null;
+ }
+
+ data.close();
+ } else {
+ localBalanceStr = null;
+ }
+
+ final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.wallet_balance_widget_content);
+
+ final String currencyCode = btcFormat.code();
+ if (MonetaryFormat.CODE_BTC.equals(currencyCode))
+ views.setImageViewResource(R.id.widget_wallet_prefix, R.drawable.currency_symbol_btc);
+ else if (MonetaryFormat.CODE_MBTC.equals(currencyCode))
+ views.setImageViewResource(R.id.widget_wallet_prefix, R.drawable.currency_symbol_mbtc);
+ else if (MonetaryFormat.CODE_UBTC.equals(currencyCode))
+ views.setImageViewResource(R.id.widget_wallet_prefix, R.drawable.currency_symbol_ubtc);
+
+ views.setTextViewText(R.id.widget_wallet_balance_btc, balanceStr);
+ views.setViewVisibility(R.id.widget_wallet_balance_local, localBalanceStr != null ? View.VISIBLE : View.GONE);
+ views.setTextViewText(R.id.widget_wallet_balance_local, localBalanceStr);
+
+ if (appWidgetOptions != null) {
+ final int minWidth = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
+ views.setViewVisibility(R.id.widget_app_icon, minWidth > 400 ? View.VISIBLE : View.GONE);
+ views.setViewVisibility(R.id.widget_button_request, minWidth > 300 ? View.VISIBLE : View.GONE);
+ views.setViewVisibility(R.id.widget_button_send, minWidth > 300 ? View.VISIBLE : View.GONE);
+ views.setViewVisibility(R.id.widget_button_send_qr, minWidth > 200 ? View.VISIBLE : View.GONE);
+ }
+
+ views.setOnClickPendingIntent(R.id.widget_button_balance,
+ PendingIntent.getActivity(context, 0, new Intent(context, WalletActivity.class), 0));
+ views.setOnClickPendingIntent(R.id.widget_button_request,
+ PendingIntent.getActivity(context, 0, new Intent(context, RequestCoinsActivity.class), 0));
+ views.setOnClickPendingIntent(R.id.widget_button_send,
+ PendingIntent.getActivity(context, 0, new Intent(context, SendCoinsActivity.class), 0));
+ views.setOnClickPendingIntent(R.id.widget_button_send_qr,
+ PendingIntent.getActivity(context, 0, new Intent(context, SendCoinsQrActivity.class), 0));
+
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ }
+
+ private static Bundle getAppWidgetOptions(final AppWidgetManager appWidgetManager, final int appWidgetId) {
+ try {
+ final Method getAppWidgetOptions = AppWidgetManager.class.getMethod("getAppWidgetOptions", Integer.TYPE);
+ final Bundle options = (Bundle) getAppWidgetOptions.invoke(appWidgetManager, appWidgetId);
+ return options;
+ } catch (final Exception x) {
+ return null;
+ }
+ }
}
diff --git a/wallet/src/de/schildbach/wallet/camera/CameraManager.java b/wallet/src/de/schildbach/wallet/camera/CameraManager.java
index 2abd9beaf4..3c44e91d37 100644
--- a/wallet/src/de/schildbach/wallet/camera/CameraManager.java
+++ b/wallet/src/de/schildbach/wallet/camera/CameraManager.java
@@ -27,6 +27,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.zxing.PlanarYUVLuminanceSource;
+
import android.annotation.SuppressLint;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -35,311 +37,275 @@
import android.hardware.Camera.PreviewCallback;
import android.view.TextureView;
-import com.google.zxing.PlanarYUVLuminanceSource;
-
/**
* @author Andreas Schildbach
*/
@SuppressWarnings("deprecation")
-public final class CameraManager
-{
- private static final int MIN_FRAME_SIZE = 240;
- private static final int MAX_FRAME_SIZE = 600;
- private static final int MIN_PREVIEW_PIXELS = 470 * 320; // normal screen
- private static final int MAX_PREVIEW_PIXELS = 1280 * 720;
-
- private Camera camera;
- private CameraInfo cameraInfo = new CameraInfo();
- private Camera.Size cameraResolution;
- private Rect frame;
- private RectF framePreview;
-
- private static final Logger log = LoggerFactory.getLogger(CameraManager.class);
-
- public Rect getFrame()
- {
- return frame;
- }
-
- public RectF getFramePreview()
- {
- return framePreview;
- }
-
- public int getFacing()
- {
- return cameraInfo.facing;
- }
-
- public int getOrientation()
- {
- return cameraInfo.orientation;
- }
-
- public Camera open(final TextureView textureView, final int displayOrientation, final boolean continuousAutoFocus) throws IOException
- {
- final int cameraId = determineCameraId();
- Camera.getCameraInfo(cameraId, cameraInfo);
-
- log.info("opening camera id {}: {}-facing, camera orientation: {}, display orientation: {}", cameraId,
- cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK ? "back" : "front", cameraInfo.orientation, displayOrientation);
- camera = Camera.open(cameraId);
-
- if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
- camera.setDisplayOrientation((720 - displayOrientation - cameraInfo.orientation) % 360);
- else if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
- camera.setDisplayOrientation((720 - displayOrientation + cameraInfo.orientation) % 360);
- else
- throw new IllegalStateException("facing: " + cameraInfo.facing);
-
- camera.setPreviewTexture(textureView.getSurfaceTexture());
-
- final Camera.Parameters parameters = camera.getParameters();
-
- cameraResolution = findBestPreviewSizeValue(parameters, textureView.getWidth(), textureView.getHeight());
-
- final int width = textureView.getWidth();
- final int height = textureView.getHeight();
-
- final int rawSize = Math.min(width * 2 / 3, height * 2 / 3);
- final int frameSize = Math.max(MIN_FRAME_SIZE, Math.min(MAX_FRAME_SIZE, rawSize));
-
- final int leftOffset = (width - frameSize) / 2;
- final int topOffset = (height - frameSize) / 2;
- frame = new Rect(leftOffset, topOffset, leftOffset + frameSize, topOffset + frameSize);
- framePreview = new RectF(frame.left * cameraResolution.width / width, frame.top * cameraResolution.height / height,
- frame.right * cameraResolution.width / width, frame.bottom * cameraResolution.height / height);
-
- final String savedParameters = parameters == null ? null : parameters.flatten();
-
- try
- {
- setDesiredCameraParameters(camera, cameraResolution, continuousAutoFocus);
- }
- catch (final RuntimeException x)
- {
- if (savedParameters != null)
- {
- final Camera.Parameters parameters2 = camera.getParameters();
- parameters2.unflatten(savedParameters);
- try
- {
- camera.setParameters(parameters2);
- setDesiredCameraParameters(camera, cameraResolution, continuousAutoFocus);
- }
- catch (final RuntimeException x2)
- {
- log.info("problem setting camera parameters", x2);
- }
- }
- }
-
- try
- {
- camera.startPreview();
- return camera;
- }
- catch (final RuntimeException x)
- {
- log.warn("something went wrong while starting camera preview", x);
- camera.release();
- throw x;
- }
- }
-
- private int determineCameraId()
- {
- final int cameraCount = Camera.getNumberOfCameras();
- final CameraInfo cameraInfo = new CameraInfo();
-
- // prefer back-facing camera
- for (int i = 0; i < cameraCount; i++)
- {
- Camera.getCameraInfo(i, cameraInfo);
- if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
- return i;
- }
-
- // fall back to front-facing camera
- for (int i = 0; i < cameraCount; i++)
- {
- Camera.getCameraInfo(i, cameraInfo);
- if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
- return i;
- }
-
- return -1;
- }
-
- public void close()
- {
- if (camera != null)
- {
- try
- {
- camera.stopPreview();
- }
- catch (final RuntimeException x)
- {
- log.warn("something went wrong while stopping camera preview", x);
- }
-
- camera.release();
- }
- }
-
- private static final Comparator numPixelComparator = new Comparator()
- {
- @Override
- public int compare(final Camera.Size size1, final Camera.Size size2)
- {
- final int pixels1 = size1.height * size1.width;
- final int pixels2 = size2.height * size2.width;
-
- if (pixels1 < pixels2)
- return 1;
- else if (pixels1 > pixels2)
- return -1;
- else
- return 0;
- }
- };
-
- private static Camera.Size findBestPreviewSizeValue(final Camera.Parameters parameters, int width, int height)
- {
- if (height > width)
- {
- final int temp = width;
- width = height;
- height = temp;
- }
-
- final float screenAspectRatio = (float) width / (float) height;
-
- final List rawSupportedSizes = parameters.getSupportedPreviewSizes();
- if (rawSupportedSizes == null)
- return parameters.getPreviewSize();
-
- // sort by size, descending
- final List supportedPreviewSizes = new ArrayList(rawSupportedSizes);
- Collections.sort(supportedPreviewSizes, numPixelComparator);
-
- Camera.Size bestSize = null;
- float diff = Float.POSITIVE_INFINITY;
-
- for (final Camera.Size supportedPreviewSize : supportedPreviewSizes)
- {
- final int realWidth = supportedPreviewSize.width;
- final int realHeight = supportedPreviewSize.height;
- final int realPixels = realWidth * realHeight;
- if (realPixels < MIN_PREVIEW_PIXELS || realPixels > MAX_PREVIEW_PIXELS)
- continue;
-
- final boolean isCandidatePortrait = realWidth < realHeight;
- final int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth;
- final int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight;
- if (maybeFlippedWidth == width && maybeFlippedHeight == height)
- return supportedPreviewSize;
-
- final float aspectRatio = (float) maybeFlippedWidth / (float) maybeFlippedHeight;
- final float newDiff = Math.abs(aspectRatio - screenAspectRatio);
- if (newDiff < diff)
- {
- bestSize = supportedPreviewSize;
- diff = newDiff;
- }
- }
-
- if (bestSize != null)
- return bestSize;
- else
- return parameters.getPreviewSize();
- }
-
- @SuppressLint("InlinedApi")
- private static void setDesiredCameraParameters(final Camera camera, final Camera.Size cameraResolution, final boolean continuousAutoFocus)
- {
- final Camera.Parameters parameters = camera.getParameters();
- if (parameters == null)
- return;
-
- final List supportedFocusModes = parameters.getSupportedFocusModes();
- final String focusMode = continuousAutoFocus ? findValue(supportedFocusModes, Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
- Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO, Camera.Parameters.FOCUS_MODE_AUTO, Camera.Parameters.FOCUS_MODE_MACRO) : findValue(
- supportedFocusModes, Camera.Parameters.FOCUS_MODE_AUTO, Camera.Parameters.FOCUS_MODE_MACRO);
- if (focusMode != null)
- parameters.setFocusMode(focusMode);
-
- parameters.setPreviewSize(cameraResolution.width, cameraResolution.height);
-
- camera.setParameters(parameters);
- }
-
- public void requestPreviewFrame(final PreviewCallback callback)
- {
- try
- {
- camera.setOneShotPreviewCallback(callback);
- }
- catch (final RuntimeException x)
- {
- log.warn("problem requesting preview frame, callback won't be called", x);
- }
- }
-
- public PlanarYUVLuminanceSource buildLuminanceSource(final byte[] data)
- {
- return new PlanarYUVLuminanceSource(data, cameraResolution.width, cameraResolution.height, (int) framePreview.left, (int) framePreview.top,
- (int) framePreview.width(), (int) framePreview.height(), false);
- }
-
- public void setTorch(final boolean enabled)
- {
- if (enabled != getTorchEnabled(camera))
- setTorchEnabled(camera, enabled);
- }
-
- private static boolean getTorchEnabled(final Camera camera)
- {
- final Camera.Parameters parameters = camera.getParameters();
- if (parameters != null)
- {
- final String flashMode = camera.getParameters().getFlashMode();
- return flashMode != null && (Camera.Parameters.FLASH_MODE_ON.equals(flashMode) || Camera.Parameters.FLASH_MODE_TORCH.equals(flashMode));
- }
-
- return false;
- }
-
- private static void setTorchEnabled(final Camera camera, final boolean enabled)
- {
- final Camera.Parameters parameters = camera.getParameters();
-
- final List supportedFlashModes = parameters.getSupportedFlashModes();
- if (supportedFlashModes != null)
- {
- final String flashMode;
- if (enabled)
- flashMode = findValue(supportedFlashModes, Camera.Parameters.FLASH_MODE_TORCH, Camera.Parameters.FLASH_MODE_ON);
- else
- flashMode = findValue(supportedFlashModes, Camera.Parameters.FLASH_MODE_OFF);
-
- if (flashMode != null)
- {
- camera.cancelAutoFocus(); // autofocus can cause conflict
-
- parameters.setFlashMode(flashMode);
- camera.setParameters(parameters);
- }
- }
- }
-
- private static String findValue(final Collection values, final String... valuesToFind)
- {
- for (final String valueToFind : valuesToFind)
- if (values.contains(valueToFind))
- return valueToFind;
-
- return null;
- }
+public final class CameraManager {
+ private static final int MIN_FRAME_SIZE = 240;
+ private static final int MAX_FRAME_SIZE = 600;
+ private static final int MIN_PREVIEW_PIXELS = 470 * 320; // normal screen
+ private static final int MAX_PREVIEW_PIXELS = 1280 * 720;
+
+ private Camera camera;
+ private CameraInfo cameraInfo = new CameraInfo();
+ private Camera.Size cameraResolution;
+ private Rect frame;
+ private RectF framePreview;
+
+ private static final Logger log = LoggerFactory.getLogger(CameraManager.class);
+
+ public Rect getFrame() {
+ return frame;
+ }
+
+ public RectF getFramePreview() {
+ return framePreview;
+ }
+
+ public int getFacing() {
+ return cameraInfo.facing;
+ }
+
+ public int getOrientation() {
+ return cameraInfo.orientation;
+ }
+
+ public Camera open(final TextureView textureView, final int displayOrientation, final boolean continuousAutoFocus)
+ throws IOException {
+ final int cameraId = determineCameraId();
+ Camera.getCameraInfo(cameraId, cameraInfo);
+
+ log.info("opening camera id {}: {}-facing, camera orientation: {}, display orientation: {}", cameraId,
+ cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK ? "back" : "front", cameraInfo.orientation,
+ displayOrientation);
+ camera = Camera.open(cameraId);
+
+ if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
+ camera.setDisplayOrientation((720 - displayOrientation - cameraInfo.orientation) % 360);
+ else if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
+ camera.setDisplayOrientation((720 - displayOrientation + cameraInfo.orientation) % 360);
+ else
+ throw new IllegalStateException("facing: " + cameraInfo.facing);
+
+ camera.setPreviewTexture(textureView.getSurfaceTexture());
+
+ final Camera.Parameters parameters = camera.getParameters();
+
+ cameraResolution = findBestPreviewSizeValue(parameters, textureView.getWidth(), textureView.getHeight());
+
+ final int width = textureView.getWidth();
+ final int height = textureView.getHeight();
+
+ final int rawSize = Math.min(width * 2 / 3, height * 2 / 3);
+ final int frameSize = Math.max(MIN_FRAME_SIZE, Math.min(MAX_FRAME_SIZE, rawSize));
+
+ final int leftOffset = (width - frameSize) / 2;
+ final int topOffset = (height - frameSize) / 2;
+ frame = new Rect(leftOffset, topOffset, leftOffset + frameSize, topOffset + frameSize);
+ framePreview = new RectF(frame.left * cameraResolution.width / width,
+ frame.top * cameraResolution.height / height, frame.right * cameraResolution.width / width,
+ frame.bottom * cameraResolution.height / height);
+
+ final String savedParameters = parameters == null ? null : parameters.flatten();
+
+ try {
+ setDesiredCameraParameters(camera, cameraResolution, continuousAutoFocus);
+ } catch (final RuntimeException x) {
+ if (savedParameters != null) {
+ final Camera.Parameters parameters2 = camera.getParameters();
+ parameters2.unflatten(savedParameters);
+ try {
+ camera.setParameters(parameters2);
+ setDesiredCameraParameters(camera, cameraResolution, continuousAutoFocus);
+ } catch (final RuntimeException x2) {
+ log.info("problem setting camera parameters", x2);
+ }
+ }
+ }
+
+ try {
+ camera.startPreview();
+ return camera;
+ } catch (final RuntimeException x) {
+ log.warn("something went wrong while starting camera preview", x);
+ camera.release();
+ throw x;
+ }
+ }
+
+ private int determineCameraId() {
+ final int cameraCount = Camera.getNumberOfCameras();
+ final CameraInfo cameraInfo = new CameraInfo();
+
+ // prefer back-facing camera
+ for (int i = 0; i < cameraCount; i++) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
+ return i;
+ }
+
+ // fall back to front-facing camera
+ for (int i = 0; i < cameraCount; i++) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
+ return i;
+ }
+
+ return -1;
+ }
+
+ public void close() {
+ if (camera != null) {
+ try {
+ camera.stopPreview();
+ } catch (final RuntimeException x) {
+ log.warn("something went wrong while stopping camera preview", x);
+ }
+
+ camera.release();
+ }
+ }
+
+ private static final Comparator numPixelComparator = new Comparator() {
+ @Override
+ public int compare(final Camera.Size size1, final Camera.Size size2) {
+ final int pixels1 = size1.height * size1.width;
+ final int pixels2 = size2.height * size2.width;
+
+ if (pixels1 < pixels2)
+ return 1;
+ else if (pixels1 > pixels2)
+ return -1;
+ else
+ return 0;
+ }
+ };
+
+ private static Camera.Size findBestPreviewSizeValue(final Camera.Parameters parameters, int width, int height) {
+ if (height > width) {
+ final int temp = width;
+ width = height;
+ height = temp;
+ }
+
+ final float screenAspectRatio = (float) width / (float) height;
+
+ final List rawSupportedSizes = parameters.getSupportedPreviewSizes();
+ if (rawSupportedSizes == null)
+ return parameters.getPreviewSize();
+
+ // sort by size, descending
+ final List supportedPreviewSizes = new ArrayList(rawSupportedSizes);
+ Collections.sort(supportedPreviewSizes, numPixelComparator);
+
+ Camera.Size bestSize = null;
+ float diff = Float.POSITIVE_INFINITY;
+
+ for (final Camera.Size supportedPreviewSize : supportedPreviewSizes) {
+ final int realWidth = supportedPreviewSize.width;
+ final int realHeight = supportedPreviewSize.height;
+ final int realPixels = realWidth * realHeight;
+ if (realPixels < MIN_PREVIEW_PIXELS || realPixels > MAX_PREVIEW_PIXELS)
+ continue;
+
+ final boolean isCandidatePortrait = realWidth < realHeight;
+ final int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth;
+ final int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight;
+ if (maybeFlippedWidth == width && maybeFlippedHeight == height)
+ return supportedPreviewSize;
+
+ final float aspectRatio = (float) maybeFlippedWidth / (float) maybeFlippedHeight;
+ final float newDiff = Math.abs(aspectRatio - screenAspectRatio);
+ if (newDiff < diff) {
+ bestSize = supportedPreviewSize;
+ diff = newDiff;
+ }
+ }
+
+ if (bestSize != null)
+ return bestSize;
+ else
+ return parameters.getPreviewSize();
+ }
+
+ @SuppressLint("InlinedApi")
+ private static void setDesiredCameraParameters(final Camera camera, final Camera.Size cameraResolution,
+ final boolean continuousAutoFocus) {
+ final Camera.Parameters parameters = camera.getParameters();
+ if (parameters == null)
+ return;
+
+ final List supportedFocusModes = parameters.getSupportedFocusModes();
+ final String focusMode = continuousAutoFocus
+ ? findValue(supportedFocusModes, Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
+ Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO, Camera.Parameters.FOCUS_MODE_AUTO,
+ Camera.Parameters.FOCUS_MODE_MACRO)
+ : findValue(supportedFocusModes, Camera.Parameters.FOCUS_MODE_AUTO, Camera.Parameters.FOCUS_MODE_MACRO);
+ if (focusMode != null)
+ parameters.setFocusMode(focusMode);
+
+ parameters.setPreviewSize(cameraResolution.width, cameraResolution.height);
+
+ camera.setParameters(parameters);
+ }
+
+ public void requestPreviewFrame(final PreviewCallback callback) {
+ try {
+ camera.setOneShotPreviewCallback(callback);
+ } catch (final RuntimeException x) {
+ log.warn("problem requesting preview frame, callback won't be called", x);
+ }
+ }
+
+ public PlanarYUVLuminanceSource buildLuminanceSource(final byte[] data) {
+ return new PlanarYUVLuminanceSource(data, cameraResolution.width, cameraResolution.height,
+ (int) framePreview.left, (int) framePreview.top, (int) framePreview.width(),
+ (int) framePreview.height(), false);
+ }
+
+ public void setTorch(final boolean enabled) {
+ if (enabled != getTorchEnabled(camera))
+ setTorchEnabled(camera, enabled);
+ }
+
+ private static boolean getTorchEnabled(final Camera camera) {
+ final Camera.Parameters parameters = camera.getParameters();
+ if (parameters != null) {
+ final String flashMode = camera.getParameters().getFlashMode();
+ return flashMode != null && (Camera.Parameters.FLASH_MODE_ON.equals(flashMode)
+ || Camera.Parameters.FLASH_MODE_TORCH.equals(flashMode));
+ }
+
+ return false;
+ }
+
+ private static void setTorchEnabled(final Camera camera, final boolean enabled) {
+ final Camera.Parameters parameters = camera.getParameters();
+
+ final List supportedFlashModes = parameters.getSupportedFlashModes();
+ if (supportedFlashModes != null) {
+ final String flashMode;
+ if (enabled)
+ flashMode = findValue(supportedFlashModes, Camera.Parameters.FLASH_MODE_TORCH,
+ Camera.Parameters.FLASH_MODE_ON);
+ else
+ flashMode = findValue(supportedFlashModes, Camera.Parameters.FLASH_MODE_OFF);
+
+ if (flashMode != null) {
+ camera.cancelAutoFocus(); // autofocus can cause conflict
+
+ parameters.setFlashMode(flashMode);
+ camera.setParameters(parameters);
+ }
+ }
+ }
+
+ private static String findValue(final Collection values, final String... valuesToFind) {
+ for (final String valueToFind : valuesToFind)
+ if (values.contains(valueToFind))
+ return valueToFind;
+
+ return null;
+ }
}
diff --git a/wallet/src/de/schildbach/wallet/data/PaymentIntent.java b/wallet/src/de/schildbach/wallet/data/PaymentIntent.java
index 3285662823..cee9c1030e 100644
--- a/wallet/src/de/schildbach/wallet/data/PaymentIntent.java
+++ b/wallet/src/de/schildbach/wallet/data/PaymentIntent.java
@@ -38,556 +38,478 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import android.os.Parcel;
-import android.os.Parcelable;
-
import com.google.common.io.BaseEncoding;
import de.schildbach.wallet.Constants;
import de.schildbach.wallet.util.Bluetooth;
import de.schildbach.wallet.util.GenericUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
+
/**
* @author Andreas Schildbach
*/
-public final class PaymentIntent implements Parcelable
-{
- public enum Standard
- {
- BIP21, BIP70
- }
-
- public final static class Output implements Parcelable
- {
- public final Coin amount;
- public final Script script;
-
- public Output(final Coin amount, final Script script)
- {
- this.amount = amount;
- this.script = script;
- }
-
- public static Output valueOf(final PaymentProtocol.Output output) throws PaymentProtocolException.InvalidOutputs
- {
- try
- {
- final Script script = new Script(output.scriptData);
- return new PaymentIntent.Output(output.amount, script);
- }
- catch (final ScriptException x)
- {
- throw new PaymentProtocolException.InvalidOutputs("unparseable script in output: " + Constants.HEX.encode(output.scriptData));
- }
- }
-
- public boolean hasAmount()
- {
- return amount != null && amount.signum() != 0;
- }
-
- @Override
- public String toString()
- {
- final StringBuilder builder = new StringBuilder();
-
- builder.append(getClass().getSimpleName());
- builder.append('[');
- builder.append(hasAmount() ? amount.toPlainString() : "null");
- builder.append(',');
- if (script.isSentToAddress() || script.isPayToScriptHash())
- builder.append(script.getToAddress(Constants.NETWORK_PARAMETERS));
- else if (script.isSentToRawPubKey())
- builder.append(Constants.HEX.encode(script.getPubKey()));
- else if (script.isSentToMultiSig())
- builder.append("multisig");
- else
- builder.append("unknown");
- builder.append(']');
-
- return builder.toString();
- }
-
- @Override
- public int describeContents()
- {
- return 0;
- }
-
- @Override
- public void writeToParcel(final Parcel dest, final int flags)
- {
- dest.writeSerializable(amount);
-
- final byte[] program = script.getProgram();
- dest.writeInt(program.length);
- dest.writeByteArray(program);
- }
-
- public static final Parcelable.Creator