I want to read barcodes using a bluetooth barcode scanner.
I don't want to use Bluetooth Keyboard Emulation (HID) mode, because is too hard to point to a textbox before any scan.
I read this developer.android.com/guide/topics/connectivity/bluetooth.html but I don't found yet something usable.
Must listen for an write event with a end-code delimiter (CR, LF, etc).
If your bluetooth barcode scanner does not have a switch* for change HID mode to SSP mode, then you can't connect with him. (* hardware or software switch)
Android connect natively with HID bluetooth (Human Interface Device) and don't let them go :).
So, I solve my problem reading and overriding a keyboard event.
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (barCodeRadearIsOn && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER || (event.getKeyCode() >= 7 && event.getKeyCode() <= 16))) {
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
if (event.getAction() == KeyEvent.ACTION_UP){
Toast.makeText(context, barCode, Toast.LENGTH_LONG).show();
....... .......
barCode = "";
}
} else {
if (event.getAction() == KeyEvent.ACTION_UP){
barCode = barCode + (char)event.getUnicodeChar();
}
}
return true;
} else {
return super.dispatchKeyEvent(event);
}
}
Notes:
barCodeRadearIsOn - users have a switch on/off
This code "intercept" only Enter and numeric characters from 0 to 9.
Related
I'm building a basic price checker app that scans a barcode and displays information for the product and am trying to run it on an android-powered tablet that comes with a built-in barcode scanner.
The scanner works and if I put a textbox on the app and focus to it, the barcode I scan gets written onto it just fine - however I have been unable to catch the input without having the app focus on a textbox (the app should have no input areas, only images and textview labels).
The scanner shows up as an HID keyboard on the input android settings.
Almsot all the posts I find here are about using the camera to scan barcodes (built my original prototype using this but performance was subpar). One old post here gave me a hint about overriding the dispatchKeyEvent as so
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getCharacters() != null && !event.getCharacters().isEmpty()) {
isRunning = true;
Log.d(TAG, "Starting");
String barcode = event.getCharacters();
new myImageTask().execute(barcode);
}
return super.dispatchKeyEvent(event);
}
However it doesn't seem to be catching any input.
I looked at overriding KeyUp and KeyDown events but they seem to be explicitly built for catching single key events.
Is there another event I could use to catch and read the scanner's full input or should I just chain the KeyDown event to buffer each individual key into a static variable and, after receiving a special input termination character and run my task on the result?
barcodeEditText.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN)
{
switch (keyCode)
{
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
saveToDBMethod();
barcodeEditText.setText("");
barcodeEditText.requestFocus();
return true;
default:
break;
}
}
return false;
}
});
It may be a hardware configuration trouble. In my case, using Honeywell Android devices with barcode scans, I always have to go to the scan settings and set in barcode reading options the wedge method to keyboard
Edit: KeyEvent.getCharacters() was deprecated in Android 29, so I am not sure the below is a viable long-term solution.
I know this was asked a few years ago, but I am able to capture barcode scans from both a Honeywell and Zebra devices, running Android 11 and 10, respectively, by overriding onKeyMultiple in MainActivity:
#Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
System.out.println("Key Multiple event: " + event.getCharacters());
return super.onKeyMultiple(keyCode, repeatCount, event);
}
Even when I don't have an input in focus, the above fires when I perform a scan. Output:
Key Multiple event: some-barcode
I wanted to check programmatically that whether the input given by user is either from soft keyboard or the barcode scanner attached to the android tablet.
There is no edit text in activity where I want to apply this so please avoid providing solutions that are applicable through EditText.
With dispatchKeyEvent you can listen for any KeyEvent from the barcode scanner.
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
// do something on input
return false; // prevent default behaviour
}
Use following code to read input/values from barcode scanner, so onKeyDown you need to override in your activity/dialog
String barcode="";
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
log("Key Down keyCode " + keyCode);
if (keyCode == KeyEvent.KEYCODE_BACK) {
return super.onKeyDown(keyCode, event);
} else if (keyCode == KeyEvent.KEYCODE_ENTER) {//if scanner doesn't return enter key code then make sure that any view must not have focus in window
//write your code to process the scanned barcode input
barcode = "";
} else {
Character input = (char) event.getUnicodeChar();
log("Scanner Input " + input);
if (Character.isDigit(input) || Character.isLetter(input)) {
barcode += input;//concat the characters
}
}
return true;
}
When I push Volume up/down from Bluetooth headset, I want to capture KeyCode of VolumeKey.
I can get KeyCode of KEYCODE_MEDIA_PLAY, KEYCODE_MEDIA_PAUSE, KEYCODE_MEDIA_NEXT and KEYCODE_MEDIA_PREVIOUS.
But I just can not get KeyCode of volume.
Do you have any solution?
If you have it, please let me know.
I think key events of different Bluetooth headsets vary and configurable.
But in general, try capture KeyEvent.KEYCODE_VOLUME_UP and KeyEvent.KEYCODE_VOLUME_DOWN.
use this to get the key events and then filter them accordingly to your need!
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
...
return true;
}else if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP)){
...
return true;
}else
return super.onKeyDown(keyCode, event);
}
I am working on a project for which I want to handle long press of my play button on bluetooth device.
For now it is working for a single click.
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
if (!Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
return;
}
KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event == null) {
return;
}
int action = event.getAction();
if (event.getKeyCode() == 126 || event.getKeyCode() == 127) {
// do something
if (action == KeyEvent.ACTION_DOWN) {
Toast.makeText(context,"BUTTON PRESSED!", Toast.LENGTH_LONG).show();
if(event.isLongPress()==true)
{
Toast.makeText(context,"Finally long press worked!!", Toast.LENGTH_LONG).show();
}
}
}
}
The method isLongPress() always returns false.
Please let me what modification can make this program work.
Thanks in advance :)
check the instruction of your BT device. Longpress calling key on headset usually means rejecting an incoming call. I am not sure if longpress Play key on headset is defined in AVRCP.
Hey, I've just started to learn Android development and ran into a problem.
Controls in the game I'm making work on virtual device, but not on phone:
I have an Xperia X10 Mini Pro
I'm making a basic Pong game to learn droid software development
The game works just fine on my Android virtual device, you can move the paddles up and down smoothly
On my phone I've figured that the onKeyDown event doesn't run until I release the button or after I've held down the button for a second or two, but then it only registers it as a brief press of the button, not like if I was holding it down
I believe that it's a feature of my phone to quickly access special characters, because some keys register different key codes when pressed quickly and when held down
The problems this results in is that I can not move the paddles, but I can do single press things, like pause the game
I can also add:
Game is heavily built around sample app LunarLander from the SDK
Lunar lander works fine in virtual device but has same issues as my pong when put in my phone
How could I force my phone to register onKeyDown events like it should? (Or at least like the virtual device does?)
Code from my view class that extends surfaceView:
#Override
public boolean onKeyDown(int keyCode, KeyEvent msg) {
return thread.doKeyDown(keyCode, msg);
}
#Override
public boolean onKeyUp(int keyCode, KeyEvent msg) {
return thread.doKeyUp(keyCode, msg);
}
Code from within the thread:
boolean doKeyDown(int keyCode, KeyEvent msg) {
synchronized (mSurfaceHolder) {
mP1Score = keyCode;//For debugging
boolean okStart = false;
if (keyCode == KeyEvent.KEYCODE_SPACE) okStart = true;
if (mMode == STATE_PAUSE && okStart) {
setState(STATE_RUNNING);
return true;
} else if (mMode == STATE_READY && okStart) {
setState(STATE_RUNNING);
return true;
} else if (mMode == STATE_GOAL && okStart) {
return true;
}else if (mMode == STATE_END_GAME && okStart) {
doStart();
return true;
} else if (mMode == STATE_RUNNING) {
if (keyCode == KeyEvent.KEYCODE_Q) {
mP1dY = -PLAYER_SPEED;//Player 1 up
return true;
} else if (keyCode == KeyEvent.KEYCODE_A) {
mP1dY = PLAYER_SPEED;//Player 1 down
return true;
} else if (keyCode == KeyEvent.KEYCODE_O) {
mP2dY = -PLAYER_SPEED;//Player 2 up
return true;
} else if (keyCode == KeyEvent.KEYCODE_L) {
mP2dY = PLAYER_SPEED;//Player 2 down;
return true;
} else if (keyCode == KeyEvent.KEYCODE_SPACE) {
pause();//Space is pressed in game
return true;
}
}
return false;
}
}
boolean doKeyUp(int keyCode, KeyEvent msg) {
boolean handled = false;
mP2Score = keyCode;//For debugging
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING) {
if (keyCode == KeyEvent.KEYCODE_Q
|| keyCode == KeyEvent.KEYCODE_A) {
mP1dY = 0;
handled = true;
} else if (keyCode == KeyEvent.KEYCODE_O
|| keyCode == KeyEvent.KEYCODE_L) {
mP2dY = 0;
handled = true;
}
}
}
return handled;
}
Complete source available here
Here's a sort-of-solution:
The problem is SE's default input method on the X10 Mini Pro. By installing a different input method on the phone (HTC_IME in my case) I can get controls to work like they do on the virtual device.
Now I only need to figure out how to make it work with the default input method and I'll have a complete solution.