diff --git a/pretixscan/app/build.gradle b/pretixscan/app/build.gradle
index 2aa0e106..fc130ef6 100644
--- a/pretixscan/app/build.gradle
+++ b/pretixscan/app/build.gradle
@@ -174,6 +174,9 @@ dependencies {
}
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.github.apg-mobile:android-round-textview:v1.0.0'
+
+ implementation "com.google.android.gms:play-services-base:18.7.2"
+ implementation "com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1"
}
sqldelight {
diff --git a/pretixscan/app/src/main/AndroidManifest.xml b/pretixscan/app/src/main/AndroidManifest.xml
index 44c0140a..2f5995bd 100644
--- a/pretixscan/app/src/main/AndroidManifest.xml
+++ b/pretixscan/app/src/main/AndroidManifest.xml
@@ -112,6 +112,10 @@
android:resource="@xml/filepaths" />
+
+
diff --git a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/AppConfig.kt b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/AppConfig.kt
index fb058f1c..af4c4e42 100644
--- a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/AppConfig.kt
+++ b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/AppConfig.kt
@@ -66,6 +66,12 @@ class AppConfig(ctx: Context) : ConfigStore {
.putString(PREFS_KEY_AUTOPRINTBADGES, "once")
.commit()
}
+ if (prefs.contains(LEGACY_PREFS_KEY_USE_CAMERA)) {
+ prefs.edit()
+ .putString(PREFS_KEY_SCAN_ENGINE, if (prefs.getBoolean(LEGACY_PREFS_KEY_USE_CAMERA, true)) "zxing" else "hardware")
+ .remove(LEGACY_PREFS_KEY_USE_CAMERA)
+ .commit()
+ }
}
override fun isDebug(): Boolean {
@@ -339,9 +345,9 @@ class AppConfig(ctx: Context) : ConfigStore {
}
}
- var useCamera: Boolean
- get() = default_prefs.getBoolean(PREFS_KEY_USE_CAMERA, true)
- set(value) = default_prefs.edit().putBoolean(PREFS_KEY_USE_CAMERA, value).apply()
+ @Deprecated("use scanEngine instead")
+ val useCamera: Boolean
+ get() = default_prefs.getString(PREFS_KEY_SCAN_ENGINE, "zxing") != "hardware"
val hideNames: Boolean
get() = default_prefs.getBoolean(PREFS_KEY_HIDE_NAMES, false)
@@ -397,6 +403,10 @@ class AppConfig(ctx: Context) : ConfigStore {
get() = default_prefs.getBoolean(PREFS_KEY_SYNC_ORDERS, true)
set(value) = default_prefs.edit().putBoolean(PREFS_KEY_SYNC_ORDERS, value).apply()
+ var scanEngine: String
+ get() = default_prefs.getString(PREFS_KEY_SCAN_ENGINE, "zxing") ?: "zxing"
+ set(value) = default_prefs.edit().putString(PREFS_KEY_SCAN_ENGINE, value).apply()
+
override fun getKnownLiveEventSlugs(): Set {
return default_prefs.getStringSet(PREFS_KEY_KNOWN_LIVE_EVENT_SLUGS, emptySet()) as Set
}
@@ -435,7 +445,7 @@ class AppConfig(ctx: Context) : ConfigStore {
val PREFS_KEY_SCAN_FLASH = "scan_flash"
val PREFS_KEY_SYNC_ORDERS = "pref_sync_orders"
val PREFS_KEY_AUTO_SWITCH = "pref_auto_switch"
- val PREFS_KEY_USE_CAMERA = "pref_use_camera"
+ val LEGACY_PREFS_KEY_USE_CAMERA = "pref_use_camera"
val PREFS_KEY_SCAN_OFFLINE = "pref_scan_offline"
val PREFS_KEY_SCAN_OFFLINE_AUTO = "pref_auto_offline"
val PREFS_KEY_SCAN_PROXY = "pref_scan_proxy"
@@ -451,6 +461,7 @@ class AppConfig(ctx: Context) : ConfigStore {
val PREFS_KEY_SEARCH_DISABLE = "pref_search_disable"
val PREFS_KEY_KIOSK_MODE = "pref_kiosk_mode"
val PREFS_KEY_MULTI_EVENT_MODE = "multi_event_mode"
+ val PREFS_KEY_SCAN_ENGINE = "pref_scan_engine"
private const val PREFS_KEY_KNOWN_LIVE_EVENT_SLUGS = "cache_known_live_event_slugs"
}
}
diff --git a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/MainActivity.kt b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/MainActivity.kt
index 85e69ee1..9680b331 100644
--- a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/MainActivity.kt
+++ b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/MainActivity.kt
@@ -56,8 +56,16 @@ import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.module.SimpleModule
+import com.google.android.gms.common.moduleinstall.InstallStatusListener
+import com.google.android.gms.common.moduleinstall.ModuleInstall
+import com.google.android.gms.common.moduleinstall.ModuleInstallRequest
+import com.google.android.gms.common.moduleinstall.ModuleInstallStatusUpdate
+import com.google.android.gms.common.moduleinstall.ModuleInstallStatusUpdate.InstallState.STATE_CANCELED
+import com.google.android.gms.common.moduleinstall.ModuleInstallStatusUpdate.InstallState.STATE_COMPLETED
+import com.google.android.gms.common.moduleinstall.ModuleInstallStatusUpdate.InstallState.STATE_FAILED
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
+import com.google.mlkit.vision.barcode.BarcodeScanning
import eu.pretix.libpretixsync.api.PretixApi
import eu.pretix.libpretixsync.check.CheckException
import eu.pretix.libpretixsync.check.OnlineCheckProvider
@@ -528,6 +536,66 @@ class MainActivity : AppCompatActivity(), ReloadableActivity, ScannerView.Result
pendingPinAction?.let { it(pin) }
}
}
+
+ if (conf.scanEngine == "mlkit") {
+ val moduleInstallClient = ModuleInstall.getClient(this)
+ val barcodeModule = BarcodeScanning.getClient()
+ moduleInstallClient.areModulesAvailable(
+ barcodeModule
+ )
+ class ModuleInstallProgressListener : InstallStatusListener {
+ override fun onInstallStatusUpdated(update: ModuleInstallStatusUpdate) {
+ // Progress info is only set when modules are in the progress of downloading.
+ update.progressInfo?.let {
+ val progress = (it.bytesDownloaded * 100 / it.totalBytesToDownload).toInt()
+ // Set the progress for the progress bar.
+ //progressBar.setProgress(progress)
+ }
+
+ if (isTerminateState(update.installState)) {
+ moduleInstallClient.unregisterListener(this)
+ }
+ if (update.installState == STATE_COMPLETED) {
+ // -> switch engine
+ switchScanEngine()
+ }
+ }
+
+ fun isTerminateState(@ModuleInstallStatusUpdate.InstallState state: Int): Boolean {
+ return state == STATE_CANCELED || state == STATE_COMPLETED || state == STATE_FAILED
+ }
+ }
+
+ val listener = ModuleInstallProgressListener()
+ val moduleInstallRequest = ModuleInstallRequest.newBuilder()
+ .addApi(barcodeModule)
+ .setListener(listener)
+ .build()
+
+ moduleInstallClient
+ .installModules(moduleInstallRequest)
+ .addOnSuccessListener {
+ if (it.areModulesAlreadyInstalled()) {
+ // Modules are already installed when the request is sent.
+ // -> switch engine
+ switchScanEngine()
+ }
+ // The install request has been sent successfully. This does not mean
+ // the installation is completed. To monitor the install status, set an
+ // InstallStatusListener to the ModuleInstallRequest.
+ }
+ .addOnFailureListener {
+ // Handle failureā¦
+ }
+ }
+ }
+
+ private fun switchScanEngine() {
+ when(conf.scanEngine) {
+ "zxing" -> binding.scannerView.setAnalyzer(ScannerView.Companion.ANALYZER.ZXING)
+ "mlkit" -> binding.scannerView.setAnalyzer(ScannerView.Companion.ANALYZER.MLKIT)
+ else -> {}
+ }
}
private fun eventButtonText(): String {
diff --git a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/Settings.kt b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/Settings.kt
index 04cf6943..28570dc3 100644
--- a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/Settings.kt
+++ b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/Settings.kt
@@ -175,6 +175,10 @@ class SettingsFragment : PreferenceFragmentCompat() {
true
}
}
+
+ // FIXME: pref_scan_engine. if BuildConfig.FLAVOR_edition == "foss", don't offer mlkit (disable?)
+ // FIXME: pref_scan_engine. check installation status of mlkit and warn for potential large download
+ // FIXME: pref_scan_engine. if changed to mlkit, check installation status
}
private fun asset_dialog(@RawRes htmlRes: Int, @StringRes title: Int) {
diff --git a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/SetupActivity.kt b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/SetupActivity.kt
index 65fc7457..661b90d6 100644
--- a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/SetupActivity.kt
+++ b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/SetupActivity.kt
@@ -83,7 +83,7 @@ class SetupActivity : AppCompatActivity(), SetupCallable {
override fun config(useCamera: Boolean) {
val conf = AppConfig(this)
- conf.useCamera = useCamera
+ conf.scanEngine = if (useCamera) "zxing" else "hardware"
}
override fun setup(url: String, token: String) {
diff --git a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/WelcomeActivity.kt b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/WelcomeActivity.kt
index f56c7343..7f8f2750 100644
--- a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/WelcomeActivity.kt
+++ b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/ui/WelcomeActivity.kt
@@ -59,7 +59,7 @@ class WelcomeActivity : AppCompatActivity() {
if (defaultToScanner()) {
val conf = AppConfig(this)
- conf.useCamera = false
+ conf.scanEngine = "hardware"
}
}
diff --git a/pretixscan/app/src/main/res/values/arrays.xml b/pretixscan/app/src/main/res/values/arrays.xml
index 4a372a78..10ddef2a 100644
--- a/pretixscan/app/src/main/res/values/arrays.xml
+++ b/pretixscan/app/src/main/res/values/arrays.xml
@@ -16,4 +16,9 @@
- once
- true
+
+ - zxing
+ - mlkit
+ - hardware
+
\ No newline at end of file
diff --git a/pretixscan/app/src/main/res/values/strings.xml b/pretixscan/app/src/main/res/values/strings.xml
index 731d3e44..eaa282d9 100644
--- a/pretixscan/app/src/main/res/values/strings.xml
+++ b/pretixscan/app/src/main/res/values/strings.xml
@@ -135,6 +135,7 @@
Enable badge printing
Print badges automatically
Printing badges requires the separate pretixPRINT app. Do you want to install it?
+ Barcode scanner to use
already scanned
total tickets sold
Attention, special ticket!
@@ -169,6 +170,11 @@
- Once, if not yet printed
- Always
+
+ - Zebra Crossing (ZXing)
+ - Google ML Kit
+ - Hardware scanner of this device
+
Please reinstall pretixSCAN
Your previous pretixSCAN version was too old and your local data cannot be used for the current version.\n\nPlease clear the storage for the pretixSCAN app or delete and reinstall the app.
Open Android App Settings
diff --git a/pretixscan/app/src/main/res/xml/app_restrictions.xml b/pretixscan/app/src/main/res/xml/app_restrictions.xml
index 391bcf62..bef77838 100644
--- a/pretixscan/app/src/main/res/xml/app_restrictions.xml
+++ b/pretixscan/app/src/main/res/xml/app_restrictions.xml
@@ -5,6 +5,7 @@
android:key="pref_sync_auto"
android:restrictionType="bool"
android:title="@string/settings_label_auto_sync" />
+
-
+