Android USB通信入门篇

Android USB开发模式

Android中USB有两种开发模式,一种是host模式,另一种是accessory模式,下面介绍一下这两种模式。

(1)Host模式:如图,此模式中,Android设备充当主机,给USB外部设备供电,常见的Host模式有:鼠标、键盘等。

(2)Accessory模式:如图,和Host模式相反,此模式中,usb设备充当主机,给android手机提供电源,常见的设备:无人机远程控制器等。

进入Hello World

配置AndroidManifest.xml文件中USB模式

在Android系统中,默认是关闭USB模式的,当我们将USB外部设备插入Android设备时,Android系统不会作出任何响应。如果我们要打开系统USB模式,需要在Android清单文件里使用<uses-feature/>标签声明响应的USB模式

Host模式

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

Accessory模式

<uses-permission android:name="android.hardware.usb.accessory" />

配置USB设备插入的通知和相关USB设备的过滤

若我们希望在插入USB设备时,Android系统能接收到提示性通知,则需要在Android组件<Activity/>中配置<intent-filter/><meta-data/>标签配置相关信息,<intent-filter/>中配置我们要接收的相关类型的信息通知,<meta-data/>配置我们需要检测的指定的设备,标签内容对应一个xml资源文件,里面配置我们指定的USB设备。如下:

<activity android:name=".ui.ChoiceModelActivity">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    <!--host模式下通知的过滤-->
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
    </intent-filter>
    <!--host模式下指定过滤设备的配置文件-->
    <meta-data
        android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
        android:resource="@xml/device_filter" />

    <!--accessory模式下通知的过滤-->
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
    </intent-filter>
    <!--accessory模式下指定过滤设备的配置文件-->
    <meta-data
        android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
        android:resource="@xml/device_filter" />

</activity>

其中xml资源文件的配置如下:

<?xml version="1.0" encoding="utf-8"?>
<rescources xmlns:android="http://schemas.android.com/apk/res/android">
    <!--host模式-->
    <usb-device
        class=""
        vendor-id=""
        product-id=""
        protoclo=""
        subclass="" />

    <!--accessory模式-->
    <usb-accessory
        model="xxx"
        manufacturer="xxx" />

Android设备与USB设备连接和通信

无论是Host模式还是Accessory模式,在进行检测获取USB设备时,都需要用到UsbManager类,只是调用不同的方法而已。如下:

Host模式

1)获取UsbManager
2)通过usbManager获取连接到的USB外部设备
3)获取USB设备引用,通过usbManager检测是否有对应权限,若无则请求权限,通过广播接收权限信息获取情况
4)与USB设备进行通信

public static final String action_usb_permission = "cn.appblog.usb.permission";

public void hostModel(Context context) {

    //获取UsbManager
    UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);

    //获取usb设备列表
    HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();

    Set<Map.Entry<String, UsbDevice>> entries = deviceList.entrySet();

    UsbDevice mUsbDevice = null;

    for (Map.Entry<String, UsbDevice> entry : entries) {
        UsbDevice value = entry.getValue();
        String key = entry.getKey();

        if (filterDevice(key, value)) {//判断是否是我们要连接的usb设备
            mUsbDevice = value;
            break;
        }
    }

    if (usbManager.hasPermission(mUsbDevice)) {//检测是否有usb权限
        requestPermission(mUsbDevice);
    } else {
        connect(mUsbDevice);
    }

}

/**
 * 请求usb权限
 * @param usbManager
 * @param parcelable
 */
public void requestPermission(Parcelable parcelable, UsbManager usbManager) {           
        UsbDevice usbDevice = (UsbDevice) parcelable;
        if (!usbManager.hasPermission(usbDevice)) {
            IntentFilter intentFilter = new IntentFilter(action_usb_permission);
            registerReceiver(mMyBroadcastReceiver, intentFilter);
            PendingIntent broadcast = PendingIntent.getBroadcast(this, 0, new Intent(action_usb_permission), 0);
            usbManager.requestPermission(usbDevice, broadcast);
        } else {
            Toast.makeText(context, "already have permission", Toast.LENGTH_SHORT).show();
        }
    }
}

public boolean connect(UsbDevice mUsbDevice) {
    if (mUsbDevice != null) {
        UsbInterface anInterface = mUsbDevice.getInterface(0);
        mUsbDeviceConnection = mUsbManager.openDevice(mUsbDevice);//连接usb设备
        if (mUsbDeviceConnection == null) {
            Toast.makeText(mContext, "mUsbDeviceConnection can't be null", Toast.LENGTH_SHORT).show();
            return false;
        }
        if (mUsbDeviceConnection.claimInterface(anInterface, true)) {
            Toast.makeText(mContext, "找到USB接口", Toast.LENGTH_SHORT).show();
            int endpointCount = anInterface.getEndpointCount();
            for (int i = 0; i < endpointCount; i++) {
                UsbEndpoint endpoint = anInterface.getEndpoint(i);
                if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (UsbConstants.USB_DIR_IN == endpoint.getDirection()) {
                        mUsbEndpoint_in = endpoint;//获取读数据通道
                    } else {
                        mUsbEndpoint_out = endpoint;//获取写数据通道
                    }
                }
            }
            return true;
        } else {
            mUsbDeviceConnection.close();//关闭连接
            Toast.makeText(mContext, "找不到USB接口", Toast.LENGTH_SHORT).show();
        }
    } else {
        Toast.makeText(mContext, "mUsbDevice can't be null", Toast.LENGTH_SHORT).show();
    }
    return false;
}

/**
 * 从usb通信设备中读取数据
 * @return
 */
public byte[] readData() {
    int inMax = mUsbEndpoint_in.getMaxPacketSize();
    byte[] bytes = new byte[inMax];
    ByteBuffer byteBuffer = ByteBuffer.allocate(inMax);
    UsbRequest usbRequest = new UsbRequest();
    usbRequest.initialize(mUsbDeviceConnection, mUsbEndpoint_in);
    usbRequest.queue(byteBuffer, inMax);
    if (mUsbDeviceConnection.requestWait() == usbRequest) {
        bytes = byteBuffer.array();
    }
    return bytes;
}

/**
 * 将数据写入到usb设备中
 * @param bytes
 */
public void sendData(byte[] bytes) {
    if (mUsbDeviceConnection == null) {
        Toast.makeText(mContext, "mUsbDeviceConnection can't be null", Toast.LENGTH_SHORT).show();
        return;
    }
    if (mUsbEndpoint_out == null) {
        Toast.makeText(mContext, "mUsbEndpoint_out can't be null", Toast.LENGTH_SHORT).show();
        return;
    }

    int i = mUsbDeviceConnection.bulkTransfer(mUsbEndpoint_out, bytes, bytes.length, 1000);
    if (i < 0) {
        Toast.makeText(mContext, "failure to write", Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(mContext, "success to write", Toast.LENGTH_SHORT).show();
    }
}

/**
 * 权限广播接收器
 */
private BroadcastReceiver mMyBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action_usb_permission.equals(action)) {
            synchronized (this) {
                UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (usbDevice != null) {
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        connect(usbDevice);
                        Toast.makeText(context, "success get permission", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(context, "failure get permission", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(context, "the usbDevice be null", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
};

/**
 * 筛选出我们想要的usb设备
 * @param name
 * @param usbDevice
 * @return
 */
public boolean filterDevice(String name, UsbDevice usbDevice) {
    // TODO: 2019/3/13 对应判断设备是否是我们要连接的设备
    return false;
}

Accessory模式

Host模式差不多,大致步骤一样,只是相关类不同而已如下

1)获取UsbManager
2)通过usbManager获取连接到的USB外部设备UsbAccessory
3)获取USB设备引用,通过usbManager检测是否有对应权限,若无则请求权限,通过广播接收权限信息获取情况
4)与UsbAccessory设备进行通信

public static final String action_usb_permission = "cn.appblog.usb.permission";

private UsbManager usbManager;

public void hostAccessory(Context context) {

    //获取UsbManager
    usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);

    //获取usb设备列表
    UsbAccessory[] accessoryList = usbManager.getAccessoryList();

    if (accessoryList == null || accessoryList.length <= = 0) {
        Toast.makeText(context, "未查询到对应设备", Toast.LENGTH_SHORT).show();
        return;
    }

    UsbAccessory mUsbAccessory = null;
    for (UsbAccessory usbAccessory : accessoryList) {
        if (filterDevice(usbAccessory)) {//判断是否使我们要连接的usb设备
            break;
        }
    }

    if (usbManager.hasPermission(mUsbAccessory)) {//检测是否有usb权限
        requestPermission(mUsbAccessory);//请求usb权限
    } else {
        connect(mUsbAccessory);//连接usb设备
    }

}

/**
 * 请求usb权限
 *
 * @param usbManager
 * @param parcelable
 */
public void requestPermission(Parcelable parcelable, UsbManager usbManager) {
    UsbAccessory usbAccessory = (UsbAccessory) parcelable;
    if (!usbManager.hasPermission(usbAccessory)) {
        IntentFilter intentFilter = new IntentFilter(action_usb_permission);
        registerReceiver(mMyBroadcastReceiver, intentFilter);
        PendingIntent broadcast = PendingIntent.getBroadcast(this, 0, new Intent(action_usb_permission), 0);
        usbManager.requestPermission(usbAccessory, broadcast);
    } else {
        Toast.makeText(context, "already have permission", Toast.LENGTH_SHORT).show();
    }
}

private FileInputStream mFileInputStream;

private FileOutputStream mFileOutputStream;

/**
 * 连接设备
 * @param usbAccessory
 * @return
 */
public boolean connect(UsbAccessory usbAccessory) {
    ParcelFileDescriptor parcelFileDescriptor = usbManager.openAccessory(usbAccessory);
    if (parcelFileDescriptor != null) {
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();

        mFileInputStream = new FileInputStream(fileDescriptor);

        mFileOutputStream = new FileOutputStream(fileDescriptor);

    }
    return false;
}

/**
 * 写入数据
 * @param data
 */
public void write(byte[] data) {
    try {
        mFileOutputStream.write(data);
    } catch (IOException e) {
        e.printStackTrace();
    }

}

/**
 * 读取数据
 */
public void read() {
    int max;//字节数据根据协议来确定
    byte[] data = new byte[max];
    mFileInputStream.read(data);
}

/**
 * 权限广播接收器
 */
private BroadcastReceiver mMyBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action_usb_permission.equals(action)) {
            synchronized (this) {
                UsbAccessory usbAccessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                if (usbAccessory != null) {
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        connect(usbAccessory);
                        Toast.makeText(context, "success get permission", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(context, "failure get permission", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(context, "the usbDevice be null", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
};

/**
 * 筛选出我们想要的usb设备
 *
 * @param usbAccessory
 * @return
 */
public boolean filterDevice(UsbAccessory usbAccessory) {
    // TODO: 2019/3/13 对应判断设备是否是我们要连接的设备
    return false;
}

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/29/introduction-to-android-usb-communication/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Android USB通信入门篇
Android USB开发模式 Android中USB有两种开发模式,一种是host模式,另一种是accessory模式,下面介绍一下这两种模式。 (1)Host模式:如图,此模式中,Andro……
<<上一篇
下一篇>>
文章目录
关闭
目 录