Skip to content

Commit

Permalink
Began implementing ring scanner, adding remoteScannerNotification fun…
Browse files Browse the repository at this point in the history
…ction in order to send notifications to the ring scanner. Added helper classes for DeviceId and RemoteScannerNotification.
  • Loading branch information
jhetrifork committed Dec 14, 2023
1 parent e3f9dc4 commit 0c5949a
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 15 deletions.
5 changes: 5 additions & 0 deletions kotlin-data-wedge-lib/src/main/java/dk/gls/kdw/KDW.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dk.gls.kdw

import dk.gls.kdw.implementation.KDWImplementation

object KDW : KDWImplementation()
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -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)
Expand Down Expand Up @@ -84,20 +96,41 @@ 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<RemoteScannerNotification>) {
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 **/
private suspend fun subscribeToScannerFlow() {
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) {
Expand All @@ -107,6 +140,11 @@ class DataWedgeHardwareScanner(

scannerStatus?.let {
val statusEnum = it.toScannerStatusEnum()


requestEnumerateScanners()


trySendBlocking(ScannerOutput.Status(statusEnum))
}
}
Expand All @@ -117,6 +155,19 @@ class DataWedgeHardwareScanner(
}
}
}
if (intent.hasExtra(RESULT_ENUMERATE_SCANNERS)) {
val scannerList = intent.getSerializableExtra(RESULT_ENUMERATE_SCANNERS) as ArrayList<Bundle>
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())
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ interface HardwareScanner {
fun scannerOutputFlow(): Flow<ScannerOutput>
fun suspendScanner()
fun resumeScanner()
fun remoteScannerNotification(deviceId: DeviceId, notifications: List<RemoteScannerNotification>)
}
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down Expand Up @@ -51,6 +52,10 @@ class ParityFlowScannerController(dataWedgeHardwareScanner: DataWedgeHardwareSca
desiredScannerStatusFlow.tryEmit(ScannerSimpleStatus.Enabled)
}

override fun remoteScannerNotification(deviceId: DeviceId, notifications: List<RemoteScannerNotification>) {
dataWedgeHardwareScanner.remoteScannerNotification(deviceId, notifications)
}

//endregion

private val scannerResult = MutableSharedFlow<ScannerOutput>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ abstract class ScannerController(

abstract fun resumeScanner()

abstract fun remoteScannerNotification(deviceId: DeviceId, notifications: List<RemoteScannerNotification>)

}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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,
Expand All @@ -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
Expand All @@ -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()
}
Original file line number Diff line number Diff line change
@@ -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 <a href="https://techdocs.zebra.com/datawedge/13-0/guide/programmers-guides/dw-programming/">For official documentation </a> under 'Data Capture'
Expand Down

0 comments on commit 0c5949a

Please sign in to comment.