From 0c5949aeb2e4302965c63481f8806a162ee423d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Christian=20Heinsen?= Date: Mon, 27 Nov 2023 12:45:25 +0100 Subject: [PATCH 1/3] Began implementing ring scanner, adding remoteScannerNotification function in order to send notifications to the ring scanner. Added helper classes for DeviceId and RemoteScannerNotification. --- .../src/main/java/dk/gls/kdw/KDW.kt | 5 ++ .../scanner/DataWedgeHardwareScanner.kt | 75 +++++++++++++++++-- .../gls/kdw/configuration/scanner/DeviceId.kt | 28 +++++++ .../configuration/scanner/HardwareScanner.kt | 1 + .../scanner/NotificationSettings.kt | 35 +++++++++ .../scanner/ParityFlowScannerController.kt | 5 ++ .../scanner/ScannerController.kt | 2 + .../{ => implementation}/KDWImplementation.kt | 18 +++-- .../dk/gls/kdw/model/scanner/ScannerStatus.kt | 2 - 9 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/KDW.kt create mode 100644 kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DeviceId.kt create mode 100644 kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/NotificationSettings.kt rename kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/{ => implementation}/KDWImplementation.kt (70%) diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/KDW.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/KDW.kt new file mode 100644 index 0000000..e9f8809 --- /dev/null +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/KDW.kt @@ -0,0 +1,5 @@ +package dk.gls.kdw + +import dk.gls.kdw.implementation.KDWImplementation + +object KDW : KDWImplementation() \ No newline at end of file diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DataWedgeHardwareScanner.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DataWedgeHardwareScanner.kt index c63ad32..58bc2df 100644 --- a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DataWedgeHardwareScanner.kt +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DataWedgeHardwareScanner.kt @@ -5,6 +5,7 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Bundle +import android.util.Log import dk.gls.kdw.model.scanner.ScannerOutput import dk.gls.kdw.model.scanner.ScannerResult import dk.gls.kdw.model.scanner.toScannerStatusEnum @@ -18,14 +19,13 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.launch + class DataWedgeHardwareScanner( private val context: Context, dispatcher: CoroutineDispatcher = Dispatchers.IO ) : HardwareScanner { companion object { - private const val TAG = "ScannerController" - //Scanner Intent data locations private const val EXTRA_DATA_STRING = "com.symbol.datawedge.data_string" private const val EXTRA_LABEL_TYPE = "com.symbol.datawedge.label_type" @@ -36,6 +36,7 @@ class DataWedgeHardwareScanner( private const val EXTRA_RESULT_NOTIFICATION = "com.symbol.datawedge.api.NOTIFICATION" private const val EXTRA_REGISTER_NOTIFICATION = "com.symbol.datawedge.api.REGISTER_FOR_NOTIFICATION" + private const val EXTRA_RESULT_NOTIFICATION_TYPE = "NOTIFICATION_TYPE" private const val EXTRA_KEY_VALUE_SCANNER_STATUS = "SCANNER_STATUS" private const val EXTRA_KEY_VALUE_PROFILE_SWITCH = "PROFILE_SWITCH" @@ -46,8 +47,8 @@ class DataWedgeHardwareScanner( private const val ACTION_DATA_WEDGE = "com.symbol.datawedge.api.ACTION" private const val EXTRA_SCANNER_INPUT_PLUGIN = "com.symbol.datawedge.api.SCANNER_INPUT_PLUGIN" - private const val ACTION_RESULT_NOTIFICATION = "com.symbol.datawedge.api.NOTIFICATION_ACTION" - private const val ACTION_RESULT = "com.symbol.datawedge.api.RESULT_ACTION" + private const val NOTIFICATION_ACTION = "com.symbol.datawedge.api.NOTIFICATION_ACTION" + private const val RESULT_ACTION = "com.symbol.datawedge.api.RESULT_ACTION" // DataWedge scanning broadcast private const val INTENT_FILTER_ACTION = "com.zebra.datacapture1.ACTION" @@ -56,6 +57,17 @@ class DataWedgeHardwareScanner( // DataWedge control scanner state private const val EXTRA_SCANNER_SUSPEND = "SUSPEND_PLUGIN" private const val EXTRA_SCANNER_RESUME = "RESUME_PLUGIN" + + // Enumerate scanners + private const val RESULT_ENUMERATE_SCANNERS = "com.symbol.datawedge.api.RESULT_ENUMERATE_SCANNERS" + private const val ENUMERATE_SCANNERS = "com.symbol.datawedge.api.ENUMERATE_SCANNERS" + + // Notify + private const val ACTION_NOTIFICATION_NOTIFY = "com.symbol.datawedge.api.notification.NOTIFY" + private const val BUNDLE_NOTIFICATION_CONFIG = "NOTIFICATION_CONFIG" + private const val EXTRA_KEY_VALUE_DEVICE_IDENTIFIER = "DEVICE_IDENTIFIER" + private const val EXTRA_KEY_VALUE_NOTIFICATION_SETTINGS = "NOTIFICATION_SETTINGS" + } private val scope = CoroutineScope(dispatcher) @@ -84,6 +96,26 @@ class DataWedgeHardwareScanner( broadcastScannerAction(context, EXTRA_SCANNER_RESUME) } + /** + * Send a notification on the remote scanner (RMS) + * @link https://techdocs.zebra.com/datawedge/8-2/guide/api/notify/ + **/ + override fun remoteScannerNotification(deviceId: DeviceId, notifications: List) { + val bundleNotificationConfig = Bundle() + bundleNotificationConfig.putString(EXTRA_KEY_VALUE_DEVICE_IDENTIFIER, deviceId.name) + bundleNotificationConfig.putIntArray(EXTRA_KEY_VALUE_NOTIFICATION_SETTINGS, notifications.map { it.value }.toIntArray()) + + val bundleNotify = Bundle() + bundleNotify.putBundle(BUNDLE_NOTIFICATION_CONFIG, bundleNotificationConfig) + + + val dataWedgeIntent = Intent() + dataWedgeIntent.action = ACTION_DATA_WEDGE + dataWedgeIntent.putExtra(ACTION_NOTIFICATION_NOTIFY, bundleNotify) + + context.sendBroadcast(dataWedgeIntent) + } + //endregion /** Register broadcast receiver for receiving barcode scans. Collect the received broadcasts and emit on scannerResult flow **/ @@ -91,13 +123,14 @@ class DataWedgeHardwareScanner( callbackFlow { val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent) { + Log.d("ScannerFlow", "${intent.action}, hasExtras: ${intent.hasExtra(RESULT_ENUMERATE_SCANNERS)}") // Received a barcode scan if (intent.action == INTENT_FILTER_ACTION) { val scannerResult = extractDataFromIntent(intent) trySendBlocking(ScannerOutput.Result(scannerResult)) } // Received a scanner or profile switch status notification - if (intent.action == ACTION_RESULT_NOTIFICATION) { + if (intent.action == NOTIFICATION_ACTION) { val extras = intent.getBundleExtra(EXTRA_RESULT_NOTIFICATION) val notificationType = extras?.getString(EXTRA_RESULT_NOTIFICATION_TYPE) when (notificationType) { @@ -107,6 +140,11 @@ class DataWedgeHardwareScanner( scannerStatus?.let { val statusEnum = it.toScannerStatusEnum() + + + requestEnumerateScanners() + + trySendBlocking(ScannerOutput.Status(statusEnum)) } } @@ -117,6 +155,19 @@ class DataWedgeHardwareScanner( } } } + if (intent.hasExtra(RESULT_ENUMERATE_SCANNERS)) { + val scannerList = intent.getSerializableExtra(RESULT_ENUMERATE_SCANNERS) as ArrayList + if(scannerList.size > 0) { + scannerList.map { bunb -> + val name = bunb.getString("SCANNER_NAME") + val connectionState = bunb.getBoolean("SCANNER_CONNECTION_STATE") + val index = bunb.getInt("SCANNER_INDEX") + val id = bunb.getString("SCANNER_IDENTIFIER") + + Log.d("ScannerList", "Scanner: name: $name connectionState: $connectionState index: $index id: $id") + } + } + } } } context.registerReceiver(receiver, createIntentFilter()) @@ -128,13 +179,23 @@ class DataWedgeHardwareScanner( } } + /** Create and send intent filter in order to retrieve enumerate triggers **/ + private fun requestEnumerateScanners() { + val dataWedgeIntent = Intent() + + dataWedgeIntent.setAction(ACTION_DATA_WEDGE) + dataWedgeIntent.putExtra(ENUMERATE_SCANNERS, "") + + context.sendBroadcast(dataWedgeIntent) + } + /** Create filter for the broadcast intent **/ private fun createIntentFilter(): IntentFilter { val filter = IntentFilter() // Register to received broadcasts via Data Wedge scanning - filter.addAction(ACTION_RESULT) + filter.addAction(RESULT_ACTION) // For notification result - filter.addAction(ACTION_RESULT_NOTIFICATION) + filter.addAction(NOTIFICATION_ACTION) // Register to received broadcasts via DataWedge scanning filter.addAction(INTENT_FILTER_ACTION) filter.addAction(INTENT_FILTER_ACTION_FROM_SERVICE) diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DeviceId.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DeviceId.kt new file mode 100644 index 0000000..6773fc7 --- /dev/null +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DeviceId.kt @@ -0,0 +1,28 @@ +package dk.gls.kdw.configuration.scanner + +enum class DeviceId { + /** Built-in imager scanner **/ + INTERNAL_IMAGER, + /** Built-in laser scanner **/ + INTERNAL_LASER, + /** Built-in camera scanner **/ + INTERNAL_CAMERA, + /** Pluggable Z-back scanner for ET50/ET55 **/ + SERIAL_SSI, + /** RS507 Bluetooth scanner **/ + BLUETOOTH_SSI, + /** RS6000 Bluetooth scanner **/ + BLUETOOTH_RS6000, + /** RS5100 Bluetooth scanner **/ + BLUETOOTH_RS5100, + /** DS2278 Bluetooth scanner **/ + BLUETOOTH_DS2278, + /** DS3678 Bluetooth scanner **/ + BLUETOOTH_DS3678, + /** Serial SSI scanner RS429 (for use with WT6000) **/ + PLUGABLE_SSI, + /** Serial SSI scanner RS5000 (for use with WT6000) **/ + PLUGABLE_SSI_RS5000, + /** DS3608 pluggable USB scanner **/ + USB_SSI_DS3608 +} \ No newline at end of file diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/HardwareScanner.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/HardwareScanner.kt index 90e712b..762af9d 100644 --- a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/HardwareScanner.kt +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/HardwareScanner.kt @@ -7,4 +7,5 @@ interface HardwareScanner { fun scannerOutputFlow(): Flow fun suspendScanner() fun resumeScanner() + fun remoteScannerNotification(deviceId: DeviceId, notifications: List) } \ No newline at end of file diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/NotificationSettings.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/NotificationSettings.kt new file mode 100644 index 0000000..93d7af5 --- /dev/null +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/NotificationSettings.kt @@ -0,0 +1,35 @@ +package dk.gls.kdw.configuration.scanner + +enum class RemoteScannerNotification(val value: Int) { + ONE_HIGH_SHORT_BEEP(0), + TWO_HIGH_SHORT_BEEPS(1), + THREE_HIGH_SHORT_BEEPS(2), + FOUR_HIGH_SHORT_BEEPS(3), + FIVE_HIGH_SHORT_BEEPS(4), + ONE_LOW_SHORT_BEEP(5), + TWO_LOW_SHORT_BEEPS(6), + THREE_LOW_SHORT_BEEPS(7), + FOUR_LOW_SHORT_BEEPS(8), + FIVE_LOW_SHORT_BEEPS(9), + ONE_HIGH_LONG_BEEP(10), + TWO_HIGH_LONG_BEEPS(11), + THREE_HIGH_LONG_BEEPS(12), + FOUR_HIGH_LONG_BEEPS(13), + FIVE_HIGH_LONG_BEEPS(14), + ONE_LOW_LONG_BEEP(15), + TWO_LOW_LONG_BEEPS(16), + THREE_LOW_LONG_BEEPS(17), + FOUR_LOW_LONG_BEEPS(18), + FIVE_LOW_LONG_BEEPS(19), + FAST_WARBLE_BEEP(20), + SLOW_WARBLE_BEEP(21), + HIGH_LOW_BEEP(22), + LOW_HIGH_BEEP(23), + HIGH_LOW_HIGH_BEEP(24), + LOW_HIGH_LOW_BEEP(25), + HIGH_HIGH_LOW_LOW(26), + GREEN_LED_OFF(42), + GREEN_LED_ON(43), + RED_LED_ON(47), + RED_LED_OFF(48) +} \ No newline at end of file diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ParityFlowScannerController.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ParityFlowScannerController.kt index 6cc1ee0..464e50e 100644 --- a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ParityFlowScannerController.kt +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ParityFlowScannerController.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.launch /** @@ -51,6 +52,10 @@ class ParityFlowScannerController(dataWedgeHardwareScanner: DataWedgeHardwareSca desiredScannerStatusFlow.tryEmit(ScannerSimpleStatus.Enabled) } + override fun remoteScannerNotification(deviceId: DeviceId, notifications: List) { + dataWedgeHardwareScanner.remoteScannerNotification(deviceId, notifications) + } + //endregion private val scannerResult = MutableSharedFlow() diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ScannerController.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ScannerController.kt index d41cdf5..2ea044a 100644 --- a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ScannerController.kt +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ScannerController.kt @@ -16,4 +16,6 @@ abstract class ScannerController( abstract fun resumeScanner() + abstract fun remoteScannerNotification(deviceId: DeviceId, notifications: List) + } \ No newline at end of file diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/KDWImplementation.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/implementation/KDWImplementation.kt similarity index 70% rename from kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/KDWImplementation.kt rename to kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/implementation/KDWImplementation.kt index ff99afc..3c9d6df 100644 --- a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/KDWImplementation.kt +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/implementation/KDWImplementation.kt @@ -1,6 +1,7 @@ -package dk.gls.kdw +package dk.gls.kdw.implementation import android.content.Context +import dk.gls.kdw.IKDW import dk.gls.kdw.configuration.ProfileConfiguration import dk.gls.kdw.configuration.SetConfigConfiguration import dk.gls.kdw.configuration.scanner.DataWedgeHardwareScanner @@ -9,6 +10,8 @@ import dk.gls.kdw.configuration.scanner.ScannerController open class KDWImplementation : IKDW { + private var dataWedgeHardwareScanner : DataWedgeHardwareScanner? = null + override fun configure( context: Context, profileConfiguration: ProfileConfiguration, @@ -20,9 +23,14 @@ open class KDWImplementation : IKDW { ).toIntent() context.sendBroadcast(dataWedgeIntent) - val dataWedgeHardwareScanner = DataWedgeHardwareScanner(context) + if(this.dataWedgeHardwareScanner == null) { + this.dataWedgeHardwareScanner = DataWedgeHardwareScanner(context) + } + - this._scannerController = scannerControllerConfiguration?.invoke(dataWedgeHardwareScanner) ?: ParityFlowScannerController(dataWedgeHardwareScanner) + if(this._scannerController == null) { + this._scannerController = scannerControllerConfiguration?.invoke(dataWedgeHardwareScanner!!) ?: ParityFlowScannerController(dataWedgeHardwareScanner!!) + } } private var _scannerController: ScannerController? = null @@ -31,6 +39,4 @@ open class KDWImplementation : IKDW { @Throws(RuntimeException::class) get() = _scannerController ?: throw RuntimeException("Accessing KDW.scannerController before calling KDW.configure(...) is not allowed!") -} - -object KDW : KDWImplementation() \ No newline at end of file +} \ No newline at end of file diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/model/scanner/ScannerStatus.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/model/scanner/ScannerStatus.kt index 8341f70..b0db7fb 100644 --- a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/model/scanner/ScannerStatus.kt +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/model/scanner/ScannerStatus.kt @@ -1,7 +1,5 @@ package dk.gls.kdw.model.scanner -import dk.gls.kdw.model.label.LabelType - /** * Scanner status indicates that the scanner is being turned on or off using the hardware buttons. * @see For official documentation under 'Data Capture' From 9e424fe22cb56bf4a39721a66ff8bf106470c255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Christian=20Heinsen?= Date: Mon, 27 Nov 2023 12:55:17 +0100 Subject: [PATCH 2/3] Updated agp, gradle compile and min sdk versions. Cleaned up proguard-rules. --- build.gradle.kts | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- kotlin-data-wedge-lib/build.gradle.kts | 4 ++-- kotlin-data-wedge-lib/proguard-rules.pro | 6 +----- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 13f40a4..796f70a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.library") version "8.0.1" apply false + id("com.android.library") version "8.2.0-rc02" apply false id("org.jetbrains.kotlin.android") version "1.8.0" apply false kotlin("plugin.serialization") version "1.8.21" } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0c85a1f..a363877 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/kotlin-data-wedge-lib/build.gradle.kts b/kotlin-data-wedge-lib/build.gradle.kts index 3bf8688..49a758e 100644 --- a/kotlin-data-wedge-lib/build.gradle.kts +++ b/kotlin-data-wedge-lib/build.gradle.kts @@ -11,10 +11,10 @@ val libraryVersion = "0.0.5" android { namespace = "dk.gls.kdw" - compileSdk = 33 + compileSdk = 34 defaultConfig { - minSdk = 26 + minSdk = 30 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") diff --git a/kotlin-data-wedge-lib/proguard-rules.pro b/kotlin-data-wedge-lib/proguard-rules.pro index 0d32dca..1d79ef5 100644 --- a/kotlin-data-wedge-lib/proguard-rules.pro +++ b/kotlin-data-wedge-lib/proguard-rules.pro @@ -26,7 +26,7 @@ } -keep class dk.gls.kdw.configuration.** { - *; + *; } -keep class dk.gls.kdw.configuration.model.** { @@ -61,10 +61,6 @@ *; } --keep class dk.gls.kdw.KDW { - *; -} - -keep class dk.gls.kdw.configuration.scanner.ParityFlowScannerController { *; } From 24cb2402b7a74f58c266b018bd30cadf4c2b1012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Christian=20Heinsen?= Date: Mon, 27 Nov 2023 14:11:28 +0100 Subject: [PATCH 3/3] Added new scanner DeviceId and RemoteScannerNotification classes to proguard rules. Renamed IHardwareScanner, corrected ScannerController constructor with HardwareScanner interface instead of DataWedgeHardwareScanner implementation. --- kotlin-data-wedge-lib/proguard-rules.pro | 8 +++++ .../scanner/DataWedgeHardwareScanner.kt | 33 ++++++++++++++----- .../configuration/scanner/HardwareScanner.kt | 11 ------- .../configuration/scanner/IHardwareScanner.kt | 25 ++++++++++++++ .../scanner/ParityFlowScannerController.kt | 17 +++++----- .../scanner/ScannerController.kt | 5 ++- 6 files changed, 68 insertions(+), 31 deletions(-) delete mode 100644 kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/HardwareScanner.kt create mode 100644 kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/IHardwareScanner.kt diff --git a/kotlin-data-wedge-lib/proguard-rules.pro b/kotlin-data-wedge-lib/proguard-rules.pro index 1d79ef5..fca7775 100644 --- a/kotlin-data-wedge-lib/proguard-rules.pro +++ b/kotlin-data-wedge-lib/proguard-rules.pro @@ -64,3 +64,11 @@ -keep class dk.gls.kdw.configuration.scanner.ParityFlowScannerController { *; } + +-keep class dk.gls.kdw.configuration.scanner.DeviceId { + *; +} + +-keep class dk.gls.kdw.configuration.scanner.RemoteScannerNotification { + *; +} \ No newline at end of file diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DataWedgeHardwareScanner.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DataWedgeHardwareScanner.kt index 58bc2df..e4cb935 100644 --- a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DataWedgeHardwareScanner.kt +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/DataWedgeHardwareScanner.kt @@ -14,16 +14,19 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.trySendBlocking +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch - class DataWedgeHardwareScanner( private val context: Context, - dispatcher: CoroutineDispatcher = Dispatchers.IO -) : HardwareScanner { + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) : IHardwareScanner { companion object { //Scanner Intent data locations @@ -67,7 +70,7 @@ class DataWedgeHardwareScanner( private const val BUNDLE_NOTIFICATION_CONFIG = "NOTIFICATION_CONFIG" private const val EXTRA_KEY_VALUE_DEVICE_IDENTIFIER = "DEVICE_IDENTIFIER" private const val EXTRA_KEY_VALUE_NOTIFICATION_SETTINGS = "NOTIFICATION_SETTINGS" - + private const val NOTIFICATIONS_DELAY: Long = 1000 } private val scope = CoroutineScope(dispatcher) @@ -96,11 +99,26 @@ class DataWedgeHardwareScanner( broadcastScannerAction(context, EXTRA_SCANNER_RESUME) } + //endregion + + //region scanner notifications + /** - * Send a notification on the remote scanner (RMS) + * Send a variable amount of notification lists specifying the notifications for the remote scanner (RMS) + * The notifications are send with a delay between parsed lists of 1000 ms + * Official documentation * @link https://techdocs.zebra.com/datawedge/8-2/guide/api/notify/ **/ - override fun remoteScannerNotification(deviceId: DeviceId, notifications: List) { + override fun remoteScannerNotifications(deviceId: DeviceId, vararg notifications: List) { + CoroutineScope(dispatcher).launch { + notifications.asFlow().map { + remoteScannerNotification(deviceId, it) + delay(NOTIFICATIONS_DELAY) + }.collect() + } + } + + private fun remoteScannerNotification(deviceId: DeviceId, notifications: List) { val bundleNotificationConfig = Bundle() bundleNotificationConfig.putString(EXTRA_KEY_VALUE_DEVICE_IDENTIFIER, deviceId.name) bundleNotificationConfig.putIntArray(EXTRA_KEY_VALUE_NOTIFICATION_SETTINGS, notifications.map { it.value }.toIntArray()) @@ -108,7 +126,6 @@ class DataWedgeHardwareScanner( val bundleNotify = Bundle() bundleNotify.putBundle(BUNDLE_NOTIFICATION_CONFIG, bundleNotificationConfig) - val dataWedgeIntent = Intent() dataWedgeIntent.action = ACTION_DATA_WEDGE dataWedgeIntent.putExtra(ACTION_NOTIFICATION_NOTIFY, bundleNotify) @@ -157,7 +174,7 @@ class DataWedgeHardwareScanner( } if (intent.hasExtra(RESULT_ENUMERATE_SCANNERS)) { val scannerList = intent.getSerializableExtra(RESULT_ENUMERATE_SCANNERS) as ArrayList - if(scannerList.size > 0) { + if (scannerList.size > 0) { scannerList.map { bunb -> val name = bunb.getString("SCANNER_NAME") val connectionState = bunb.getBoolean("SCANNER_CONNECTION_STATE") diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/HardwareScanner.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/HardwareScanner.kt deleted file mode 100644 index 762af9d..0000000 --- a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/HardwareScanner.kt +++ /dev/null @@ -1,11 +0,0 @@ -package dk.gls.kdw.configuration.scanner - -import dk.gls.kdw.model.scanner.ScannerOutput -import kotlinx.coroutines.flow.Flow - -interface HardwareScanner { - fun scannerOutputFlow(): Flow - fun suspendScanner() - fun resumeScanner() - fun remoteScannerNotification(deviceId: DeviceId, notifications: List) -} \ No newline at end of file diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/IHardwareScanner.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/IHardwareScanner.kt new file mode 100644 index 0000000..3e84d05 --- /dev/null +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/IHardwareScanner.kt @@ -0,0 +1,25 @@ +package dk.gls.kdw.configuration.scanner + +import dk.gls.kdw.model.scanner.ScannerOutput +import kotlinx.coroutines.flow.Flow + +interface IHardwareScanner { + /** + * Receive the [ScannerOutput] as a flow + */ + fun scannerOutputFlow(): Flow + + /** Suspend the scanner **/ + fun suspendScanner() + + /** Resume the scanner **/ + fun resumeScanner() + + /** + * Send a variable amount of notification lists specifying the notifications for the remote scanner (RMS) + * The notifications are send with a delay between parsed lists of 1000 ms + * Official documentation + * @link https://techdocs.zebra.com/datawedge/8-2/guide/api/notify/ + **/ + fun remoteScannerNotifications(deviceId: DeviceId, vararg notifications: List) +} \ No newline at end of file diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ParityFlowScannerController.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ParityFlowScannerController.kt index 464e50e..7598b7d 100644 --- a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ParityFlowScannerController.kt +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ParityFlowScannerController.kt @@ -9,14 +9,13 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.launch /** - * The parity flow scanner controller filters unnecessary calls to the underlying [DataWedgeHardwareScanner] by checking the last reported scanner status before sending new resume or suspend commands + * The parity flow scanner controller filters unnecessary calls to the underlying [IHardwareScanner] by checking the last reported scanner status before sending new resume or suspend commands * Therefore this scanner controllers [resumeScanner] and [suspendScanner] methods can safely be called multiple times without resulting in unnecessary broadcast intents being send to the Data wedge */ -class ParityFlowScannerController(dataWedgeHardwareScanner: DataWedgeHardwareScanner) : ScannerController(dataWedgeHardwareScanner) { +class ParityFlowScannerController(dataWedgeIHardwareScanner: IHardwareScanner) : ScannerController(dataWedgeIHardwareScanner) { //We have an actual scanner status flow and a desired scanner status flow for combining later private val actualScannerStatusEnumFlow = MutableSharedFlow(replay = 1) @@ -32,7 +31,7 @@ class ParityFlowScannerController(dataWedgeHardwareScanner: DataWedgeHardwareSca /** * Receive the [ScannerOutput] as a flow */ - override fun scannerOutputFlow(): Flow = dataWedgeHardwareScanner.scannerOutputFlow() + override fun scannerOutputFlow(): Flow = dataWedgeIHardwareScanner.scannerOutputFlow() //region Scanner status public interface @@ -52,8 +51,8 @@ class ParityFlowScannerController(dataWedgeHardwareScanner: DataWedgeHardwareSca desiredScannerStatusFlow.tryEmit(ScannerSimpleStatus.Enabled) } - override fun remoteScannerNotification(deviceId: DeviceId, notifications: List) { - dataWedgeHardwareScanner.remoteScannerNotification(deviceId, notifications) + override fun remoteScannerNotifications(deviceId: DeviceId, vararg notifications: List) { + dataWedgeIHardwareScanner.remoteScannerNotifications(deviceId, *notifications) } //endregion @@ -64,7 +63,7 @@ class ParityFlowScannerController(dataWedgeHardwareScanner: DataWedgeHardwareSca private fun CoroutineScope.subscribeToScannerFlow() = launch { scannerOutputFlow().collect { - if(it is ScannerOutput.Status) { + if (it is ScannerOutput.Status) { actualScannerStatusEnumFlow.emit(it.scannerStatus.toScannerSimpleStatus()) } } @@ -76,8 +75,8 @@ class ParityFlowScannerController(dataWedgeHardwareScanner: DataWedgeHardwareSca Log.d("ParityFlowScannerController", "scannerStatusParityFlow: $actual, $desired") if (actual != desired) { when (desired) { - ScannerSimpleStatus.Disabled -> dataWedgeHardwareScanner.suspendScanner() - ScannerSimpleStatus.Enabled -> dataWedgeHardwareScanner.resumeScanner() + ScannerSimpleStatus.Disabled -> dataWedgeIHardwareScanner.suspendScanner() + ScannerSimpleStatus.Enabled -> dataWedgeIHardwareScanner.resumeScanner() } } }.collect() diff --git a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ScannerController.kt b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ScannerController.kt index 2ea044a..7841470 100644 --- a/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ScannerController.kt +++ b/kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/configuration/scanner/ScannerController.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow * The scanner controller makes it possible to suspend and resume the scanner and monitor [ScannerOutput] using a Flow */ abstract class ScannerController( - val dataWedgeHardwareScanner: DataWedgeHardwareScanner + val dataWedgeIHardwareScanner: IHardwareScanner ) { abstract fun scannerOutputFlow(): Flow @@ -16,6 +16,5 @@ abstract class ScannerController( abstract fun resumeScanner() - abstract fun remoteScannerNotification(deviceId: DeviceId, notifications: List) - + abstract fun remoteScannerNotifications(deviceId: DeviceId, vararg notifications: List) } \ No newline at end of file