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"> + + + +