From 48b609b653180b1145b2103097837e514e58364d Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 17 Aug 2022 16:13:59 -0300 Subject: [wallet] Scan QR codes in mixed mode so we can scan inverted codes as well --- .../src/main/java/net/taler/wallet/MainActivity.kt | 68 ++++++++++++++-------- .../src/main/java/net/taler/wallet/MainFragment.kt | 2 +- .../main/java/net/taler/wallet/MainViewModel.kt | 8 +++ wallet/src/main/java/net/taler/wallet/Utils.kt | 10 ---- .../wallet/transactions/TransactionsFragment.kt | 3 +- .../wallet/withdraw/ManualWithdrawFragment.kt | 7 ++- 6 files changed, 57 insertions(+), 41 deletions(-) (limited to 'wallet/src/main') diff --git a/wallet/src/main/java/net/taler/wallet/MainActivity.kt b/wallet/src/main/java/net/taler/wallet/MainActivity.kt index 1ba05ac..ea604c4 100644 --- a/wallet/src/main/java/net/taler/wallet/MainActivity.kt +++ b/wallet/src/main/java/net/taler/wallet/MainActivity.kt @@ -46,10 +46,14 @@ import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCal import com.google.android.material.navigation.NavigationView.OnNavigationItemSelectedListener import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_LONG import com.google.android.material.snackbar.Snackbar -import com.google.zxing.integration.android.IntentIntegrator -import com.google.zxing.integration.android.IntentIntegrator.parseActivityResult +import com.google.zxing.client.android.Intents.Scan.MIXED_SCAN +import com.google.zxing.client.android.Intents.Scan.SCAN_TYPE +import com.journeyapps.barcodescanner.ScanContract +import com.journeyapps.barcodescanner.ScanOptions +import com.journeyapps.barcodescanner.ScanOptions.QR_CODE import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import net.taler.common.EventObserver import net.taler.common.isOnline import net.taler.common.showError import net.taler.wallet.BuildConfig.VERSION_CODE @@ -65,6 +69,7 @@ import java.net.URL import java.util.Locale.ROOT import javax.net.ssl.HttpsURLConnection + class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, OnPreferenceStartFragmentCallback { @@ -73,6 +78,11 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, private lateinit var ui: ActivityMainBinding private lateinit var nav: NavController + private val barcodeLauncher = registerForActivityResult(ScanContract()) { result -> + if (result == null || result.contents == null) return@registerForActivityResult + handleTalerUri(result.contents, "QR code") + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ui = ActivityMainBinding.inflate(layoutInflater) @@ -118,6 +128,17 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, registerReceiver(nfcConnectedReceiver, IntentFilter(MERCHANT_NFC_CONNECTED)) registerReceiver(nfcDisconnectedReceiver, IntentFilter(MERCHANT_NFC_DISCONNECTED)) registerReceiver(tunnelResponseReceiver, IntentFilter(HTTP_TUNNEL_RESPONSE)) + + model.scanCodeEvent.observe(this, EventObserver { + val scanOptions = ScanOptions().apply { + setPrompt("") + setBeepEnabled(true) + setOrientationLocked(false) + setDesiredBarcodeFormats(QR_CODE) + addExtra(SCAN_TYPE, MIXED_SCAN) + } + if (it) barcodeLauncher.launch(scanOptions) + }) } override fun onBackPressed() { @@ -135,15 +156,6 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, return true } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (requestCode == IntentIntegrator.REQUEST_CODE) { - parseActivityResult(requestCode, resultCode, data)?.contents?.let { contents -> - handleTalerUri(contents, "QR code") - } - } - } - override fun onDestroy() { unregisterReceiver(triggerPaymentReceiver) unregisterReceiver(nfcConnectedReceiver) @@ -152,13 +164,18 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, super.onDestroy() } - private fun getTalerAction(uri: Uri, maxRedirects: Int, actionFound: MutableLiveData): MutableLiveData { + private fun getTalerAction( + uri: Uri, + maxRedirects: Int, + actionFound: MutableLiveData, + ): MutableLiveData { val scheme = uri.scheme ?: return actionFound if (scheme == "http" || scheme == "https") { model.viewModelScope.launch(Dispatchers.IO) { - val conn: HttpsURLConnection = URL(uri.toString()).openConnection() as HttpsURLConnection - Log.v(TAG, "prepare query: ${uri}") + val conn: HttpsURLConnection = + URL(uri.toString()).openConnection() as HttpsURLConnection + Log.v(TAG, "prepare query: $uri") conn.setRequestProperty("Accept", "text/html") conn.connectTimeout = 5000 conn.requestMethod = "HEAD" @@ -175,12 +192,13 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, } if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM - || status == HttpURLConnection.HTTP_SEE_OTHER) { + || status == HttpURLConnection.HTTP_SEE_OTHER + ) { val location = conn.headerFields["Location"] if (location != null && location[0] != null) { Log.v(TAG, "location redirect: ${location[0]}") val locUri = Uri.parse(location[0]) - getTalerAction(locUri, maxRedirects -1, actionFound) + getTalerAction(locUri, maxRedirects - 1, actionFound) } } } @@ -200,10 +218,10 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, connectToWifi(this, uri.fragment!!) } - getTalerAction(uri, 3, MutableLiveData()).observe(this) { url -> - Log.v(TAG, "found action $url") + getTalerAction(uri, 3, MutableLiveData()).observe(this) { u -> + Log.v(TAG, "found action $u") - val normalizedURL = url.lowercase(ROOT) + val normalizedURL = u.lowercase(ROOT) val action = normalizedURL.substring( if (normalizedURL.startsWith("taler://")) { "taler://".length @@ -218,25 +236,25 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, action.startsWith("pay/") -> { Log.v(TAG, "navigating!") nav.navigate(R.id.action_global_promptPayment) - model.paymentManager.preparePay(url) + model.paymentManager.preparePay(u) } action.startsWith("tip/") -> { Log.v(TAG, "navigating!") nav.navigate(R.id.action_global_promptTip) - model.tipManager.prepareTip(url) + model.tipManager.prepareTip(u) } action.startsWith("withdraw/") -> { Log.v(TAG, "navigating!") // there's more than one entry point, so use global action nav.navigate(R.id.action_global_promptWithdraw) - model.withdrawManager.getWithdrawalDetails(url) + model.withdrawManager.getWithdrawalDetails(u) } action.startsWith("refund/") -> { model.showProgressBar.value = true - model.refundManager.refund(url).observe(this, Observer(::onRefundResponse)) + model.refundManager.refund(u).observe(this, Observer(::onRefundResponse)) } else -> { - showError(R.string.error_unsupported_uri, "From: $from\nURI: $url") + showError(R.string.error_unsupported_uri, "From: $from\nURI: $u") } } } @@ -292,7 +310,7 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, override fun onPreferenceStartFragment( caller: PreferenceFragmentCompat, - pref: Preference + pref: Preference, ): Boolean { when (pref.key) { "pref_backup" -> nav.navigate(R.id.action_nav_settings_to_nav_settings_backup) diff --git a/wallet/src/main/java/net/taler/wallet/MainFragment.kt b/wallet/src/main/java/net/taler/wallet/MainFragment.kt index 6c84925..2521e29 100644 --- a/wallet/src/main/java/net/taler/wallet/MainFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/MainFragment.kt @@ -62,7 +62,7 @@ class MainFragment : Fragment() { }) ui.mainFab.setOnClickListener { - scanQrCode(requireActivity()) + model.scanCode() } ui.mainFab.setOnLongClickListener { findNavController().navigate(R.id.action_nav_main_to_nav_uri_input) diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt index 5041037..92113aa 100644 --- a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt +++ b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt @@ -97,6 +97,9 @@ class MainViewModel(val app: Application) : AndroidViewModel(app) { private val mTransactionsEvent = MutableLiveData>() val transactionsEvent: LiveData> = mTransactionsEvent + private val mScanCodeEvent = MutableLiveData>() + val scanCodeEvent: LiveData> = mScanCodeEvent + private val mLastBackup = MutableLiveData( // fake backup time until we actually do backup System.currentTimeMillis() - @@ -151,4 +154,9 @@ class MainViewModel(val app: Application) : AndroidViewModel(app) { api.sendRequest("tunnelResponse", respJson) } + @UiThread + fun scanCode() { + mScanCodeEvent.value = true.toEvent() + } + } diff --git a/wallet/src/main/java/net/taler/wallet/Utils.kt b/wallet/src/main/java/net/taler/wallet/Utils.kt index 388bf61..1b5af64 100644 --- a/wallet/src/main/java/net/taler/wallet/Utils.kt +++ b/wallet/src/main/java/net/taler/wallet/Utils.kt @@ -16,7 +16,6 @@ package net.taler.wallet -import android.app.Activity import android.content.Context import android.net.ConnectivityManager import android.net.ConnectivityManager.NetworkCallback @@ -30,15 +29,6 @@ import android.widget.Toast import android.widget.Toast.LENGTH_LONG import androidx.annotation.RequiresApi import androidx.core.content.getSystemService -import com.google.zxing.integration.android.IntentIntegrator - -fun scanQrCode(activity: Activity) { - IntentIntegrator(activity).apply { - setPrompt("") - setBeepEnabled(true) - setOrientationLocked(false) - }.initiateScan(listOf(IntentIntegrator.QR_CODE)) -} fun connectToWifi(context: Context, ssid: String) { if (SDK_INT >= 29) { diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt index fddaaec..da8508a 100644 --- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt @@ -41,7 +41,6 @@ import net.taler.common.fadeOut import net.taler.wallet.MainViewModel import net.taler.wallet.R import net.taler.wallet.databinding.FragmentTransactionsBinding -import net.taler.wallet.scanQrCode interface OnTransactionClickListener { fun onTransactionClicked(transaction: Transaction) @@ -118,7 +117,7 @@ class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode. onTransactionsResult(result) } ui.mainFab.setOnClickListener { - scanQrCode(requireActivity()) + model.scanCode() } ui.mainFab.setOnLongClickListener { findNavController().navigate(R.id.action_nav_transactions_to_nav_uri_input) diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt index 660fec2..500b6e7 100644 --- a/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt @@ -29,7 +29,6 @@ import net.taler.common.hideKeyboard import net.taler.wallet.MainViewModel import net.taler.wallet.R import net.taler.wallet.databinding.FragmentManualWithdrawBinding -import net.taler.wallet.scanQrCode import java.util.Locale class ManualWithdrawFragment : Fragment() { @@ -50,7 +49,9 @@ class ManualWithdrawFragment : Fragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - ui.qrCodeButton.setOnClickListener { scanQrCode(requireActivity()) } + ui.qrCodeButton.setOnClickListener { + model.scanCode() + } ui.currencyView.text = exchangeItem.currency val paymentOptions = exchangeItem.paytoUris.mapNotNull { paytoUri -> Uri.parse(paytoUri).authority?.uppercase(Locale.getDefault()) @@ -66,7 +67,7 @@ class ManualWithdrawFragment : Fragment() { return } ui.amountLayout.error = null - var value = 0.0 + val value: Double try { value = ui.amountView.text.toString().replace(',', '.').toDouble() } catch (e: NumberFormatException) { -- cgit v1.2.3