User Level

The User Level regroups the features that have an impact on the user experience.

The Socket barcode scanners provide ways to notify the user when the barcode read is correct or incorrect without the need for the user to check the screen of the host.

The scanner has 3 types of feedback: sound, LED and vibrate.

For example, depending on the environment, you may want to turn off the sound and use only the vibration.

Here are some examples on how to use these feedback mechanisms.

Turning off the Sound

Turning off the good read sound is a simple 2 step process. Since this setting is persistent on the scanner, it is best to first read this setting when the scanner connects and depending on its state, either change it or just continue on.

Let’s imagine we would like to offer to the user a switch button in the UI to turn on or off the beep when scanning a barcode.

The didNotifyArrivalForDevice delegate is used to request the actual state of the scanner local decode action so the switch to configure this setting could be positioned accordingly to the actual state of the scanner decode action.

The code might look like this:

  • Swift
  • ObjectiveC
func didNotifyArrivalForDevice(_ device: CaptureHelperDevice, withResult result: SKTResult) {
    print("didNotifyArrivalForDevice: \(String(describing: device.deviceInfo.name))")
    self.statusLabel.text = device.deviceInfo.name

    device.getDecodeActionWithCompletionHandler { (result: SKTResult, decodeAction:SKTCaptureLocalDecodeAction?) in
        print("get decode action returns \(result.rawValue)")
        if result == SKTCaptureErrors.E_NOERROR {
            device.decodeAction = decodeAction!
            DispatchQueue.main.async {
                self.beepOnOffSwitch.isEnabled = true
                if decodeAction!.contains(.beep) {
                  self.beepOnOffSwitch.isOn = true
                } else {
                    self.beepOnOffSwitch.isOn = false
                }
            }
        }
    }
    lastDevice = device
}
-(void)didNotifyArrivalForDevice:(SKTCaptureHelperDevice*) device withResult:(SKTResult) result{
    NSLog(@"Receive device arrival for %@", device.friendlyName);
    dispatch_async(dispatch_get_main_queue(), ^{
        _statusLabel.text = device.friendlyName;
    });

    // ask for the device Battery Level
    [device getBatteryLevelWithCompletionHandler:^(SKTResult result, NSInteger levelInPercentage) {
        [self displayBatteryLevel: levelInPercentage];
    }];

    [device getDecodeActionWithCompletionHandler:^(SKTResult result, SKTCaptureLocalDecodeAction decodeAction) {
        if (result == SKTCaptureE_NOERROR){
            device.localDecodeAction = decodeAction;
            dispatch_async(dispatch_get_main_queue(), ^{
                if((decodeAction&SKTCaptureLocalDecodeActionBeep) == SKTCaptureLocalDecodeActionBeep){
                    [[self beepSwitch]setOn: TRUE];
                }
                else {
                    [[self beepSwitch]setOn: FALSE];
                }
                [[self beepSwitch]setEnabled:TRUE];
            });
        }
    }];
    _lastDeviceConnected = device;
}

Note

The completion handler of getDecodeActionWithCompletionHandler has the code refreshing the UI in the main dispatch queue. This is important because the UI controls can only be updated from the main UI thread. This could be also done by setting the property dispatchQueue of CaptureHelperDevice to DipatchQueue.main in which case the completion handler execution will always occur in the main thread.

Then the handler of the beepOnOffSwitch switch is in charge of turning off or on the beep when the scanner reads a barcode and the code could look like this:

  • Swift
  • ObjectiveC
@IBAction func didBeepOnOffSwitch(_ sender: Any) {
    beepOnOffSwitch.isOn = !beepOnOffSwitch.isOn
    beepOnOffSwitch.isEnabled = false
    if let device = lastDevice as CaptureHelperDevice! {
        var decodeAction = device.decodeAction
        if beepOnOffSwitch.isOn == true {
            decodeAction.insert(.beep)
        } else {
            decodeAction.remove(.beep)
        }
        device.setDecodeAction(decodeAction, withCompletionHandler: { (result: SKTResult) in
            if result == SKTCaptureErrors.E_NOERROR {
                device.decodeAction = decodeAction
            } else {
                self.beepOnOffSwitch.isOn = !self.beepOnOffSwitch.isOn
            }
            self.beepOnOffSwitch.isEnabled = true
        })
    }
}
-(IBAction)didChangeBeepSwitch:(id)sender {
    SKTCaptureLocalDecodeAction decodeAction = _lastDeviceConnected.localDecodeAction;
    if( [[self beepSwitch]isOn]){
        decodeAction = decodeAction | SKTCaptureLocalDecodeActionBeep;
    }
    else{
        decodeAction = decodeAction& ~SKTCaptureLocalDecodeActionBeep;
    }
    [_lastDeviceConnected setDecodeAction:decodeAction completionHandler:^(SKTResult result) {
        NSLog(@"Setting the Decode Action returned: %ld", (long)result);
        if (result == SKTCaptureE_NOERROR){
            _lastDeviceConnected.localDecodeAction = decodeAction;
        }
        else {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[self beepSwitch]setOn:![[self beepSwitch]isOn]];
            });
        }
    }];
}

Note

This code update the UI controls directly in the completion handler and that is possible only if the dispatchQueue of the device object has been previously set to DispatchQueue.main. This could be done in the didNotifyArrivalForDevice delegate.

The current state of the device decode action is saved by adding a computed property decodeAction in an extension for CaptureHelperDevice. Since a Swift extension class cannot declare properties, the original CaptureHelperDevice and CaptureHelper classes both provide a extensionProperties member which is a dictionary with a string as key and Any as value that can be used to implement this kind of feature.

So in this particular example our extension class could look like this:

  • Swift
  • ObjectiveC
extension CaptureHelperDevice {
  var decodeAction : SKTCaptureLocalDecodeAction {
      get {
          return extensionProperties["decodeAction"] as! SKTCaptureLocalDecodeAction
      }
      set (newValue){
          extensionProperties["decodeAction"] = newValue
      }
  }
}
#import "SktCaptureHelper.h"

@interface SKTCaptureHelperDevice (Persistence)
@property (getter=getLocalDecodeAction, setter=setLocalDecodeAction:)SKTCaptureLocalDecodeAction localDecodeAction;

@end

Here the decode action is stored in the extensionProperties of the CaptureHelperDevice class. That’s how we can keep the actual value of the decode action by adding this computed property: decodeAction.

Locate the Scanner

‘’Locate the Scanner’’ might be a nice feature to help the user identify which scanner is theirs in a situation where more than one scanner is in the area. This feature could be implemented with a repeated action of sending a Data Confirmation to the scanner to cause the scanner to beep or flash or vibrate. Here is code example of a command that would need to be in a timer handler:

  • Swift
  • ObjectiveC
if let device = lastDevice as CaptureHelperDevice! {
    device.setDataConfirmationWithLed(.green, withBeep: .good, withRumble: .good, withCompletionHandler: { (
        result: SKTResult) in
      print("setDataConfirmation returns \(result.rawValue)")
    })
}
if (_lastDeviceConnected != nil) {
    [_lastDeviceConnected setDataConfirmationWithLed:SKTCaptureDataConfirmationLedGreen
                          withBeep:SKTCaptureDataConfirmationBeepGood
                          withRumble:SKTCaptureDataConfirmationRumbleGood
                          completionHandler:^(SKTResult result) {
        NSLog(@"setDataConfirmation returns: %ld",(long)result);
    }];
}

The lastDevice in this code is set to a CaptureHelperDevice instance in the didNotifyArrivalForDevice delegate to reference the last connected device.

Note

Triggering the scanner remotely shows the scanner aiming light which could also help to find or identify the connected scanner. This use requires caution though because it might scan a barcode.

Wrong Barcode Indication

Wrong barcode indication can be useful when a user scans a barcode but that barcode was not expected at that moment in the application or is not the expected symbology or format. Of course the application UI could display a user friendly error, but maybe the user is scanning a bunch of barcodes without looking at the screen. So sending back to the user an indication that something is wrong after having scanning a barcode might be useful.

Here is an example of code that can be invoked when such a condition occurs in the application:

  • Swift
  • ObjectiveC
device.setDataConfirmationWithLed(.red, withBeep: .bad, withRumble: .bad, withCompletionHandler: { (
    result: SKTResult) in
  print("setDataConfirmation returns \(result.rawValue)")
})
[device setDataConfirmationWithLed:SKTCaptureDataConfirmationLedRed
        withBeep:SKTCaptureDataConfirmationBeepBad
        withRumble:SKTCaptureDataConfirmationRumbleBad
        completionHandler:^(SKTResult result) {
      NSLog(@"setDataConfirmation returns: %ld",(long)result);
}];

The device in this code is a CaptureHelperDevice object instance.

Disabling the Scanner Trigger Button

Upon detection of a wrong barcode and requiring the user to acknowledge an eventual informational message on the host screen, the Scanner Trigger button can be disabled. Here is a sample code for disabling the Scanner Trigger button:

  • Swift
  • ObjectiveC
device.setTrigger(.disable, withCompletionHandler: { (result: SKTResult, _ propertyResult: SKTCaptureProperty?) in
  print("disabling the trigger returns \(result.rawValue)")
})
SKTCaptureTrigger trigger = SKTCaptureTriggerDisable;
[_lastDeviceConnected setTrigger:trigger completionHandler:^(SKTResult result, SKTCaptureProperty *propertyResult) {
  NSLog(@"The trigger is %ld with result %ld",(long)trigger,(long)result);
}];

And to re-enable the button:

  • Swift
  • ObjectiveC
device.setTrigger(.enable, withCompletionHandler: { (result: SKTResult, _ propertyResult: SKTCaptureProperty?) in
  print("enabling the trigger returns \(result.rawValue)")
})
SKTCaptureTrigger trigger = SKTCaptureTriggerEnable;
[_lastDeviceConnected setTrigger:trigger completionHandler:^(SKTResult result, SKTCaptureProperty *propertyResult) {
  NSLog(@"The trigger is %ld with result %ld",(long)trigger,(long)result);
}];

The Device in this code is a CaptureHelperDevice object instance.

Note

The Scanner can be configured with a Data Confirmation Mode set to either the application or to Capture. In both cases, the trigger is disabled until the data is confirmed or a timeout has elapsed. Please refer to the Application Level Data Confirmation from the App.