java - Android MTP 客户端打开整个设备而不是单个界面

标签 java android interface usb mtp

我有一个复合 USB 小工具,我想连接到 Android 手机。它包含以下串行、MTP 和大容量存储接口(interface):

interface :: id : 0, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
interface :: id : 1, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
interface :: id : 2, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage

我的问题是试图同时打开串行和 MTP 接口(interface)。这是我的代码:

private class SetupInterfacesRunnable implements Runnable
{
    @Override
    public void run()
    {
        synchronized(MyService.this)
        {
            usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
            usbConnection = usbManager.openDevice(usbDevice);

            /*
            interface :: id : 0, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
            interface :: id : 1, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
            interface :: id : 2, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
            interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage
             */

            // Interface 1 on the composite usb device is cdc acm data.
            serialPort = UsbSerialDevice.createUsbSerialDevice(usbDevice, usbConnection, 1);
            if(serialPort != null)
            {
                if(serialPort.open())
                {
                    serialPort.setBaudRate(115200);
                    serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
                    serialPort.setParity(UsbSerialInterface.PARITY_NONE);
                    serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
                    serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);

                    mUIHandler.post(notifyRadgetConnected);

                    // set the callback to catch serial data
                    serialPort.read(mCallback);

                    mUIHandler.post(handshake);

                }else
                {
                    // Serial port could not be opened, maybe an I/O error or it CDC driver was chosen it does not really fit
                    LoggerV2.e("Failed to open device serial port");
                }
            }else
            {
                // No driver for given device, even generic CDC driver could not be loaded
                LoggerV2.e("Failed to find driver for the serial device");
            }

            // Interface 2 on the composite usb device is MTP. 
            MtpDevice mtpDevice = new MtpDevice(usbDevice);
            if (!mtpDevice.open(usbConnection)) {
                LoggerV2.e("Failed to obtain device mtp storage");
            }

        }
    }
}

我正在使用的串行实现 (felHR85/UsbSerial) 能够打开单个接口(interface),但是,我看不到以这种方式实现 MTPDevice 类的简单方法。

Android MTP API 似乎希望在调用打开函数时打开整个设备/连接。

native_open(mDevice.getDeviceName(), connection.getFileDescriptor());

API 文档: https://developer.android.com/reference/android/mtp/MtpDevice.html

源代码: https://android.googlesource.com/platform/frameworks/base/+/master/media/java/android/mtp/MtpDevice.java

我看不到只打开一个界面的方法。我是否缺少使用连接在同一设备上打开多个接口(interface)的一些简单方法?

最佳答案

简短的回答/解决方法是在接口(interface) 0 上运行 MTP 响应程序,然后在 MTP 设备之后打开串行端口。

较长的答案是... 深入研究代码后,我发现 native_open 调用通过以下源文件进行过滤:

  • MtpDevice.java
    • android_mtp_MtpDevice.cpp
      • MtpDevice.cpp

MtpDevice.cpp: https://android.googlesource.com/platform/frameworks/av/+/master/media/mtp/MtpDevice.cpp

在 MtpDevice.cpp 中,我似乎会失败,并在日志中打印“未找到端点\n”错误消息,就好像它找不到正确的端点一样。

现在我最终通过首先使用 MTP 重新排序接口(interface)来解决这个问题:

interface :: id : 0, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
interface :: id : 1, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
interface :: id : 2, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage

这让我可以先打开MTP设备,然后通过接口(interface)打开串口:

private class SetupInterfacesRunnable implements Runnable
{
    @Override
    public void run()
    {
        synchronized(RadgetService.this)
        {
            usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
            usbConnection = usbManager.openDevice(usbDevice);

            /*
            interface :: id : 0, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
            interface :: id : 1, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
            interface :: id : 2, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
            interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage
             */

            // Interface 0 on the composite device is MTP
            MtpDevice mtpDevice = new MtpDevice(usbDevice);
            if (!mtpDevice.open(usbConnection)) {
                LoggerV2.e("Failed to obtain radget mtp storage");
            }
            else
            {
                LoggerV2.i("Opened MTP storage: %s", mtpDevice.getDeviceName());

                int[] storageIds = mtpDevice.getStorageIds();
                if (storageIds == null) {
                    LoggerV2.i("No mtp storage id's found");
                    return;
                }

                /*
                 * scan each storage
                 */
                for (int storageId : storageIds) {
                    LoggerV2.i("~~~~Storage id: %d~~~~", storageId);
                    scanObjectsInStorage(mtpDevice, storageId, 0, 0);
                }
            }

            // Interface 2 on the composite usb device is cdc acm data.
            serialPort = UsbSerialDevice.createUsbSerialDevice(usbDevice, usbConnection, 2);
            if(serialPort != null)
            {
                if(serialPort.open())
                {
                    serialPort.setBaudRate(115200);
                    serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
                    serialPort.setParity(UsbSerialInterface.PARITY_NONE);
                    serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
                    serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);

                    mUIHandler.post(notifyRadgetConnected);

                    // set the callback to catch serial data
                    serialPort.read(mCallback);

                    mUIHandler.post(handshake);

                }else
                {
                    // Serial port could not be opened, maybe an I/O error or it CDC driver was chosen it does not really fit
                    LoggerV2.e("Failed to open device serial port");
                }
            }else
            {
                // No driver for given device, even generic CDC driver could not be loaded
                LoggerV2.e("Failed to find driver for serial device");
            }

        }
    }
}

关于java - Android MTP 客户端打开整个设备而不是单个界面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42680742/

相关文章:

java - 如何将我的应用程序的大小设置为与图像相同

java - 如何 JUnit 测试我的模拟方法是否使用我想要的参数(不仅仅是 id,而是深度相等匹配器)调用?

android - 为什么 AppCompatActivity 不像 Activity 那样抛出 RuntimeException ("Stub!")?

android - 如何从 Android 连接 phpmyadmin

oop - 为什么类的私有(private)部分被视为接口(interface)?

c# - 如何在 C# 中处理组合类

java - 为什么监听器有时注册到 "this",有时注册到匿名类?

java - 由于什么原因从 Apache httpClient 中删除了预身份验证?

java - 使用 SHA-256 散列图像字节会产生许多随机冲突,我做错了什么?

java - 如何在每次按下屏幕时绘制新的位图