Tweaks & Fixes (#153)

* clear error

* isAddressValid refactoring

* better numpad layout

* receive qr code as card

* scan integrated address
This commit is contained in:
m2049r 2017-12-09 20:38:01 +01:00 committed by GitHub
parent e6522769d0
commit ae62c528aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 157 additions and 82 deletions

View File

@ -8,8 +8,8 @@ android {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 25
versionCode 48
versionName "1.2.8"
versionCode 49
versionName "1.2.9"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {

View File

@ -62,8 +62,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
@Override
public void handleResult(Result rawResult) {
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE) &&
(rawResult.getText().startsWith(QR_SCHEME))) {
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE)) {
if (onScannedListener.onScanned(rawResult.getText())) {
return;
} else {

View File

@ -72,8 +72,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private View tvPaymentIdIntegrated;
private View llPaymentId;
private String scannedAmount = null;
OnScanListener onScanListener;
public interface OnScanListener {
@ -113,8 +111,8 @@ public class SendAddressWizardFragment extends SendWizardFragment {
etAddress.getEditText().addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
if ((etAddress.getEditText().getText().toString().length() == INTEGRATED_ADDRESS_LENGTH) &&
checkAddressNoError()) { // we have an integrated address
etAddress.setError(null);
if (isIntegratedAddress()) {
etPaymentId.getEditText().getText().clear();
llPaymentId.setVisibility(View.GONE);
tvPaymentIdIntegrated.setVisibility(View.VISIBLE);
@ -190,7 +188,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private boolean checkAddressNoError() {
String address = etAddress.getEditText().getText().toString();
return Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet());
return Wallet.isAddressValid(address);
}
private boolean checkAddress() {
@ -205,8 +203,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private boolean isIntegratedAddress() {
String address = etAddress.getEditText().getText().toString();
return Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet())
&& address.length() == 106;
return (address.length() == INTEGRATED_ADDRESS_LENGTH) && Wallet.isAddressValid(address);
}
private boolean checkPaymentId() {

View File

@ -121,8 +121,8 @@ public class SendAmountWizardFragment extends SendWizardFragment {
// getAmount is null if exchange is in progress
if ((evAmount.getAmount() != null) && evAmount.getAmount().isEmpty()) {
final BarcodeData data = sendListener.popBarcodeData();
if ((data != null) && (data.amount > 0)) {
evAmount.setAmount(Wallet.getDisplayAmount(data.amount));
if ((data != null) && (data.amount != null)) {
evAmount.setAmount(data.amount);
}
}
}

View File

@ -727,8 +727,9 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
private BarcodeData scannedData = null;
@Override
public boolean onScanned(String uri) {
BarcodeData bcData = parseMoneroUri(uri);
public boolean onScanned(String qrCode) {
// #gurke
BarcodeData bcData = BarcodeData.fromQrCode(qrCode);
if (bcData != null) {
this.scannedData = bcData;
popFragmentStack(null);
@ -738,49 +739,6 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
}
}
/**
* Parse and decode a monero scheme string. It is here because it needs to validate the data.
*
* @param uri String containing a monero URL
* @return BarcodeData object or null if uri not valid
*/
public BarcodeData parseMoneroUri(String uri) {
if (uri == null) return null;
if (!uri.startsWith(ScannerFragment.QR_SCHEME)) return null;
String noScheme = uri.substring(ScannerFragment.QR_SCHEME.length());
Uri monero = Uri.parse(noScheme);
Map<String, String> parms = new HashMap<>();
String query = monero.getQuery();
if (query != null) {
String[] args = query.split("&");
for (String arg : args) {
String[] namevalue = arg.split("=");
if (namevalue.length == 0) {
continue;
}
parms.put(Uri.decode(namevalue[0]).toLowerCase(),
namevalue.length > 1 ? Uri.decode(namevalue[1]) : null);
}
}
String address = monero.getPath();
String paymentId = parms.get(ScannerFragment.QR_PAYMENTID);
String amountString = parms.get(ScannerFragment.QR_AMOUNT);
long amount = -1;
if (amountString != null) {
amount = Wallet.getAmountFromString(amountString);
}
if ((paymentId != null) && !Wallet.isPaymentIdValid(paymentId)) {
return null;
}
if (Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet())) {
return new BarcodeData(address, paymentId, amount);
}
return null;
}
@Override
public BarcodeData popScannedData() {
BarcodeData data = scannedData;

View File

@ -16,14 +16,122 @@
package com.m2049r.xmrwallet.data;
import android.net.Uri;
import com.m2049r.xmrwallet.model.Wallet;
import java.util.HashMap;
import java.util.Map;
import timber.log.Timber;
public class BarcodeData {
public static final String XMR_SCHEME = "monero:";
public static final String XMR_PAYMENTID = "tx_payment_id";
public static final String XMR_AMOUNT = "tx_amount";
static final String BTC_SCHEME = "bitcoin:";
static final String BTC_AMOUNT = "amount";
public enum Asset {
XMR
}
public Asset asset = null;
public String address = null;
public String paymentId = null;
public long amount = -1;
public String amount = null;
public BarcodeData(String address, String paymentId, long amount) {
public BarcodeData(Asset asset, String address) {
this.asset = asset;
this.address = address;
}
public BarcodeData(Asset asset, String address, String amount) {
this.asset = asset;
this.address = address;
this.amount = amount;
}
public BarcodeData(Asset asset, String address, String paymentId, String amount) {
this.asset = asset;
this.address = address;
this.paymentId = paymentId;
this.amount = amount;
}
static public BarcodeData fromQrCode(String qrCode) {
// check for monero uri
BarcodeData bcData = parseMoneroUri(qrCode);
// check for naked monero address / integrated address
if (bcData == null) {
bcData = parseMoneroNaked(qrCode);
}
return bcData;
}
/**
* Parse and decode a monero scheme string. It is here because it needs to validate the data.
*
* @param uri String containing a monero URL
* @return BarcodeData object or null if uri not valid
*/
static public BarcodeData parseMoneroUri(String uri) {
Timber.d("parseMoneroUri=%s", uri);
if (uri == null) return null;
if (!uri.startsWith(XMR_SCHEME)) return null;
String noScheme = uri.substring(XMR_SCHEME.length());
Uri monero = Uri.parse(noScheme);
Map<String, String> parms = new HashMap<>();
String query = monero.getQuery();
if (query != null) {
String[] args = query.split("&");
for (String arg : args) {
String[] namevalue = arg.split("=");
if (namevalue.length == 0) {
continue;
}
parms.put(Uri.decode(namevalue[0]).toLowerCase(),
namevalue.length > 1 ? Uri.decode(namevalue[1]) : "");
}
}
String address = monero.getPath();
String paymentId = parms.get(XMR_PAYMENTID);
String amount = parms.get(XMR_AMOUNT);
if (amount != null) {
try {
Double.parseDouble(amount);
} catch (NumberFormatException ex) {
Timber.d(ex.getLocalizedMessage());
return null; // we have an amount but its not a number!
}
}
if ((paymentId != null) && !Wallet.isPaymentIdValid(paymentId)) {
Timber.d("paymentId invalid");
return null;
}
if (!Wallet.isAddressValid(address)) {
Timber.d("address invalid");
return null;
}
return new BarcodeData(Asset.XMR, address, paymentId, amount);
}
static public BarcodeData parseMoneroNaked(String address) {
Timber.d("parseMoneroNaked=%s", address);
if (address == null) return null;
if (!Wallet.isAddressValid(address)) {
Timber.d("address invalid");
return null;
}
return new BarcodeData(Asset.XMR, address);
}
}

View File

@ -154,6 +154,10 @@ public class Wallet {
public static native boolean isPaymentIdValid(String payment_id);
public static boolean isAddressValid(String address) {
return isAddressValid(address, WalletManager.getInstance().isTestNet());
}
public static native boolean isAddressValid(String address, boolean isTestNet);
//TODO static static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error);

View File

@ -121,13 +121,25 @@
android:textSize="16sp"
android:visibility="invisible" />
<ImageView
android:id="@+id/qrCode"
android:layout_width="match_parent"
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/cvQrCode"
android:layout_margin="16dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="#00000000" />
android:layout_gravity="center"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
card_view:cardCornerRadius="2dp"
card_view:cardElevation="8dp"
card_view:contentPadding="4dp">
<ImageView
android:id="@+id/qrCode"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="#00000000" />
</android.support.v7.widget.CardView>
</FrameLayout>
</LinearLayout>

View File

@ -8,7 +8,9 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center">
<TextView
android:id="@+id/numberPad1"
@ -18,7 +20,6 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:tag="1"
android:text="1" />
@ -30,7 +31,6 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:tag="2"
android:text="2" />
@ -42,14 +42,16 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:tag="3"
android:text="3" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center">
<TextView
android:id="@+id/numberPad4"
@ -59,7 +61,6 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:tag="4"
android:text="4" />
@ -71,7 +72,6 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:tag="5"
android:text="5" />
@ -83,14 +83,15 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:tag="6"
android:text="6" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center">
<TextView
android:id="@+id/numberPad7"
@ -100,7 +101,6 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:tag="7"
android:text="7" />
@ -112,7 +112,6 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:tag="8"
android:text="8" />
@ -124,14 +123,15 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:tag="9"
android:text="9" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center">
<TextView
android:id="@+id/numberPadPoint"
@ -141,7 +141,6 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:text="." />
<TextView
@ -152,18 +151,16 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:tag="0"
android:text="0" />
<ImageView
android:id="@+id/numberPadBackSpace"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_height="36sp"
android:layout_gravity="center"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:padding="16dp"
android:src="@drawable/ic_backspace_black_36dp" />
</LinearLayout>