Browse Source

Functional QR Code Reader with Lineage OS

master
jahway603 4 years ago
parent
commit
eb77fceab0
  1. 4
      app/build.gradle
  2. 3
      app/src/main/AndroidManifest.xml
  3. 105
      app/src/main/java/org/myhush/silentdragon/MainActivity.kt
  4. 131
      app/src/main/java/org/myhush/silentdragon/QrReaderActivity.kt
  5. 20
      app/src/main/res/layout/activity_qr_reader.xml
  6. 24
      app/src/main/res/layout/custom_qrcode_layout.xml
  7. 2
      build.gradle

4
app/build.gradle

@ -86,7 +86,9 @@ dependencies {
implementation 'com.google.android.gms:play-services-vision:17.0.2' implementation 'com.google.android.gms:play-services-vision:17.0.2'
implementation 'com.github.joshjdevl.libsodiumjni:libsodium-jni-aar:2.0.1' implementation 'com.github.joshjdevl.libsodiumjni:libsodium-jni-aar:2.0.1'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.19' implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.19'
implementation 'com.journeyapps:zxing-android-embedded:3.6.0' //implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
implementation 'com.journeyapps:zxing-android-embedded:3.6.0@aar'
implementation 'com.google.zxing:core:3.3.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'

3
app/src/main/AndroidManifest.xml

@ -52,7 +52,8 @@
<activity <activity
android:name="org.myhush.silentdragon.QrReaderActivity" android:name="org.myhush.silentdragon.QrReaderActivity"
android:screenOrientation="portrait"/> android:screenOrientation="fullSensor"
tools:replace="screenOrientation" />
<activity <activity
android:name="org.myhush.silentdragon.TxDetailsActivity" android:name="org.myhush.silentdragon.TxDetailsActivity"
android:label="@string/title_activity_tx_details" android:label="@string/title_activity_tx_details"

105
app/src/main/java/org/myhush/silentdragon/MainActivity.kt

@ -14,23 +14,16 @@ import android.text.Html
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import android.widget.Button import android.widget.Button
import android.widget.ScrollView import android.widget.ScrollView
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import com.beust.klaxon.Klaxon import com.beust.klaxon.Klaxon
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.zxing.client.android.Intents
import com.google.zxing.client.android.Intents.Scan.QR_CODE_MODE
import com.google.zxing.integration.android.IntentIntegrator
import com.google.zxing.integration.android.IntentResult
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_qr_reader.*
import kotlinx.android.synthetic.main.content_main.* import kotlinx.android.synthetic.main.content_main.*
import org.myhush.silentdragon.DataModel.ConnectionStatus import org.myhush.silentdragon.DataModel.ConnectionStatus
import org.myhush.silentdragon.DataModel.connStatus import org.myhush.silentdragon.DataModel.connStatus
@ -45,9 +38,6 @@ class MainActivity : AppCompatActivity(),
TODO("not implemented") //To change body of created functions use File | Settings | File Templates. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
// IntentIntegrator is part of zxing-android-embedded to read QR codes
private lateinit var intentIntegrator: IntentIntegrator
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
//StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()) // TESTING //StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()) // TESTING
@ -60,20 +50,17 @@ class MainActivity : AppCompatActivity(),
// When creating, clear all the data first // When creating, clear all the data first
setMainStatus("") setMainStatus("")
DataModel.init()
intentIntegrator = IntentIntegrator(this) DataModel.init()
btnConnect.setOnClickListener { btnConnect.setOnClickListener {
//startActivity(Intent(this@MainActivity, QrReaderActivity::class.java)) val intent = Intent(this, QrReaderActivity::class.java)
run { intent.putExtra("REQUEST_CODE",
intentIntegrator.setDesiredBarcodeFormats(QR_CODE_MODE) QrReaderActivity.REQUEST_CONNDATA
intentIntegrator.setCameraId(0) // set to back camera )
intentIntegrator.setBeepEnabled(true) startActivityForResult(intent,
intentIntegrator.setOrientationLocked(false) // trying to force portrait here, but it's not working QrReaderActivity.REQUEST_CONNDATA
intentIntegrator.setPrompt("Go to Apps -> Connect mobile app on your desktop wallet and scan the QR Code to connect") )
intentIntegrator.initiateScan()
}
} }
btnReconnect.setOnClickListener { btnReconnect.setOnClickListener {
@ -353,39 +340,49 @@ class MainActivity : AppCompatActivity(),
super.onDestroy() super.onDestroy()
} }
// the toasts work here so commenting out override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
/*override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) {
QrReaderActivity.REQUEST_CONNDATA -> {
if (resultCode == Activity.RESULT_OK) {
Log.i(TAG, "Main Activity got result for QrCode: ${data?.dataString}")
// Check to make sure that the result is an actual address
if (!(data?.dataString ?: "").startsWith("ws")) {
Toast.makeText(
applicationContext,
getString(R.string.is_not_a_valid_connection_string, data?.dataString),
Toast.LENGTH_SHORT
).show()
return
}
var result: IntentResult? = IntentIntegrator.parseActivityResult(requestCode, resultCode, data) val conComponents = data?.dataString?.split(",")
if (conComponents?.size ?: 0 < 2 || conComponents?.size ?: 0 > 3) {
Toast.makeText(
applicationContext,
getString(R.string.is_not_a_valid_connection_string, data?.dataString),
Toast.LENGTH_SHORT
).show()
return
}
if(result != null){ val conString = conComponents!![0]
val secretHex = conComponents[1]
val allowInternetConnections =
if (conComponents.size == 3) conComponents[2] == "1" else false
if(result.contents != null){ DataModel.setSecretHex(secretHex)
//Toast.makeText(applicationContext, result.contents,Toast.LENGTH_LONG).show() DataModel.setConnString(
Toast.makeText(this, "Scanned: " + result.contents, Toast.LENGTH_LONG).show(); conString,
} else { applicationContext
//Toast.makeText(applicationContext,"scan failed",Toast.LENGTH_SHORT).show() )
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show() DataModel.setAllowInternet(
} allowInternetConnections
} else { )
super.onActivityResult(requestCode, resultCode, data)
}
}*/
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { ConnectionManager.refreshAllData()
var result: IntentResult? = IntentIntegrator.parseActivityResult(requestCode, resultCode, data) }
if(result != null){
if(result.contents != null){
Log.d("MainActivity", "Scanned" + result.contents)
Toast.makeText(this, "Scanned: " + result.contents, Toast.LENGTH_LONG).show();
processMobileConnectorText(result.contents)
} else {
Log.d("MainActivity", "Cancelled scan")
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show()
} }
} else {
super.onActivityResult(requestCode, resultCode, data)
} }
} }
@ -400,15 +397,5 @@ class MainActivity : AppCompatActivity(),
updateUI(true) updateUI(true)
} }
private fun processMobileConnectorText(qrcodeInfo: String) {
if (qrcodeInfo.startsWith("ws")) {
Log.i(TAG, "It's a ws connection")
//Toast.makeText(this, "YEAH " + qrcodeInfo.toString(), Toast.LENGTH_SHORT).show();
} else {
Log.i(TAG, "Not a ws connection")
//Toast.makeText(this, "Not a ws connection", Toast.LENGTH_SHORT).show();
}
}
private val TAG = "MainActivity" private val TAG = "MainActivity"
} }

131
app/src/main/java/org/myhush/silentdragon/QrReaderActivity.kt

@ -2,29 +2,26 @@
package org.myhush.silentdragon package org.myhush.silentdragon
import android.app.Activity import android.app.Activity
import android.app.AlertDialog
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.core.app.ActivityCompat import android.text.InputType
import androidx.core.content.ContextCompat
import androidx.appcompat.app.AppCompatActivity
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem 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 import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.zxing.ResultPoint
import com.journeyapps.barcodescanner.BarcodeCallback
import com.journeyapps.barcodescanner.BarcodeResult
import com.journeyapps.barcodescanner.CaptureManager
import kotlinx.android.synthetic.main.activity_qr_reader.*
class QrReaderActivity : AppCompatActivity() { class QrReaderActivity : AppCompatActivity() {
lateinit var captureManager: CaptureManager
companion object { companion object {
const val REQUEST_ADDRESS = 1 const val REQUEST_ADDRESS = 1
@ -43,7 +40,26 @@ class QrReaderActivity : AppCompatActivity() {
lblErrorMsg.text = "" lblErrorMsg.text = ""
setupCamera() btnQrCodeCancel.setOnClickListener {
setResult(Activity.RESULT_CANCELED)
finish()
}
captureManager = CaptureManager(this, barcodeView)
captureManager.initializeFromIntent(intent, savedInstanceState)
barcodeView.decodeSingle(object: BarcodeCallback{
override fun barcodeResult(result: BarcodeResult?) {
result?.let {
if (result.text != null) {
processQrCodeText(result.text)
}
}
}
override fun possibleResultPoints(resultPoints: MutableList<ResultPoint>?) {
}
})
} }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
@ -92,63 +108,19 @@ class QrReaderActivity : AppCompatActivity() {
} }
} }
private fun setupCamera() { override fun onPause() {
val cameraView = findViewById<SurfaceView>(R.id.camera_view) super.onPause()
captureManager.onPause()
val barcodeDetector = BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.QR_CODE).build() }
val cameraSource = CameraSource.Builder(this, barcodeDetector)
.setAutoFocusEnabled(true)
.setRequestedPreviewSize(640, 480)
.build()
cameraView.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
try {
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}")
}
} catch (ie: IOException) {
Log.e("CAMERA SOURCE", ie.toString())
}
}
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 onResume() {
override fun release() {} super.onResume()
captureManager.onResume()
}
override fun receiveDetections(detections: Detector.Detections<Barcode>) { override fun onDestroy() {
val barcodes = detections.detectedItems super.onDestroy()
if (barcodes.size() != 0) { captureManager.onDestroy()
runOnUiThread {
val barcodeInfo = barcodes.valueAt(0).displayValue
processText(barcodeInfo)
}
}
}
})
} }
private fun processText(barcodeInfo: String) { private fun processText(barcodeInfo: String) {
@ -174,15 +146,13 @@ class QrReaderActivity : AppCompatActivity() {
err = err.substring(0, 22) + "...." + err.substring(err.length - 22, err.length) err = err.substring(0, 22) + "...." + err.substring(err.length - 22, err.length)
} }
lblErrorMsg.text = getString(R.string.is_not_a_valid_hush_address, err) lblErrorMsg.text = getString(R.string.is_not_a_valid_hush_address, err)
return return
} }
// The data seems valid, so return it. // The data seems valid, so return it.
val data = Intent() val data = Intent()
// Payment URIs are often formatted as "hush:<addr>", but this casuses parsing problems. // Payment URIs are often formatted as "hush:<addr>", but this causes parsing problems.
// So change it to hush://<addr>, so that it parses properly // So change it to hush://<addr>, so that it parses properly
if (barcodeInfo.startsWith("hush:") && !barcodeInfo.startsWith("hush://")) { if (barcodeInfo.startsWith("hush:") && !barcodeInfo.startsWith("hush://")) {
data.data = Uri.parse(barcodeInfo.replaceFirst("hush:", "hush://")) data.data = Uri.parse(barcodeInfo.replaceFirst("hush:", "hush://"))
@ -194,5 +164,22 @@ class QrReaderActivity : AppCompatActivity() {
finish() finish()
} }
private fun processQrCodeText(qrcodeInfo: String) {
if (qrcodeInfo.startsWith("ws")) {
Log.i(TAG, "It's a ws connection")
//Toast.makeText(this, "YEAH: " + qrcodeInfo, Toast.LENGTH_SHORT).show();
val data = Intent() // The data seems valid, so return it
data.data = Uri.parse(qrcodeInfo)
setResult(Activity.RESULT_OK, data)
finish()
} else {
Log.i(TAG, "Not a ws connection")
//Toast.makeText(this, "Not a ws connection", Toast.LENGTH_SHORT).show();
setResult(Activity.RESULT_CANCELED)
finish()
}
}
private val TAG = "QrReader" private val TAG = "QrReader"
} }

20
app/src/main/res/layout/activity_qr_reader.xml

@ -9,23 +9,15 @@
tools:context="org.myhush.silentdragon.QrReaderActivity" tools:context="org.myhush.silentdragon.QrReaderActivity"
tools:showIn="@layout/activity_qr_reader"> tools:showIn="@layout/activity_qr_reader">
<SurfaceView <com.journeyapps.barcodescanner.DecoratedBarcodeView
android:id="@+id/camera_view" android:id="@+id/barcodeView"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@+id/txtQrCodeHelp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent"
app:zxing_scanner_layout="@layout/custom_qrcode_layout" />
<ImageView
android:id="@+id/imageView4"
android:layout_width="0dp"
android:layout_height="200dp"
android:src="#ee000000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView <TextView
android:id="@+id/txtQrCodeHelp" android:id="@+id/txtQrCodeHelp"

24
app/src/main/res/layout/custom_qrcode_layout.xml

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.journeyapps.barcodescanner.BarcodeView
android:id="@+id/zxing_barcode_surface"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:zxing_framing_rect_height="300dp"
app:zxing_framing_rect_width="300dp" />
<com.journeyapps.barcodescanner.ViewfinderView
android:id="@+id/zxing_viewfinder_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:zxing_possible_result_points="@color/zxing_custom_possible_result_points"
app:zxing_result_view="@color/zxing_custom_result_view"
app:zxing_viewfinder_laser="@color/zxing_custom_viewfinder_laser"
app:zxing_viewfinder_mask="@color/zxing_custom_viewfinder_mask" />
</androidx.constraintlayout.widget.ConstraintLayout>

2
build.gradle

@ -11,7 +11,7 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.6.0' // does this need 4.0 or another version? classpath 'com.android.tools.build:gradle:3.6.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${Deps.kotlinVersion}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${Deps.kotlinVersion}"
classpath 'io.fabric.tools:gradle:1.31.2' classpath 'io.fabric.tools:gradle:1.31.2'

Loading…
Cancel
Save