Several people have already received their samples. I've got more requests about samples, so I think about going for a short pick-and-place assembly run. Hand-soldering is OK for 1-2 prototypes, otherwise it just takes way too much time. Currently I'm waiting to get quotes.
Here's a simple "getting started" guide:
Device Manager (InputStickUtility):
To use InputStick you have to install DeviceManager app on your Android phone.
Installation:
- Make sure that "allow installation of non-market applications" is checked in your devices settings.
- Copy DeviceManager.apk to your device and install it.
Pairing with InputStick:
- Plug InputStick into any USB port in order to power it up.
- Run DeviceManager, if Bluetooth is disabled it will ask you to enable it.
- Manage devices -> Add device -> Discover device -> Select device form the list -> Add device.
- By default it will be named "Dev-00" and set as "Home", however application will ask you if you want to edit this.
Settings:
Dialog settings:
- Always ask: each time you will be asked to manually select InputStick device that you want to connect to. Use this if you want to be sure that no application will be able to connect to InputStick without you knowing.
- Ask when more than 1 [Default]: you will be asked to select device only when more than one InputStick is paired with your phone. Otherwise it will connect automatically.
- Never ask: you won't be bothered with dialog. If there is more than one device paired, it will attempt to connect to the one marked as "Default device".
Toast settings:
- Show all - show all toasts, useful mainly in my case.
- Show important - show only important toasts, useful for application developers.
- Show none [Default] : DeviceManager won't be displaying any Toast messages.
Status Bar Notifications:
- Enabled - notification will be displayed when InputStick device is in use.
- Disabled - no notifications will be displayed.
Demo apps:
Use Connect/Disconnect button, exact behaviour depends on configuration of DeviceManager. If it is the first time that you are using your InputStick device you will be asked to enter PIN code (1234), unless you have already paired it manually.
BUG: if attempt to establish Bluetooth connection fails (InputStick not plugged in, out of range etc), pressing "Connect" again will do nothing. You have to kill the app and try again. Next API release will solve this issue.
Depending on USB host, OS, and settings it may take some time to detect new hardware and install drivers. During this period you won't be able to
use application, even though it may appear to be ready. Next time, this should be much faster (OS will recognize the device using PID/VID pair).
API & Demos:
Import InputStickLibrary project into Eclipse:
- File -> Import -> Existing projects into workspace -> browse -> select InputStickLibrary directory -> check "Copy into workspace" -> Finish
Depending on your ADT version you may get some error messages, in such case go to:
- Project Properties -> Android -> Select build target -> OK
- Android Tools -> Fix project properties
This should fix all error messages. Do the same for demo projects.
Starting new project:
- Create new Android project. Choose minimum SDK > 2.3.
- Project Properties -> Android -> Add -> Select InputStickLibrary -> OK
Using API in your project:
Let's take "HelloInputStick" project as an example. This simple app uses USBKeyboard class to type:
Hello world!
XyZ
This version is a little bit different from the one posted some time ago. Comments should explain everything. (GitHub)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.helloinputstick; | |
import android.app.Activity; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.view.View.OnClickListener; | |
import android.widget.Button; | |
import com.example.inputsticklibrary.usb.USBDevice; | |
import com.example.inputsticklibrary.usb.USBDeviceListener; | |
import com.example.inputsticklibrary.usb.devices.USBKeyboard; | |
//USBDeviceListener interface allows to receive callbacks | |
public class HelloInputStick extends Activity implements USBDeviceListener { | |
//create new instance of USBKeyboard | |
//if your app consists of more than one Activity | |
//it might be a good idea to use some sort of Singleton class to share USBKeyboard | |
private static final USBKeyboard keyb = new USBKeyboard(); | |
private Button buttonConnect; | |
private Button buttonType; | |
//called when data is received form USB host | |
@Override | |
public void onUSBData(int endpoint, byte[] data) { | |
// TODO Auto-generated method stub | |
//USBKeyboard already takes care of handling NumLock/CapsLock/ScrollLock state | |
} | |
//Called when connection state has changed, update UI | |
public void onUSBEvent(int code) { | |
manageUI(); | |
} | |
//Set appropriate caption for buttonConnect, depending on current connection state | |
//Enable buttonType only if InputStick has been successfully enumerated | |
private void manageUI() { | |
int state = keyb.getState(); | |
switch (state) { | |
case USBDevice.STATE_NONE: | |
buttonConnect.setText(getString(R.string.string_connect)); | |
buttonConnect.setEnabled(true); | |
enableUI(false); | |
break; | |
case USBDevice.STATE_CONNECTING: | |
buttonConnect.setText(getString(R.string.string_connecting)); | |
buttonConnect.setEnabled(false); | |
enableUI(false); | |
break; | |
case USBDevice.STATE_CONNECTED: | |
buttonConnect.setText(getString(R.string.string_disconnect)); | |
buttonConnect.setEnabled(true); | |
enableUI(false); | |
break; | |
case USBDevice.STATE_READY: | |
buttonConnect.setText(getString(R.string.string_disconnect)); | |
buttonConnect.setEnabled(true); | |
enableUI(true); | |
break; | |
} | |
} | |
private void enableUI(boolean enabled) { | |
buttonType.setEnabled(enabled); | |
} | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_hello_input_stick); | |
//Pass application context! | |
//It will allow to bind to InputStickService (part of DeviceManager app) | |
keyb.setContext(this.getApplicationContext()); | |
buttonConnect = (Button) findViewById(R.id.buttonConnect); | |
buttonConnect.setOnClickListener(new OnClickListener() { | |
public void onClick(View arg0) { | |
//Action depends on current connection state | |
switch (keyb.getState()) { | |
case USBDevice.STATE_NONE: | |
keyb.connect(); | |
break; | |
case USBDevice.STATE_CONNECTED: | |
case USBDevice.STATE_READY: | |
keyb.disconnect(); | |
break; | |
} | |
} | |
}); | |
buttonType = (Button) findViewById(R.id.buttonType); | |
//choose one! | |
buttonType.setOnClickListener(new MyOnClickListener()); | |
//buttonType.setOnClickListener(new MyOnClickListenerCaps()); | |
//buttonType.setOnClickListener(new MyOnClickListenerLayout()); | |
} | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
//register as a listener for callbacks | |
keyb.registerListener(this); | |
//Update UI depending on current connection state | |
manageUI(); | |
} | |
@Override | |
protected void onPause() { | |
super.onPause(); | |
//Activity is paused, unregister listener | |
keyb.unregisterListener(); | |
} | |
//1) Simple case: ignore CapsLock and assume keyboard layout used in OS is set to EN-US or compatible | |
private class MyOnClickListener implements OnClickListener { | |
@Override | |
public void onClick(View arg0) { | |
//SHIFT key + H key = 'H' | |
keyb.pressAndRelease(USBKeyboard.SHIFT_LEFT, USBKeyboard.KEY_H); | |
//E key = 'e' | |
keyb.pressAndRelease(USBKeyboard.NONE, USBKeyboard.KEY_E); | |
//'llo world!', USBKeyboard class takes care of adding SHIFT key when necessary | |
keyb.type("llo world!"); | |
//press ENTER key | |
keyb.pressAndRelease(USBKeyboard.NONE, USBKeyboard.KEY_ENTER); | |
//type 'XyZ' | |
keyb.type("XyZ"); | |
} | |
} | |
//2) Take state of CapsLock into account | |
private class MyOnClickListenerCaps implements OnClickListener { | |
@Override | |
public void onClick(View arg0) { | |
if (keyb.isCapsLockOn()) { | |
//CapsLock is on! Change case of keys affected by CapsLock | |
keyb.type("hELLO WORLD!"); | |
keyb.pressAndRelease(USBKeyboard.NONE, USBKeyboard.KEY_ENTER); | |
keyb.type("xYz"); | |
} else { | |
keyb.pressAndRelease(USBKeyboard.SHIFT_LEFT, USBKeyboard.KEY_H); | |
keyb.pressAndRelease(USBKeyboard.NONE, USBKeyboard.KEY_E); | |
keyb.type("llo world!"); | |
keyb.pressAndRelease(USBKeyboard.NONE, USBKeyboard.KEY_ENTER); | |
keyb.type("XyZ"); | |
} | |
} | |
} | |
//3) Assume that USB host uses different keyboard layout: qwertz instead of qwerty | |
private class MyOnClickListenerLayout implements OnClickListener { | |
@Override | |
public void onClick(View arg0) { | |
if (keyb.isCapsLockOn()) { | |
//CapsLock is on! Change case of keys affected by CapsLock | |
keyb.type("hELLO WORLD!"); | |
keyb.pressAndRelease(USBKeyboard.NONE, USBKeyboard.KEY_ENTER); | |
//replace 'z' and 'y' characters to produce expected result | |
keyb.type("xZy"); | |
} else { | |
keyb.pressAndRelease(USBKeyboard.SHIFT_LEFT, USBKeyboard.KEY_H); | |
keyb.pressAndRelease(USBKeyboard.NONE, USBKeyboard.KEY_E); | |
keyb.type("llo world!"); | |
keyb.pressAndRelease(USBKeyboard.NONE, USBKeyboard.KEY_ENTER); | |
//replace 'z' and 'y' characters to produce expected result | |
keyb.type("XzY"); | |
} | |
} | |
} | |
} |
For other device classes see: this post