sending done + added Transfers + tweaks

This commit is contained in:
m2049r
2017-08-19 13:44:04 +02:00
parent b0efdca928
commit 40da44222e
17 changed files with 256 additions and 192 deletions
@@ -53,6 +53,7 @@ import java.nio.channels.FileChannel;
public class LoginActivity extends AppCompatActivity
implements LoginFragment.Listener, GenerateFragment.Listener, GenerateReviewFragment.Listener {
static final String TAG = "LoginActivity";
private static final String GENERATE_STACK = "gen";
static final int DAEMON_TIMEOUT = 500; // deamon must respond in 500ms
@@ -264,7 +265,7 @@ public class LoginActivity extends AppCompatActivity
}
void startGenerateFragment() {
replaceFragment(new GenerateFragment(), "gen", null);
replaceFragment(new GenerateFragment(), GENERATE_STACK, null);
Log.d(TAG, "GenerateFragment placed");
}
@@ -397,7 +398,7 @@ public class LoginActivity extends AppCompatActivity
&&
(testWallet(walletPath, password) == Wallet.Status.Status_Ok);
if (rc) {
popFragmentStack("gen");
popFragmentStack(GENERATE_STACK);
Toast.makeText(LoginActivity.this,
getString(R.string.generate_wallet_created), Toast.LENGTH_SHORT).show();
} else {
@@ -41,8 +41,6 @@ import com.m2049r.xmrwallet.util.TxData;
public class SendFragment extends Fragment {
static final String TAG = "GenerateFragment";
static final public String ARG_WALLETID = "walletId";
EditText etAddress;
EditText etPaymentId;
EditText etAmount;
@@ -56,11 +54,11 @@ public class SendFragment extends Fragment {
TextView tvTxDust;
Button bSend;
final static int Mixins[] = {4, 6, 8, 10, 13}; // must macth the layout
final static int Mixins[] = {4, 6, 8, 10, 13}; // must match the layout XML
final static PendingTransaction.Priority Priorities[] =
{PendingTransaction.Priority.Priority_Low,
PendingTransaction.Priority.Priority_Medium,
PendingTransaction.Priority.Priority_High}; // must macth the layout
PendingTransaction.Priority.Priority_High}; // must match the layout XML
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -87,12 +85,12 @@ public class SendFragment extends Fragment {
etAddress.setText("9tDC52GsMjTNt4dpnRCwAF7ekVBkbkgkXGaMKTcSTpBhGpqkPX56jCNRydLq9oGjbbAQBsZhLfgmTKsntmxRd3TaJFYM2f8");
boolean testnet = WalletManager.getInstance().isTestNet();
// TODO die if NOT testnet
if (!testnet) throw new IllegalStateException("Sending TX only on testnet. sorry.");
Helper.showKeyboard(getActivity());
etAddress.requestFocus();
etAddress.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
Log.d(TAG, actionId + "/" + (event == null ? null : event.toString()));
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
if (addressOk()) {
etPaymentId.requestFocus();
@@ -180,7 +178,7 @@ public class SendFragment extends Fragment {
int mixin = Mixins[sMixin.getSelectedItemPosition()];
int priorityIndex = sPriority.getSelectedItemPosition();
PendingTransaction.Priority priority = Priorities[priorityIndex];
Log.d(TAG, dst_addr + "/" + paymentId + "/" + amount + "/" + mixin + "/" + priority.toString());
//Log.d(TAG, dst_addr + "/" + paymentId + "/" + amount + "/" + mixin + "/" + priority.toString());
TxData txData = new TxData(
dst_addr,
paymentId,
@@ -198,6 +196,7 @@ public class SendFragment extends Fragment {
activityCallback.onPrepareSend(txData);
}
private void send() {
activityCallback.onSend();
}
@@ -227,11 +226,12 @@ public class SendFragment extends Fragment {
if (status != PendingTransaction.Status.Status_Ok) {
Log.d(TAG, "Wallet store failed: " + pendingTransaction.getErrorString());
}
/*
Log.d(TAG, "transaction amount " + pendingTransaction.getAmount());
Log.d(TAG, "transaction fee " + pendingTransaction.getFee());
Log.d(TAG, "transaction dust " + pendingTransaction.getDust());
Log.d(TAG, "transactions " + pendingTransaction.getTxCount());
*/
llConfirmSend.setVisibility(View.VISIBLE);
tvTxAmount.setText(Wallet.getDisplayAmount(pendingTransaction.getAmount()));
tvTxFee.setText(Wallet.getDisplayAmount(pendingTransaction.getFee()));
@@ -47,6 +47,10 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
private boolean synced = false;
public boolean isSynced() {
return synced;
}
@Override
protected void onStart() {
super.onStart();
@@ -187,8 +191,7 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
wl.acquire();
Log.d(TAG, "WakeLock acquired");
} catch (SecurityException ex) {
Log.d(TAG, "WakeLock NOT acquired");
Log.d(TAG, ex.getLocalizedMessage());
Log.d(TAG, "WakeLock NOT acquired: " + ex.getLocalizedMessage());
wl = null;
}
}
@@ -252,25 +255,39 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
///////////////////////////
// WalletService.Observer
///////////////////////////
// refresh and return if successful
@Override
public void onRefreshed(final Wallet wallet, final boolean full) {
public boolean onRefreshed(final Wallet wallet, final boolean full) {
Log.d(TAG, "onRefreshed()");
if (wallet.isSynchronized()) {
releaseWakeLock(); // the idea is to stay awake until synced
if (!synced) {
onProgress(null);
saveWallet(); // save on first sync
synced = true;
}
}
// TODO check which fragment is loaded
final WalletFragment walletFragment = (WalletFragment)
getFragmentManager().findFragmentById(R.id.fragment_container);
runOnUiThread(new Runnable() {
public void run() {
walletFragment.onRefreshed(wallet, full);
try {
final WalletFragment walletFragment = (WalletFragment)
getFragmentManager().findFragmentById(R.id.fragment_container);
if (wallet.isSynchronized()) {
releaseWakeLock(); // the idea is to stay awake until synced
if (!synced) {
onProgress(null);
saveWallet(); // save on first sync
synced = true;
runOnUiThread(new Runnable() {
public void run() {
walletFragment.onSynced();
}
});
}
}
});
runOnUiThread(new Runnable() {
public void run() {
walletFragment.onRefreshed(wallet, full);
}
});
return true;
} catch (ClassCastException ex) {
// not in wallet fragment (probably send monero)
// keep calm and carry on
}
return false;
}
@Override
@@ -36,6 +36,7 @@ import android.widget.TextView;
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Transfer;
import com.m2049r.xmrwallet.model.Wallet;
import java.text.NumberFormat;
@@ -53,6 +54,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
LinearLayout llProgress;
TextView tvProgress;
ProgressBar pbProgress;
Button bSend;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -66,7 +68,8 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
tvUnlockedBalance = (TextView) view.findViewById(R.id.tvUnlockedBalance);
tvBlockHeightProgress = (TextView) view.findViewById(R.id.tvBlockHeightProgress);
tvConnectionStatus = (TextView) view.findViewById(R.id.tvConnectionStatus);
Button bSend = (Button) view.findViewById(R.id.bSend);
bSend = (Button) view.findViewById(R.id.bSend);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list);
RecyclerView.ItemDecoration itemDecoration = new
@@ -85,13 +88,18 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
}
});
activityCallback.setTitle(getString(R.string.status_wallet_loading));
if (activityCallback.isSynced()) {
onSynced();
}
// activityCallback.setTitle(getString(R.string.status_wallet_loading));
activityCallback.forceUpdate();
return view;
}
// Callbacks from TransactionInfoAdapter
@Override
public void onInteraction(final View view, final TransactionInfo infoItem) {
@@ -103,7 +111,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
@Override
public void onClick(DialogInterface dialog, int which) {
ClipboardManager clipboardManager = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("TX", infoItem.getHash());
ClipData clip = ClipData.newPlainText("TX", infoItem.hash);
clipboardManager.setPrimaryClip(clip);
}
});
@@ -113,11 +121,25 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
public void onClick(DialogInterface dialog, int which) {
}
});
builder.setMessage("TX ID: " + infoItem.getHash() +
"\nPayment ID: " + infoItem.getPaymentId() +
"\nBlockHeight: " + infoItem.getBlockHeight() +
"\nAmount: " + Wallet.getDisplayAmount(infoItem.getAmount()) +
"\nFee: " + Wallet.getDisplayAmount(infoItem.getFee()));
// TODO use strings.xml
StringBuffer sb = new StringBuffer();
sb.append("TX ID: ").append(infoItem.hash);
sb.append("\nPayment ID: ").append(infoItem.paymentId);
sb.append("\nBlockHeight: ").append(infoItem.blockheight);
sb.append("\nAmount: ");
sb.append(infoItem.direction == TransactionInfo.Direction.Direction_In ? "+" : "-");
sb.append(Wallet.getDisplayAmount(infoItem.amount));
sb.append("\nFee: ").append(Wallet.getDisplayAmount(infoItem.fee));
sb.append("\nTransfers:");
if (infoItem.transfers.size() > 0) {
for (Transfer transfer : infoItem.transfers) {
sb.append("\n[").append(transfer.address.substring(0, 6)).append("] ");
sb.append(Wallet.getDisplayAmount(transfer.amount));
}
} else {
sb.append("-");
}
builder.setMessage(sb.toString());
AlertDialog alert1 = builder.create();
alert1.show();
}
@@ -133,6 +155,11 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
updateStatus(wallet);
}
public void onSynced() { // TODO watchonly
bSend.setVisibility(View.VISIBLE);
bSend.setEnabled(true);
}
public void onProgress(final String text) {
if (text != null) {
tvProgress.setText(text);
@@ -225,6 +252,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
void onSendRequest();
boolean isSynced();
}
@Override
@@ -88,8 +88,8 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
Collections.sort(data, new Comparator<TransactionInfo>() {
@Override
public int compare(TransactionInfo o1, TransactionInfo o2) {
long b1 = o1.getBlockHeight();
long b2 = o2.getBlockHeight();
long b1 = o1.blockheight;
long b2 = o2.blockheight;
return (b1 > b2) ? -1 : (b1 < b2) ? 1 : 0;
}
});
@@ -134,20 +134,20 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
void bind(int position) {
this.infoItem = infoItems.get(position);
String displayAmount = Wallet.getDisplayAmount(infoItem.getAmount());
String displayAmount = Wallet.getDisplayAmount(infoItem.amount);
// TODO fix this with i8n code
String amountParts[] = displayAmount.split("\\.");
// TODO what if there is no decimal point?
this.tvAmount.setText(amountParts[0]);
this.tvAmountDecimal.setText(amountParts[1]);
if (infoItem.getDirection() == TransactionInfo.Direction.Direction_In) {
if (infoItem.direction == TransactionInfo.Direction.Direction_In) {
setTxColour(TX_GREEN);
} else {
setTxColour(TX_RED);
}
this.tvDate.setText(getDate(infoItem.getTimestamp()));
this.tvTime.setText(getTime(infoItem.getTimestamp()));
this.tvDate.setText(getDate(infoItem.timestamp));
this.tvTime.setText(getTime(infoItem.timestamp));
itemView.setOnClickListener(this);
}
@@ -37,7 +37,7 @@ public class PendingTransaction {
Priority_Low(1),
Priority_Medium(2),
Priority_High(3),
Priority_Last(4); // TODO is this true?
Priority_Last(4);
private int value;
@@ -16,6 +16,7 @@
package com.m2049r.xmrwallet.model;
import java.util.ArrayList;
import java.util.List;
public class TransactionHistory {
@@ -29,6 +30,7 @@ public class TransactionHistory {
this.handle = handle;
}
/*
public TransactionInfo getTransaction(int i) {
long infoHandle = getTransactionByIndexJ(i);
return new TransactionInfo(infoHandle);
@@ -38,7 +40,7 @@ public class TransactionHistory {
long infoHandle = getTransactionByIdJ(id);
return new TransactionInfo(infoHandle);
}
*/
/*
public List<TransactionInfo> getAll() {
List<Long> handles = getAllJ();
@@ -51,12 +53,20 @@ public class TransactionHistory {
*/
public native int getCount();
private native long getTransactionByIndexJ(int i);
//private native long getTransactionByIndexJ(int i);
private native long getTransactionByIdJ(String id);
//private native long getTransactionByIdJ(String id);
public native List<TransactionInfo> getAll();
public List<TransactionInfo> getAll() {
return transactions;
}
public native void refresh();
private List<TransactionInfo> transactions = new ArrayList<>();
public void refresh() {
transactions = refreshJ();
}
private native List<TransactionInfo> refreshJ();
}
@@ -16,79 +16,57 @@
package com.m2049r.xmrwallet.model;
import java.util.List;
// this is not the TransactionInfo from the API as that is owned by the TransactionHistory
// this is a POJO for the TransactionInfoAdapter
public class TransactionInfo {
static {
System.loadLibrary("monerujo");
}
public long handle;
TransactionInfo(long handle) {
this.handle = handle;
}
static final String TAG = "TransactionInfo";
public enum Direction {
Direction_In,
Direction_Out
}
public class Transfer {
long amount;
String address;
public Direction direction;
public boolean isPending;
public boolean isFailed;
public long amount;
public long fee;
public long blockheight;
public String hash;
public long timestamp;
public String paymentId;
public long confirmations;
public List<Transfer> transfers;
public Transfer(long amount, String address) {
this.amount = amount;
this.address = address;
}
public long getAmount() {
return amount;
}
public String getAddress() {
return address;
}
public TransactionInfo(
int direction,
boolean isPending,
boolean isFailed,
long amount,
long fee,
long blockheight,
String hash,
long timestamp,
String paymentId,
long confirmations,
List<Transfer> transfers) {
this.direction = Direction.values()[direction];
this.isPending = isPending;
this.isFailed = isFailed;
this.amount = amount;
this.fee = fee;
this.blockheight = blockheight;
this.hash = hash;
this.timestamp = timestamp;
this.paymentId = paymentId;
this.confirmations = confirmations;
this.transfers = transfers;
}
public String toString() {
return getDirection() + "@" + getBlockHeight() + " " + getAmount();
return direction + "@" + blockheight + " " + amount;
}
public Direction getDirection() {
return TransactionInfo.Direction.values()[getDirectionJ()];
}
public native int getDirectionJ();
public native boolean isPending();
public native boolean isFailed();
public native long getAmount();
public native long getFee();
public native long getBlockHeight();
public native long getConfirmations();
public native String getHash();
public native long getTimestamp();
public native String getPaymentId();
/*
private List<Transfer> transfers;
public List<Transfer> getTransfers() { // not threadsafe
if (this.transfers == null) {
this.transfers = getTransfersJ();
}
return this.transfers;
}
private native List<Transfer> getTransfersJ();
*/
}
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2017 m2049r
*
* 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 com.m2049r.xmrwallet.model;
import android.util.Log;
public class Transfer {
public long amount;
public String address;
public Transfer(long amount, String address) {
Log.d("Transfer", address + "/" + amount);
//Log.d("Transfer", "/" + amount);
this.amount = amount;
this.address = address;
}
}
@@ -162,7 +162,6 @@ public class Wallet {
//TODO virtual int autoRefreshInterval() const = 0;
// TODO - good place to keep this ?
private PendingTransaction pendingTransaction = null;
public PendingTransaction getPendingTransaction() {
@@ -205,8 +204,11 @@ public class Wallet {
private TransactionHistory history = null;
public TransactionHistory getHistory() {
Log.d(TAG, "A");
if (history == null) {
Log.d(TAG, "B");
history = new TransactionHistory(getHistoryJ());
Log.d(TAG, "C");
}
return history;
}
@@ -26,7 +26,7 @@ import android.os.Process;
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
* The started Thread has a stck size of STACK_SIZE (=3MB)
* The started Thread has a stck size of STACK_SIZE (=5MB)
*/
public class MoneroHandlerThread extends Thread {
// from src/cryptonote_config.h
@@ -113,10 +113,12 @@ public class WalletService extends Service {
updateDaemonState(wallet, wallet.isSynchronized() ? height : 0);
if (!wallet.isSynchronized()) {
// we want to see our transactions as they come in
Log.d(TAG, "newBlock() refresh history");
wallet.getHistory().refresh();
Log.d(TAG, "newBlock() history refreshed");
int txCount = wallet.getHistory().getCount();
if (txCount > lastTxCount) {
lastTxCount = txCount;
lastTxCount = txCount; // TODO maybe do this later
fullRefresh = true;
}
}
@@ -138,10 +140,10 @@ public class WalletService extends Service {
if (updated) {
if (observer != null) {
updateDaemonState(wallet, 0);
TransactionHistory history = wallet.getHistory();
history.refresh();
if (observer != null) observer.onRefreshed(wallet, true);
updated = false;
wallet.getHistory().refresh();
if (observer != null) {
updated = !observer.onRefreshed(wallet, true);
}
}
}
}
@@ -196,7 +198,7 @@ public class WalletService extends Service {
}
public interface Observer {
void onRefreshed(Wallet wallet, boolean full);
boolean onRefreshed(Wallet wallet, boolean full);
void onProgress(String text);
@@ -262,7 +264,7 @@ public class WalletService extends Service {
if (cmd.equals(REQUEST_CMD_LOAD)) {
String walletId = extras.getString(REQUEST_WALLET, null);
String walletPw = extras.getString(REQUEST_CMD_LOAD_PW, null);
Log.d(TAG, "LOAD wallet " + walletId);// + ":" + walletPw);
Log.d(TAG, "LOAD wallet " + walletId);
if (walletId != null) {
showProgress(getString(R.string.status_wallet_loading));
showProgress(10);
@@ -270,7 +272,7 @@ public class WalletService extends Service {
}
} else if (cmd.equals(REQUEST_CMD_STORE)) {
Wallet myWallet = getWallet();
Log.d(TAG, "storing wallet: " + myWallet.getName());
Log.d(TAG, "STORE wallet: " + myWallet.getName());
boolean rc = myWallet.store();
Log.d(TAG, "wallet stored: " + myWallet.getName() + " with rc=" + rc);
if (!rc) {
@@ -279,14 +281,12 @@ public class WalletService extends Service {
if (observer != null) observer.onWalletStored(rc);
} else if (cmd.equals(REQUEST_CMD_TX)) {
Wallet myWallet = getWallet();
Log.d(TAG, "creating tx for wallet: " + myWallet.getName());
Log.d(TAG, "CREATE TX for wallet: " + myWallet.getName());
TxData txData = extras.getParcelable(REQUEST_CMD_TX_DATA);
PendingTransaction pendingTransaction = myWallet.createTransaction(
txData.dst_addr, txData.paymentId, txData.amount, txData.mixin, txData.priority);
PendingTransaction.Status status = pendingTransaction.getStatus();
Log.d(TAG, "transaction status " + status);
Log.d(TAG, "transaction amount " + pendingTransaction.getAmount());
Log.d(TAG, "transaction fee " + pendingTransaction.getFee());
if (status != PendingTransaction.Status.Status_Ok) {
Log.d(TAG, "Create Transaction failed: " + pendingTransaction.getErrorString());
}
@@ -294,7 +294,7 @@ public class WalletService extends Service {
if (observer != null) observer.onCreatedTransaction(pendingTransaction);
} else if (cmd.equals(REQUEST_CMD_SEND)) {
Wallet myWallet = getWallet();
Log.d(TAG, "send tx for wallet: " + myWallet.getName());
Log.d(TAG, "SEND TX for wallet: " + myWallet.getName());
PendingTransaction pendingTransaction = myWallet.getPendingTransaction();
if (pendingTransaction.getStatus() != PendingTransaction.Status.Status_Ok) {
Log.e(TAG, "PendingTransaction is " + pendingTransaction.getStatus());
@@ -46,7 +46,7 @@ public class Helper {
dir.mkdirs(); // try to make it
}
if (!dir.isDirectory()) {
String msg = "Directory " + dir.getAbsolutePath() + " does not exists.";
String msg = "Directory " + dir.getAbsolutePath() + " does not exist.";
Log.e(TAG, msg);
throw new IllegalStateException(msg);
}
@@ -59,7 +59,7 @@ public class Helper {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_DENIED) {
Log.d("permission", "permission denied to WRITE_EXTERNAL_STORAGE - requesting it");
Log.d(TAG, "Permission denied to WRITE_EXTERNAL_STORAGE - requesting it");
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
context.requestPermissions(permissions, PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
return false;