diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4f56cb1ec..016006d7b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -50,11 +50,8 @@
-
-
-
+
+
+
+
+
) = perms.filter {
) != PackageManager.PERMISSION_GRANTED
}
+/**
+ * Camera permission (or empty if we already have what we need)
+ */
+fun Context.getCameraPermissions(): List {
+ val perms = mutableListOf(Manifest.permission.CAMERA)
+
+ return getMissingPermissions(perms)
+}
+
+/** @return true if the user already has camera permission */
+fun Context.hasCameraPermission() = getCameraPermissions().isEmpty()
+
/**
* A list of missing background location permissions (or empty if we already have what we need)
*/
@@ -41,4 +53,4 @@ fun Context.getBackgroundPermissions(): List {
}
/** @return true if the user already has background location permission */
-fun Context.hasBackgroundPermission() = getBackgroundPermissions().isEmpty()
\ No newline at end of file
+fun Context.hasBackgroundPermission() = getBackgroundPermissions().isEmpty()
diff --git a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt
index c3a745316..b2ca3fb80 100644
--- a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt
+++ b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt
@@ -4,6 +4,7 @@ import android.content.ActivityNotFoundException
import android.content.Intent
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
+import android.net.Uri
import android.os.Bundle
import android.os.RemoteException
import android.view.LayoutInflater
@@ -19,7 +20,9 @@ import com.geeksville.android.Logging
import com.geeksville.android.hideKeyboard
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
import com.geeksville.mesh.model.Channel
import com.geeksville.mesh.model.ChannelOption
@@ -29,6 +32,8 @@ import com.geeksville.mesh.service.MeshService
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.google.protobuf.ByteString
+import com.google.zxing.integration.android.IntentIntegrator
+import java.net.MalformedURLException
import java.security.SecureRandom
@@ -70,6 +75,8 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
binding.channelOptions.isEnabled = isEditing
binding.shareButton.isEnabled = !isEditing
+ binding.resetButton.isEnabled = isEditing
+ binding.scanButton.isEnabled = isEditing
binding.channelNameView.isEnabled = isEditing
if (isEditing) // Dim the (stale) QR code while editing...
binding.qrView.setDim()
@@ -86,7 +93,6 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
// Only let buttons work if we are connected to the radio
binding.shareButton.isEnabled = connected
- binding.resetButton.isEnabled = connected && Channel.default != channel
binding.editableCheckbox.isChecked = false // start locked
if (channel != null) {
@@ -203,6 +209,28 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
.show()
}
+ binding.scanButton.setOnClickListener {
+ if ((requireActivity() as MainActivity).hasCameraPermission()) {
+ val zxingScan = IntentIntegrator.forSupportFragment(this)
+ zxingScan.setCameraId(0)
+ zxingScan.setPrompt("")
+ zxingScan.setBeepEnabled(false)
+ zxingScan.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE)
+ zxingScan.initiateScan()
+ } 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()
+ }
+ }
+
// Note: Do not use setOnCheckedChanged here because we don't want to be called when we programmatically disable editing
binding.editableCheckbox.setOnClickListener { _ ->
@@ -287,4 +315,25 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
return ChannelProtos.ChannelSettings.ModemConfig.UNRECOGNIZED
}
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ val result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
+ if (result != null) {
+ if (result.contents == null) {
+ Snackbar.make(binding.scanButton, R.string.channel_invalid, Snackbar.LENGTH_LONG).show()
+ } else {
+ try {
+ val intent = Intent(Intent.ACTION_VIEW)
+ intent.data = ChannelSet(Uri.parse(result.contents)).getChannelUrl(false)
+ startActivity(intent)
+ } catch (ex: ActivityNotFoundException) {
+ Snackbar.make(binding.scanButton, R.string.channel_invalid, Snackbar.LENGTH_LONG).show()
+ } catch (ex: MalformedURLException) {
+ Snackbar.make(binding.scanButton, R.string.channel_invalid, Snackbar.LENGTH_LONG).show()
+ }
+ }
+ } else {
+ super.onActivityResult(requestCode, resultCode, data)
+ }
+ }
}
diff --git a/app/src/main/res/layout/channel_fragment.xml b/app/src/main/res/layout/channel_fragment.xml
index af5ea0dbb..d916757ca 100644
--- a/app/src/main/res/layout/channel_fragment.xml
+++ b/app/src/main/res/layout/channel_fragment.xml
@@ -98,30 +98,40 @@
android:id="@+id/resetButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="32dp"
+ android:layout_marginEnd="10dp"
android:text="@string/reset"
app:icon="@drawable/ic_twotone_public_24"
app:layout_constraintBottom_toBottomOf="@id/bottomButtonsGuideline"
- app:layout_constraintStart_toStartOf="parent" />
+ app:layout_constraintEnd_toStartOf="@id/editableCheckbox" />
+
+
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent" />
Cancelar (sem acesso ao rádio)
Permitir (exibe diálogo)
Fornecer localização para mesh
+ Permissão da câmera
+ Precisamos acessar a câmera para escanear códigos QR. Nenhuma foto ou video são armazenados.
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index d6b331a91..61a6895a8 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -112,4 +112,6 @@
Cancelar (sem acesso ao rádio)
Permitir (exibe diálogo)
Fornecer localização para mesh
+ Precisamos acessar a câmera para escanear códigos QR. Nenhuma foto ou video são armazenados.
+ Permissão da câmera
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 206bc2adf..a40f0de64 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -116,4 +116,6 @@
Cancel (no radio access)
Allow (will show dialog)
Provide location to mesh
+ Camera permission
+ We must be granted access to the camera to read QR codes. No pictures or videos will be saved.
\ No newline at end of file