Pierrick Valentin
Pierrick Valentin

Reputation: 21

How to configure a Zebra TC21 Datawedge profile programatically in an Android Kotlin app?

I am developing an Android inventory app in Kotlin for Zebra TC21 devices, and I would like to configure a Datawedge profile programmatically. I need to scan qr codes with the integrated scanner, and RFID tags with a Zebra RFD4031. I would like the scanned data to be transmitted by "Intent output" with Broadcast mode. I also want the "key output" to be disabled.

I tried with this code:

class DatawedgeConfig {
    val baseConfig = createBaseConfig()

    fun initialize(context: Context) {
        try {
            createProfile(context)
            configureProfile(context)
            configureInput(context)
            configureOutput(context)
            Log.d("DatawedgeConfig", "DataWedge initialized successfully")
        } catch (e: Exception) {
            Log.e("DatawedgeConfig", "Error initializing DataWedge", e)
        }
    }

    private fun createBaseConfig(): Bundle {
        return Bundle().apply {
            putString("PROFILE_NAME", DATAWEDGE_PROFILE_NAME)
            putString("PROFILE_ENABLED", "true")
            putString("CONFIG_MODE", "UPDATE")
        }
    }

    fun createProfile(context: Context) {
        val intent = Intent()
        intent.action = "com.symbol.datawedge.api.ACTION"
        intent.putExtra("com.symbol.datawedge.api.CREATE_PROFILE", DATAWEDGE_PROFILE_NAME)
        try {
            context.sendBroadcast(intent)
            Log.d("DatawedgeConfig", "Profile created successfully")
        } catch (e: Exception) {
            Log.e("DatawedgeConfig", "Error creating profile", e)
        }
    }

    fun configureProfile(context: Context) {
        val intent = Intent()
        intent.action = "com.symbol.datawedge.api.ACTION"
        intent.putExtra("com.symbol.datawedge.api.SET_CONFIG", Bundle().apply {
            baseConfig.putParcelableArray("APP_LIST", arrayOf(Bundle().apply {
                putString("PACKAGE_NAME", context.packageName)
                putStringArray("ACTIVITY_LIST", arrayOf("*"))
            }))
        })

        Log.d("DataWedgeConfig", "Configuring profile: $baseConfig")

        try {
            context.sendBroadcast(intent)
            Log.d("DatawedgeConfig", "Profile configured successfully (PACKAGE_NAME : ${context.packageName})")
        } catch (e: Exception) {
            Log.e("DatawedgeConfig", "Error configuring profile", e)
        }
    }

    fun configureInput(context: Context) {
        val intent = Intent()
        intent.action = "com.symbol.datawedge.api.ACTION"
        intent.putExtra("com.symbol.datawedge.api.SET_CONFIG", Bundle().apply {
            baseConfig.putParcelableArray("PLUGIN_CONFIG", arrayOf(Bundle().apply {
                putString("PLUGIN_NAME", "BARCODE")
                putString("RESET_CONFIG", "true")
                putBundle("PARAM_LIST", Bundle().apply {
                    putString("scanner_selection", "auto")
                    putString("decoder_rfid", "true")
                    putString("decoder_qr_code", "true")
                })
            }))
        })
        try {
            context.sendBroadcast(intent)
            Log.d("DatawedgeConfig", "Input configured successfully")
        } catch (e: Exception) {
            Log.e("DatawedgeConfig", "Error configuring input", e)
        }
    }

    fun configureOutput(context: Context) {
        val intent = Intent()
        intent.action = "com.symbol.datawedge.api.ACTION"
        intent.putExtra("com.symbol.datawedge.api.SET_CONFIG", Bundle().apply {
            baseConfig.putParcelableArray("PLUGIN_CONFIG", arrayOf(Bundle().apply {
                putString("PLUGIN_NAME", "INTENT")
                putString("RESET_CONFIG", "true")
                putBundle("PARAM_LIST", Bundle().apply {
                    putString("intent_output_enabled", "true")
                    putString("intent_action", DATAWEDGE_ACTION)
                    putString("intent_delivery", "2")
                })
            }))
        })
        try {
            context.sendBroadcast(intent)
            Log.d("DatawedgeConfig", "Output configured successfully")
        } catch (e: Exception) {
            Log.e("DatawedgeConfig", "Error configuring output", e)
        }
    }
}

The profile is actually created if it doesn't exist, but none of the options in the "SET_CONFIG" bundle is apllied. So, my app isn't associated with the created profile, and the intent output isn't neither enabled nor configured with the given values. I don't understand why.

Upvotes: 1

Views: 162

Answers (1)

Pierrick Valentin
Pierrick Valentin

Reputation: 21

I've finally found a solution. I share it for those who'd be interested:

import android.content.Context
import android.content.Intent
import android.os.Bundle
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class DWConfig @Inject constructor(
    @ApplicationContext private val context: Context,
) {
    val setConfigBundle = Bundle().apply {
        putString("PROFILE_NAME", DATAWEDGE_PROFILE_NAME)
        putString("PROFILE_ENABLED", "true")
        putString("CONFIG_MODE", "CREATE_IF_NOT_EXIST")
    }

    val appConfig = Bundle().apply {
        putString("PACKAGE_NAME", context.packageName)
        putStringArray(
            "ACTIVITY_LIST", arrayOf(
                "${context.packageName}.MainActivity",
            )
        )
    }

    val barcodeParamList = Bundle().apply {
        putString("scanner_input_enabled", "true")
        putString("scanner_selection", "auto")
        putString("charset_name", "ISO-8859-1")
        putString("auto_charset_preferred_order", "UTF-8;GB2312")
        putString("auto_charset_failure_option", "UTF-8")
        putString("volume_slider_type", "3")
    }

    val barcodeConfigBundle = Bundle().apply {
        putString("PLUGIN_NAME", "BARCODE")
        putString("RESET_CONFIG", "true")
    }

    val intentParamList = Bundle().apply {
        putString("intent_output_enabled", "true")
        putString("intent_action", DATAWEDGE_INTENT_ACTION)
        putString("intent_delivery", "2")
    }

    val intentConfigBundle = Bundle().apply {
        putString("PLUGIN_NAME", "INTENT")
        putString("RESET_CONFIG", "true")
    }

    val rfidParamList = Bundle().apply {
        putString("rfid_input_enabled", "true")
        putString("rfid_beeper_enable", "false")
        putString("rfid_led_enable", "true")
        putString("rfid_antenna_transmit_power", "30")
        putString("rfid_memory_bank", "3")
        putString("rfid_session", "1")
        putString("rfid_trigger_mode", "0")
        putString("rfid_filter_duplicate_tags", "true")
        putString("rfid_hardware_trigger_enabled", "true")
        putString("rfid_tag_read_duration", "250")
    }

    val rfidConfigBundle = Bundle().apply {
        putString("PLUGIN_NAME", "RFID")
        putString("RESET_CONFIG", "true")
    }

    val keystrokeParamList = Bundle().apply {
        putString("keystroke_output_enabled", "false")
    }

    val keystrokeConfigBundle = Bundle().apply {
        putString("PLUGIN_NAME", "KEYSTROKE")
        putString("RESET_CONFIG", "true")
    }

    private fun setAppList() {
        setConfigBundle.putParcelableArray(
            "APP_LIST", arrayOf(
                appConfig
            )
        )
    }
    
    private fun setPluginConfig() {
        setConfigBundle.remove("PLUGIN_CONFIG")
        barcodeConfigBundle.putBundle("PARAM_LIST", barcodeParamList)
        intentConfigBundle.putBundle("PARAM_LIST", intentParamList)
        rfidConfigBundle.putBundle("PARAM_LIST", rfidParamList)
        keystrokeConfigBundle.putBundle("PARAM_LIST", keystrokeParamList)

        setConfigBundle.putParcelableArrayList(
            "PLUGIN_CONFIG", arrayListOf(
                barcodeConfigBundle,
                intentConfigBundle,
                rfidConfigBundle,
                keystrokeConfigBundle
            )
        )
    }

    private fun sendConfig() {
        val intent = Intent().apply {
            action = "com.symbol.datawedge.api.ACTION"
            putExtra("com.symbol.datawedge.api.SET_CONFIG", setConfigBundle)
        }

        context.sendBroadcast(intent)
    }

    fun initialize() : Boolean {
        try {
            
            setAppList()
            setPluginConfig()
            sendConfig()
            return true
            
        } catch (e: Exception) {
            
            Log.e("DWConfig", "Error initializing DataWedge", e)
            return false
            
        }
    }
}

I call initialize() method during the launch of my app:

@HiltViewModel
class MainViewModel @Inject constructor(
    private val dwConfig: DWConfig
) : ViewModel() {

    fun initializeDataWedge(): Boolean {
        return dwConfig.initialize()
    }

    ...

}
@HiltAndroidApp
class MainApplication : Application() {
    @Composable
    fun App(activity: MainActivity, mainViewModel: MainViewModel) {

        LaunchedEffect(Unit) {

            val dataWedgeJob = async { mainViewModel.initializeDataWedge() }
            
            ...

            dataWedgeJob.await()

            ...
}

I found most of the informations that I needed here (unfortunately, all the examples are written in Java) : https://techdocs.zebra.com/datawedge/13-0/guide/api/setconfig/

Almost all the parameters that you can configure in the Datawedge App are referenced here with their ids and their possible values that you can set programmatically.

Upvotes: 1

Related Questions