From f5535dbefa90d662b13485eb583d1f1349b41e22 Mon Sep 17 00:00:00 2001
From: m2049r <30435443+m2049r@users.noreply.github.com>
Date: Wed, 30 Aug 2017 19:54:27 +0200
Subject: [PATCH] QR Scanning incl. payment id
---
.idea/libraries/core_1_9_8.xml | 10 ++
.idea/libraries/core_3_3_0.xml | 11 ++
.idea/libraries/zxing_1_9_8.xml | 10 ++
app/build.gradle | 1 +
app/src/main/AndroidManifest.xml | 1 +
.../com/m2049r/xmrwallet/ScannerFragment.java | 131 ++++++++++++++++++
.../com/m2049r/xmrwallet/SendFragment.java | 60 +++++++-
.../com/m2049r/xmrwallet/WalletActivity.java | 64 ++++++++-
.../xmrwallet/service/WalletService.java | 1 +
.../m2049r/xmrwallet/util/BarcodeData.java | 28 ++++
.../com/m2049r/xmrwallet/util/Helper.java | 29 ++++
app/src/main/res/layout/send_fragment.xml | 107 ++++++++------
app/src/main/res/values/strings.xml | 9 +-
13 files changed, 411 insertions(+), 51 deletions(-)
create mode 100644 .idea/libraries/core_1_9_8.xml
create mode 100644 .idea/libraries/core_3_3_0.xml
create mode 100644 .idea/libraries/zxing_1_9_8.xml
create mode 100644 app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java
create mode 100644 app/src/main/java/com/m2049r/xmrwallet/util/BarcodeData.java
diff --git a/.idea/libraries/core_1_9_8.xml b/.idea/libraries/core_1_9_8.xml
new file mode 100644
index 00000000..0be1e35c
--- /dev/null
+++ b/.idea/libraries/core_1_9_8.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/core_3_3_0.xml b/.idea/libraries/core_3_3_0.xml
new file mode 100644
index 00000000..de46baa5
--- /dev/null
+++ b/.idea/libraries/core_3_3_0.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/zxing_1_9_8.xml b/.idea/libraries/zxing_1_9_8.xml
new file mode 100644
index 00000000..e9af3efd
--- /dev/null
+++ b/.idea/libraries/zxing_1_9_8.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index ecd41f6e..36a9850f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -46,5 +46,6 @@ dependencies {
compile 'com.android.support:support-v4:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support:cardview-v7:25.3.1'
+ compile 'me.dm7.barcodescanner:zxing:1.9.8'
testCompile 'junit:junit:4.12'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0d7245cd..0f9eb50f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
= 0));
- } else {
- return ((address.length() == 95) && ("4".indexOf(address.charAt(0)) >= 0));
- }
+ return Helper.isAddressOk(address, WalletManager.getInstance().isTestNet());
}
private boolean amountOk() {
@@ -321,6 +336,8 @@ public class SendFragment extends Fragment {
bSweep.setEnabled(true);
bPrepareSend.setEnabled(true);
llConfirmSend.setVisibility(View.GONE);
+ bSend.setEnabled(true);
+ etNotes.setEnabled(true);
bReallySend.setVisibility(View.GONE);
}
@@ -347,6 +364,35 @@ public class SendFragment extends Fragment {
void onDisposeRequest();
+ void onScanAddress();
+
+ BarcodeData getScannedData();
+
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ BarcodeData data = activityCallback.getScannedData();
+ if (data != null) {
+ String scannedAddress = data.address;
+ if (scannedAddress != null) {
+ etAddress.setText(scannedAddress);
+ }
+ String scannedPaymenId = data.paymentId;
+ if (scannedPaymenId != null) {
+ etPaymentId.setText(scannedPaymenId);
+ }
+ }
+ // jump to first empty field
+ if (etAddress.getText().toString().isEmpty()) {
+ etAddress.requestFocus();
+ } else if (etPaymentId.getText().toString().isEmpty()) {
+ etPaymentId.requestFocus();
+ } else {
+ etAmount.requestFocus();
+ }
+ Log.d(TAG, "onResume");
}
@Override
diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java
index e7511131..b5c1d054 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java
@@ -23,9 +23,11 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
+import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
@@ -39,10 +41,14 @@ import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.WalletService;
+import com.m2049r.xmrwallet.util.BarcodeData;
+import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.TxData;
public class WalletActivity extends AppCompatActivity implements WalletFragment.Listener,
- WalletService.Observer, SendFragment.Listener, TxFragment.Listener, GenerateReviewFragment.ListenerWithWallet {
+ WalletService.Observer, SendFragment.Listener, TxFragment.Listener,
+ GenerateReviewFragment.ListenerWithWallet,
+ ScannerFragment.Listener {
private static final String TAG = "WalletActivity";
public static final String REQUEST_ID = "id";
@@ -596,4 +602,60 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
public void onDisposeRequest() {
getWallet().disposePendingTransaction();
}
+
+
+ private void startScanFragment() {
+ Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_container);
+ if (fragment instanceof SendFragment) {
+ Bundle extras = new Bundle();
+ replaceFragment(new ScannerFragment(), null, extras);
+ }
+ }
+
+ /// QR scanner callbacks
+ @Override
+ public void onScanAddress() {
+ if (Helper.getCameraPermission(this)) {
+ startScanFragment();
+ } else {
+ Log.i(TAG, "Waiting for permissions");
+ }
+
+ }
+
+ private BarcodeData scannedData = null;
+
+ @Override
+ public void onAddressScanned(String address, String paymentId) {
+ // Log.d(TAG, "got " + address);
+ scannedData = new BarcodeData(address, paymentId);
+ popFragmentStack(null);
+ }
+
+ @Override
+ public BarcodeData getScannedData() {
+ BarcodeData data = scannedData;
+ scannedData = null;
+ return data;
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
+ Log.d(TAG, "onRequestPermissionsResult()");
+ switch (requestCode) {
+ case Helper.PERMISSIONS_REQUEST_CAMERA:
+ // If request is cancelled, the result arrays are empty.
+ if (grantResults.length > 0
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ startScanFragment();
+ } else {
+ String msg = getString(R.string.message_camera_not_permitted);
+ Log.e(TAG, msg);
+ Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
+ }
+ break;
+ default:
+ }
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java
index 22d67d0d..374c83c0 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java
@@ -127,6 +127,7 @@ public class WalletService extends Service {
boolean fullRefresh = false;
updateDaemonState(wallet, wallet.isSynchronized() ? height : 0);
if (!wallet.isSynchronized()) {
+ updated = true;
// we want to see our transactions as they come in
wallet.getHistory().refresh();
int txCount = wallet.getHistory().getCount();
diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/BarcodeData.java b/app/src/main/java/com/m2049r/xmrwallet/util/BarcodeData.java
new file mode 100644
index 00000000..6c94c490
--- /dev/null
+++ b/app/src/main/java/com/m2049r/xmrwallet/util/BarcodeData.java
@@ -0,0 +1,28 @@
+/*
+ * 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.util;
+
+public class BarcodeData {
+ public String address = null;
+ public String paymentId = null;
+ //String amount = null:
+
+ public BarcodeData(String address, String paymentId) {
+ this.address = address;
+ this.paymentId = paymentId;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java
index f3454527..e94064b1 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java
@@ -27,6 +27,7 @@ import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import com.m2049r.xmrwallet.R;
+import com.m2049r.xmrwallet.model.WalletManager;
import java.io.File;
@@ -71,6 +72,24 @@ public class Helper {
}
}
+ public static final int PERMISSIONS_REQUEST_CAMERA = 1;
+
+ static public boolean getCameraPermission(Activity context) {
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+ if (context.checkSelfPermission(Manifest.permission.CAMERA)
+ == PackageManager.PERMISSION_DENIED) {
+ Log.d(TAG, "Permission denied for CAMERA - requesting it");
+ String[] permissions = {Manifest.permission.CAMERA};
+ context.requestPermissions(permissions, PERMISSIONS_REQUEST_CAMERA);
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+
static public String getWalletPath(Context context, String aWalletName) {
File walletDir = getStorageRoot(context);
//d(TAG, "walletdir=" + walletDir.getAbsolutePath());
@@ -107,4 +126,14 @@ public class Helper {
static public void hideKeyboardAlways(Activity act) {
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
+
+ static public boolean isAddressOk(String address, boolean testnet) {
+ if (address == null) return false;
+ if (testnet) {
+ return ((address.length() == 95) && ("9A".indexOf(address.charAt(0)) >= 0));
+ } else {
+ return ((address.length() == 95) && ("4".indexOf(address.charAt(0)) >= 0));
+ }
+ }
+
}
diff --git a/app/src/main/res/layout/send_fragment.xml b/app/src/main/res/layout/send_fragment.xml
index b1a15e9b..135132da 100644
--- a/app/src/main/res/layout/send_fragment.xml
+++ b/app/src/main/res/layout/send_fragment.xml
@@ -16,7 +16,7 @@
-
+ android:orientation="horizontal"
+ android:layout_marginBottom="4sp"
+ android:layout_marginTop="4sp"
+ android:weightSum="10">
+
+
+
+
+
@@ -124,18 +149,19 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
+ android:layout_marginBottom="4sp"
+ android:layout_marginTop="4sp"
android:visibility="gone">
-
@@ -171,9 +197,9 @@
@@ -198,9 +224,9 @@
@@ -221,7 +247,7 @@
android:id="@+id/etNotes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
+ android:layout_marginTop="4sp"
android:hint="@string/send_notes_hint"
android:imeOptions="actionDone"
android:inputType="textMultiLine"
@@ -232,8 +258,9 @@
android:id="@+id/bSend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginTop="8dp"
+ android:layout_marginBottom="4sp"
+ android:layout_marginTop="4sp"
+ android:minHeight="36sp"
android:background="@color/colorPrimary"
android:text="@string/send_send_hint" />
@@ -241,8 +268,8 @@
android:id="@+id/bReallySend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginTop="8dp"
+ android:layout_marginBottom="4sp"
+ android:layout_marginTop="4sp"
android:background="@color/moneroOrange"
android:text="@string/send_really_send_hint"
android:visibility="gone" />
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1d3851a0..c1553fe2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -5,7 +5,7 @@
Details
- [<user>:<pass>@]<daemonhost>[:<port>]
+ [<user>:<pass>@]<daemon>[:<port>]
Net Selection
TestNet
MainNet
@@ -58,6 +58,7 @@
Problems
External Storage is not writable! Panic!
We really need those External Storage permissions!
+ No camera = No QR scanning!
Create Wallet
Wallet Name
@@ -111,11 +112,13 @@
Mixin
Sweep
Generate
+ Scan
Prepare
Dispose (Undo)
Spend my sweet Moneroj
- I understand I am on mainnet\nTHis is real Monero!
-
+ I understand I am sending real Monero!
+ Not a monero QR Code
+ Invalid Monero address
Preparing transaction
Amount