mirror of
https://github.com/m2049r/xmrwallet
synced 2025-04-08 14:36:38 +02:00
Tweaks & Fixes (#153)
* clear error * isAddressValid refactoring * better numpad layout * receive qr code as card * scan integrated address
This commit is contained in:
parent
e6522769d0
commit
ae62c528aa
app
build.gradle
src/main
java/com/m2049r/xmrwallet
ScannerFragment.javaSendAddressWizardFragment.javaSendAmountWizardFragment.javaWalletActivity.java
data
model
res/layout
@ -8,8 +8,8 @@ android {
|
|||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 48
|
versionCode 49
|
||||||
versionName "1.2.8"
|
versionName "1.2.9"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
|
@ -62,8 +62,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleResult(Result rawResult) {
|
public void handleResult(Result rawResult) {
|
||||||
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE) &&
|
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE)) {
|
||||||
(rawResult.getText().startsWith(QR_SCHEME))) {
|
|
||||||
if (onScannedListener.onScanned(rawResult.getText())) {
|
if (onScannedListener.onScanned(rawResult.getText())) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -72,8 +72,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
private View tvPaymentIdIntegrated;
|
private View tvPaymentIdIntegrated;
|
||||||
private View llPaymentId;
|
private View llPaymentId;
|
||||||
|
|
||||||
private String scannedAmount = null;
|
|
||||||
|
|
||||||
OnScanListener onScanListener;
|
OnScanListener onScanListener;
|
||||||
|
|
||||||
public interface OnScanListener {
|
public interface OnScanListener {
|
||||||
@ -113,8 +111,8 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
etAddress.getEditText().addTextChangedListener(new TextWatcher() {
|
etAddress.getEditText().addTextChangedListener(new TextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable editable) {
|
public void afterTextChanged(Editable editable) {
|
||||||
if ((etAddress.getEditText().getText().toString().length() == INTEGRATED_ADDRESS_LENGTH) &&
|
etAddress.setError(null);
|
||||||
checkAddressNoError()) { // we have an integrated address
|
if (isIntegratedAddress()) {
|
||||||
etPaymentId.getEditText().getText().clear();
|
etPaymentId.getEditText().getText().clear();
|
||||||
llPaymentId.setVisibility(View.GONE);
|
llPaymentId.setVisibility(View.GONE);
|
||||||
tvPaymentIdIntegrated.setVisibility(View.VISIBLE);
|
tvPaymentIdIntegrated.setVisibility(View.VISIBLE);
|
||||||
@ -190,7 +188,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
private boolean checkAddressNoError() {
|
private boolean checkAddressNoError() {
|
||||||
String address = etAddress.getEditText().getText().toString();
|
String address = etAddress.getEditText().getText().toString();
|
||||||
return Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet());
|
return Wallet.isAddressValid(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkAddress() {
|
private boolean checkAddress() {
|
||||||
@ -205,8 +203,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
private boolean isIntegratedAddress() {
|
private boolean isIntegratedAddress() {
|
||||||
String address = etAddress.getEditText().getText().toString();
|
String address = etAddress.getEditText().getText().toString();
|
||||||
return Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet())
|
return (address.length() == INTEGRATED_ADDRESS_LENGTH) && Wallet.isAddressValid(address);
|
||||||
&& address.length() == 106;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkPaymentId() {
|
private boolean checkPaymentId() {
|
||||||
|
@ -121,8 +121,8 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||||||
// getAmount is null if exchange is in progress
|
// getAmount is null if exchange is in progress
|
||||||
if ((evAmount.getAmount() != null) && evAmount.getAmount().isEmpty()) {
|
if ((evAmount.getAmount() != null) && evAmount.getAmount().isEmpty()) {
|
||||||
final BarcodeData data = sendListener.popBarcodeData();
|
final BarcodeData data = sendListener.popBarcodeData();
|
||||||
if ((data != null) && (data.amount > 0)) {
|
if ((data != null) && (data.amount != null)) {
|
||||||
evAmount.setAmount(Wallet.getDisplayAmount(data.amount));
|
evAmount.setAmount(data.amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -727,8 +727,9 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
|||||||
private BarcodeData scannedData = null;
|
private BarcodeData scannedData = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onScanned(String uri) {
|
public boolean onScanned(String qrCode) {
|
||||||
BarcodeData bcData = parseMoneroUri(uri);
|
// #gurke
|
||||||
|
BarcodeData bcData = BarcodeData.fromQrCode(qrCode);
|
||||||
if (bcData != null) {
|
if (bcData != null) {
|
||||||
this.scannedData = bcData;
|
this.scannedData = bcData;
|
||||||
popFragmentStack(null);
|
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
|
@Override
|
||||||
public BarcodeData popScannedData() {
|
public BarcodeData popScannedData() {
|
||||||
BarcodeData data = scannedData;
|
BarcodeData data = scannedData;
|
||||||
|
@ -16,14 +16,122 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet.data;
|
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 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 address = null;
|
||||||
public String paymentId = 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.address = address;
|
||||||
this.paymentId = paymentId;
|
this.paymentId = paymentId;
|
||||||
this.amount = amount;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
@ -154,6 +154,10 @@ public class Wallet {
|
|||||||
|
|
||||||
public static native boolean isPaymentIdValid(String payment_id);
|
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);
|
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);
|
//TODO static static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error);
|
||||||
|
@ -121,13 +121,25 @@
|
|||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:visibility="invisible" />
|
android:visibility="invisible" />
|
||||||
|
|
||||||
<ImageView
|
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/qrCode"
|
android:id="@+id/cvQrCode"
|
||||||
android:layout_width="match_parent"
|
android:layout_margin="16dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:adjustViewBounds="true"
|
android:layout_gravity="center"
|
||||||
android:background="#00000000" />
|
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>
|
</FrameLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/numberPad1"
|
android:id="@+id/numberPad1"
|
||||||
@ -18,7 +20,6 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:tag="1"
|
android:tag="1"
|
||||||
android:text="1" />
|
android:text="1" />
|
||||||
|
|
||||||
@ -30,7 +31,6 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:tag="2"
|
android:tag="2"
|
||||||
android:text="2" />
|
android:text="2" />
|
||||||
|
|
||||||
@ -42,14 +42,16 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:tag="3"
|
android:tag="3"
|
||||||
android:text="3" />
|
android:text="3" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/numberPad4"
|
android:id="@+id/numberPad4"
|
||||||
@ -59,7 +61,6 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:tag="4"
|
android:tag="4"
|
||||||
android:text="4" />
|
android:text="4" />
|
||||||
|
|
||||||
@ -71,7 +72,6 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:tag="5"
|
android:tag="5"
|
||||||
android:text="5" />
|
android:text="5" />
|
||||||
|
|
||||||
@ -83,14 +83,15 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:tag="6"
|
android:tag="6"
|
||||||
android:text="6" />
|
android:text="6" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/numberPad7"
|
android:id="@+id/numberPad7"
|
||||||
@ -100,7 +101,6 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:tag="7"
|
android:tag="7"
|
||||||
android:text="7" />
|
android:text="7" />
|
||||||
|
|
||||||
@ -112,7 +112,6 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:tag="8"
|
android:tag="8"
|
||||||
android:text="8" />
|
android:text="8" />
|
||||||
|
|
||||||
@ -124,14 +123,15 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:tag="9"
|
android:tag="9"
|
||||||
android:text="9" />
|
android:text="9" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/numberPadPoint"
|
android:id="@+id/numberPadPoint"
|
||||||
@ -141,7 +141,6 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:text="." />
|
android:text="." />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -152,18 +151,16 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="8dp"
|
|
||||||
android:tag="0"
|
android:tag="0"
|
||||||
android:text="0" />
|
android:text="0" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/numberPadBackSpace"
|
android:id="@+id/numberPadBackSpace"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="36sp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:padding="16dp"
|
|
||||||
android:src="@drawable/ic_backspace_black_36dp" />
|
android:src="@drawable/ic_backspace_black_36dp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user