You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
7.1 KiB

// Copyright 2019 The Hush developers
package org.myhush.silentdragon
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
6 years ago
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.SurfaceHolder
import android.view.SurfaceView
import com.google.android.gms.vision.CameraSource
import com.google.android.gms.vision.Detector
import com.google.android.gms.vision.barcode.Barcode
import com.google.android.gms.vision.barcode.BarcodeDetector
import kotlinx.android.synthetic.main.activity_qr_reader.*
import java.io.IOException
import android.app.AlertDialog
import android.text.InputType
import android.widget.EditText
class QrReaderActivity : AppCompatActivity() {
companion object {
6 years ago
const val REQUEST_ADDRESS = 1
const val REQUEST_CONNDATA = 2
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_qr_reader)
6 years ago
title = "Scan QR Code"
val code = intent.getIntExtra("REQUEST_CODE", 0)
if (code == REQUEST_ADDRESS)
txtQrCodeHelp.text = ""
5 years ago
lblErrorMsg.text = ""
5 years ago
setupCamera()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
50 -> {
if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
// Do what if user refuses permission? Go back?
6 years ago
} else {
5 years ago
recreate()
}
}
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_qrcodereader, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_manual_input -> {
val builder = AlertDialog.Builder(this)
builder.setTitle("Paste the code here manually")
// Set up the input
val input = EditText(this)
// Specify the type of input expected; this, for example, sets the input as a password, and will mask the text
input.inputType = InputType.TYPE_CLASS_TEXT
builder.setView(input)
// Set up the buttons
builder.setPositiveButton("OK") { dialog, which ->
run {
val txt = input.text.toString()
processText(txt)
}
}
builder.setNegativeButton("Cancel") { dialog, which -> dialog.cancel() }
builder.create().show()
return true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun setupCamera() {
val cameraView = findViewById<SurfaceView>(R.id.camera_view)
val barcodeDetector = BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.QR_CODE).build()
val cameraSource = CameraSource.Builder(this, barcodeDetector)
.setAutoFocusEnabled(true)
5 years ago
.setRequestedPreviewSize(640, 480)
.build()
5 years ago
cameraView.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
try {
5 years ago
if (ContextCompat.checkSelfPermission(applicationContext, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this@QrReaderActivity, arrayOf(android.Manifest.permission.CAMERA), 50)
} else {
cameraSource.start(cameraView.holder)
val w = cameraView.width
val h = cameraView.height
val scale = cameraSource.previewSize.width.toDouble() / cameraSource.previewSize.height.toDouble()
val scaleWidth = (h.toDouble() / scale).toInt()
cameraView.layout((w - scaleWidth)/2, 0, scaleWidth , h)
println("Preview size: ${cameraSource.previewSize}")
5 years ago
}
} catch (ie: IOException) {
Log.e("CAMERA SOURCE", ie.message)
}
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}
override fun surfaceDestroyed(holder: SurfaceHolder) {
cameraSource.stop()
}
})
btnQrCodeCancel.setOnClickListener {
setResult(Activity.RESULT_CANCELED)
finish()
}
barcodeDetector.setProcessor(object : Detector.Processor<Barcode> {
override fun release() {}
override fun receiveDetections(detections: Detector.Detections<Barcode>) {
val barcodes = detections.detectedItems
if (barcodes.size() != 0) {
6 years ago
runOnUiThread {
6 years ago
val barcodeInfo = barcodes.valueAt(0).displayValue
processText(barcodeInfo)
}
}
}
})
}
private fun processText(barcodeInfo: String) {
val code = intent.getIntExtra("REQUEST_CODE", 0)
// See if this the data is of the right format
if (code == REQUEST_CONNDATA && !barcodeInfo.startsWith("ws")) {
Log.i(TAG, "Not a connection")
var err = barcodeInfo
if (err.length > 48) {
err = err.substring(0, 22) + "...." + err.substring(err.length - 22, err.length)
}
5 years ago
lblErrorMsg.text = "\"$err\" is not a valid connection string!"
return
}
if (code == REQUEST_ADDRESS &&
!DataModel.isValidAddress(StringBuilder(barcodeInfo).toString()) &&
!barcodeInfo.startsWith("hush:")) {
Log.i(TAG, "Not an address")
var err = barcodeInfo
if (err.length > 48) {
err = err.substring(0, 22) + "...." + err.substring(err.length - 22, err.length)
}
5 years ago
lblErrorMsg.text = "\"$err\" is not a valid HUSH address!"
return
}
5 years ago
// The data seems valid, so return it.
val data = Intent()
5 years ago
// Payment URIs are often formatted as "hush:<addr>", but this casuses parsing problems.
// So change it to hush://<addr>, so that it parses properly
if (barcodeInfo.startsWith("hush:") && !barcodeInfo.startsWith("hush://")) {
data.data = Uri.parse(barcodeInfo.replaceFirst("hush:", "hush://"))
5 years ago
} else {
data.data = Uri.parse(barcodeInfo)
}
setResult(Activity.RESULT_OK, data)
finish()
}
private val TAG = "QrReader"
}