summaryrefslogtreecommitdiffstats
path: root/mobile/android/android-components/components/feature/qr/src/main
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:42 +0000
commitda4c7e7ed675c3bf405668739c3012d140856109 (patch)
treecdd868dba063fecba609a1d819de271f0d51b23e /mobile/android/android-components/components/feature/qr/src/main
parentAdding upstream version 125.0.3. (diff)
downloadfirefox-da4c7e7ed675c3bf405668739c3012d140856109.tar.xz
firefox-da4c7e7ed675c3bf405668739c3012d140856109.zip
Adding upstream version 126.0.upstream/126.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mobile/android/android-components/components/feature/qr/src/main')
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/AndroidManifest.xml7
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/QrFeature.kt145
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/QrFragment.kt786
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/views/AutoFitTextureView.kt71
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/views/CustomViewFinder.kt298
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/drawable-hdpi/qr_cam_focus.webpbin0 -> 148 bytes
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/drawable-ldpi/qr_cam_focus.webpbin0 -> 100 bytes
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/drawable-mdpi/qr_cam_focus.webpbin0 -> 104 bytes
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/drawable-xhdpi/qr_cam_focus.webpbin0 -> 140 bytes
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/drawable-xxhdpi/qr_cam_focus.webpbin0 -> 202 bytes
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/drawable-xxxhdpi/qr_cam_focus.webpbin0 -> 140 bytes
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/layout/fragment_layout.xml35
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-am/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-an/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ar/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ast/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-az/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-azb/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ban/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-be/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-bg/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-bn/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-br/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-bs/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ca/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-cak/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ceb/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ckb/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-co/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-cs/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-cy/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-da/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-de/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-dsb/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-el/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-en-rCA/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-en-rGB/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-eo/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-es-rAR/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-es-rCL/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-es-rES/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-es-rMX/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-es/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-et/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-eu/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-fa/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-fi/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-fr/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-fur/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-fy-rNL/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-gd/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-gl/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-gn/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-gu-rIN/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-hi-rIN/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-hil/strings.xml7
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-hr/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-hsb/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-hu/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-hy-rAM/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ia/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-in/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-is/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-it/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-iw/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ja/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ka/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-kaa/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-kab/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-kk/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-kmr/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-kn/strings.xml7
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ko/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-lo/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-lt/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-mix/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-mr/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-my/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-nb-rNO/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ne-rNP/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-nl/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-nn-rNO/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-oc/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-pa-rIN/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-pa-rPK/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-pl/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-pt-rBR/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-pt-rPT/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-rm/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ro/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ru/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-sat/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-sc/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-si/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-sk/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-skr/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-sl/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-sq/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-sr/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-su/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-sv-rSE/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ta/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-te/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-tg/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-th/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-tl/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-tok/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-tr/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-trs/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-tt/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ug/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-uk/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-ur/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-uz/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-vi/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-yo/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-zh-rCN/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values-zh-rTW/strings.xml10
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values/colors.xml8
-rw-r--r--mobile/android/android-components/components/feature/qr/src/main/res/values/strings.xml13
120 files changed, 2417 insertions, 0 deletions
diff --git a/mobile/android/android-components/components/feature/qr/src/main/AndroidManifest.xml b/mobile/android/android-components/components/feature/qr/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..592249325c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/AndroidManifest.xml
@@ -0,0 +1,7 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ - You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <uses-permission android:name="android.permission.CAMERA" />
+</manifest>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/QrFeature.kt b/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/QrFeature.kt
new file mode 100644
index 0000000000..87a55dbcc4
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/QrFeature.kt
@@ -0,0 +1,145 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package mozilla.components.feature.qr
+
+import android.Manifest.permission.CAMERA
+import android.content.Context
+import androidx.annotation.MainThread
+import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
+import androidx.fragment.app.FragmentManager
+import mozilla.components.support.base.feature.LifecycleAwareFeature
+import mozilla.components.support.base.feature.OnNeedToRequestPermissions
+import mozilla.components.support.base.feature.PermissionsFeature
+import mozilla.components.support.base.feature.UserInteractionHandler
+import mozilla.components.support.ktx.android.content.isPermissionGranted
+
+typealias OnScanResult = (result: String) -> Unit
+
+/**
+ * Feature implementation that provides QR scanning functionality via the [QrFragment].
+ *
+ * @property context a reference to the context.
+ * @property fragmentManager a reference to a [FragmentManager], used to start
+ * the [QrFragment].
+ * @property onScanResult a callback invoked with the result of the QR scan.
+ * The callback will always be invoked on the main thread.
+ * @property onNeedToRequestPermissions a callback invoked when permissions
+ * need to be requested before a QR scan can be performed. Once the request
+ * is completed, [onPermissionsResult] needs to be invoked. This feature
+ * will request [android.Manifest.permission.CAMERA].
+ * @property scanMessage (Optional) String resource for an optional message
+ * to be laid out below the QR scan viewfinder
+ */
+class QrFeature(
+ private val context: Context,
+ private val fragmentManager: FragmentManager,
+ private val onScanResult: OnScanResult = { },
+ override val onNeedToRequestPermissions: OnNeedToRequestPermissions = { },
+ @StringRes
+ private var scanMessage: Int? = null,
+) : LifecycleAwareFeature, UserInteractionHandler, PermissionsFeature {
+ private var containerViewId: Int = 0
+
+ private val qrFragment
+ get() = fragmentManager.findFragmentByTag(QR_FRAGMENT_TAG) as? QrFragment
+
+ @Suppress("MemberVisibilityCanBePrivate")
+ val isScanInProgress
+ get() = qrFragment != null
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal val scanCompleteListener: QrFragment.OnScanCompleteListener = object : QrFragment.OnScanCompleteListener {
+ @MainThread
+ override fun onScanComplete(result: String) {
+ setScanCompleteListener(null)
+ removeQrFragment()
+ onScanResult(result)
+ }
+ }
+
+ override fun start() {
+ setScanCompleteListener(scanCompleteListener)
+ }
+
+ override fun stop() {
+ // Prevent an already in progress qr decode operation informing us later of a result
+ // and so triggering an IllegalStateException when trying to remove the qr fragment.
+ setScanCompleteListener(null)
+ }
+
+ override fun onBackPressed(): Boolean {
+ return removeQrFragment()
+ }
+
+ /**
+ * Starts the QR scanner fragment and listens for scan results.
+ *
+ * @param containerViewId optional id of the container this fragment is to
+ * be placed in, defaults to [android.R.id.content].
+ *
+ * @return true if the scanner was started or false if permissions still
+ * need to be requested.
+ */
+ fun scan(containerViewId: Int = android.R.id.content): Boolean {
+ this.containerViewId = containerViewId
+
+ return if (context.isPermissionGranted(CAMERA)) {
+ when (isScanInProgress) {
+ true -> qrFragment?.startScanning()
+ false -> fragmentManager.beginTransaction()
+ .add(containerViewId, QrFragment.newInstance(scanCompleteListener, scanMessage), QR_FRAGMENT_TAG)
+ .commit()
+ }
+ true
+ } else {
+ onNeedToRequestPermissions(arrayOf(CAMERA))
+ false
+ }
+ }
+
+ /**
+ * Notifies the feature that the permission request was completed. If the
+ * requested permissions were granted it will open the QR scanner.
+ */
+ override fun onPermissionsResult(permissions: Array<String>, grantResults: IntArray) {
+ if (context.isPermissionGranted(CAMERA)) {
+ scan(containerViewId)
+ } else {
+ // It is possible that we started scanning then the user is will update
+ // the camera permission in Android settings.
+ // The client app is expected to ask again for the camera permission when the app is resumed
+ // and this request can be denied by the user so we should interrupt the in-progress scanning.
+ removeQrFragment()
+ }
+ }
+
+ /**
+ * Removes the QR fragment.
+ *
+ * @return true if the fragment was removed, otherwise false.
+ */
+ internal fun removeQrFragment(): Boolean {
+ qrFragment?.let {
+ fragmentManager.beginTransaction().remove(it).commit()
+ return true
+ }
+ return false
+ }
+
+ /**
+ * Set a callback for when a qr code has been successfully scanned and decoded.
+ */
+ @VisibleForTesting
+ internal fun setScanCompleteListener(listener: QrFragment.OnScanCompleteListener?) {
+ (fragmentManager.findFragmentByTag(QR_FRAGMENT_TAG) as? QrFragment)?.let {
+ it.scanCompleteListener = listener
+ }
+ }
+
+ companion object {
+ internal const val QR_FRAGMENT_TAG = "MOZAC_QR_FRAGMENT"
+ }
+}
diff --git a/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/QrFragment.kt b/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/QrFragment.kt
new file mode 100644
index 0000000000..e92e37cb7b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/QrFragment.kt
@@ -0,0 +1,786 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. */
+
+package mozilla.components.feature.qr
+
+import android.Manifest.permission
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.ImageFormat
+import android.graphics.Matrix
+import android.graphics.Point
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.SurfaceTexture
+import android.hardware.camera2.CameraAccessException
+import android.hardware.camera2.CameraCaptureSession
+import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraManager
+import android.hardware.camera2.CaptureRequest
+import android.hardware.camera2.params.OutputConfiguration
+import android.hardware.camera2.params.SessionConfiguration
+import android.media.Image
+import android.media.ImageReader
+import android.os.Build
+import android.os.Bundle
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.Looper
+import android.util.Size
+import android.view.LayoutInflater
+import android.view.Surface
+import android.view.TextureView
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.widget.TextView
+import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
+import androidx.core.content.ContextCompat.getColor
+import androidx.core.view.WindowInsetsCompat
+import androidx.fragment.app.Fragment
+import com.google.zxing.BinaryBitmap
+import com.google.zxing.LuminanceSource
+import com.google.zxing.MultiFormatReader
+import com.google.zxing.PlanarYUVLuminanceSource
+import com.google.zxing.common.HybridBinarizer
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import mozilla.components.feature.qr.views.AutoFitTextureView
+import mozilla.components.feature.qr.views.CustomViewFinder
+import mozilla.components.support.base.log.logger.Logger
+import mozilla.components.support.ktx.android.content.hasCamera
+import mozilla.components.support.ktx.android.content.isPermissionGranted
+import java.io.Serializable
+import java.util.ArrayList
+import java.util.Collections
+import java.util.Comparator
+import java.util.concurrent.Executor
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import java.util.concurrent.RejectedExecutionException
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * A [Fragment] that displays a QR scanner.
+ *
+ * This class is based on Camera2BasicFragment from:
+ *
+ * https://github.com/googlesamples/android-Camera2Basic
+ * https://github.com/kismkof/camera2basic
+ */
+@Suppress("LargeClass", "TooManyFunctions")
+class QrFragment : Fragment() {
+ private val logger = Logger("mozac-qr")
+
+ @VisibleForTesting
+ internal var multiFormatReader = MultiFormatReader()
+ private val coroutineScope = CoroutineScope(Dispatchers.Default)
+
+ /**
+ * [TextureView.SurfaceTextureListener] handles several lifecycle events on a [TextureView].
+ */
+ private val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
+
+ override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) {
+ tryOpenCamera(width, height)
+ }
+
+ override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {
+ configureTransform(width, height)
+ }
+
+ @Suppress("EmptyFunctionBlock")
+ override fun onSurfaceTextureUpdated(texture: SurfaceTexture) { }
+
+ override fun onSurfaceTextureDestroyed(texture: SurfaceTexture): Boolean {
+ return true
+ }
+ }
+
+ internal lateinit var textureView: AutoFitTextureView
+ internal lateinit var customViewFinder: CustomViewFinder
+ internal lateinit var cameraErrorView: TextView
+
+ @StringRes
+ internal var scanMessage: Int? = null
+ internal var cameraId: String? = null
+ private var captureSession: CameraCaptureSession? = null
+ internal var cameraDevice: CameraDevice? = null
+ internal var previewSize: Size? = null
+
+ /**
+ * Listener invoked when the QR scan completed successfully.
+ */
+ interface OnScanCompleteListener : Serializable {
+ /**
+ * Invoked to provide access to the result of the QR scan.
+ */
+ fun onScanComplete(result: String)
+ }
+
+ @Volatile internal var scanCompleteListener: OnScanCompleteListener? = null
+ set(value) {
+ field = object : OnScanCompleteListener {
+ override fun onScanComplete(result: String) {
+ Handler(Looper.getMainLooper()).apply {
+ post {
+ context?.let {
+ customViewFinder.setViewFinderColor(
+ getColor(it, R.color.mozac_feature_qr_scan_success_color),
+ )
+ }
+ value?.onScanComplete(result)
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * [CameraDevice.StateCallback] is called when [CameraDevice] changes its state.
+ */
+ internal val stateCallback = object : CameraDevice.StateCallback() {
+
+ override fun onOpened(cameraDevice: CameraDevice) {
+ cameraOpenCloseLock.release()
+ this@QrFragment.cameraDevice = cameraDevice
+ createCameraPreviewSession()
+ }
+
+ override fun onDisconnected(cameraDevice: CameraDevice) {
+ cameraOpenCloseLock.release()
+ cameraDevice.close()
+ this@QrFragment.cameraDevice = null
+ }
+
+ override fun onError(cameraDevice: CameraDevice, error: Int) {
+ cameraOpenCloseLock.release()
+ cameraDevice.close()
+ this@QrFragment.cameraDevice = null
+ }
+ }
+
+ /**
+ * An additional thread for running tasks that shouldn't block the UI.
+ * A [Handler] for running tasks in the background.
+ */
+ @VisibleForTesting
+ internal var backgroundThread: HandlerThread? = null
+
+ @VisibleForTesting
+ internal var backgroundHandler: Handler? = null
+
+ @VisibleForTesting
+ internal var backgroundExecutor: ExecutorService? = null
+ private var previewRequestBuilder: CaptureRequest.Builder? = null
+ private var previewRequest: CaptureRequest? = null
+
+ /**
+ * A [Semaphore] to prevent the app from exiting before closing the camera.
+ */
+ private val cameraOpenCloseLock = Semaphore(1)
+
+ /**
+ * Orientation of the camera sensor
+ */
+ private var sensorOrientation: Int = 0
+
+ /**
+ * An [ImageReader] that handles still image capture.
+ * This is the output file for our picture.
+ */
+ private var imageReader: ImageReader? = null
+ private val imageAvailableListener = object : ImageReader.OnImageAvailableListener {
+
+ private var image: Image? = null
+
+ override fun onImageAvailable(reader: ImageReader) {
+ try {
+ image = reader.acquireNextImage()
+ val availableImage = image
+ if (availableImage != null && scanCompleteListener != null) {
+ val source = readImageSource(availableImage)
+ if (qrState == STATE_FIND_QRCODE) {
+ qrState = STATE_DECODE_PROGRESS
+
+ coroutineScope.launch {
+ tryScanningSource(source)
+ }
+ }
+ }
+ } finally {
+ image?.close()
+ }
+ }
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.fragment_layout, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ textureView = view.findViewById<View>(R.id.texture) as AutoFitTextureView
+ customViewFinder = view.findViewById<View>(R.id.view_finder) as CustomViewFinder
+ cameraErrorView = view.findViewById<View>(R.id.camera_error) as TextView
+
+ CustomViewFinder.setMessage(scanMessage)
+ qrState = STATE_FIND_QRCODE
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ // It's possible that the Fragment is resumed to a scanning state
+ // while in the meantime the camera permission was removed. Avoid any issues.
+ if (requireContext().isPermissionGranted(permission.CAMERA)) {
+ startScanning()
+ }
+ }
+
+ override fun onPause() {
+ closeCamera()
+ stopBackgroundThread()
+ stopExecutorService()
+ super.onPause()
+ }
+
+ override fun onStop() {
+ // Ensure we'll continue tracking qr codes when the user returns to the application
+ qrState = STATE_FIND_QRCODE
+
+ super.onStop()
+ }
+
+ internal fun maybeStartBackgroundThread() {
+ if (backgroundThread == null) {
+ backgroundThread = HandlerThread("CameraBackground")
+ }
+
+ backgroundThread?.let {
+ if (!it.isAlive) {
+ it.start()
+ backgroundHandler = Handler(it.looper)
+ }
+ }
+ }
+
+ internal fun stopBackgroundThread() {
+ backgroundThread?.quitSafely()
+ try {
+ backgroundThread?.join()
+ backgroundThread = null
+ backgroundHandler = null
+ } catch (e: InterruptedException) {
+ logger.debug("Interrupted while stopping background thread", e)
+ }
+ }
+
+ internal fun maybeStartExecutorService() {
+ if (backgroundExecutor == null) {
+ backgroundExecutor = Executors.newSingleThreadExecutor()
+ }
+ }
+
+ internal fun stopExecutorService() {
+ backgroundExecutor?.shutdownNow()
+ backgroundExecutor = null
+ }
+
+ /**
+ * Open the camera and start the qr scanning functionality.
+ * Assumes the camera permission is granted for the app.
+ * If any issues occur this will fail gracefully and show an error message.
+ */
+ fun startScanning() {
+ maybeStartBackgroundThread()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ maybeStartExecutorService()
+ }
+ // When the screen is turned off and turned back on, the SurfaceTexture is already
+ // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
+ // a camera and start preview from here (otherwise, we wait until the surface is ready in
+ // the SurfaceTextureListener).
+ if (textureView.isAvailable) {
+ tryOpenCamera(textureView.width, textureView.height)
+ } else {
+ textureView.surfaceTextureListener = surfaceTextureListener
+ }
+ }
+
+ /**
+ * Sets up member variables related to camera.
+ *
+ * @param width The width of available size for camera preview
+ * @param height The height of available size for camera preview
+ */
+ @Suppress("ComplexMethod")
+ internal fun setUpCameraOutputs(width: Int, height: Int) {
+ val displayRotation = getScreenRotation()
+
+ val manager = activity?.getSystemService(Context.CAMERA_SERVICE) as CameraManager? ?: return
+
+ for (cameraId in manager.cameraIdList) {
+ val characteristics = manager.getCameraCharacteristics(cameraId)
+
+ val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
+ if (facing == CameraCharacteristics.LENS_FACING_FRONT) {
+ continue
+ }
+
+ val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
+ ?: continue
+ val largest = Collections.max(map.getOutputSizes(ImageFormat.YUV_420_888).asList(), CompareSizesByArea())
+ imageReader = ImageReader.newInstance(MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT, ImageFormat.YUV_420_888, 2)
+ .apply { setOnImageAvailableListener(imageAvailableListener, backgroundHandler) }
+
+ // Find out if we need to swap dimension to get the preview size relative to sensor coordinate.
+
+ sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) as Int
+
+ @Suppress("MagicNumber")
+ val swappedDimensions = when (displayRotation) {
+ Surface.ROTATION_0, Surface.ROTATION_180 -> sensorOrientation == 90 || sensorOrientation == 270
+ Surface.ROTATION_90, Surface.ROTATION_270 -> sensorOrientation == 0 || sensorOrientation == 180
+ else -> false
+ }
+
+ val displaySize = activity?.windowManager?.getDisplaySize() ?: Point()
+
+ var rotatedPreviewWidth = width
+ var rotatedPreviewHeight = height
+ var maxPreviewWidth = displaySize.x
+ var maxPreviewHeight = displaySize.y
+
+ if (swappedDimensions) {
+ rotatedPreviewWidth = height
+ rotatedPreviewHeight = width
+ maxPreviewWidth = displaySize.y
+ maxPreviewHeight = displaySize.x
+ }
+
+ maxPreviewWidth = min(maxPreviewWidth, MAX_PREVIEW_WIDTH)
+ maxPreviewHeight = min(maxPreviewHeight, MAX_PREVIEW_HEIGHT)
+
+ val optimalSize = chooseOptimalSize(
+ map.getOutputSizes(SurfaceTexture::class.java),
+ rotatedPreviewWidth,
+ rotatedPreviewHeight,
+ maxPreviewWidth,
+ maxPreviewHeight,
+ largest,
+ )
+
+ adjustPreviewSize(optimalSize)
+ this.cameraId = cameraId
+ return
+ }
+ }
+
+ internal fun adjustPreviewSize(optimalSize: Size) {
+ // We're seeing slow unreliable scans with distorted screens on some devices
+ // so we're making the preview and scan area a square of the optimal size
+ // to prevent that.
+ val length = min(optimalSize.height, optimalSize.width)
+ textureView.setAspectRatio(length, length)
+ this.previewSize = Size(length, length)
+ }
+
+ /**
+ * Tries to open the camera and displays an error message in case
+ * there's no camera available or we fail to open it. Applications
+ * should ideally check for camera availability, but we use this
+ * as a fallback in case they don't.
+ */
+ @Suppress("TooGenericExceptionCaught")
+ internal fun tryOpenCamera(width: Int, height: Int, skipCheck: Boolean = false) {
+ try {
+ if (context?.hasCamera() == true || skipCheck) {
+ openCamera(width, height)
+ hideNoCameraAvailableError()
+ } else {
+ showNoCameraAvailableError()
+ }
+ } catch (e: Exception) {
+ showNoCameraAvailableError()
+ }
+ }
+
+ private fun showNoCameraAvailableError() {
+ cameraErrorView.visibility = View.VISIBLE
+ customViewFinder.visibility = View.GONE
+ }
+
+ private fun hideNoCameraAvailableError() {
+ cameraErrorView.visibility = View.GONE
+ customViewFinder.visibility = View.VISIBLE
+ }
+
+ /**
+ * Opens the camera specified by [QrFragment.cameraId].
+ */
+ @SuppressLint("MissingPermission")
+ @Suppress("ThrowsCount")
+ internal fun openCamera(width: Int, height: Int) {
+ try {
+ setUpCameraOutputs(width, height)
+ if (cameraId == null) {
+ throw IllegalStateException("No camera found on device")
+ }
+
+ configureTransform(width, height)
+
+ val activity = activity
+ val manager = activity?.getSystemService(Context.CAMERA_SERVICE) as CameraManager?
+
+ if (!cameraOpenCloseLock.tryAcquire(CAMERA_CLOSE_LOCK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ throw IllegalStateException("Time out waiting to lock camera opening.")
+ }
+ manager?.openCamera(cameraId as String, stateCallback, backgroundHandler)
+ } catch (e: InterruptedException) {
+ throw IllegalStateException("Interrupted while trying to lock camera opening.", e)
+ } catch (e: CameraAccessException) {
+ logger.error("Failed to open camera", e)
+ }
+ }
+
+ /**
+ * Closes the current [CameraDevice].
+ */
+ internal fun closeCamera() {
+ try {
+ cameraOpenCloseLock.acquire()
+ cameraDevice?.close()
+ cameraDevice = null
+ imageReader?.close()
+ imageReader = null
+
+ // captureSession should be closed as a last step in case background executor terminated
+ captureSession?.close()
+ captureSession = null
+ } catch (e: InterruptedException) {
+ throw IllegalStateException("Interrupted while trying to lock camera closing.", e)
+ } catch (e: RejectedExecutionException) { // This exception was found in automated testing
+ logger.error("backgroundExecutor terminated", e)
+ } finally {
+ cameraOpenCloseLock.release()
+ }
+ }
+
+ /**
+ * Configures the necessary [android.graphics.Matrix] transformation to `textureView`.
+ * This method should be called after the camera preview size is determined in
+ * [setUpCameraOutputs] and also the size of `textureView` is fixed.
+ *
+ * @param viewWidth The width of `textureView`
+ * @param viewHeight The height of `textureView`
+ */
+ @VisibleForTesting
+ internal fun configureTransform(viewWidth: Int, viewHeight: Int) {
+ val size = previewSize ?: return
+
+ val rotation = getScreenRotation()
+ val matrix = Matrix()
+ val viewRect = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())
+ val bufferRect = RectF(0f, 0f, size.height.toFloat(), size.width.toFloat())
+ val centerX = viewRect.centerX()
+ val centerY = viewRect.centerY()
+
+ @Suppress("MagicNumber")
+ if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY())
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL)
+ val scale = max(viewHeight.toFloat() / size.height, viewWidth.toFloat() / size.width)
+ matrix.postScale(scale, scale, centerX, centerY)
+ matrix.postRotate((90 * (rotation - 2)).toFloat(), centerX, centerY)
+ } else if (Surface.ROTATION_180 == rotation) {
+ matrix.postRotate(180f, centerX, centerY)
+ }
+ textureView.setTransform(matrix)
+ }
+
+ /**
+ * Creates a new [CameraCaptureSession] for camera preview.
+ */
+ @Suppress("ComplexMethod")
+ internal fun createCameraPreviewSession() {
+ val texture = textureView.surfaceTexture
+
+ val size = previewSize as Size
+ // We configure the size of default buffer to be the size of camera preview we want.
+ texture?.setDefaultBufferSize(size.width, size.height)
+
+ val surface = Surface(texture)
+ val mImageSurface = imageReader?.surface
+
+ handleCaptureException("Failed to create camera preview session") {
+ cameraDevice?.let {
+ previewRequestBuilder = it.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply {
+ addTarget(mImageSurface as Surface)
+ addTarget(surface)
+ }
+
+ val captureCallback = object : CameraCaptureSession.CaptureCallback() {}
+ val stateCallback = object : CameraCaptureSession.StateCallback() {
+ override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
+ if (null == cameraDevice) return
+
+ previewRequestBuilder?.set(
+ CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE,
+ )
+
+ previewRequest = previewRequestBuilder?.build()
+ captureSession = cameraCaptureSession
+
+ handleCaptureException("Failed to request capture") {
+ cameraCaptureSession.setRepeatingRequest(
+ previewRequest as CaptureRequest,
+ captureCallback,
+ backgroundHandler,
+ )
+ }
+ }
+
+ override fun onConfigureFailed(cameraCaptureSession: CameraCaptureSession) {
+ logger.error("Failed to configure CameraCaptureSession")
+ }
+ }
+ createCaptureSessionCompat(it, mImageSurface as Surface, surface, stateCallback)
+ }
+ }
+ }
+
+ @VisibleForTesting
+ internal fun createCaptureSessionCompat(
+ camera: CameraDevice,
+ imageSurface: Surface,
+ surface: Surface,
+ stateCallback: CameraCaptureSession.StateCallback,
+ ) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ if (shouldStartExecutorService()) {
+ maybeStartExecutorService()
+ }
+ val sessionConfig = SessionConfiguration(
+ SessionConfiguration.SESSION_REGULAR,
+ listOf(OutputConfiguration(imageSurface), OutputConfiguration(surface)),
+ backgroundExecutor as Executor,
+ stateCallback,
+ )
+ camera.createCaptureSession(sessionConfig)
+ } else {
+ @Suppress("DEPRECATION")
+ camera.createCaptureSession(listOf(imageSurface, surface), stateCallback, null)
+ }
+ }
+
+ @VisibleForTesting
+ internal fun shouldStartExecutorService(): Boolean = backgroundExecutor == null
+
+ @Suppress("TooGenericExceptionCaught")
+ private fun handleCaptureException(msg: String, block: () -> Unit) {
+ try {
+ block()
+ } catch (e: Exception) {
+ when (e) {
+ is CameraAccessException, is IllegalStateException -> {
+ logger.error(msg, e)
+ }
+ else -> throw e
+ }
+ }
+ }
+
+ /**
+ * Compares two `Size`s based on their areas.
+ */
+ internal class CompareSizesByArea : Comparator<Size> {
+ override fun compare(lhs: Size, rhs: Size): Int {
+ return java.lang.Long.signum(lhs.width.toLong() * lhs.height - rhs.width.toLong() * rhs.height)
+ }
+ }
+
+ companion object {
+ internal const val STATE_FIND_QRCODE = 0
+ internal const val STATE_DECODE_PROGRESS = 1
+ internal const val STATE_QRCODE_EXIST = 2
+
+ internal const val MAX_PREVIEW_WIDTH = 786
+ internal const val MAX_PREVIEW_HEIGHT = 786
+
+ private const val CAMERA_CLOSE_LOCK_TIMEOUT_MS = 2500L
+
+ /**
+ * Returns a new instance of QR Fragment
+ * @param listener Listener invoked when the QR scan completed successfully.
+ * @param scanMessage (Optional) Scan message to be displayed.
+ */
+ fun newInstance(listener: OnScanCompleteListener, scanMessage: Int? = null): QrFragment {
+ return QrFragment().apply {
+ scanCompleteListener = listener
+ this.scanMessage = scanMessage
+ }
+ }
+
+ /**
+ * Given `choices` of `Size`s supported by a camera, choose the smallest one that
+ * is at least as large as the respective texture view size, and that is at most as large as the
+ * respective max size, and whose aspect ratio matches with the specified value. If such size
+ * doesn't exist, choose the largest one that is at most as large as the respective max size,
+ * and whose aspect ratio matches with the specified value.
+ *
+ * @param choices The list of sizes that the camera supports for the intended output class
+ * @param textureViewWidth The width of the texture view relative to sensor coordinate
+ * @param textureViewHeight The height of the texture view relative to sensor coordinate
+ * @param maxWidth The maximum width that can be chosen
+ * @param maxHeight The maximum height that can be chosen
+ * @param aspectRatio The aspect ratio
+ * @return The optimal `Size`, or an arbitrary one if none were big enough.
+ */
+ @Suppress("ComplexMethod")
+ internal fun chooseOptimalSize(
+ choices: Array<Size>,
+ textureViewWidth: Int,
+ textureViewHeight: Int,
+ maxWidth: Int,
+ maxHeight: Int,
+ aspectRatio: Size,
+ ): Size {
+ // Collect the supported resolutions that are at least as big as the preview Surface
+ val bigEnough = ArrayList<Size>()
+ // Collect the supported resolutions that are smaller than the preview Surface
+ val notBigEnough = ArrayList<Size>()
+ val w = aspectRatio.width
+ val h = aspectRatio.height
+ for (option in choices) {
+ if (option.width <= maxWidth && option.height <= maxHeight &&
+ option.height == option.width * h / w
+ ) {
+ if (option.width >= textureViewWidth && option.height >= textureViewHeight) {
+ bigEnough.add(option)
+ } else {
+ notBigEnough.add(option)
+ }
+ }
+ }
+
+ // Pick the smallest of those big enough. If there is no one big enough, pick the
+ // largest of those not big enough.
+ return when {
+ bigEnough.size > 0 -> Collections.min(bigEnough, CompareSizesByArea())
+ notBigEnough.size > 0 -> Collections.max(notBigEnough, CompareSizesByArea())
+ else -> choices[0]
+ }
+ }
+
+ internal fun readImageSource(image: Image): PlanarYUVLuminanceSource {
+ val plane = image.planes[0]
+ val buffer = plane.buffer
+ val data = ByteArray(buffer.remaining()).also { buffer.get(it) }
+
+ val height = image.height
+ val width = image.width
+ val dataWidth = width + ((plane.rowStride - plane.pixelStride * width) / plane.pixelStride)
+ return PlanarYUVLuminanceSource(data, dataWidth, height, 0, 0, width, height, false)
+ }
+
+ @Volatile internal var qrState: Int = 0
+ }
+
+ @VisibleForTesting
+ internal fun tryScanningSource(source: LuminanceSource) {
+ if (qrState != STATE_DECODE_PROGRESS) {
+ return
+ }
+ val result = decodeSource(source) ?: decodeSource(source.invert())
+ result?.let {
+ scanCompleteListener?.onScanComplete(it)
+ }
+ }
+
+ @VisibleForTesting
+ @Suppress("TooGenericExceptionCaught")
+ internal fun decodeSource(source: LuminanceSource): String? {
+ return try {
+ val bitmap = createBinaryBitmap(source)
+ val rawResult = multiFormatReader.decodeWithState(bitmap)
+ if (rawResult != null) {
+ qrState = STATE_QRCODE_EXIST
+ rawResult.toString()
+ } else {
+ qrState = STATE_FIND_QRCODE
+ null
+ }
+ } catch (e: Exception) {
+ qrState = STATE_FIND_QRCODE
+ null
+ } finally {
+ multiFormatReader.reset()
+ }
+ }
+
+ @VisibleForTesting
+ internal fun createBinaryBitmap(source: LuminanceSource) =
+ BinaryBitmap(HybridBinarizer(source))
+
+ /**
+ * Returns the screen rotation
+ *
+ * @return the actual rotation of the device is one of these values:
+ * [Surface.ROTATION_0], [Surface.ROTATION_90], [Surface.ROTATION_180], [Surface.ROTATION_270]
+ */
+ @VisibleForTesting
+ internal fun getScreenRotation(): Int? {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ this.context?.display?.rotation
+ } else {
+ @Suppress("DEPRECATION")
+ activity?.windowManager?.defaultDisplay?.rotation
+ }
+ }
+}
+
+/**
+ * Returns the size of the display, in pixels.
+ */
+@VisibleForTesting
+internal fun WindowManager.getDisplaySize(): Point {
+ val size = Point()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ // Tests for this branch will be added after
+ // https://github.com/mozilla-mobile/android-components/issues/9684 is implemented.
+ val windowMetrics = this.currentWindowMetrics
+ val windowInsets: WindowInsetsCompat = WindowInsetsCompat.toWindowInsetsCompat(windowMetrics.windowInsets)
+
+ val insets = windowInsets.getInsetsIgnoringVisibility(
+ WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.displayCutout(),
+ )
+ val insetsWidth = insets.right + insets.left
+ val insetsHeight = insets.top + insets.bottom
+
+ val bounds: Rect = windowMetrics.bounds
+ size.set(bounds.width() - insetsWidth, bounds.height() - insetsHeight)
+ } else {
+ @Suppress("DEPRECATION")
+ this.defaultDisplay.getSize(size)
+ }
+ return size
+}
diff --git a/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/views/AutoFitTextureView.kt b/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/views/AutoFitTextureView.kt
new file mode 100644
index 0000000000..51c6759d0f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/views/AutoFitTextureView.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. */
+
+package mozilla.components.feature.qr.views
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.TextureView
+import android.view.View
+import androidx.annotation.VisibleForTesting
+
+/**
+ * A [TextureView] that can be adjusted to a specified aspect ratio.
+ */
+open class AutoFitTextureView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyle: Int = 0,
+) : TextureView(context, attrs, defStyle) {
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal var mRatioWidth = 0
+ private set
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal var mRatioHeight = 0
+ private set
+
+ /**
+ * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
+ * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
+ * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
+ *
+ * @param width Relative horizontal size
+ * @param height Relative vertical size
+ */
+ fun setAspectRatio(width: Int, height: Int) {
+ if (width < 0 || height < 0) {
+ throw IllegalArgumentException("Size cannot be negative.")
+ }
+ mRatioWidth = width
+ mRatioHeight = height
+ requestLayout()
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ val width = View.MeasureSpec.getSize(widthMeasureSpec)
+ val height = View.MeasureSpec.getSize(heightMeasureSpec)
+ if (0 == mRatioWidth || 0 == mRatioHeight) {
+ setMeasuredDimension(width, height)
+ } else {
+ if (width < height * mRatioWidth / mRatioHeight) {
+ setMeasuredDimension(width, width * mRatioHeight / mRatioWidth)
+ } else {
+ setMeasuredDimension(height * mRatioWidth / mRatioHeight, height)
+ }
+ }
+ }
+}
diff --git a/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/views/CustomViewFinder.kt b/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/views/CustomViewFinder.kt
new file mode 100644
index 0000000000..47051f3f20
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/java/mozilla/components/feature/qr/views/CustomViewFinder.kt
@@ -0,0 +1,298 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package mozilla.components.feature.qr.views
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.Rect
+import android.os.Build
+import android.text.Layout
+import android.text.StaticLayout
+import android.text.TextPaint
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.ColorInt
+import androidx.annotation.Px
+import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
+import androidx.appcompat.widget.AppCompatImageView
+import androidx.core.content.ContextCompat
+import androidx.core.text.HtmlCompat
+import mozilla.components.support.ktx.android.util.dpToPx
+import mozilla.components.support.ktx.android.util.spToPx
+import kotlin.math.min
+import kotlin.math.roundToInt
+
+/**
+ * A [View] that shows a ViewFinder positioned in center of the camera view and draws an Overlay
+ */
+@Suppress("LargeClass")
+class CustomViewFinder @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+) : AppCompatImageView(context, attrs) {
+ private var messageResource: Int? = null
+ private val overlayPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
+ internal val viewFinderPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
+ private var viewFinderPath: Path = Path()
+ private var viewFinderPathSaved: Boolean = false
+ private var overlayPath: Path = Path()
+ private var overlayPathSaved: Boolean = false
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal lateinit var viewFinderRectangle: Rect
+ private var viewFinderCornersSize: Float = 0f
+ private var viewFinderCornersRadius: Float = 0f
+ private var viewFinderTop: Float = 0f
+ private var viewFinderLeft: Float = 0f
+ private var viewFinderRight: Float = 0f
+ private var viewFinderBottom: Float = 0f
+ private var normalizedRadius: Float = 0f
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal var scanMessageLayout: StaticLayout? = null
+ private lateinit var messageTextPaint: TextPaint
+
+ init {
+ isSaveEnabled = true
+ overlayPaint.style = Paint.Style.FILL
+ viewFinderPaint.style = Paint.Style.STROKE
+ overlayPath.fillType = Path.FillType.EVEN_ODD
+ viewFinderPath.fillType = Path.FillType.EVEN_ODD
+
+ this.layoutParams = ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ )
+ this.setOverlayColor(DEFAULT_OVERLAY_COLOR)
+ this.setViewFinderColor(DEFAULT_VIEWFINDER_COLOR)
+ this.setViewFinderStroke(DEFAULT_VIEWFINDER_THICKNESS_DP.dpToPx(resources.displayMetrics))
+ this.setViewFinderCornerRadius(DEFAULT_VIEWFINDER_CORNERS_RADIUS_DP.dpToPx(resources.displayMetrics))
+ }
+
+ /** Calculates viewfinder rectangle and triggers calculating message layout that depends on it */
+ internal fun computeViewFinderRect(width: Int, height: Int) {
+ if (width > 0 && height > 0) {
+ val minimumDimension = min(width.toFloat(), height.toFloat())
+
+ val viewFinderSide = (minimumDimension * DEFAULT_VIEWFINDER_WIDTH_RATIO).roundToInt()
+
+ val viewFinderLeftOrRight = (width - viewFinderSide) / 2
+ val viewFinderTopOrBottom = (height - viewFinderSide) / 2
+ viewFinderRectangle = Rect(
+ viewFinderLeftOrRight,
+ viewFinderTopOrBottom,
+ viewFinderLeftOrRight + viewFinderSide,
+ viewFinderTopOrBottom + viewFinderSide,
+ )
+
+ this.setViewFinderCornerSize(DEFAULT_VIEWFINDER_CORNER_SIZE_RATIO * viewFinderRectangle.width())
+
+ viewFinderTop = viewFinderRectangle.top.toFloat()
+ viewFinderLeft = viewFinderRectangle.left.toFloat()
+ viewFinderRight = viewFinderRectangle.right.toFloat()
+ viewFinderBottom = viewFinderRectangle.bottom.toFloat()
+ normalizedRadius = min(viewFinderCornersRadius, (viewFinderCornersSize - 1).coerceAtLeast(0f))
+
+ showMessage(scanMessageStringRes)
+ }
+ }
+
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
+ computeViewFinderRect(width, height)
+ }
+
+ // useful when you have a disappearing keyboard
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ redraw()
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration?) {
+ super.onConfigurationChanged(newConfig)
+ redraw()
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ drawOverlay(canvas)
+ drawViewFinder(canvas)
+ drawMessage(canvas)
+ }
+
+ private fun redraw() {
+ overlayPathSaved = false
+ viewFinderPathSaved = false
+ computeViewFinderRect(width, height)
+ invalidate()
+ }
+
+ /** Draws the Overlay */
+ private fun drawOverlay(canvas: Canvas) {
+ if (!overlayPathSaved) {
+ overlayPath.apply {
+ reset()
+ moveTo(viewFinderLeft, viewFinderTop + normalizedRadius)
+ quadTo(viewFinderLeft, viewFinderTop, viewFinderLeft + normalizedRadius, viewFinderTop)
+ lineTo(viewFinderRight - normalizedRadius, viewFinderTop)
+ quadTo(viewFinderRight, viewFinderTop, viewFinderRight, viewFinderTop + normalizedRadius)
+ lineTo(viewFinderRight, viewFinderBottom - normalizedRadius)
+ quadTo(viewFinderRight, viewFinderBottom, viewFinderRight - normalizedRadius, viewFinderBottom)
+ lineTo(viewFinderLeft + normalizedRadius, viewFinderBottom)
+ quadTo(viewFinderLeft, viewFinderBottom, viewFinderLeft, viewFinderBottom - normalizedRadius)
+ lineTo(viewFinderLeft, viewFinderTop + normalizedRadius)
+ moveTo(0f, 0f)
+ lineTo(width.toFloat(), 0f)
+ lineTo(width.toFloat(), height.toFloat())
+ lineTo(0f, height.toFloat())
+ lineTo(0f, 0f)
+ }
+ overlayPathSaved = true
+ }
+ canvas.drawPath(overlayPath, overlayPaint)
+ }
+
+ /** Draws the ViewFinder */
+ private fun drawViewFinder(canvas: Canvas) {
+ if (!viewFinderPathSaved) {
+ viewFinderPath.apply {
+ reset()
+ moveTo(viewFinderLeft, viewFinderTop + viewFinderCornersSize)
+ lineTo(viewFinderLeft, viewFinderTop + normalizedRadius)
+ quadTo(viewFinderLeft, viewFinderTop, viewFinderLeft + normalizedRadius, viewFinderTop)
+ lineTo(viewFinderLeft + viewFinderCornersSize, viewFinderTop)
+ moveTo(viewFinderRight - viewFinderCornersSize, viewFinderTop)
+ lineTo(viewFinderRight - normalizedRadius, viewFinderTop)
+ quadTo(viewFinderRight, viewFinderTop, viewFinderRight, viewFinderTop + normalizedRadius)
+ lineTo(viewFinderRight, viewFinderTop + viewFinderCornersSize)
+ moveTo(viewFinderRight, viewFinderBottom - viewFinderCornersSize)
+ lineTo(viewFinderRight, viewFinderBottom - normalizedRadius)
+ quadTo(viewFinderRight, viewFinderBottom, viewFinderRight - normalizedRadius, viewFinderBottom)
+ lineTo(viewFinderRight - viewFinderCornersSize, viewFinderBottom)
+ moveTo(viewFinderLeft + viewFinderCornersSize, viewFinderBottom)
+ lineTo(viewFinderLeft + normalizedRadius, viewFinderBottom)
+ quadTo(viewFinderLeft, viewFinderBottom, viewFinderLeft, viewFinderBottom - normalizedRadius)
+ lineTo(viewFinderLeft, viewFinderBottom - viewFinderCornersSize)
+ }
+ viewFinderPathSaved = true
+ }
+ canvas.drawPath(viewFinderPath, this.viewFinderPaint)
+ }
+
+ /**
+ * Creates a Static Layout used to show a message below the viewfinder
+ */
+ @Suppress("Deprecation")
+ private fun showMessage(@StringRes scanMessageId: Int?) {
+ val scanMessage = if (scanMessageId != null) {
+ HtmlCompat.fromHtml(
+ context.getString(scanMessageId),
+ HtmlCompat.FROM_HTML_MODE_LEGACY,
+ )
+ } else {
+ ""
+ }
+ messageTextPaint = TextPaint().apply {
+ isAntiAlias = true
+ color = ContextCompat.getColor(context, android.R.color.white)
+ textSize = SCAN_MESSAGE_TEXT_SIZE_SP.spToPx(resources.displayMetrics)
+ }
+
+ scanMessageLayout =
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ StaticLayout.Builder.obtain(
+ scanMessage,
+ 0,
+ scanMessage.length,
+ messageTextPaint,
+ viewFinderRectangle.width(),
+ ).setAlignment(Layout.Alignment.ALIGN_CENTER).build()
+ } else {
+ StaticLayout(
+ scanMessage,
+ messageTextPaint,
+ viewFinderRectangle.width(),
+ Layout.Alignment.ALIGN_CENTER,
+ 1.0f,
+ 0.0f,
+ true,
+ )
+ }
+
+ messageResource = scanMessageId
+ }
+
+ /** Draws text below the ViewFinder. */
+ private fun drawMessage(canvas: Canvas) {
+ canvas.save()
+ canvas.translate(
+ viewFinderRectangle.left.toFloat(),
+ viewFinderRectangle.bottom.toFloat() +
+ SCAN_MESSAGE_TOP_PADDING_DP.dpToPx(resources.displayMetrics),
+ )
+ scanMessageLayout?.draw(canvas)
+ canvas.restore()
+ }
+
+ /** Sets the color for the Overlay. */
+ private fun setOverlayColor(@ColorInt color: Int) {
+ overlayPaint.color = color
+ if (isLaidOut) {
+ invalidate()
+ }
+ }
+
+ /** Sets the stroke color for the ViewFinder. */
+ fun setViewFinderColor(@ColorInt color: Int) {
+ viewFinderPaint.color = color
+ if (isLaidOut) {
+ invalidate()
+ }
+ }
+
+ /** Sets the stroke width for the ViewFinder. */
+ private fun setViewFinderStroke(@Px stroke: Float) {
+ viewFinderPaint.strokeWidth = stroke
+ if (isLaidOut) {
+ invalidate()
+ }
+ }
+
+ /** Sets the corner size for the ViewFinder. */
+ private fun setViewFinderCornerSize(@Px size: Float) {
+ viewFinderCornersSize = size
+ if (isLaidOut) {
+ invalidate()
+ }
+ }
+
+ /** Sets the corner radius for the ViewFinder. */
+ private fun setViewFinderCornerRadius(@Px radius: Float) {
+ viewFinderCornersRadius = radius
+ if (isLaidOut) {
+ invalidate()
+ }
+ }
+
+ companion object {
+ internal const val DEFAULT_VIEWFINDER_WIDTH_RATIO = 0.5f
+ private const val DEFAULT_OVERLAY_COLOR = 0x77000000
+ private const val DEFAULT_VIEWFINDER_COLOR = Color.WHITE
+ private const val DEFAULT_VIEWFINDER_THICKNESS_DP = 4f
+ private const val DEFAULT_VIEWFINDER_CORNER_SIZE_RATIO = 0.25f
+ private const val DEFAULT_VIEWFINDER_CORNERS_RADIUS_DP = 8f
+ private const val SCAN_MESSAGE_TOP_PADDING_DP = 10f
+ internal const val SCAN_MESSAGE_TEXT_SIZE_SP = 12f
+ internal var scanMessageStringRes: Int? = null
+
+ /** Sets the message to be displayed below ViewFinder. */
+ fun setMessage(scanMessageStringRes: Int?) {
+ this.scanMessageStringRes = scanMessageStringRes
+ }
+ }
+}
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/drawable-hdpi/qr_cam_focus.webp b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-hdpi/qr_cam_focus.webp
new file mode 100644
index 0000000000..9c9f4585e0
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-hdpi/qr_cam_focus.webp
Binary files differ
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/drawable-ldpi/qr_cam_focus.webp b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-ldpi/qr_cam_focus.webp
new file mode 100644
index 0000000000..64f1ff0285
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-ldpi/qr_cam_focus.webp
Binary files differ
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/drawable-mdpi/qr_cam_focus.webp b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-mdpi/qr_cam_focus.webp
new file mode 100644
index 0000000000..0f06992180
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-mdpi/qr_cam_focus.webp
Binary files differ
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/drawable-xhdpi/qr_cam_focus.webp b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-xhdpi/qr_cam_focus.webp
new file mode 100644
index 0000000000..eb0340a6be
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-xhdpi/qr_cam_focus.webp
Binary files differ
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/drawable-xxhdpi/qr_cam_focus.webp b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-xxhdpi/qr_cam_focus.webp
new file mode 100644
index 0000000000..d26d0b8a34
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-xxhdpi/qr_cam_focus.webp
Binary files differ
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/drawable-xxxhdpi/qr_cam_focus.webp b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-xxxhdpi/qr_cam_focus.webp
new file mode 100644
index 0000000000..5c28c6b470
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/drawable-xxxhdpi/qr_cam_focus.webp
Binary files differ
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/layout/fragment_layout.xml b/mobile/android/android-components/components/feature/qr/src/main/res/layout/fragment_layout.xml
new file mode 100644
index 0000000000..0b930d33e5
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/layout/fragment_layout.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/background_dark"
+ android:clickable="true"
+ android:focusable="true"
+ tools:ignore="Overdraw">
+
+ <TextView
+ android:id="@+id/camera_error"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/mozac_feature_qr_scanner_no_camera"
+ android:textColor="@android:color/white"
+ android:visibility="gone" />
+
+ <mozilla.components.feature.qr.views.AutoFitTextureView
+ android:id="@+id/texture"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_centerInParent="true" />
+
+ <mozilla.components.feature.qr.views.CustomViewFinder
+ android:id="@+id/view_finder"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_centerInParent="true" />
+
+</RelativeLayout>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-am/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-am/strings.xml
new file mode 100644
index 0000000000..5c33f13247
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-am/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">የQR ስካነር</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">በመሳሪያው ላይ ምንም ካሜራ የለም</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-an/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-an/strings.xml
new file mode 100644
index 0000000000..6b2518105f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-an/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Escaner QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Lo dispositivo no tiene camara disponible</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ar/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ar/strings.xml
new file mode 100644
index 0000000000..a4563264a5
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ar/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">ماسح رمز QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">ما من كمرة متاحة في الجهاز</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ast/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ast/strings.xml
new file mode 100644
index 0000000000..c1ae3c897f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ast/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Escáner de códigos QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nun hai nenguna cámara disponible nel preséu</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-az/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-az/strings.xml
new file mode 100644
index 0000000000..db835de8d2
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-az/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR skaner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Cihazda kamera yoxdur</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-azb/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-azb/strings.xml
new file mode 100644
index 0000000000..e101130566
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-azb/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR اسکنچی‌سی</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">جهازدا کامئرا یوخ</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ban/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ban/strings.xml
new file mode 100644
index 0000000000..06d0258b86
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ban/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR scanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Ten wénten kaméra ring perangkat</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-be/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-be/strings.xml
new file mode 100644
index 0000000000..b69588cfef
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-be/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-сканэр</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Няма даступнай камеры на прыладзе</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-bg/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-bg/strings.xml
new file mode 100644
index 0000000000..2e354a11f7
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-bg/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Скенер за QR код</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Устройството не разполага с камера</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-bn/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-bn/strings.xml
new file mode 100644
index 0000000000..ccafaf7766
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-bn/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR স্ক্যানার</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">ডিভাইসে কোনো ক্যামেরা নেই</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-br/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-br/strings.xml
new file mode 100644
index 0000000000..f076513b3e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-br/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">C’hwilerver QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">N’eus bet kavet kamera ebet</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-bs/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-bs/strings.xml
new file mode 100644
index 0000000000..ea89910221
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-bs/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR skener</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nema dostupne kamere na uređaju</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ca/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ca/strings.xml
new file mode 100644
index 0000000000..f6c743ec4c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ca/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Escàner de QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">No hi ha cap càmera disponible en el dispositiu</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-cak/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-cak/strings.xml
new file mode 100644
index 0000000000..ede6264fbc
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-cak/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR tz\'ajwachib\'äl</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Majun elesäy wachib\'äl pa ri okisab\'äl</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ceb/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ceb/strings.xml
new file mode 100644
index 0000000000..36247920f0
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ceb/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR scanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Wala\'y camera nga magamit sa device</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ckb/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ckb/strings.xml
new file mode 100644
index 0000000000..8928c305dd
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ckb/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">پشکنەری QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">کامێرا بوونی نیە لەسەر ئەم ئامێرە</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-co/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-co/strings.xml
new file mode 100644
index 0000000000..1c38f1ea2f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-co/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Analiza di codice QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Alcunu apparechju-fotò hè dispunibule nant’à l’apparechju</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-cs/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-cs/strings.xml
new file mode 100644
index 0000000000..394f65f77a
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-cs/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Skener QR kódů</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Zařízení nemá fotoaparát</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-cy/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-cy/strings.xml
new file mode 100644
index 0000000000..ca4c7127b8
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-cy/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Sganiwr QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nid oes camera ar gael ar y ddyfais</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-da/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-da/strings.xml
new file mode 100644
index 0000000000..af86f6552d
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-da/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-skanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Intet kamera tilgængelig på enheden</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-de/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-de/strings.xml
new file mode 100644
index 0000000000..79aa856fa0
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-de/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-Scanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Keine Kamera auf dem Gerät verfügbar</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-dsb/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-dsb/strings.xml
new file mode 100644
index 0000000000..1d0c62d9a4
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-dsb/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-skanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Žedna kamera njejo k dispoziciji na rěźe</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-el/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-el/strings.xml
new file mode 100644
index 0000000000..4fa0a90e5b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-el/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Σάρωση QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Η συσκευή σας δεν διαθέτει κάμερα</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-en-rCA/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000000..5fae94c403
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-en-rCA/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR scanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">No camera available on device</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-en-rGB/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000000..5fae94c403
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-en-rGB/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR scanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">No camera available on device</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-eo/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-eo/strings.xml
new file mode 100644
index 0000000000..2be7a096dd
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-eo/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Skanilo QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Neniu fimilo disponebla en la aparato</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rAR/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rAR/strings.xml
new file mode 100644
index 0000000000..b0b62591ce
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rAR/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Escáner de QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">No hay cámara disponible en el dispositivo</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rCL/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rCL/strings.xml
new file mode 100644
index 0000000000..b0b62591ce
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rCL/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Escáner de QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">No hay cámara disponible en el dispositivo</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rES/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rES/strings.xml
new file mode 100644
index 0000000000..b0b62591ce
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rES/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Escáner de QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">No hay cámara disponible en el dispositivo</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rMX/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rMX/strings.xml
new file mode 100644
index 0000000000..b0b62591ce
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-es-rMX/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Escáner de QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">No hay cámara disponible en el dispositivo</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-es/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000000..b0b62591ce
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-es/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Escáner de QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">No hay cámara disponible en el dispositivo</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-et/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-et/strings.xml
new file mode 100644
index 0000000000..9e31766b3c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-et/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-skanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Seadme kaamera pole saadaval</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-eu/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-eu/strings.xml
new file mode 100644
index 0000000000..ecd1d47fa6
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-eu/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR eskanerra</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Kamera ez dago erabilgarri gailuan</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-fa/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-fa/strings.xml
new file mode 100644
index 0000000000..66d7e8892f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-fa/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">پویندهٔ رمزینهٔ پاس</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">دوربین در این افزاره در دسترس نیست</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-fi/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000000..ca95dd65f3
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-fi/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-skanneri</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Kameraa ei ole käytettävissä tällä laitteella</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-fr/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000000..9e580ec1d2
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-fr/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Scanner QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Aucune caméra disponible sur l’appareil</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-fur/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-fur/strings.xml
new file mode 100644
index 0000000000..e9ff7a2bd9
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-fur/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Scansionadôr QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nissune fotocjamare disponibile sul dispositîf</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-fy-rNL/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-fy-rNL/strings.xml
new file mode 100644
index 0000000000..866102f55b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-fy-rNL/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-scanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Gjin kamera beskikber op apparaat</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-gd/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-gd/strings.xml
new file mode 100644
index 0000000000..e326071aff
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-gd/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Sganair QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Chan eil camara ri làimh air an uidheam</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-gl/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-gl/strings.xml
new file mode 100644
index 0000000000..95eea190f8
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-gl/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Escáner de QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Non hai cámara dispoñíbel no dispositivo</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-gn/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-gn/strings.xml
new file mode 100644
index 0000000000..29987db474
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-gn/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR moha’ãngaha</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Ndaipóri ta’ãngamýi mba’e’okápe</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-gu-rIN/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-gu-rIN/strings.xml
new file mode 100644
index 0000000000..18860156b9
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-gu-rIN/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR સ્કેનર</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">ઉપકરણ પર કોઈ કેમેરો ઉપલબ્ધ નથી</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-hi-rIN/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-hi-rIN/strings.xml
new file mode 100644
index 0000000000..1bc5719127
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-hi-rIN/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR स्कैनर</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">डिवाइस पर कोई कैमरा उपलब्ध नहीं है</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-hil/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-hil/strings.xml
new file mode 100644
index 0000000000..5e64717bca
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-hil/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR scanner</string>
+
+ </resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-hr/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-hr/strings.xml
new file mode 100644
index 0000000000..e3829462a1
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-hr/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR skener</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Na uređaju nema kamere</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-hsb/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-hsb/strings.xml
new file mode 100644
index 0000000000..357f90e1b6
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-hsb/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-skener</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Na graće žana kamera k dispoziciji njeje</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-hu/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-hu/strings.xml
new file mode 100644
index 0000000000..1818bcbaea
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-hu/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-leolvasó</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nincs elérhető kamera az eszközön</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-hy-rAM/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000000..5deb3d814c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-hy-rAM/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR սկաներ</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Սարքում տեսախցիկը հասնելի չէ</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ia/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ia/strings.xml
new file mode 100644
index 0000000000..dfcbe5740d
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ia/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Scanditor de QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nulle camera disponibile sur le apparato</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-in/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-in/strings.xml
new file mode 100644
index 0000000000..358ce12175
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-in/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Pemindai QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Tidak ada kamera yang tersedia di perangkat</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-is/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-is/strings.xml
new file mode 100644
index 0000000000..6927a627a8
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-is/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-skanni</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Engin myndavél tiltæk á tækinu</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-it/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000000..7c936c965b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-it/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Scanner QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nessuna fotocamera disponibile sul dispositivo</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-iw/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-iw/strings.xml
new file mode 100644
index 0000000000..82896d047c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-iw/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">סורק QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">אין מצלמה זמינה במכשיר</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ja/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ja/strings.xml
new file mode 100644
index 0000000000..a4eb8620c6
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ja/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR コードスキャナー</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">使用可能なカメラが端末にありません</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ka/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ka/strings.xml
new file mode 100644
index 0000000000..6ed347acb1
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ka/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-წამკითხველი</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">მოწყობილობაზე კამერა არაა</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-kaa/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-kaa/strings.xml
new file mode 100644
index 0000000000..c87ff57355
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-kaa/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR skaner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Qurılmada kamera joq</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-kab/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-kab/strings.xml
new file mode 100644
index 0000000000..a95b95687a
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-kab/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">alnafraḍ QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Ulac takamiṛat deg ibenk</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-kk/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-kk/strings.xml
new file mode 100644
index 0000000000..dd74fd220b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-kk/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR сканері</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Құрылғыда камера жоқ</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-kmr/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-kmr/strings.xml
new file mode 100644
index 0000000000..808536e55d
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-kmr/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Xwînera QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Di cîhazê de kamera tune</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-kn/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-kn/strings.xml
new file mode 100644
index 0000000000..d059ae06be
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-kn/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">ಕ್ಯೂಆರ್ ಸ್ಕ್ಯಾನರ್</string>
+
+ </resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ko/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ko/strings.xml
new file mode 100644
index 0000000000..b57f4803f5
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ko/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR 스캐너</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">기기에 사용 가능한 카메라 없음</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-lo/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-lo/strings.xml
new file mode 100644
index 0000000000..aff4d28c6c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-lo/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">ຕົວສະແກນ QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">ອຸປະກອນນີ້ບໍ່ມີກ້ອງ</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-lt/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-lt/strings.xml
new file mode 100644
index 0000000000..dde9b8fc28
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-lt/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR skaitytuvas</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Įrenginyje nėra kameros</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-mix/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-mix/strings.xml
new file mode 100644
index 0000000000..e4e5924041
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-mix/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Ndatava QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Koo ña ndatava nu kaa ndusu ku</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-mr/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-mr/strings.xml
new file mode 100644
index 0000000000..ce55ae4e3c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-mr/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR स्कॅनर</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">उपकरणावर कोणताही कॅमेरा उपलब्ध नाही</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-my/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-my/strings.xml
new file mode 100644
index 0000000000..5e66f1b09c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-my/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR ဖတ်ရန်</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">စက်တွင်ကင်မရာမပါပါ</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-nb-rNO/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-nb-rNO/strings.xml
new file mode 100644
index 0000000000..7e1f547927
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-nb-rNO/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-skanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Ingen kamera tilgjengelige på enheten</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ne-rNP/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ne-rNP/strings.xml
new file mode 100644
index 0000000000..1b22f9fc30
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ne-rNP/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR स्क्यानर</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">यन्त्रमा कुनै क्यामरा उपलब्ध छैन</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-nl/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-nl/strings.xml
new file mode 100644
index 0000000000..bbd95f9d57
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-nl/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-scanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Geen camera beschikbaar op apparaat</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-nn-rNO/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-nn-rNO/strings.xml
new file mode 100644
index 0000000000..24e3198e26
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-nn-rNO/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-skannar</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Ingen kamera tilgjengelege på eininga</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-oc/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-oc/strings.xml
new file mode 100644
index 0000000000..1828bb344f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-oc/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Numerizador QR còdi</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Cap de camèra pas disponibla sul periferic</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-pa-rIN/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-pa-rIN/strings.xml
new file mode 100644
index 0000000000..097b5d7efb
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-pa-rIN/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR ਸਕੈਨਰ</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">ਡਿਵਾਈਸ ਉੱਤੇ ਕੈਮਰਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-pa-rPK/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-pa-rPK/strings.xml
new file mode 100644
index 0000000000..425257dbbf
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-pa-rPK/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">کیوآر کوڈ سکین والا</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">کوئی کیمرہ نہیں لبھیا</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-pl/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000000..4f6016e055
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-pl/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Skaner kodów QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Urządzenie nie ma aparatu</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-pt-rBR/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000000..eb2379dd0f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Scanner QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nenhuma câmera disponível no dispositivo</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-pt-rPT/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000000..cf4d062a1b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-pt-rPT/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Digitalizador QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nenhuma câmara disponível no dispositivo</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-rm/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-rm/strings.xml
new file mode 100644
index 0000000000..46cc46ca31
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-rm/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Scanner QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nagina camera disponibla en l\'apparat</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ro/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ro/strings.xml
new file mode 100644
index 0000000000..534096197c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ro/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Scanner QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nu există camere disponibile pe dispozitiv</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ru/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000000..8c14a264d3
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ru/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Считыватель штрих-кодов</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">На этом устройстве камера недоступна</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-sat/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-sat/strings.xml
new file mode 100644
index 0000000000..74a96b7d83
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-sat/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR ᱥᱠᱟᱱᱚᱨ</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">ᱥᱟᱫᱷᱚᱱ ᱨᱮ ᱠᱮᱢᱨᱟ ᱵᱟᱹᱱᱩᱜ-ᱟ</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-sc/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-sc/strings.xml
new file mode 100644
index 0000000000..ee4c7fd470
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-sc/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Iscansionadore de QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nissuna càmera a disponimentu in su dispositivu</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-si/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-si/strings.xml
new file mode 100644
index 0000000000..d841d8365a
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-si/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR සුපිරික්සකය</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">උපාංගයෙහි රූගතයක් නැත</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-sk/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-sk/strings.xml
new file mode 100644
index 0000000000..1f60626aa0
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-sk/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Skener QR kódov</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Zariadenie nemá fotoaparát</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-skr/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-skr/strings.xml
new file mode 100644
index 0000000000..e44642f62c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-skr/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR سکینر</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">ڈیوائس تے کوئی کیمرہ دستیاب کائنی</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-sl/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-sl/strings.xml
new file mode 100644
index 0000000000..efffc8172e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-sl/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Bralnik QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Naprava nima razpoložljive kamere</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-sq/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-sq/strings.xml
new file mode 100644
index 0000000000..8c8796d692
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-sq/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Skanues QR-esh</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">S’ka kamera të përdorshme në pajisje</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-sr/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-sr/strings.xml
new file mode 100644
index 0000000000..91503317dd
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-sr/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR скенер</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">На уређају није доступна камера</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-su/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-su/strings.xml
new file mode 100644
index 0000000000..9091036029
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-su/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Paminday QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Henteu aya kaméra dina alat</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-sv-rSE/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-sv-rSE/strings.xml
new file mode 100644
index 0000000000..cc0601fb83
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-sv-rSE/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR-skanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Ingen kamera tillgänglig på enheten</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ta/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ta/strings.xml
new file mode 100644
index 0000000000..18cb652d7e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ta/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR வருடி</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">சாதனத்தில் படக்கருவி இல்லை</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-te/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-te/strings.xml
new file mode 100644
index 0000000000..8ab2d2d6da
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-te/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR స్కానర్</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">పరికరంలో కెమెరా లేదు</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-tg/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-tg/strings.xml
new file mode 100644
index 0000000000..f614203639
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-tg/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Аксбардории QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Ягон камера дар дастгоҳ дастрас нест</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-th/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-th/strings.xml
new file mode 100644
index 0000000000..03d2a7c3a8
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-th/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">ตัวสแกน QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">ไม่มีกล้องที่พร้อมใช้งานบนอุปกรณ์</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-tl/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-tl/strings.xml
new file mode 100644
index 0000000000..f61d1973fc
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-tl/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR scanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Walang magagamit na camera sa aparato</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-tok/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-tok/strings.xml
new file mode 100644
index 0000000000..43d57c4a0e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-tok/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">ilo lukin pi leko sona</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">ilo sina li jo ala e ilo lukin</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-tr/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-tr/strings.xml
new file mode 100644
index 0000000000..b64a1decc7
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-tr/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR tarayıcı</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Cihazda kamera yok</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-trs/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-trs/strings.xml
new file mode 100644
index 0000000000..0f85b43439
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-trs/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Sa natsij nej QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Nitāj aga\’ nari ñadu\’ua nikāj aga\’ nan</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-tt/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-tt/strings.xml
new file mode 100644
index 0000000000..2828e3f906
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-tt/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR сканеры</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Җиһазда камера юк</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ug/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ug/strings.xml
new file mode 100644
index 0000000000..67ff29d85d
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ug/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR سايىلىغۇچ</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">كامېرا يوق ئىكەن</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-uk/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-uk/strings.xml
new file mode 100644
index 0000000000..4154a29991
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-uk/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Сканер QR-кодів</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Немає доступу до камери пристрою</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-ur/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-ur/strings.xml
new file mode 100644
index 0000000000..dc2d085e48
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-ur/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR سکینر</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">آلہ پر کوئی کمیرہ دستیاب نہیں ہے</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-uz/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-uz/strings.xml
new file mode 100644
index 0000000000..ba70db4633
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-uz/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR skaner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Qurilmada kamera mavjud emas</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-vi/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-vi/strings.xml
new file mode 100644
index 0000000000..78039314fd
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-vi/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Quét mã QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Hiện không tìm thấy máy ảnh trên thiết bị</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-yo/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-yo/strings.xml
new file mode 100644
index 0000000000..a17b5f6d7a
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-yo/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">Síkánà QR</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">Kò sí ẹ̀rọ-ayàwòrán kankan lórí ẹ̀rọ yìí</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-zh-rCN/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000000..cdf50696d8
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">扫码器</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">设备上没有可用的相机</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values-zh-rTW/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000000..5023389874
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values-zh-rTW/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR Code 掃描器</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">裝置上無攝影機可用</string>
+
+</resources>
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values/colors.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values/colors.xml
new file mode 100644
index 0000000000..004d4bbd59
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values/colors.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<resources>
+ <color name="mozac_feature_qr_scan_success_color">#9059FF</color>
+</resources> \ No newline at end of file
diff --git a/mobile/android/android-components/components/feature/qr/src/main/res/values/strings.xml b/mobile/android/android-components/components/feature/qr/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..dcf8ae522c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/qr/src/main/res/values/strings.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<resources>
+
+ <!-- Content description (not visible, for screen readers etc.): Description of an image view. -->
+ <string name="mozac_feature_qr_scanner">QR scanner</string>
+
+ <!-- Text shown if no camera is available on the device and the QR scanner cannot be displayed. -->
+ <string name="mozac_feature_qr_scanner_no_camera">No camera available on device</string>
+
+</resources>