1717package fr.acinq.phoenix.send
1818
1919import android.Manifest
20+ import android.app.Activity
2021import android.app.AlertDialog
2122import android.content.Intent
2223import android.content.pm.PackageManager
24+ import android.graphics.BitmapFactory
25+ import android.net.Uri
2326import android.os.Bundle
24- import android.os.Handler
2527import android.view.LayoutInflater
2628import android.view.View
2729import android.view.ViewGroup
2830import androidx.core.app.ActivityCompat
2931import androidx.core.content.ContextCompat
3032import androidx.lifecycle.ViewModelProvider
33+ import androidx.lifecycle.lifecycleScope
3134import androidx.navigation.fragment.findNavController
3235import androidx.navigation.fragment.navArgs
3336import com.google.common.base.Strings
34- import com.google.zxing.BarcodeFormat
35- import com.google.zxing.ResultPoint
37+ import com.google.zxing.*
3638import com.google.zxing.client.android.Intents
39+ import com.google.zxing.common.HybridBinarizer
40+ import com.google.zxing.multi.qrcode.QRCodeMultiReader
3741import com.journeyapps.barcodescanner.BarcodeCallback
3842import com.journeyapps.barcodescanner.BarcodeResult
3943import fr.acinq.eclair.payment.PaymentRequest
@@ -46,9 +50,14 @@ import fr.acinq.phoenix.lnurl.LNUrlPay
4650import fr.acinq.phoenix.lnurl.LNUrlWithdraw
4751import fr.acinq.phoenix.utils.*
4852import fr.acinq.phoenix.utils.customviews.ButtonView
53+ import kotlinx.coroutines.CoroutineExceptionHandler
54+ import kotlinx.coroutines.Dispatchers
55+ import kotlinx.coroutines.launch
56+ import kotlinx.coroutines.withContext
4957import org.slf4j.Logger
5058import org.slf4j.LoggerFactory
5159
60+
5261class ReadInputFragment : BaseFragment () {
5362
5463 override val log: Logger = LoggerFactory .getLogger(this ::class .java)
@@ -91,8 +100,6 @@ class ReadInputFragment : BaseFragment() {
91100 mBinding.scanView.pause()
92101 }
93102 is ReadInputState .Done .Lightning -> {
94- // check payment request chain
95- val acceptedPrefix = PaymentRequest .prefixes().get(Wallet .getChainHash())
96103 // additional controls
97104 if (app.state.value?.getNodeId() == it.pr.nodeId()) {
98105 log.debug(" abort payment to self" )
@@ -170,6 +177,13 @@ class ReadInputFragment : BaseFragment() {
170177 context?.let { model.readInput(ClipboardHelper .read(it)) }
171178 }
172179
180+ mBinding.browseButton.setOnClickListener {
181+ startActivityForResult(Intent (Intent .ACTION_GET_CONTENT ).apply {
182+ addCategory(Intent .CATEGORY_OPENABLE )
183+ type = " image/*"
184+ }, Constants .INTENT_PICK_IMAGE_FILE )
185+ }
186+
173187 mBinding.cancelButton.setOnClickListener { findNavController().popBackStack() }
174188
175189 mBinding.errorButton.setOnClickListener {
@@ -202,6 +216,13 @@ class ReadInputFragment : BaseFragment() {
202216 mBinding.scanView.pause()
203217 }
204218
219+ override fun onActivityResult (requestCode : Int , resultCode : Int , data : Intent ? ) {
220+ super .onActivityResult(requestCode, resultCode, data)
221+ if (requestCode == Constants .INTENT_PICK_IMAGE_FILE && resultCode == Activity .RESULT_OK ) {
222+ readBitmap(data?.data)
223+ }
224+ }
225+
205226 private fun startScanning () {
206227 if (model.inputState.value is ReadInputState .Error || model.inputState.value is ReadInputState .Done ) {
207228 model.inputState.postValue(ReadInputState .Scanning )
@@ -224,4 +245,25 @@ class ReadInputFragment : BaseFragment() {
224245 }
225246 }
226247
248+ private fun readBitmap (uri : Uri ? ) {
249+ lifecycleScope.launch(Dispatchers .IO + CoroutineExceptionHandler { _, e ->
250+ log.error(" failed to load or read QR code image from uri=$uri : " , e)
251+ model.inputState.postValue(ReadInputState .Error .UnhandledInput )
252+ }) {
253+ val bitmap = requireContext().contentResolver.openFileDescriptor(uri!! , " r" )?.use {
254+ BitmapFactory .decodeFileDescriptor(it.fileDescriptor)
255+ }!!
256+ val pixels = IntArray (bitmap.width * bitmap.height)
257+ bitmap.getPixels(pixels, 0 , bitmap.width, 0 , 0 , bitmap.width, bitmap.height)
258+ val binaryBitmap = BinaryBitmap (HybridBinarizer (RGBLuminanceSource (bitmap.width, bitmap.height, pixels)))
259+ val result = QRCodeMultiReader ().decodeMultiple(
260+ binaryBitmap
261+ )
262+ log.info(" successfully read QR code with result=$result " )
263+ withContext(Dispatchers .Main ) {
264+ model.readInput(result.first().text)
265+ }
266+ }
267+ }
268+
227269}
0 commit comments