I'm developing an Android app for Android Smart TVs, and I'm facing difficulties accessing data from a connected USB device within the app. The app needs to detect USB devices connected to the Android Smart TV and fetch files from the USB storage.
I've implemented the necessary steps to detect USB devices and request permission to access them using the UsbManager and UsbDeviceConnection classes. However, I'm unable to access the content inside the USB drive using standard Java I/O classes for file operations.
Here's a summary of what I've tried:
- Detecting USB devices connected to the Android Smart TV using UsbManager.
- Requesting permission to access USB devices using UsbManager.requestPermission().
- Attempting to read files from the USB storage using FileInputStream and File classes.
Despite implementing these steps, I'm unable to access the data from the USB device.
Can someone provide guidance or a working example on how to properly access and fetch files from a connected USB device on an Android Smart TV within an Android app? Are there any specific considerations or limitations for accessing USB storage on Android Smart TVs that I should be aware of?
Any insights, code snippets, or resources would be greatly appreciated.
Thanks in advance!
Here is my code
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 { val usbDeviceDetailsList = mutableListOf() 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() 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(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 { val imageBitmaps = mutableListOf() 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 { val fileList = mutableListOf() // 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 // } }
Источник: https://stackoverflow.com/questions/781 ... ndroid-app