Merge pull request #431 from meshtastic/mlkit-scan

add mlkit barcode scanner
pull/433/head
Andre Kirchhoff 2022-05-17 17:42:26 -03:00 zatwierdzone przez GitHub
commit 747ce82a7b
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
5 zmienionych plików z 100 dodań i 34 usunięć

Wyświetl plik

@ -173,9 +173,10 @@ dependencies {
// location services
implementation 'com.google.android.gms:play-services-location:19.0.1'
// For Google Sign-In (owner name accesss)
implementation 'com.google.android.gms:play-services-auth:20.1.0'
// ML Kit barcode scanning
implementation 'com.google.android.gms:play-services-code-scanner:16.0.0-beta1'
// Add the Firebase SDK for Crashlytics.
implementation 'com.google.firebase:firebase-crashlytics:18.2.6'

Wyświetl plik

@ -97,6 +97,9 @@
<meta-data
android:name="firebase_analytics_collection_enabled"
android:value="false" />
<meta-data
android:name="com.google.mlkit.vision.DEPENDENCIES"
android:value="barcode_ui"/>
<!-- we need bind job service for oreo -->
<service

Wyświetl plik

@ -518,8 +518,7 @@ class MainActivity : BaseActivity(), Logging,
requestedChannelUrl = appLinkData
// if the device is connected already, process it now
if (model.isConnected())
perhapsChangeChannel()
perhapsChangeChannel()
// We now wait for the device to connect, once connected, we ask the user if they want to switch to the new channel
}
@ -721,16 +720,16 @@ class MainActivity : BaseActivity(), Logging,
}
}
fun perhapsChangeChannel(url: Uri? = requestedChannelUrl) {
// If the is opening a channel URL, handle it now
if (url != null) {
private fun perhapsChangeChannel(url: Uri? = requestedChannelUrl) {
// if the device is connected already, process it now
if (url != null && model.isConnected()) {
requestedChannelUrl = null
try {
val channels = ChannelSet(url)
val primary = channels.primaryChannel
if (primary == null)
showSnackbar(R.string.channel_invalid)
else {
requestedChannelUrl = null
MaterialAlertDialogBuilder(this)
.setTitle(R.string.new_channel_rcvd)
@ -967,6 +966,15 @@ class MainActivity : BaseActivity(), Logging,
}
}
// Call perhapsChangeChannel() whenever [changeChannelUrl] updates with a non-null value
model.requestChannelUrl.observe(this) { url ->
url?.let {
requestedChannelUrl = url
model.clearRequestChannelUrl()
perhapsChangeChannel()
}
}
try {
bindMeshService()
} catch (ex: BindFailedException) {

Wyświetl plik

@ -107,6 +107,20 @@ class UIViewModel @Inject constructor(
private val _channels = MutableLiveData<ChannelSet?>()
val channels: LiveData<ChannelSet?> get() = _channels
private val _requestChannelUrl = MutableLiveData<Uri?>(null)
val requestChannelUrl: LiveData<Uri?> get() = _requestChannelUrl
fun setRequestChannelUrl(channelUrl: Uri) {
_requestChannelUrl.value = channelUrl
}
/**
* Called immediately after activity observes requestChannelUrl
*/
fun clearRequestChannelUrl() {
_requestChannelUrl.value = null
}
var positionBroadcastSecs: Int?
get() {
_radioConfig.value?.preferences?.let {

Wyświetl plik

@ -1,5 +1,6 @@
package com.geeksville.mesh.ui
import android.Manifest
import android.content.ActivityNotFoundException
import android.content.Intent
import android.graphics.ColorMatrix
@ -13,15 +14,15 @@ import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.ArrayAdapter
import android.widget.ImageView
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.activityViewModels
import com.geeksville.analytics.DataPair
import com.geeksville.android.GeeksvilleApplication
import com.geeksville.android.Logging
import com.geeksville.android.hideKeyboard
import com.geeksville.android.isGooglePlayAvailable
import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.ChannelProtos
import com.geeksville.mesh.MainActivity
import com.geeksville.mesh.R
import com.geeksville.mesh.android.hasCameraPermission
import com.geeksville.mesh.databinding.ChannelFragmentBinding
@ -31,9 +32,11 @@ import com.geeksville.mesh.model.ChannelSet
import com.geeksville.mesh.model.UIViewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions
import com.google.mlkit.vision.codescanner.GmsBarcodeScanning
import com.google.protobuf.ByteString
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions
import dagger.hilt.android.AndroidEntryPoint
import java.security.SecureRandom
@ -189,6 +192,52 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
}
}
private fun zxingScan() {
debug("Starting zxing QR code scanner")
val zxingScan = ScanOptions()
zxingScan.setCameraId(0)
zxingScan.setPrompt("")
zxingScan.setBeepEnabled(false)
zxingScan.setDesiredBarcodeFormats(ScanOptions.QR_CODE)
barcodeLauncher.launch(zxingScan)
}
private fun requestPermissionAndScan() {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.camera_required)
.setMessage(R.string.why_camera_required)
.setNeutralButton(R.string.cancel) { _, _ ->
debug("Camera permission denied")
}
.setPositiveButton(getString(R.string.accept)) { _, _ ->
requestPermissionAndScanLauncher.launch(Manifest.permission.CAMERA)
}
.show()
}
private fun mlkitScan() {
debug("Starting ML Kit QR code scanner")
val options = GmsBarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE
)
.build()
val scanner = GmsBarcodeScanning.getClient(requireContext(), options)
scanner.startScan()
.addOnSuccessListener { barcode ->
if (barcode.rawValue != null)
model.setRequestChannelUrl(Uri.parse(barcode.rawValue))
}
.addOnFailureListener {
Snackbar.make(
requireView(),
R.string.channel_invalid,
Snackbar.LENGTH_SHORT
).show()
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -212,25 +261,14 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
}
binding.scanButton.setOnClickListener {
if ((requireActivity() as MainActivity).hasCameraPermission()) {
debug("Starting QR code scanner")
val zxingScan = ScanOptions()
zxingScan.setCameraId(0)
zxingScan.setPrompt("")
zxingScan.setBeepEnabled(false)
zxingScan.setDesiredBarcodeFormats(ScanOptions.QR_CODE)
barcodeLauncher.launch(zxingScan)
if (isGooglePlayAvailable(requireContext())) {
mlkitScan()
} else {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.camera_required)
.setMessage(R.string.why_camera_required)
.setNeutralButton(R.string.cancel) { _, _ ->
debug("Camera permission denied")
}
.setPositiveButton(getString(R.string.accept)) { _, _ ->
(requireActivity() as MainActivity).requestCameraPermission()
}
.show()
if (requireContext().hasCameraPermission()) {
zxingScan()
} else {
requestPermissionAndScan()
}
}
}
@ -315,16 +353,18 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
if (getString(item.configRes) == selectedChannelOptionString)
return item.modemConfig
}
return ChannelProtos.ChannelSettings.ModemConfig.UNRECOGNIZED
}
// Register the launcher and result handler
private val barcodeLauncher: ActivityResultLauncher<ScanOptions> = registerForActivityResult(
ScanContract()
) { result: ScanIntentResult ->
private val requestPermissionAndScanLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { allowed ->
if (allowed) zxingScan()
}
// Register zxing launcher and result handler
private val barcodeLauncher = registerForActivityResult(ScanContract()) { result ->
if (result.contents != null) {
((requireActivity() as MainActivity).perhapsChangeChannel(Uri.parse(result.contents)))
model.setRequestChannelUrl(Uri.parse(result.contents))
}
}
}