kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
commit
747ce82a7b
|
@ -173,9 +173,10 @@ dependencies {
|
||||||
|
|
||||||
// location services
|
// location services
|
||||||
implementation 'com.google.android.gms:play-services-location:19.0.1'
|
implementation 'com.google.android.gms:play-services-location:19.0.1'
|
||||||
|
|
||||||
// For Google Sign-In (owner name accesss)
|
// For Google Sign-In (owner name accesss)
|
||||||
implementation 'com.google.android.gms:play-services-auth:20.1.0'
|
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.
|
// Add the Firebase SDK for Crashlytics.
|
||||||
implementation 'com.google.firebase:firebase-crashlytics:18.2.6'
|
implementation 'com.google.firebase:firebase-crashlytics:18.2.6'
|
||||||
|
|
|
@ -97,6 +97,9 @@
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="firebase_analytics_collection_enabled"
|
android:name="firebase_analytics_collection_enabled"
|
||||||
android:value="false" />
|
android:value="false" />
|
||||||
|
<meta-data
|
||||||
|
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||||
|
android:value="barcode_ui"/>
|
||||||
|
|
||||||
<!-- we need bind job service for oreo -->
|
<!-- we need bind job service for oreo -->
|
||||||
<service
|
<service
|
||||||
|
|
|
@ -518,8 +518,7 @@ class MainActivity : BaseActivity(), Logging,
|
||||||
requestedChannelUrl = appLinkData
|
requestedChannelUrl = appLinkData
|
||||||
|
|
||||||
// if the device is connected already, process it now
|
// 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
|
// 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) {
|
private fun perhapsChangeChannel(url: Uri? = requestedChannelUrl) {
|
||||||
// If the is opening a channel URL, handle it now
|
// if the device is connected already, process it now
|
||||||
if (url != null) {
|
if (url != null && model.isConnected()) {
|
||||||
|
requestedChannelUrl = null
|
||||||
try {
|
try {
|
||||||
val channels = ChannelSet(url)
|
val channels = ChannelSet(url)
|
||||||
val primary = channels.primaryChannel
|
val primary = channels.primaryChannel
|
||||||
if (primary == null)
|
if (primary == null)
|
||||||
showSnackbar(R.string.channel_invalid)
|
showSnackbar(R.string.channel_invalid)
|
||||||
else {
|
else {
|
||||||
requestedChannelUrl = null
|
|
||||||
|
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.new_channel_rcvd)
|
.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 {
|
try {
|
||||||
bindMeshService()
|
bindMeshService()
|
||||||
} catch (ex: BindFailedException) {
|
} catch (ex: BindFailedException) {
|
||||||
|
|
|
@ -107,6 +107,20 @@ class UIViewModel @Inject constructor(
|
||||||
private val _channels = MutableLiveData<ChannelSet?>()
|
private val _channels = MutableLiveData<ChannelSet?>()
|
||||||
val channels: LiveData<ChannelSet?> get() = _channels
|
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?
|
var positionBroadcastSecs: Int?
|
||||||
get() {
|
get() {
|
||||||
_radioConfig.value?.preferences?.let {
|
_radioConfig.value?.preferences?.let {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.geeksville.mesh.ui
|
package com.geeksville.mesh.ui
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.ColorMatrix
|
import android.graphics.ColorMatrix
|
||||||
|
@ -13,15 +14,15 @@ import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import com.geeksville.analytics.DataPair
|
import com.geeksville.analytics.DataPair
|
||||||
import com.geeksville.android.GeeksvilleApplication
|
import com.geeksville.android.GeeksvilleApplication
|
||||||
import com.geeksville.android.Logging
|
import com.geeksville.android.Logging
|
||||||
import com.geeksville.android.hideKeyboard
|
import com.geeksville.android.hideKeyboard
|
||||||
|
import com.geeksville.android.isGooglePlayAvailable
|
||||||
import com.geeksville.mesh.AppOnlyProtos
|
import com.geeksville.mesh.AppOnlyProtos
|
||||||
import com.geeksville.mesh.ChannelProtos
|
import com.geeksville.mesh.ChannelProtos
|
||||||
import com.geeksville.mesh.MainActivity
|
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.android.hasCameraPermission
|
import com.geeksville.mesh.android.hasCameraPermission
|
||||||
import com.geeksville.mesh.databinding.ChannelFragmentBinding
|
import com.geeksville.mesh.databinding.ChannelFragmentBinding
|
||||||
|
@ -31,9 +32,11 @@ import com.geeksville.mesh.model.ChannelSet
|
||||||
import com.geeksville.mesh.model.UIViewModel
|
import com.geeksville.mesh.model.UIViewModel
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
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.google.protobuf.ByteString
|
||||||
import com.journeyapps.barcodescanner.ScanContract
|
import com.journeyapps.barcodescanner.ScanContract
|
||||||
import com.journeyapps.barcodescanner.ScanIntentResult
|
|
||||||
import com.journeyapps.barcodescanner.ScanOptions
|
import com.journeyapps.barcodescanner.ScanOptions
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import java.security.SecureRandom
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
@ -212,25 +261,14 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.scanButton.setOnClickListener {
|
binding.scanButton.setOnClickListener {
|
||||||
if ((requireActivity() as MainActivity).hasCameraPermission()) {
|
if (isGooglePlayAvailable(requireContext())) {
|
||||||
debug("Starting QR code scanner")
|
mlkitScan()
|
||||||
val zxingScan = ScanOptions()
|
|
||||||
zxingScan.setCameraId(0)
|
|
||||||
zxingScan.setPrompt("")
|
|
||||||
zxingScan.setBeepEnabled(false)
|
|
||||||
zxingScan.setDesiredBarcodeFormats(ScanOptions.QR_CODE)
|
|
||||||
barcodeLauncher.launch(zxingScan)
|
|
||||||
} else {
|
} else {
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
if (requireContext().hasCameraPermission()) {
|
||||||
.setTitle(R.string.camera_required)
|
zxingScan()
|
||||||
.setMessage(R.string.why_camera_required)
|
} else {
|
||||||
.setNeutralButton(R.string.cancel) { _, _ ->
|
requestPermissionAndScan()
|
||||||
debug("Camera permission denied")
|
}
|
||||||
}
|
|
||||||
.setPositiveButton(getString(R.string.accept)) { _, _ ->
|
|
||||||
(requireActivity() as MainActivity).requestCameraPermission()
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,16 +353,18 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
|
||||||
if (getString(item.configRes) == selectedChannelOptionString)
|
if (getString(item.configRes) == selectedChannelOptionString)
|
||||||
return item.modemConfig
|
return item.modemConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
return ChannelProtos.ChannelSettings.ModemConfig.UNRECOGNIZED
|
return ChannelProtos.ChannelSettings.ModemConfig.UNRECOGNIZED
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the launcher and result handler
|
private val requestPermissionAndScanLauncher =
|
||||||
private val barcodeLauncher: ActivityResultLauncher<ScanOptions> = registerForActivityResult(
|
registerForActivityResult(ActivityResultContracts.RequestPermission()) { allowed ->
|
||||||
ScanContract()
|
if (allowed) zxingScan()
|
||||||
) { result: ScanIntentResult ->
|
}
|
||||||
|
|
||||||
|
// Register zxing launcher and result handler
|
||||||
|
private val barcodeLauncher = registerForActivityResult(ScanContract()) { result ->
|
||||||
if (result.contents != null) {
|
if (result.contents != null) {
|
||||||
((requireActivity() as MainActivity).perhapsChangeChannel(Uri.parse(result.contents)))
|
model.setRequestChannelUrl(Uri.parse(result.contents))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue