USB 配件概述

USB配件模式允许用户连接专为Android设备设计的USB主机硬件。当Android设备处于USB配件模式时,附带的Android USB配件充当主机,为USB总线供电,并枚举连接的设备。

附件必须遵守Android附件开发工具包文档(https://source.android.com/devices/accessories/)中概述的Android附件协议。这使得不能作为USB主机的Android供电设备仍然可以与USB硬件进行交互。

选择合适的USB配件API

Android 3.1(API级别12)支持USB附件模式,该功能也向后移植到Android 2.3.4(API级别10),以支持更广泛的设备。Android 2.3.4中的USB附件模式需要使用 Google API附加库,在com.android.future.usb包下;在Android3.1则在平台APIandroid.hardware.usb包下。

API概述
classDescription
UsbManager允许您枚举连接的USB附件并与之通信。
UsbAccessory表示USB附件,包含访问其标识信息的方法。

注意:Google附加库和平台API之间的使用差异

usb附件通信流程

当用户将USB配件连接到Android设备时,Android系统可以确定您的应用程序是否对连接的配件感兴趣。如果是这样,您可以根据需要设置与附件的通信。为此,您的应用程序必须:
1、通过使用过滤附件附加事件的过滤器或通过枚举连接的附件并找到合适的附件来发现连接的附件。
2、如果尚未获得,需请求与附件通信的权限。
3、通过在适当的接口端点上读取和写入数据来与附件通信。

发现附件

应用程序可以通过使用意图过滤器来发现附件,以便在用户连接附件时通知或通过枚举已连接的附件。如果您希望应用程序能够自动检测所需的附件,则使用意图过滤器非常有用。如果您想获得所有连接附件的列表,或者您的应用程序没有过滤意图,则枚举连接的附件非常有用。
- 使用意图过滤器
可以简单快捷地发现特定的USB附件。
通过指定一个响应USB附件插入的intent-filter,和声明具体USB附件特征的meta-data(指定一个xml文件,声明要检测的目标usb附件的相关属性,包括manufacturer制造商、model型号、version版本 )

// AndroidManifest
<manifest ...>
   ...
<application>
<activity ...>
    ...
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
    </intent-filter>
    <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
        android:resource="@xml/accessory_filter" />
</activity>
</application>
</manifest>
// res/xml/accessory_filter.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    //制造商、型号、版本号
    <usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" />
</resources>
//In your activity, you can obtain theUsbAccessory that represents the attached accessory from the intent like this:
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
  • 枚举附件
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbAccessory[] accessoryList = manager.getAccessoryList();
获取通信权限

如果您的应用程序使用意图过滤器来发现连接时的USB附件,则插入相关USB附件时,系统会出现一个弹框,在用户允许您的应用程序处理意图时,它会自动获得通信权限。 如果没有,您必须在与附件通信连接之前在应用程序中明确请求权限,否则会抛出运行时异常。

首先创建一个广播接收者,用于监听用户对通信权限的审批情况,UsbManager.EXTRA_PERMISSION_GRANTED字段值代表审批结果。当你调用requestPermission()后,系统会弹出一个权限审批对话框给用户。
private static final String ACTION_USB_PERMISSION =
    "com.android.example.USB_PERMISSION";
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (ACTION_USB_PERMISSION.equals(action)) {
            synchronized (this) {
                UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    if(accessory != null){
                        //call method to set up accessory communication
                    }
                }
                else {
                    Log.d(TAG, "permission denied for accessory " + accessory);
                }
            }
        }
    }
};
//在Activity的onCreate()中注册广播,
UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
private static final String ACTION_USB_PERMISSION =
    "com.android.example.USB_PERMISSION";
...
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
//在通信前,检查通信权限
UsbAccessory accessory;
...
if (mUsbManager.hasPermission(accessory)) {
    //进行通信相关的操作
    ...
} else {
    mUsbManager.requestPermission(accessory, mPermissionIntent);
}
与附件通信

您可以使用UsbManager获取文件描述符来与附件通信,您可以设置输入和输出流以读取和写入描述符的数据。流表示附件的输入和输出批量端点。您应该在另一个线程中设置设备和附件之间的通信,因此您不会锁定主UI线程。以下示例显示如何打开与之通信的附件:

UsbAccessory mAccessory;
ParcelFileDescriptor mFileDescriptor;
FileInputStream mInputStream;
FileOutputStream mOutputStream;
...
private void openAccessory() {
    Log.d(TAG, "openAccessory: " + accessory);
    mFileDescriptor = mUsbManager.openAccessory(mAccessory);
    if (mFileDescriptor != null) {
        FileDescriptor fd = mFileDescriptor.getFileDescriptor();
        mInputStream = new FileInputStream(fd);
        mOutputStream = new FileOutputStream(fd);
        Thread thread = new Thread(null, this, "AccessoryThread");
        thread.start();
    }
}

在线程的run()方法中,您可以使用FileInputStream或FileOutputStream对象读取和写入附件。从带有FileInputStream对象的附件读取数据时,请确保您使用的缓冲区足以存储USB数据包数据。Android附件协议支持最多16384字节的数据包缓冲区,因此您可以选择始终将缓冲区声明为此大小,以简化操作。

断开与附件的通信

完成与附件的通信或附件已分离后,请关闭通过呼叫打开的文件描述符close()。要收听分离的事件,请创建如下的广播接收器:

BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
            UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
            if (accessory != null) {
                // call your method that cleans up and closes communication with the accessory
            }
        }
    }
};

在应用程序中创建广播接收器而不是清单,允许您的应用程序仅在其运行时处理分离的事件。这样,分离事件仅发送到当前正在运行的应用程序,而不是广播到所有应用程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值