【Android】联通性 -- USB主机模式

2024-04-05 01:08
文章标签 android 模式 主机 usb 联通

本文主要是介绍【Android】联通性 -- USB主机模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文译自:http://developer.android.com/guide/topics/connectivity/usb/host.html

当你的Android设备在USB主机模式中时,它作为USB主机给从属设备供电,并会列举被连接的USB设备。USB主机模式在Android3.1以后开始被支持。

一,API概要

        在开始之前,重要的是要理解工作中所需要的类。下表介绍了在android.hardware.usb包中的USB主机模式API。 

        表1    USB主机模式API

介绍

UsbManager

用于列举被连接的USB设备,并跟其通信。

UsbDevice

代表了一个被连接的USB设备,并且包含了访问它的识别信息、接口、和端点的方法。

UsbInterface

代表了一个USB设备的接口,该接口定义了设备的一组功能。一个设备可以有一个或多个用于通信的接口。

UsbEndpoint

代表一个接口端点,它是跟接口通信的通道。一个接口可以有一个或多个端点,通常会有跟设备进行双工通信的输入和输出端点。

UsbDeviceConnection

代表一个设备连接,它在端点之上传输数据。这个类用于在连接的两个设备间使用同步或异步的方式来回发送数据。

UsbRequest

代表一个通过UsbDeviceConnection对象跟设备通信的异步请求。

UsbConstants

定义了跟Linux内核中linux/usb/ch9.h文件定义对应的USB常量。

        在大多数情况中,跟USB设备通信时,需要使用所有这些类(如果你是在使用异步通信,那么只需要使用UsbRequest类)。通常,要使用UsbManager对象来获取期望的UsbDevice对象。当你有了这个UsbDevice对象时,就需要查找对应的UsbInterface对象和基于该接口通信的UsbEndpoint对象。一旦获取了正确的端点,就可以打开UsbDeviceConnect对象来跟USB设备进行通信了。

二,Android清单要求

        在使用USB主机模式API工作之前,你需要把以下介绍的内容添加到你的应用程序清单中:

        1.   因为不是所有的Android设备都保证支持USB主机模式,所以要在你的应用程序声明中包含<uses-feature>元素,以声明你的应用程序要使用android.hardware.usb.host功能。

        2.   把应用程序的最小SDK设置为API Level 12或更高的版本。在较早的API版本中不存在USB主机模式API。

        3.   如果你希望你的应用程序能够获得接入USB设备时的通知,那么还要在你的主Activity中指定用android.hardware.usb.action.USB_DEVICE_ATTACHED类型的Intent来配对的<intent-filter>和<meta-data>元素。<meta-data>元素要指向一个外部的XML资源文件,该文件声明了希望检测的设备的识别信息(对方设备发过来的信息)

        在这个XML资源文件中,要用<usb-device>元素来声明你想要过滤的USB设备。以下列出了<usb-device>元素的属性。通常,使用vendor-id和product-id来指定你所希望过滤的特定的设备,并且使用class、subclass和protocol来指定你所希望过滤的USB设备组,如大容量存储设备或数码相机。你可以不指定任何属性,或所有全部属性。不指定任何属性,就会跟所有USB设备匹配,如果应用程序需要,就可以这样做:

A. vendor-id

B. product-id

C. class

D. subclass

E.  protocol(设备或接口)

在res/xml目录中保存这个资源文件。该资源文件的名称(不含.xml扩展名)必须跟<meta-data>元素中指定的名称相同。XML资源文件的格式请看下例。

三,清单和资源文件的示例

以下是一个简单的清单文件和它所对应的资源文件:

<manifest ...>

   <uses-feature android:name="android.hardware.usb.host" />

   <uses-sdk android:minSdkVersion="12" />

   ...

   <application>

       <activity ...>

           ...

           <intent-filter>

               <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />

           </intent-filter>

 

           <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"

               android:resource="@xml/device_filter" />

       </activity>

   </application>

</manifest>

在这个实例中,下面的资源文件应该被保存在res/xml/device_filter.xml中,并且指定了所有的用于过滤USB设备的属性:

<?xml version="1.0" encoding="utf-8"?>

<resources>

   <usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />

</resources>

四,跟设备一起工作

        当用户把USB设备接入到Android设备上时,Android系统能够判断你的应用程序是否对接入的设备感兴趣。如果是你的应用程序感兴趣的设备,你就可以跟你期望的设备建立通信。以下是你的应用程序必须要做的工作:

     1. 使用以下两种方法之一来发现接入的UDB设备:

              A. 使用Intent过滤器,过滤用户接入USB设备时所发出的通知;

              B. 列举已经接入的USB设备。

     2. 如果没获取接入USB设备的权限,会向用户请求接入USB设备的权限。

     3. 通过读写对应接口端点上的数据来跟USB设备通信。

五,发现设备

        用户既可以通过使用

              1.用户接入USB设备时所发出Intent过滤通知

              2.也可以通过列举已经接入的USB设备

        来发现USB设备。

        如果你希望你的应用程序能够自动的检测到你所期望的USB设备,那么要使用Intent过滤器。

        如果你想要过的接入的所有的已经接入的设备列表,或者是你的应用程序没有过滤对应的Intent对象,那么要使用列举的方法。

六,使用Intent过滤器

         为了让你的应用程序发现一个特殊的USB设备,你可以指定一个android.hardware.usb.action.USB_DEVICE_ATTACHED类型的Intent过滤器。跟这个Intent过滤器一起,你还需要指定一个指定了USB设备属性的资源文件,如果产品和供应商ID。当用户接入的设备跟你的设备过滤器匹配的时候,系统会显示一个对话框,询问你是否允许它们启动你的应用程序。如果用户接收,应用程序会自动的被授予访问设备的权限,一直到设备断开连接。

以下示例演示了如何声明Intent过滤器:

<activity ...>

...

   <intent-filter>

       <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />

   </intent-filter>

 

   <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"

       android:resource="@xml/device_filter" />

</activity>

 

以下示例演示了如何声明对应的你感兴趣的USB设备的资源文件:

<?xml version="1.0" encoding="utf-8"?>

<resources>

   <usb-device vendor-id="1234" product-id="5678" />

</resources>

在你的Activity中,按照如下的方法,你可以从Intent对象中获得一个代表接入的设备的UsbDevice对象:

UsbDevice device=(UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

七,列举设备

        当你的应用程序要在运行时检测当前接入的所有的USB设备时,它可以列举总线上的设备。使用getDeviceList()方法来获取已经接入的所有的USB设备的hash map。该hash map使用USB设备的名称做key:

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);

... 

HashMap<String, UsbDevice> deviceList = manager.getDeviceList();

UsbDevice device = deviceList.get("deviceName");

如果你愿意,也可以使用hash map的迭代器来处理每个设备:

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);

...

HashMap<String, UsbDevice> deviceList = manager.getDeviceList();

Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();

while(deviceIterator.hasNext()){

   UsbDevice device = deviceIterator.next()

   //your code

}

八,获取跟设备通信的权限

         在跟USB设备进行通信之前,你的应用程序必须要获取用户的许可

       注意:如果你的应用程序使用Intent过滤器来发现接入的USB设备,而且用户允许你的应用程序处理该Intent,那么它会自动的接收权限,否则,在你的应用程序接入该设备之前,必须明确的申请权限。

         明确的申请权限在某些情况下是必须的,如你的应用程序列举已经接入的USB设备并想要跟其中的一个设备通信的时候。在试图跟一个设备通信之前,你必须要检查是否有访问设备的权限。否则,如果用户拒绝了你访问该设备的请求,你会收到一个运行时错误。

         要明确的获取这个权限,首先要创建一个广播接收器。这个接收器用于监听你调用requestPermission()方法时,系统所发出的Intent对象。调用requestPermission()方法时,系统会显示一个对话框,询问用户是否允许跟该USB设备进行连接。下列代码演示如何创建这个广播接收器:

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) {

               UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

 

               if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {

                   if(device != null){

                     //call method to set up device communication

                  }

               }

               else {

                   Log.d(TAG, "permission denied for device " + device);

               }

           }

       }

   }

};

在你的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);

调用requestPermission()方法,显示申请接入设备的权限的对话框:

UsbDevice device;

...

mUsbManager.requestPermission(device, mPermissionIntent);

        当用户应答了该对话框时,你的广播接收器就会收到一个包含EXTRA_PERMISSINO_GRANTED类型附加字段的Intent对象,该字段用一个布尔值来代表回答结果。在连接该设备之前,要检查这个字段的值是否是true。

九,跟设备进行通信

         跟USB设备的通信既可以是异步的,也可以是同步的。在异步的情况下,你应该创建一个线程来执行所有的数据传输,以便不至于阻塞UI线程。要正确的建立跟设备的通信,你需要获得准备与其通信的设备所对应的UsbInterface和UsbEndpoint对象,并且使用UsbDeviceConnection对象把请求发送给这个端点。通常步骤如下:

          1.       检查UsbDevice对象的属性,如产品ID、供应商ID、或者设备的分类,判断该设备是否是你所想要的设备;

          2.       当你确认它是你想要与其通信的设备时,就要找到该设备对应的UsbInterface对象以及跟该接口对象一起的UsbEndpoint对象。接口可以有一个或多个端点,通常会有用于双工通信的输入和输出端点;

          3.       当你找正确的端点时,就可以打开一个该端点上的UsbDeviceConnection对象;

          4.       使用bulkTransfer()或controlTransfer()方法,把你想要传输的数据提供给端点。你应该在另外一个线程中执行本步骤的操作,以便防止阻塞主UI线程。

          以下代码片段是一个普通的同步传输数据的方法。你的代码应该有更多的逻辑用于查找用来通信的正确的接口和端点,并且还应该在一个不同于主UI线程的线程中来进行数据传输:

private Byte[] bytes

private static int TIMEOUT = 0;

private boolean forceClaim = true;

 

...

 

UsbInterface intf = device.getInterface(0);

UsbEndpoint endpoint = intf.getEndpoint(0);

UsbDeviceConnection connection = mUsbManager.openDevice(device);

connection.claimInterface(intf, forceClaim);

connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread

要异步的发送数据,就要使用UsbRequest类来进行初始化,并发送一个异步请求,让后用requestWait()方法等待结果。

更多的信息请看Adb test sample,它显示了怎样进行异步块数据数据传输,MissleLauncher sample显示了如何监听异步的中断端点。

十,中断跟设备的通信

         在你完成跟设备的通信,或者设备被分离时,就要调用releaseInterface()方法和close()方法来关闭UsbInterface和UsbDeviceConnection对象。创建下面这样的广播接收器来监听分离事件:

BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

   public void onReceive(Context context, Intent intent) {

       String action = intent.getAction();

 

     if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {

           UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

           if (device != null) {

               // call your method that cleans up and closes communication with the device

           }

       }

   }

};

如果在应用程序中创建广播接收器,但没有在清单中注册,那么就允许你的应用程序只在运行时处理分离事件。这种情况下,分离事件只会发送给当前运行的应用程序,并且不是广播给所有的应用程序
学习

 

这篇关于【Android】联通性 -- USB主机模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/877283

相关文章

如何开启和关闭3GB模式

https://jingyan.baidu.com/article/4d58d5414dfc2f9dd4e9c082.html

十四、观察者模式与访问者模式详解

21.观察者模式 21.1.课程目标 1、 掌握观察者模式和访问者模式的应用场景。 2、 掌握观察者模式在具体业务场景中的应用。 3、 了解访问者模式的双分派。 4、 观察者模式和访问者模式的优、缺点。 21.2.内容定位 1、 有 Swing开发经验的人群更容易理解观察者模式。 2、 访问者模式被称为最复杂的设计模式。 21.3.观察者模式 观 察 者 模 式 ( Obser

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

android 免费短信验证功能

没有太复杂的使用的话,功能实现比较简单粗暴。 在www.mob.com网站中可以申请使用免费短信验证功能。 步骤: 1.注册登录。 2.选择“短信验证码SDK” 3.下载对应的sdk包,我这是选studio的。 4.从头像那进入后台并创建短信验证应用,获取到key跟secret 5.根据技术文档操作(initSDK方法写在setContentView上面) 6.关键:在有用到的Mo

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

Android我的二维码扫描功能发展史(完整)

最近在研究下二维码扫描功能,跟据从网上查阅的资料到自己勉强已实现扫描功能来一一介绍我的二维码扫描功能实现的发展历程: 首页通过网络搜索发现做android二维码扫描功能看去都是基于google的ZXing项目开发。 2、搜索怎么使用ZXing实现自己的二维码扫描:从网上下载ZXing-2.2.zip以及core-2.2-source.jar文件,分别解压两个文件。然后把.jar解压出来的整个c

android 带与不带logo的二维码生成

该代码基于ZXing项目,这个网上能下载得到。 定义的控件以及属性: public static final int SCAN_CODE = 1;private ImageView iv;private EditText et;private Button qr_btn,add_logo;private Bitmap logo,bitmap,bmp; //logo图标private st

Android多线程下载见解

通过for循环开启N个线程,这是多线程,但每次循环都new一个线程肯定很耗内存的。那可以改用线程池来。 就以我个人对多线程下载的理解是开启一个线程后: 1.通过HttpUrlConnection对象获取要下载文件的总长度 2.通过RandomAccessFile流对象在本地创建一个跟远程文件长度一样大小的空文件。 3.通过文件总长度/线程个数=得到每个线程大概要下载的量(线程块大小)。

时间服务器中,适用于国内的 NTP 服务器地址,可用于时间同步或 Android 加速 GPS 定位

NTP 是什么?   NTP 是网络时间协议(Network Time Protocol),它用来同步网络设备【如计算机、手机】的时间的协议。 NTP 实现什么目的?   目的很简单,就是为了提供准确时间。因为我们的手表、设备等,经常会时间跑着跑着就有误差,或快或慢的少几秒,时间长了甚至误差过分钟。 NTP 服务器列表 最常见、熟知的就是 www.pool.ntp.org/zo