Skip to content

Commit

Permalink
Merge pull request #26 from m2049r/feature_qr
Browse files Browse the repository at this point in the history
QR Scanning incl. payment id
  • Loading branch information
m2049r authored Aug 30, 2017
2 parents 2d42a02 + f5535db commit e51425b
Show file tree
Hide file tree
Showing 13 changed files with 411 additions and 51 deletions.
10 changes: 10 additions & 0 deletions .idea/libraries/core_1_9_8.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions .idea/libraries/core_3_3_0.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions .idea/libraries/zxing_1_9_8.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CAMERA" />

<application
android:allowBackup="true"
Expand Down
131 changes: 131 additions & 0 deletions app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright (c) 2017 dm77, 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;

import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper;

import me.dm7.barcodescanner.zxing.ZXingScannerView;

public class ScannerFragment extends Fragment implements ZXingScannerView.ResultHandler {
static final String TAG = "ScannerFragment";

Listener activityCallback;

public interface Listener {
void onAddressScanned(String address, String paymentId);

boolean isPaymentIdValid(String paymentId);
}

private ZXingScannerView mScannerView;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
mScannerView = new ZXingScannerView(getActivity());
return mScannerView;
}

@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume");
mScannerView.setResultHandler(this);
mScannerView.startCamera();
}

static final String URI_PREFIX = "monero:";
static final String PAYMENTID_STRING = "?tx_payment_id=";

@Override
public void handleResult(Result rawResult) {
Log.d(TAG, rawResult.getBarcodeFormat().toString() + "/" + rawResult.getText());
String text = rawResult.getText();
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE) &&
(text.startsWith(URI_PREFIX))) {
String address = null;
String paymentId = null;
String s = text.substring(URI_PREFIX.length());
if (s.length() == 95) {
address = s;
} else {
int i = s.indexOf(PAYMENTID_STRING);
if ((i == 95) && (s.length() == (95 + PAYMENTID_STRING.length() + 16))) {
address = s.substring(0, 95);
paymentId = s.substring(95 + PAYMENTID_STRING.length());
if (!activityCallback.isPaymentIdValid(paymentId)) {
address = null;
}
}
}
if (Helper.isAddressOk(address, WalletManager.getInstance().isTestNet())) {
activityCallback.onAddressScanned(address, paymentId);
return;
} else {
Toast.makeText(getActivity(), getString(R.string.send_qr_address_invalid), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getActivity(), getString(R.string.send_qr_invalid), Toast.LENGTH_SHORT).show();
}

// Note from dm77:
// * Wait 2 seconds to resume the preview.
// * On older devices continuously stopping and resuming camera preview can result in freezing the app.
// * I don't know why this is the case but I don't have the time to figure out.
Handler handler = new Handler();
handler.postDelayed(new

Runnable() {
@Override
public void run() {
mScannerView.resumeCameraPreview(ScannerFragment.this);
}
}, 2000);
}

@Override
public void onPause() {
Log.d(TAG, "onPause");
mScannerView.stopCamera();
super.onPause();
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.d(TAG, "attaching scan");
if (context instanceof Listener) {
this.activityCallback = (Listener) context;
} else {
throw new ClassCastException(context.toString()
+ " must implement Listener");
}
}
}
60 changes: 53 additions & 7 deletions app/src/main/java/com/m2049r/xmrwallet/SendFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
Expand All @@ -40,14 +42,16 @@
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.BarcodeData;
import com.m2049r.xmrwallet.util.TxData;

public class SendFragment extends Fragment {
static final String TAG = "GenerateFragment";
static final String TAG = "SendFragment";

EditText etAddress;
EditText etPaymentId;
EditText etAmount;
Button bAddress;
Button bSweep;
Spinner sMixin;
Spinner sPriority;
Expand Down Expand Up @@ -80,6 +84,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
etAddress = (EditText) view.findViewById(R.id.etAddress);
etPaymentId = (EditText) view.findViewById(R.id.etPaymentId);
etAmount = (EditText) view.findViewById(R.id.etAmount);
bAddress = (Button) view.findViewById(R.id.bAddress);
bSweep = (Button) view.findViewById(R.id.bSweep);
bPrepareSend = (Button) view.findViewById(R.id.bPrepareSend);
bPaymentId = (Button) view.findViewById(R.id.bPaymentId);
Expand Down Expand Up @@ -194,6 +199,13 @@ public void onClick(View v) {
}
});

bAddress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
activityCallback.onScanAddress();
}
});

bPaymentId.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Expand Down Expand Up @@ -231,7 +243,14 @@ public void onClick(View v) {
if (testnet) {
send();
} else {
bReallySend.setVisibility(View.VISIBLE);
etNotes.setEnabled(false);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
bReallySend.setVisibility(View.VISIBLE);
}
}, 1000);
}
}
});
Expand All @@ -256,11 +275,7 @@ private void setPrepareButtonState() {

private boolean addressOk() {
String address = etAddress.getText().toString();
if (WalletManager.getInstance().isTestNet()) {
return ((address.length() == 95) && ("9A".indexOf(address.charAt(0)) >= 0));
} else {
return ((address.length() == 95) && ("4".indexOf(address.charAt(0)) >= 0));
}
return Helper.isAddressOk(address, WalletManager.getInstance().isTestNet());
}

private boolean amountOk() {
Expand Down Expand Up @@ -321,6 +336,8 @@ private void enableEdit() {
bSweep.setEnabled(true);
bPrepareSend.setEnabled(true);
llConfirmSend.setVisibility(View.GONE);
bSend.setEnabled(true);
etNotes.setEnabled(true);
bReallySend.setVisibility(View.GONE);
}

Expand All @@ -347,6 +364,35 @@ public interface Listener {

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
Expand Down
Loading

0 comments on commit e51425b

Please sign in to comment.