Reformat code, and move other LiveDatas to their own respective services.

NOTE: As of this commit, the app logs the wallet seed for development purposes.
This commit is contained in:
pokkst 2022-09-07 15:06:09 -05:00
parent b9a4ab18e1
commit e2face7c33
No known key found for this signature in database
GPG Key ID: 90C2ED85E67A50FF
26 changed files with 163 additions and 121 deletions

View File

@ -1,27 +1,25 @@
package com.m2049r.xmrwallet;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.AddressService;
import com.m2049r.xmrwallet.service.BalanceService;
import com.m2049r.xmrwallet.service.HistoryService;
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
import com.m2049r.xmrwallet.service.TxService;
import java.io.File;
import java.util.List;
public class MainActivity extends AppCompatActivity implements MoneroHandlerThread.Listener {
private final MutableLiveData<String> _address = new MutableLiveData<>("");
public LiveData<String> address = _address;
private final MutableLiveData<Long> _balance = new MutableLiveData<>(0L);
public LiveData<Long> balance = _balance;
private final MutableLiveData<List<TransactionInfo>> _history = new MutableLiveData<>();
public LiveData<List<TransactionInfo>> history = _history;
private MoneroHandlerThread thread = null;
private TxService txService = null;
private BalanceService balanceService = null;
private AddressService addressService = null;
private HistoryService historyService = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -37,7 +35,7 @@ public class MainActivity extends AppCompatActivity implements MoneroHandlerThre
private void init() {
File walletFile = new File(getApplicationInfo().dataDir, "xmr_wallet");
Wallet wallet = null;
if(walletFile.exists()) {
if (walletFile.exists()) {
wallet = WalletManager.getInstance().openWallet(walletFile.getAbsolutePath(), "");
} else {
wallet = WalletManager.getInstance().createWallet(walletFile, "", "English", 0);
@ -46,17 +44,15 @@ public class MainActivity extends AppCompatActivity implements MoneroHandlerThre
thread = new MoneroHandlerThread("WalletService", wallet, this);
thread.start();
this.txService = new TxService(this, thread);
this.balanceService = new BalanceService(this, thread);
this.addressService = new AddressService(this, thread);
this.historyService = new HistoryService(this, thread);
}
@Override
public void onRefresh() {
WalletManager walletManager = WalletManager.getInstance();
Wallet wallet = walletManager.getWallet();
if(wallet != null) {
String address = wallet.getLastSubaddress(0);
_history.postValue(wallet.getHistory().getAll());
_balance.postValue(wallet.getBalance());
_address.postValue(address);
}
this.historyService.refreshHistory();
this.balanceService.refreshBalance();
this.addressService.refreshAddress();
}
}

View File

@ -110,7 +110,7 @@ public class Node {
private boolean favourite = false;
@Getter
@Setter
private boolean selected = false;
private final boolean selected = false;
@Override
public int hashCode() {
@ -144,13 +144,13 @@ public class Node {
if ((nodeString == null) || nodeString.isEmpty())
throw new IllegalArgumentException("daemon is empty");
String daemonAddress;
String a[] = nodeString.split("@");
String[] a = nodeString.split("@");
if (a.length == 1) { // no credentials
daemonAddress = a[0];
username = "";
password = "";
} else if (a.length == 2) { // credentials
String userPassword[] = a[0].split(":");
String[] userPassword = a[0].split(":");
if (userPassword.length != 2)
throw new IllegalArgumentException("User:Password invalid");
username = userPassword[0];
@ -164,12 +164,12 @@ public class Node {
throw new IllegalArgumentException("Too many @");
}
String daParts[] = daemonAddress.split("/");
String[] daParts = daemonAddress.split("/");
if ((daParts.length > 3) || (daParts.length < 1))
throw new IllegalArgumentException("Too many '/' or too few");
daemonAddress = daParts[0];
String da[] = daemonAddress.split(":");
String[] da = daemonAddress.split(":");
if ((da.length > 2) || (da.length < 1))
throw new IllegalArgumentException("Too many ':' or too few");
String host = da[0];

View File

@ -21,8 +21,6 @@ import android.text.Html;
import android.text.Spanned;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.m2049r.levin.scanner.LevinPeer;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.util.NetCipherHelper;
@ -65,7 +63,7 @@ public class NodeInfo extends Node {
private boolean tested = false;
@Getter
@Setter
private boolean selecting = false;
private final boolean selecting = false;
public void clear() {
height = 0;

View File

@ -95,7 +95,7 @@ public class TxDataBtc extends TxData {
if (crypto.isCasefull()) { // compare as-is
return address.equals(btcAddress);
} else { // normalize & compare (e.g. ETH with and without checksum capitals
return address.toLowerCase().equals(btcAddress.toLowerCase());
return address.equalsIgnoreCase(btcAddress);
}
}
}

View File

@ -1,20 +1,6 @@
package com.m2049r.xmrwallet.fragment.home;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.fragment.NavHostFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -24,24 +10,20 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment;
import com.m2049r.xmrwallet.MainActivity;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.Crypto;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.service.AddressService;
import com.m2049r.xmrwallet.service.BalanceService;
import com.m2049r.xmrwallet.service.TxService;
import com.m2049r.xmrwallet.util.Helper;
import java.util.HashMap;
import java.util.Map;
import timber.log.Timber;
public class HomeFragment extends Fragment {
@ -58,7 +40,7 @@ public class HomeFragment extends Fragment {
super.onViewCreated(view, savedInstanceState);
mViewModel = new ViewModelProvider(this).get(HomeViewModel.class);
MainActivity mainActivity = (MainActivity) getActivity();
if(mainActivity == null) return;
if (mainActivity == null) return;
ImageView settingsImageView = view.findViewById(R.id.settings_imageview);
ImageView addressImageView = view.findViewById(R.id.monero_qr_imageview);
@ -68,14 +50,14 @@ public class HomeFragment extends Fragment {
EditText amountEditText = view.findViewById(R.id.amount_edittext);
Button sendButton = view.findViewById(R.id.send_button);
mainActivity.address.observe(getViewLifecycleOwner(), addr -> {
if(!addr.isEmpty()) {
AddressService.getInstance().address.observe(getViewLifecycleOwner(), addr -> {
if (!addr.isEmpty()) {
addressTextView.setText(addr);
addressImageView.setImageBitmap(mViewModel.generate(addr, 256, 256));
}
});
mainActivity.balance.observe(getViewLifecycleOwner(), balance -> {
BalanceService.getInstance().balance.observe(getViewLifecycleOwner(), balance -> {
balanceTextView.setText(getString(R.string.wallet_balance_text, Wallet.getDisplayAmount(balance)));
});
@ -93,12 +75,12 @@ public class HomeFragment extends Fragment {
String address = addressEditText.getText().toString().trim();
String amount = amountEditText.getText().toString().trim();
boolean validAddress = Wallet.isAddressValid(address);
if(validAddress && !amount.isEmpty()) {
if (validAddress && !amount.isEmpty()) {
sendButton.setEnabled(false);
TxService.getInstance().sendTx(address, amount);
} else if(!validAddress) {
} else if (!validAddress) {
Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show();
} else if(amount.isEmpty()) {
} else if (amount.isEmpty()) {
Toast.makeText(getActivity(), getString(R.string.send_amount_empty), Toast.LENGTH_SHORT).show();
}
});
@ -106,11 +88,11 @@ public class HomeFragment extends Fragment {
private void navigate(int destination) {
FragmentActivity activity = getActivity();
if(activity != null) {
if (activity != null) {
FragmentManager fm = activity.getSupportFragmentManager();
NavHostFragment navHostFragment =
(NavHostFragment) fm.findFragmentById(R.id.nav_host_fragment);
if(navHostFragment != null) {
if (navHostFragment != null) {
navHostFragment.getNavController().navigate(destination);
}
}

View File

@ -3,12 +3,14 @@ package com.m2049r.xmrwallet.fragment.home;
import android.graphics.Bitmap;
import androidx.lifecycle.ViewModel;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.util.HashMap;
import java.util.Map;

View File

@ -4,22 +4,13 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.model.Wallet;
public class SettingsFragment extends Fragment {

View File

@ -2,6 +2,6 @@ package com.m2049r.xmrwallet.fragment.settings;
import androidx.lifecycle.ViewModel;
public class SettingsViewModel extends ViewModel{
public class SettingsViewModel extends ViewModel {
}

View File

@ -147,7 +147,7 @@ public enum Instruction {
return (byte) (value & 0xFF);
}
private int value;
private final int value;
Instruction(int value) {
this.value = value;

View File

@ -45,7 +45,7 @@ public class Ledger {
private static final byte PROTOCOL_VERSION = 0x03;
public static final int SW_OK = 0x9000;
public static final int SW_INS_NOT_SUPPORTED = 0x6D00;
public static final int OK[] = {SW_OK};
public static final int[] OK = {SW_OK};
public static final int MINIMUM_LEDGER_VERSION = (1 << 16) + (8 << 8) + (0); // 1.6.0
public static UsbDevice findDevice(UsbManager usbManager) {
@ -153,7 +153,7 @@ public class Ledger {
return result;
}
private byte[] exchangeCheck(byte[] apdu, int acceptedSW[]) throws BTChipException {
private byte[] exchangeCheck(byte[] apdu, int[] acceptedSW) throws BTChipException {
byte[] response = exchange(apdu);
if (acceptedSW == null) {
return response;
@ -166,7 +166,7 @@ public class Ledger {
throw new BTChipException("Invalid status", lastSW);
}
private byte[] exchangeApduNoOpt(Instruction instruction, byte[] data, int acceptedSW[])
private byte[] exchangeApduNoOpt(Instruction instruction, byte[] data, int[] acceptedSW)
throws BTChipException {
byte[] apdu = new byte[data.length + 6];
apdu[0] = PROTOCOL_VERSION;

View File

@ -37,7 +37,7 @@ public enum NetworkType {
return value;
}
private int value;
private final int value;
NetworkType(int value) {
this.value = value;

View File

@ -58,7 +58,7 @@ public class PendingTransaction {
return value;
}
private int value;
private final int value;
Priority(int value) {
this.value = value;

View File

@ -27,7 +27,7 @@ public class TransactionHistory {
System.loadLibrary("monerujo");
}
private long handle;
private final long handle;
int accountIndex;

View File

@ -19,6 +19,7 @@ package com.m2049r.xmrwallet.model;
public interface WalletListener {
/**
* moneySpent - called when money spent
*
* @param txId - transaction id
* @param amount - tvAmount
*/
@ -26,6 +27,7 @@ public interface WalletListener {
/**
* moneyReceived - called when money received
*
* @param txId - transaction id
* @param amount - tvAmount
*/
@ -33,6 +35,7 @@ public interface WalletListener {
/**
* unconfirmedMoneyReceived - called when payment arrived in tx pool
*
* @param txId - transaction id
* @param amount - tvAmount
*/
@ -40,6 +43,7 @@ public interface WalletListener {
/**
* newBlock - called when new block received
*
* @param height - block height
*/
void newBlock(long height);

View File

@ -0,0 +1,27 @@
package com.m2049r.xmrwallet.service;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.m2049r.xmrwallet.MainActivity;
import com.m2049r.xmrwallet.model.WalletManager;
public class AddressService extends ServiceBase {
public static AddressService instance = null;
public static AddressService getInstance() {
return instance;
}
private final MutableLiveData<String> _address = new MutableLiveData<>("");
public LiveData<String> address = _address;
public AddressService(MainActivity mainActivity, MoneroHandlerThread thread) {
super(mainActivity, thread);
instance = this;
}
public void refreshAddress() {
_address.postValue(WalletManager.getInstance().getWallet().getAddress());
}
}

View File

@ -0,0 +1,27 @@
package com.m2049r.xmrwallet.service;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.m2049r.xmrwallet.MainActivity;
import com.m2049r.xmrwallet.model.WalletManager;
public class BalanceService extends ServiceBase {
public static BalanceService instance = null;
public static BalanceService getInstance() {
return instance;
}
private final MutableLiveData<Long> _balance = new MutableLiveData<>(0L);
public LiveData<Long> balance = _balance;
public BalanceService(MainActivity mainActivity, MoneroHandlerThread thread) {
super(mainActivity, thread);
instance = this;
}
public void refreshBalance() {
_balance.postValue(WalletManager.getInstance().getWallet().getBalance());
}
}

View File

@ -0,0 +1,34 @@
package com.m2049r.xmrwallet.service;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.m2049r.xmrwallet.MainActivity;
import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.WalletManager;
import java.util.List;
public class HistoryService extends ServiceBase {
public static HistoryService instance = null;
public static HistoryService getInstance() {
return instance;
}
private final MutableLiveData<List<TransactionInfo>> _history = new MutableLiveData<>();
public LiveData<List<TransactionInfo>> history = _history;
public HistoryService(MainActivity mainActivity, MoneroHandlerThread thread) {
super(mainActivity, thread);
instance = this;
}
public void refreshHistory() {
_history.postValue(WalletManager.getInstance().getWallet().getHistory().getAll());
}
public List<TransactionInfo> getHistory() {
return WalletManager.getInstance().getWallet().getHistory().getAll();
}
}

View File

@ -17,18 +17,9 @@
package com.m2049r.xmrwallet.service;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.m2049r.xmrwallet.data.DefaultNodes;
import com.m2049r.xmrwallet.data.Node;
import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.fragment.home.HomeViewModel;
import com.m2049r.xmrwallet.model.PendingTransaction;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletListener;
@ -64,15 +55,20 @@ public class MoneroHandlerThread extends Thread implements WalletListener {
}
@Override
public void moneySpent(String txId, long amount) {}
public void moneySpent(String txId, long amount) {
}
@Override
public void moneyReceived(String txId, long amount) {}
public void moneyReceived(String txId, long amount) {
}
@Override
public void unconfirmedMoneyReceived(String txId, long amount) {}
public void unconfirmedMoneyReceived(String txId, long amount) {
}
@Override
public void newBlock(long height) {
if(height % 1000 == 0) {
if (height % 1000 == 0) {
refresh();
}
}

View File

@ -3,8 +3,8 @@ package com.m2049r.xmrwallet.service;
import com.m2049r.xmrwallet.MainActivity;
public class ServiceBase {
private MainActivity mainActivity;
private MoneroHandlerThread thread;
private final MainActivity mainActivity;
private final MoneroHandlerThread thread;
public ServiceBase(MainActivity mainActivity, MoneroHandlerThread thread) {
this.mainActivity = mainActivity;

View File

@ -5,10 +5,11 @@ import com.m2049r.xmrwallet.livedata.SingleLiveEvent;
public class TxService extends ServiceBase {
public static TxService instance = null;
public static TxService getInstance() {
return instance;
}
private final SingleLiveEvent _clearSendEvent = new SingleLiveEvent();
public SingleLiveEvent clearSendEvent = _clearSendEvent;
@ -19,7 +20,7 @@ public class TxService extends ServiceBase {
public void sendTx(String address, String amount) {
boolean success = this.getThread().sendTx(address, amount);
if(success) {
if (success) {
_clearSendEvent.call();
}
}

View File

@ -30,31 +30,19 @@ import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.hardware.fingerprint.FingerprintManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.CancellationSignal;
import android.os.StrictMode;
import android.system.ErrnoException;
import android.system.Os;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputLayout;
import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.data.Crypto;
@ -68,9 +56,7 @@ import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.Calendar;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.HttpsURLConnection;

View File

@ -155,7 +155,7 @@ public class NetCipherHelper implements StatusCallback {
DISABLED,
NOT_INSTALLED,
NOT_ENABLED,
UNKNOWN;
UNKNOWN
}
private Status status = Status.UNKNOWN;

View File

@ -18,7 +18,6 @@ package com.m2049r.xmrwallet.util;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import androidx.appcompat.app.AppCompatDelegate;

View File

@ -38,6 +38,7 @@ import org.xbill.DNS.Type;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -107,7 +108,7 @@ public class OpenAliasHelper {
SimpleResolver sr = new SimpleResolver(DNSSEC_SERVERS[new Random().nextInt(DNSSEC_SERVERS.length)]);
ValidatingResolver vr = new ValidatingResolver(sr);
vr.setTimeout(0, DNS_LOOKUP_TIMEOUT);
vr.loadTrustAnchors(new ByteArrayInputStream(ROOT.getBytes("ASCII")));
vr.loadTrustAnchors(new ByteArrayInputStream(ROOT.getBytes(StandardCharsets.US_ASCII)));
Record qr = Record.newRecord(Name.fromConstantString(name + "."), Type.TXT, DClass.IN);
Message response = vr.send(Message.newQuery(qr));
final int rcode = response.getRcode();

View File

@ -41,7 +41,7 @@ public class RestoreHeight {
return Singleton;
}
private Map<String, Long> blockheight = new HashMap<>();
private final Map<String, Long> blockheight = new HashMap<>();
RestoreHeight() {
blockheight.put("2014-05-01", 18844L);

View File

@ -213,8 +213,6 @@ public class BitcoinAddressValidator {
if (remainderSize >= 5) return false;
// ignore checksum at end and get last byte of program
if ((data[data.length - 1 - 6] & ((1 << remainderSize) - 1)) != 0) return false;
return true;
return (data[data.length - 1 - 6] & ((1 << remainderSize) - 1)) == 0;
}
}