All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.schildbach.wallet.integration.android.BitcoinIntegration Maven / Gradle / Ivy

/**
 * Copyright 2012-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.schildbach.wallet.integration.android;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.widget.Toast;

/**
 * @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/schildbach/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
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy