Android Things:用户驱动-输入
一、驱动介绍
输入用户驱动程序为应用程序提供接口,向Android的输入管道注入事件。有了这个API,应用程序可以使用Peripheral I/O模拟一个人机界面的设备(HID)或者连接外部硬件到输入系统。比如说,我们可以使用开关按钮GPIO的信号输入,通过输入驱动API模拟呈键盘上按键的输入事件,下面我们会具体演示如何实现。
二、使用步骤
实现输入用户驱动,有如下步骤:
1.创建驱动:使用InputDriver.Builder和源类型SOURCE_CLASS_BUTTON创建一个新的输入驱动实例。
2.注册驱动:使用UserDriverManager的registerInputDriver()方法注册这个驱动。
public class TouchpadDriverService extends Service {
// Driver parameters
private static final String DRIVER_NAME = "Touchpad";
private static final int DRIVER_VERSION = 1;
private InputDriver mDriver;
@Override
public void onCreate() {
super.onCreate();
mDriver = InputDriver.builder(InputDevice.SOURCE_TOUCHPAD)
.setName(DRIVER_NAME)
.setVersion(DRIVER_VERSION)
.setAbsMax(MotionEvent.AXIS_X, 255)
.setAbsMax(MotionEvent.AXIS_Y, 255)
.build();
UserDriverManager manager = UserDriverManager.getManager();
manager.registerInputDriver(mDriver);
}
}
3. 转换事件:当一个硬件事件发生,使用当前的事件代码和输入动作为每个状态改变构造一个新的KeyEvent。
4. 注入事件:使用输入驱动的emit()方法向这个驱动中注入事件。
private void triggerEvent(boolean pressed) {
int action = pressed ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
KeyEvent[] events = new KeyEvent[] {new KeyEvent(action, KEY_CODE)};
if (!mDriver.emit(events)) {
Log.w(TAG, "Unable to emit key event");
}
}
5.处理事件:在前台Activity通过实现onKeyDown()、onKeyUp()和onGenericMotionEvent()方法来获取相关事件,并处理。
public class HomeActivity extends Activity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Handle key pressed and repeated events
return true;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// Handle key released events
return true;
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
// Handle motion input events
return true;
}
}
6.注销驱动:当你不在需要关键事件的时候注销驱动。
public class TouchpadDriverService extends Service {
@Override
public void onDestroy() {
super.onDestroy();
UserDriverManager manager = UserDriverManager.getManager();
manager.unregisterInputDriver(mDriver);
}
}
三、案例展示
这里我们实现一个最简单的模拟键盘,通过两个开关按钮的GPIO信号输入,通过输入驱动API分别模拟键盘上a和b字母的输入。
1. 硬件准备
- 树莓派3开发板 1块
- 面板板 1块
- 按钮开关 2个
- 电阻 2个
- 杜邦线(母对公,公对公) 若干
2. 电路搭建
电路图3. 代码实现
InputDemo\app\src\main\java\com\chengxiang\inputdemo\KeyDriverService.java
public class KeyDriverService extends Service {
private static final String TAG = KeyDriverService.class.getSimpleName();
private static final String A_DRIVER_NAME = "Akey";
private static final int A_DRIVER_VERSION = 1;
private static final int A_KEY_CODE = KeyEvent.KEYCODE_A;
private static final String B_DRIVER_NAME = "Bkey";
private static final int B_DRIVER_VERSION = 1;
private static final int B_KEY_CODE = KeyEvent.KEYCODE_B;
private static final String A_GPIO_NAME = "BCM5";
private static final String B_GPIO_NAME = "BCM6";
private UserDriverManager mUserDriverManager;
private InputDriver mADriver;
private InputDriver mBDriver;
private Gpio mAGpio;
private Gpio mBGpio;
private GpioCallback mGpioCallback = new GpioCallback() {
@Override
public boolean onGpioEdge(Gpio gpio) {
Log.d(TAG, "onGpioEdge");
try {
//获取开关按键的信号输入后,转换成A和B按键的输入事件
if (gpio == mAGpio) {
triggerEvent(mADriver, gpio.getValue(), A_KEY_CODE);
} else if (gpio == mBGpio) {
triggerEvent(mBDriver, gpio.getValue(), B_KEY_CODE);
}
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
@Override
public void onGpioError(Gpio gpio, int error) {
Log.w(TAG, gpio + ": Error event " + error);
}
};
public KeyDriverService() {
}
@Override
public void onCreate() {
super.onCreate();
PeripheralManagerService manager = new PeripheralManagerService();
try {
mAGpio = manager.openGpio(A_GPIO_NAME);
mAGpio.setDirection(Gpio.DIRECTION_IN);
mAGpio.setActiveType(Gpio.ACTIVE_LOW);
mAGpio.setEdgeTriggerType(Gpio.EDGE_BOTH);
mAGpio.registerGpioCallback(mGpioCallback);
mBGpio = manager.openGpio(B_GPIO_NAME);
mBGpio.setDirection(Gpio.DIRECTION_IN);
mBGpio.setActiveType(Gpio.ACTIVE_LOW);
mBGpio.setEdgeTriggerType(Gpio.EDGE_BOTH);
mBGpio.registerGpioCallback(mGpioCallback);
} catch (IOException e) {
e.printStackTrace();
}
//分别创建A字母按键和B字母按键输入驱动实例
mADriver = InputDriver.builder(InputDevice.SOURCE_CLASS_BUTTON).setName(A_DRIVER_NAME)
.setVersion(A_DRIVER_VERSION).setKeys(new int[]{A_KEY_CODE}).build();
mBDriver = InputDriver.builder(InputDevice.SOURCE_CLASS_BUTTON).setName(B_DRIVER_NAME)
.setVersion(B_DRIVER_VERSION).setKeys(new int[]{B_KEY_CODE}).build();
//注册A字母按键和B字母按键输入驱动
mUserDriverManager = UserDriverManager.getManager();
mUserDriverManager.registerInputDriver(mADriver);
mUserDriverManager.registerInputDriver(mBDriver);
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onDestroy() {
super.onDestroy();
if (mAGpio != null) {
try {
mAGpio.unregisterGpioCallback(mGpioCallback);
mAGpio.close();
mAGpio = null;
} catch (IOException e) {
Log.w(TAG, "Unable to close GPIO", e);
}
}
if (mBGpio != null) {
try {
mBGpio.unregisterGpioCallback(mGpioCallback);
mBGpio.close();
mBGpio = null;
} catch (IOException e) {
Log.w(TAG, "Unable to close GPIO", e);
}
}
//当你不在需要关键事件的时候注销驱动
mUserDriverManager.unregisterInputDriver(mADriver);
mUserDriverManager.unregisterInputDriver(mBDriver);
}
private void triggerEvent(InputDriver inputDriver, boolean pressed, int keyCode) {
int action = pressed ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
KeyEvent[] events = new KeyEvent[]{new KeyEvent(action, keyCode)};
//使用emit()方法转换成Android事件
if (!inputDriver.emit(events)) {
Log.w(TAG, "Unable to emit key event");
}
}
}
InputDemo\app\src\main\java\com\chengxiang\inputdemo\MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private EditText mEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEditText = (EditText) findViewById(R.id.edittext);
//这里我们将输入焦点放在输入框中,故按下开关按钮会输入A和B字母
mEditText.requestFocus();
}
//在前台Activity通过实现onKeyDown()、onKeyUp()和onGenericMotionEvent()方法来获取相关事件
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
Log.d(TAG,"onKeyUp:" + keyCode);
return true;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d(TAG,"onKeyDown:" + keyCode);
return true;
}
public void toNext(View view) {
Intent intent = new Intent(this,NextActivity.class);
startActivity(intent);
}
}
4. 运行结果
点击开关按钮,在输入框中会输入对应的A和B字母。
1.抛弃各种找元器件的烦恼,来“1024工场”旗舰店,一次性买到你所想要的:树莓派套装—专为Android Things打造。
电脑用户,点击如下链接进入淘宝宝贝页面:
https://item.taobao.com/item.htm?spm=686.1000925.0.0.3f11c9ed68fPu7&id=549263158263
手机用户,打开淘宝客户端扫描二维码:
宝贝二维码
2.完整和持续更新的《使用Android打开物联网开发大门——Andoid Thigns开发》文档,欢迎大家阅读!
https://www.kancloud.cn/workshop1024/android_things_develop/360773
这里写图片描述
3.新技术,新未来!欢迎大家关注“1024工场”微信服务号,时刻关注我们的最新的技术讯息。(甭客气!尽情的扫描或者长按!)
服务号
4.加入“Android Things开发”QQ讨论群,一起学习一起Hi。(甭客气!尽情的扫描或者长按!)
qq群