|
17 | 17 |
|
18 | 18 | package de.schildbach.wallet.ui;
|
19 | 19 |
|
| 20 | +import java.math.BigDecimal; |
20 | 21 | import java.math.BigInteger;
|
21 | 22 |
|
22 | 23 | import javax.annotation.CheckForNull;
|
23 | 24 | import javax.annotation.Nonnull;
|
24 | 25 | import javax.annotation.Nullable;
|
25 | 26 |
|
| 27 | +import android.app.AlertDialog; |
| 28 | +import android.util.Log; |
| 29 | +import android.widget.Toast; |
| 30 | +import com.google.bitcoin.core.InsufficientMoneyException; |
| 31 | +import com.google.bitcoin.core.VerificationException; |
| 32 | +import org.litecoin.LitecoinWallet; |
26 | 33 | import org.slf4j.Logger;
|
27 | 34 | import org.slf4j.LoggerFactory;
|
28 | 35 |
|
@@ -845,52 +852,111 @@ private void handleGo()
|
845 | 852 | sendRequest.changeAddress = WalletUtils.pickOldestKey(wallet).toAddress(Constants.NETWORK_PARAMETERS);
|
846 | 853 | sendRequest.emptyWallet = amount.equals(wallet.getBalance(BalanceType.AVAILABLE));
|
847 | 854 |
|
848 |
| - new SendCoinsOfflineTask(wallet, backgroundHandler) |
849 |
| - { |
850 |
| - @Override |
851 |
| - protected void onSuccess(final Transaction transaction) |
852 |
| - { |
853 |
| - sentTransaction = transaction; |
| 855 | + // Multi-part transaction creation to properly calculate fee |
| 856 | + // Complete the transaction in order to get the final size |
| 857 | + try { |
| 858 | + wallet.completeTx(sendRequest); |
| 859 | + } catch (InsufficientMoneyException e) { |
| 860 | + Log.i("wallet_ltc", "Insufficient funds when completing tx"); |
| 861 | + Toast |
| 862 | + .makeText(getActivity(), "Insufficient funds. Please lower the amount and try again.", Toast.LENGTH_LONG) |
| 863 | + .show(); |
| 864 | + return; |
| 865 | + } |
| 866 | + // Get the size of the transaction |
| 867 | + /* |
| 868 | + Log.d("Litecoin", "Transaction size is " + sendRequest.tx.getLength()); |
| 869 | + BigInteger nTransactionFee = Constants.MIN_TX_FEE; |
| 870 | + BigInteger nFeePerKB = Constants.TX_FEE_PER_KB; |
| 871 | + BigInteger nSizeFee = nFeePerKB.multiply(new BigInteger(Integer.toString(sendRequest.tx.getLength() / 1000))); |
| 872 | + BigInteger nPayFee = nTransactionFee.add(nSizeFee); |
| 873 | + */ |
| 874 | + |
| 875 | + if(sendRequest.fee.compareTo(Constants.MIN_TX_FEE) > 0) |
| 876 | + { |
| 877 | + Log.i("LitecoinSendCoins", "Higher fee: " + |
| 878 | + sendRequest.fee.toString() + " < " + sendRequest.fee.toString()); |
| 879 | + |
| 880 | + new AlertDialog.Builder(SendCoinsFragment.this.getActivity()) |
| 881 | + .setMessage("Transaction requires fee of " + |
| 882 | + new BigDecimal(sendRequest.fee).divide(new BigDecimal("100000000")) + ". Continue?") |
| 883 | + .setTitle("Extra fee needed") |
| 884 | + .setCancelable(true) |
| 885 | + .setNeutralButton(android.R.string.cancel, |
| 886 | + new DialogInterface.OnClickListener() { |
| 887 | + public void onClick(DialogInterface dialog, int whichButton) { |
| 888 | + startActivity(new Intent(getActivity(), WalletActivity.class)); |
| 889 | + getActivity().finish(); |
| 890 | + } |
| 891 | + }) |
| 892 | + .setPositiveButton(android.R.string.ok, |
| 893 | + new DialogInterface.OnClickListener() { |
| 894 | + public void onClick(DialogInterface dialogInterface, int i) { |
| 895 | + // Fees are agreeable |
| 896 | + // Process the transaction |
| 897 | + // Send Asynchronously |
| 898 | + new NormalSendCoinsOfflineTask(wallet, backgroundHandler).commitRequest(sendRequest); |
| 899 | + } |
| 900 | + }) |
| 901 | + .show(); |
| 902 | + } else { |
| 903 | + // No fee recalculation necessary |
| 904 | + // Process the transaction |
| 905 | + // Send Asynchronously |
| 906 | + new NormalSendCoinsOfflineTask(wallet, backgroundHandler).commitRequest(sendRequest); |
| 907 | + } |
854 | 908 |
|
855 |
| - state = State.SENDING; |
856 |
| - updateView(); |
| 909 | + } |
857 | 910 |
|
858 |
| - sentTransaction.getConfidence().addEventListener(sentTransactionConfidenceListener); |
| 911 | + class NormalSendCoinsOfflineTask extends SendCoinsOfflineTask { |
859 | 912 |
|
860 |
| - if (bluetoothAdapter != null && bluetoothAdapter.isEnabled() && bluetoothMac != null && bluetoothEnableView.isChecked()) |
861 |
| - { |
862 |
| - new SendBluetoothTask(bluetoothAdapter, backgroundHandler) |
863 |
| - { |
864 |
| - @Override |
865 |
| - protected void onResult(final boolean ack) |
866 |
| - { |
867 |
| - bluetoothAck = ack; |
| 913 | + public NormalSendCoinsOfflineTask(@Nonnull Wallet wallet, @Nonnull Handler backgroundHandler) { |
| 914 | + super(wallet, backgroundHandler); |
| 915 | + } |
868 | 916 |
|
869 |
| - if (state == State.SENDING) |
870 |
| - state = State.SENT; |
| 917 | + @Override |
| 918 | + protected void onSuccess(@Nonnull final Transaction transaction) |
| 919 | + { |
| 920 | + sentTransaction = transaction; |
871 | 921 |
|
872 |
| - updateView(); |
873 |
| - } |
874 |
| - }.send(bluetoothMac, transaction); // send asynchronously |
875 |
| - } |
| 922 | + state = State.SENDING; |
| 923 | + updateView(); |
876 | 924 |
|
877 |
| - application.broadcastTransaction(sentTransaction); |
| 925 | + sentTransaction.getConfidence().addEventListener(sentTransactionConfidenceListener); |
878 | 926 |
|
879 |
| - final Intent result = new Intent(); |
880 |
| - BitcoinIntegration.transactionHashToResult(result, sentTransaction.getHashAsString()); |
881 |
| - activity.setResult(Activity.RESULT_OK, result); |
882 |
| - } |
| 927 | + if (bluetoothAdapter != null && bluetoothAdapter.isEnabled() && bluetoothMac != null && bluetoothEnableView.isChecked()) |
| 928 | + { |
| 929 | + new SendBluetoothTask(bluetoothAdapter, backgroundHandler) |
| 930 | + { |
| 931 | + @Override |
| 932 | + protected void onResult(final boolean ack) |
| 933 | + { |
| 934 | + bluetoothAck = ack; |
883 | 935 |
|
884 |
| - @Override |
885 |
| - protected void onFailure() |
886 |
| - { |
887 |
| - state = State.FAILED; |
888 |
| - updateView(); |
| 936 | + if (state == State.SENDING) |
| 937 | + state = State.SENT; |
889 | 938 |
|
890 |
| - activity.longToast(R.string.send_coins_error_msg); |
891 |
| - } |
892 |
| - }.sendCoinsOffline(sendRequest); // send asynchronously |
893 |
| - } |
| 939 | + updateView(); |
| 940 | + } |
| 941 | + }.send(bluetoothMac, transaction); // send asynchronously |
| 942 | + } |
| 943 | + |
| 944 | + application.broadcastTransaction(sentTransaction); |
| 945 | + |
| 946 | + final Intent result = new Intent(); |
| 947 | + BitcoinIntegration.transactionHashToResult(result, sentTransaction.getHashAsString()); |
| 948 | + activity.setResult(Activity.RESULT_OK, result); |
| 949 | + } |
| 950 | + |
| 951 | + @Override |
| 952 | + protected void onFailure() |
| 953 | + { |
| 954 | + state = State.FAILED; |
| 955 | + updateView(); |
| 956 | + |
| 957 | + activity.longToast(R.string.send_coins_error_msg); |
| 958 | + } |
| 959 | + } |
894 | 960 |
|
895 | 961 | private void handleScan()
|
896 | 962 | {
|
@@ -940,8 +1006,14 @@ public CharSequence convertToString(final Cursor cursor)
|
940 | 1006 | @Override
|
941 | 1007 | public Cursor runQueryOnBackgroundThread(final CharSequence constraint)
|
942 | 1008 | {
|
943 |
| - final Cursor cursor = activity.managedQuery(AddressBookProvider.contentUri(activity.getPackageName()), null, |
944 |
| - AddressBookProvider.SELECTION_QUERY, new String[] { constraint.toString() }, null); |
| 1009 | + final Cursor cursor; |
| 1010 | + try { |
| 1011 | + cursor = activity.managedQuery(AddressBookProvider.contentUri(activity.getPackageName()), |
| 1012 | + null, AddressBookProvider.SELECTION_QUERY, new String[] { constraint.toString() }, null); |
| 1013 | + } catch(NullPointerException e) { |
| 1014 | + Log.i("wallet_ltc", "NULL Pointer exception when doing address book completion"); |
| 1015 | + return null; |
| 1016 | + } |
945 | 1017 | return cursor;
|
946 | 1018 | }
|
947 | 1019 | }
|
|
0 commit comments