如何在Android应用程序中读取USB串口并从Android智能电视获取文件?

问题描述 投票:0回答:1

我正在为 Android 智能电视开发 Android 应用程序,但在应用程序内从连接的 USB 设备访问数据时遇到困难。该应用程序需要检测连接到 Android 智能电视的 USB 设备并从 USB 存储中获取文件。

我已经实现了检测 USB 设备并请求使用 UsbManager 和 UsbDeviceConnection 类访问它们的权限的必要步骤。但是,我无法使用标准 Java I/O 类进行文件操作来访问 USB 驱动器内的内容。

这是我尝试过的总结:

  1. 使用 UsbManager 检测连接到 Android 智能电视的 USB 设备。
  2. 使用 UsbManager.requestPermission() 请求访问 USB 设备的权限。
  3. 尝试使用 FileInputStream 和 File 类从 USB 存储读取文件。

尽管执行了这些步骤,我仍无法从 USB 设备访问数据。

有人可以提供有关如何在 Android 应用程序中从 Android 智能电视上连接的 USB 设备正确访问和获取文件的指南或工作示例吗?在 Android 智能电视上访问 USB 存储有什么我应该注意的具体注意事项或限制吗?

任何见解、代码片段或资源将不胜感激。

提前致谢!

这是我的代码

import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.hardware.usb.UsbConstants
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbEndpoint
import android.hardware.usb.UsbInterface
import android.hardware.usb.UsbManager
import android.os.Build
import android.os.Environment
import android.util.Log
import androidx.annotation.RequiresApi
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.nio.ByteBuffer

class SerialPortReader {

    private lateinit var usbManager: UsbManager
    private lateinit var usbInterface: UsbInterface
    private lateinit var usbEndpoint: UsbEndpoint
    private lateinit var usbDeviceConnection: UsbDeviceConnection
    private val ACTION_USB_PERMISSION = "com.example.usb_seriel_image.USB_PERMISSION"

    @RequiresApi(Build.VERSION_CODES.O)
    fun fetchConnectedUsbDevices(context: Context): List<Map<String, String>> {
        val usbDeviceDetailsList = mutableListOf<Map<String, String>>()

        try {
            usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager

            // Create a PendingIntent for USB permission request

            val permissionIntent =
                PendingIntent.getBroadcast(
                    context, 0, Intent(ACTION_USB_PERMISSION),
                    PendingIntent.FLAG_IMMUTABLE
                )

            // Register a BroadcastReceiver to handle USB permission request result
            context.registerReceiver(
                usbPermissionReceiver, IntentFilter(ACTION_USB_PERMISSION),
                Context.RECEIVER_NOT_EXPORTED
            )

            for (device in usbManager.deviceList.values) {
                val usbDeviceDetails = mutableMapOf<String, String>()

                usbDeviceDetails["deviceName"] = device.productName.toString()
                usbDeviceDetails["manufacturer"] = device.manufacturerName.toString()
                usbDeviceDetails["productId"] = device.productId.toString()
                usbDeviceDetails["vendorId"] = device.vendorId.toString()
                usbDeviceDetailsList.add(usbDeviceDetails)

                if (!device.productName!!.contains("Wireless_Device")) {
                    // Request permission to access USB device
                    usbManager.requestPermission(device, permissionIntent)
                    getImageDataFromUsbDevices(context!!, device)
                } else {
//                    return listOf(mapOf("message" to "No USB devices found"))
                }
            }
        } catch (error: Exception) {
            Log.e("[USB_SERIAL]", error.toString())
        }
        return usbDeviceDetailsList
    }

    fun getImageDataFromUsbDevices(context: Context, usbDevice: UsbDevice) {
        usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager

        val permissionIntent =
            PendingIntent.getBroadcast(
                context, 0, Intent(ACTION_USB_PERMISSION),
                PendingIntent.FLAG_IMMUTABLE
            )
        usbInterface = usbDevice.getInterface(0)
        usbEndpoint = usbInterface.getEndpoint(0)

        usbDeviceConnection = usbManager.openDevice(usbDevice)
        usbDeviceConnection.claimInterface(usbInterface, true)
        usbManager.requestPermission(usbDevice, permissionIntent)
        val imageData = readImagesFromUsbDevice(context, usbDevice)
        val data = getImageData(usbDevice)
        val bitmap = BitmapFactory.decodeByteArray(data, 0, data.size)
        saveImage(bitmap)

        usbDeviceConnection.releaseInterface(usbInterface)
        usbDeviceConnection.close()
    }

    private fun getImageData(usbDevice: UsbDevice): ByteArray {
        val buffer = ByteBuffer.allocate(64 * 1024)
        val packetSize = usbDevice.getInterface(0).getEndpoint(0).maxPacketSize

        while (buffer.position() < buffer.capacity()) {
            usbDeviceConnection.bulkTransfer(
                usbEndpoint, buffer.array(), buffer.position(),
                Math.min(packetSize, buffer.remaining()), 0
            )
        }

        return buffer.array()
    }

    private fun saveImage(bitmap: Bitmap) {
        val sdCard = Environment.getExternalStorageDirectory()
        val imagePath = "$sdCard/ImageFromUsb.jpg"
        val fileOutputStream: FileOutputStream
        val file = File(imagePath)

        try {
            fileOutputStream = FileOutputStream(file)
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream)
            fileOutputStream.flush()
            fileOutputStream.close()
            Log.d("[USB_SERIAL]", "Image saved at $imagePath")
        } catch (e: IOException) {
            Log.e("[USB_SERIAL]", e.toString())
        }
    }

    private val usbPermissionReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action == ACTION_USB_PERMISSION) {
                val granted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true)
                val device = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_ACCESSORY)
                if (granted && device != null) {
                    // Permission granted, proceed with accessing the USB device
                    getImageDataFromUsbDevices(context!!, device)
                } else {
                    // Permission denied, handle accordingly
                }
            }
        }
    }

    // Function to read images from USB device
    @RequiresApi(Build.VERSION_CODES.R)
    fun readImagesFromUsbDevice(context: Context, usbDevice: UsbDevice): List<Bitmap> {
        val imageBitmaps = mutableListOf<Bitmap>()
        val usbDeviceConnection = usbManager.openDevice(usbDevice)

        val permissionIntent =
            PendingIntent.getBroadcast(
                context, 0, Intent(ACTION_USB_PERMISSION),
                PendingIntent.FLAG_IMMUTABLE
            )
        // Check if USB device connection is null
        if (usbDeviceConnection != null) {
            val usbInterface = usbDevice.getInterface(0)
            val usbEndpoint = usbInterface.getEndpoint(0)

            // Access files on the USB drive
            val usbRootDirectory = Environment.getStorageDirectory()
            val usbDrive = File(usbRootDirectory, "/")

            val usbDeviceRootDirectory = getUsbDeviceRootDirectory(context, usbDevice)
//            val usbDrive = File(usbRootDirectory, "/")

// Get all files from the USB drive
            val allFiles = getAllFilesFromUsbDrive(usbDrive)
            // Filter image files (you can adjust file extensions as needed)
            val imageFiles = usbDrive.listFiles { _, name ->
                name.endsWith(".jpg") || name.endsWith(".jpleg") || name.endsWith(".png")
            }

            // Read and decode each image file
            imageFiles?.forEach { file ->
                try {
                    val inputStream = FileInputStream(file)
                    val bitmap = BitmapFactory.decodeStream(inputStream)
                    inputStream.close()
                    imageBitmaps.add(bitmap)
                } catch (e: Exception) {
                    Log.e("USB_IMAGE_READ", "Error reading image file: ${file.absolutePath}", e)
                }
            }
        } else {
            Log.e("USB_CONNECTION", "Failed to open USB device connection")
        }

        return imageBitmaps
    }

    fun getAllFilesFromUsbDrive(directory: File): List<File> {
        val fileList = mutableListOf<File>()

        // Check if the directory exists and is a directory
        if (directory.exists() && directory.isDirectory) {
            val files = directory.listFiles()

            // Loop through all files in the directory
            files?.forEach { file ->
                if (file.isDirectory) {
                    // Recursively call the function to get files from subdirectories
                    fileList.addAll(getAllFilesFromUsbDrive(file))
                } else {
                    // Add the file to the list
                    fileList.add(file)
                }
            }
        }

        return fileList
    }


    fun getUsbDeviceRootDirectory(context: Context, usbDevice: UsbDevice): File? {
        val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager

        val permissionIntent =
            PendingIntent.getBroadcast(
                context, 0, Intent(ACTION_USB_PERMISSION),
                PendingIntent.FLAG_IMMUTABLE
            )
        val deviceList = usbManager.deviceList
//        for (deviceEntry in deviceList.entries) {
//            val device = deviceEntry.value
//            if (device.deviceId == usbDevice.deviceId) {
        val usbDeviceConnection = usbManager.openDevice(usbDevice)
        val usbInterface = usbDevice.getInterface(0)
        usbManager.requestPermission(usbDevice, permissionIntent)
        // Iterate over the endpoints to find the one with file system access
        for (endpointIndex in 0 until usbInterface.endpointCount) {
            val endpoint = usbInterface.getEndpoint(endpointIndex)
            if (endpoint.type == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                // Check if the endpoint supports file system access
//                        if (endpoint.direction == UsbConstants.USB_DIR_IN) {
//                            // IN endpoint, skip as it's for data from the device to host
//                            continue
//                        } else if (endpoint.direction == UsbConstants.USB_DIR_OUT) {
//                            // OUT endpoint, skip as it's for data from host to device
//                            continue
//                        }

                // Found the correct endpoint, get the device's file system root directory
                val usbDeviceConnection = usbManager.openDevice(usbDevice)
                if (usbDeviceConnection != null && usbDeviceConnection.claimInterface(
                        usbInterface,
                        true
                    )
                ) {
                    // Get the file system root directory
                    val fsRoot = "/mnt/usb_storage/"
                    return File(fsRoot)
                }
            }
        }
//            }
//        }
        return null
    }

//    // Usage example:
//    val usbDeviceRootDirectory = getUsbDeviceRootDirectory(context, usbDevice)
//    if (usbDeviceRootDirectory != null)
//    {
//        // You have successfully obtained the USB device's file system root directory
//        // Now you can perform operations on files within this directory
//    } else
//    {
//        // Failed to obtain the USB device's file system root directory
//        // Handle the error accordingly
//    }

}
android kotlin serial-port usb smart-tv
1个回答
0
投票

使用 ACTION_OPEN_DOCUMENT_TREE 让用户选择驱动器或其上的文件夹。

© www.soinside.com 2019 - 2024. All rights reserved.