Saat berada dalam mode host USB, perangkat Android berfungsi sebagai host USB, mengaktifkan bus, dan memerinci perangkat USB yang terhubung. Mode host USB didukung di Android 3.1 dan yang lebih tinggi.
Ringkasan API
Sebelum memulai, penting untuk memahami semua class yang perlu Anda gunakan. Tabel
berikut menjelaskan API host USB dalam paket android.hardware.usb
.
Class | Deskripsi |
---|---|
UsbManager |
Memungkinkan Anda memerinci dan berkomunikasi dengan perangkat USB yang tersambung. |
UsbDevice |
Mewakili perangkat USB yang terhubung dan berisi metode untuk mengakses informasi identitas, antarmuka, dan endpoint-nya. |
UsbInterface |
Menampilkan antarmuka perangkat USB, yang menentukan serangkaian fungsi untuk perangkat. Perangkat dapat memiliki satu atau beberapa antarmuka yang dapat digunakan untuk berkomunikasi. |
UsbEndpoint |
Menunjukkan antarmuka endpoint, yang merupakan saluran komunikasi untuk antarmuka ini. Antarmuka dapat memiliki satu atau beberapa endpoint, serta biasanya memiliki endpoint input dan output untuk komunikasi dua arah dengan perangkat. |
UsbDeviceConnection |
Menunjukkan koneksi ke perangkat, yang mentransfer data pada endpoint. Dengan class ini, Anda dapat mengirim data bolak-balik secara sinkron atau asinkron. |
UsbRequest |
Menunjukkan konten asinkron untuk berkomunikasi dengan perangkat melalui UsbDeviceConnection . |
UsbConstants |
Menentukan konstanta USB yang sesuai dengan definisi dalam linux/usb/ch9.h di kernel Linux. |
Umumnya, Anda perlu menggunakan semua class ini (UsbRequest
hanya diperlukan jika Anda melakukan komunikasi asinkron)
saat berkomunikasi dengan perangkat USB. Secara umum, Anda perlu mendapatkan UsbManager
untuk mengambil UsbDevice
yang diinginkan.
Jika memiliki perangkat, Anda perlu menemukan UsbInterface
dan UsbEndpoint
yang sesuai untuk antarmuka
tersebut untuk berkomunikasi. Setelah mendapatkan endpoint yang benar, buka UsbDeviceConnection
untuk berkomunikasi dengan perangkat USB.
Persyaratan manifes Android
Daftar berikut menjelaskan hal yang perlu Anda tambahkan ke file manifes aplikasi sebelum menggunakan API host USB:
- Karena tidak semua perangkat Android dijamin mendukung API host USB,
sertakan elemen
<uses-feature>
yang mendeklarasikan bahwa aplikasi Anda menggunakan fiturandroid.hardware.usb.host
. - Tetapkan SDK minimum aplikasi ke API Level 12 atau yang lebih tinggi. API host USB tidak ada pada API level sebelumnya.
- Jika ingin aplikasi Anda diberi tahu tentang perangkat USB yang terpasang, tentukan
pasangan elemen
<intent-filter>
dan<meta-data>
untuk intentandroid.hardware.usb.action.USB_DEVICE_ATTACHED
dalam aktivitas utama Anda. Elemen<meta-data>
mengarah ke file resource XML eksternal yang mendeklarasikan informasi identitas tentang perangkat yang ingin dideteksi.Dalam file resource XML, deklarasikan elemen
<usb-device>
untuk perangkat USB yang ingin Anda filter. Daftar berikut menjelaskan atribut<usb-device>
. Secara umum, gunakan ID produk dan vendor jika Anda ingin memfilter perangkat tertentu serta gunakan class, subclass, dan protokol jika Anda ingin memfilter sekelompok perangkat USB, seperti perangkat penyimpanan massal atau kamera digital. Anda dapat menentukan tidak satu pun atau semua atribut ini. Tidak menentukan atribut akan cocok dengan setiap perangkat USB, jadi hanya lakukan hal ini jika aplikasi Anda memerlukannya:vendor-id
product-id
class
subclass
protocol
(perangkat atau antarmuka)
Simpan file resource di direktori
res/xml/
. Nama file resource (tanpa ekstensi .xml) harus sama dengan yang Anda tentukan dalam elemen<meta-data>
. Format untuk file resource XML ada dalam contoh di bawah.
Contoh file resource dan manifes
Contoh berikut menunjukkan contoh manifes dan file resource yang sesuai:
<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>
Dalam hal ini, file resource berikut harus disimpan di
res/xml/device_filter.xml
dan menentukan bahwa setiap perangkat USB dengan atribut
yang ditentukan harus difilter:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" /> </resources>
Menggunakan perangkat
Saat pengguna menghubungkan perangkat USB ke perangkat Android, sistem Android dapat menentukan apakah aplikasi Anda tertarik pada perangkat yang terhubung. Jika demikian, Anda dapat menyiapkan komunikasi dengan perangkat jika diinginkan. Untuk melakukannya, aplikasi Anda harus:
- Temukan perangkat USB yang terhubung dengan menggunakan filter intent agar diberi tahu saat pengguna menghubungkan perangkat USB atau dengan memerinci perangkat USB yang sudah terhubung.
- Meminta izin kepada pengguna untuk tersambung ke perangkat USB, jika belum diizinkan.
- Berkomunikasi dengan perangkat USB dengan membaca dan menulis data pada endpoint antarmuka yang sesuai.
Menemukan perangkat
Aplikasi Anda dapat menemukan perangkat USB dengan menggunakan filter intent agar diberi tahu saat pengguna menghubungkan perangkat atau dengan memerinci perangkat USB yang sudah terhubung. Penggunaan filter intent berguna jika Anda ingin aplikasi Anda otomatis mendeteksi perangkat yang diinginkan. Memerinci perangkat USB yang terhubung akan berguna jika Anda ingin mendapatkan daftar semua perangkat yang terhubung atau jika aplikasi Anda tidak memfilter intent.
Menggunakan filter intent
Agar aplikasi menemukan perangkat USB tertentu, Anda dapat menentukan filter intent untuk
memfilter intent android.hardware.usb.action.USB_DEVICE_ATTACHED
. Bersama dengan
filter intent ini, Anda harus menentukan file resource yang menentukan properti perangkat
USB, seperti ID produk dan vendor. Saat pengguna menghubungkan perangkat yang sesuai dengan filter
perangkat Anda, sistem akan menampilkan dialog yang menanyakan apakah mereka ingin memulai aplikasi Anda.
Jika pengguna menyetujuinya, aplikasi Anda secara otomatis memiliki izin untuk mengakses perangkat hingga
koneksi perangkat terputus.
Contoh berikut menunjukkan cara mendeklarasikan filter 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>
Contoh berikut menunjukkan cara mendeklarasikan file resource yang sesuai yang menentukan perangkat USB yang diinginkan:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" /> </resources>
Dalam aktivitas, Anda bisa mendapatkan UsbDevice
yang mewakili
perangkat yang terpasang dari intent seperti ini:
Kotlin
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
Java
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
Memerinci perangkat
Jika ingin memeriksa semua perangkat USB yang saat ini tersambung
selagi berjalan, aplikasi Anda dapat memerinci perangkat di bus. Gunakan metode getDeviceList()
untuk mendapatkan peta hash semua
perangkat USB yang terhubung. Peta hash disertakan oleh nama perangkat USB jika Anda ingin
mendapatkan perangkat dari peta.
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager ... val deviceList = manager.getDeviceList() val device = deviceList.get("deviceName")
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); ... HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); UsbDevice device = deviceList.get("deviceName");
Jika diinginkan, Anda juga dapat memperoleh iterator dari peta hash dan memproses setiap perangkat satu per satu:
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager .. val deviceList: HashMap<String, UsbDevice> = manager.deviceList deviceList.values.forEach { device -> // your code }
Java
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 }
Mendapatkan izin untuk berkomunikasi dengan perangkat
Sebelum berkomunikasi dengan perangkat USB, aplikasi Anda harus mendapatkan izin dari pengguna.
Catatan: Jika aplikasi Anda menggunakan filter intent untuk menemukan perangkat USB saat terhubung, aplikasi tersebut akan otomatis menerima izin jika pengguna mengizinkan aplikasi Anda menangani intent. Jika tidak, Anda harus meminta izin secara eksplisit di aplikasi sebelum dapat menghubungkannya ke perangkat.
Meminta izin secara eksplisit mungkin diperlukan dalam beberapa situasi, seperti saat aplikasi Anda memerinci perangkat USB yang sudah terhubung, lalu ingin berkomunikasi dengan salah satunya. Anda harus memeriksa izin untuk mengakses perangkat sebelum mencoba berkomunikasi dengannya. Jika tidak, Anda akan menerima error runtime jika pengguna menolak izin untuk mengakses perangkat.
Untuk mendapatkan izin secara eksplisit, buat penerima siaran terlebih dahulu. Penerima ini memproses
intent yang disiarkan saat Anda memanggil requestPermission()
. Panggilan ke requestPermission()
menampilkan dialog kepada
pengguna untuk meminta izin untuk terhubung ke perangkat. Kode contoh berikut menunjukkan cara
membuat penerima siaran:
Kotlin
private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION" private val usbReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (ACTION_USB_PERMISSION == intent.action) { synchronized(this) { val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { device?.apply { // call method to set up device communication } } else { Log.d(TAG, "permission denied for device $device") } } } } }
Java
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; private final BroadcastReceiver usbReceiver = 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); } } } } };
Untuk mendaftarkan penerima siaran, tambahkan penerima siaran ini di metode onCreate()
dalam
aktivitas Anda:
Kotlin
private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION" ... val manager = getSystemService(Context.USB_SERVICE) as UsbManager ... permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE) val filter = IntentFilter(ACTION_USB_PERMISSION) registerReceiver(usbReceiver, filter)
Java
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; ... permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(usbReceiver, filter);
Untuk menampilkan dialog yang meminta izin kepada pengguna untuk tersambung ke perangkat, panggil requestPermission()
metode:
Kotlin
lateinit var device: UsbDevice ... usbManager.requestPermission(device, permissionIntent)
Java
UsbDevice device; ... usbManager.requestPermission(device, permissionIntent);
Saat pengguna membalas dialog, penerima siaran Anda akan menerima intent yang berisi
tambahan EXTRA_PERMISSION_GRANTED
, yang berupa boolean
yang menunjukkan jawabannya. Periksa nilai true dalam tambahan ini sebelum menghubungkan ke
perangkat.
Berkomunikasi dengan perangkat
Komunikasi dengan perangkat USB dapat bersifat tersinkron atau asinkron. Dalam kedua kasus tersebut, Anda
harus membuat thread baru untuk melakukan semua transmisi data, sehingga UI thread
tidak diblokir. Untuk menyiapkan komunikasi dengan perangkat secara tepat, Anda perlu mendapatkan
UsbInterface
dan UsbEndpoint
perangkat yang sesuai yang ingin digunakan untuk berkomunikasi dan mengirim permintaan pada endpoint ini dengan UsbDeviceConnection
. Secara umum, kode Anda harus:
- Periksa atribut objek
UsbDevice
, seperti ID produk, ID vendor, atau class perangkat untuk mengetahui apakah Anda ingin berkomunikasi dengan perangkat atau tidak. - Setelah yakin ingin berkomunikasi dengan perangkat, temukan
UsbInterface
yang sesuai yang ingin digunakan untuk berkomunikasi, besertaUsbEndpoint
antarmuka tersebut yang sesuai. Antarmuka dapat memiliki satu atau beberapa endpoint, dan biasanya akan memiliki endpoint input dan output untuk komunikasi dua arah. - Setelah menemukan endpoint yang benar, buka
UsbDeviceConnection
pada endpoint tersebut. - Sediakan metode
bulkTransfer()
ataucontrolTransfer()
untuk data yang ingin dikirim pada endpoint. Anda harus melakukan langkah ini di thread lain untuk mencegah pemblokiran UI thread utama. Untuk mengetahui informasi selengkapnya tentang cara menggunakan thread di Android, lihat Proses dan Thread.
Cuplikan kode berikut menunjukkan cara mudah untuk melakukan transfer data sinkron. Kode Anda harus memiliki lebih banyak logika agar dapat menemukan antarmuka dan endpoint yang tepat dengan benar untuk berkomunikasi dan juga harus melakukan transfer data di thread yang berbeda dari UI thread utama:
Kotlin
private lateinit var bytes: ByteArray private val TIMEOUT = 0 private val forceClaim = true ... device?.getInterface(0)?.also { intf -> intf.getEndpoint(0)?.also { endpoint -> usbManager.openDevice(device)?.apply { claimInterface(intf, forceClaim) bulkTransfer(endpoint, bytes, bytes.size, TIMEOUT) //do in another thread } } }
Java
private Byte[] bytes; private static int TIMEOUT = 0; private boolean forceClaim = true; ... UsbInterface intf = device.getInterface(0); UsbEndpoint endpoint = intf.getEndpoint(0); UsbDeviceConnection connection = usbManager.openDevice(device); connection.claimInterface(intf, forceClaim); connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread
Untuk mengirim data secara asinkron, gunakan class UsbRequest
untuk initialize
dan queue
dalam permintaan asinkron, lalu tunggu hasilnya
dengan requestWait()
.
Menghentikan komunikasi dengan perangkat
Setelah selesai berkomunikasi dengan perangkat atau jika perangkat dilepas, tutup UsbInterface
dan UsbDeviceConnection
dengan
memanggil releaseInterface()
dan
close()
. Untuk memproses peristiwa terpisah,
buat penerima siaran seperti di bawah ini:
Kotlin
var usbReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (UsbManager.ACTION_USB_DEVICE_DETACHED == intent.action) { val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) device?.apply { // call your method that cleans up and closes communication with the device } } } }
Java
BroadcastReceiver usbReceiver = 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 } } } };
Membuat penerima siaran dalam aplikasi, dan bukan manifes, memungkinkan aplikasi Anda hanya menangani peristiwa terpisah saat sedang berjalan. Dengan cara ini, peristiwa terpisah hanya dikirim ke aplikasi yang sedang berjalan dan tidak disiarkan ke semua aplikasi.