Mode aksesori USB memungkinkan pengguna menghubungkan hardware host USB yang dirancang khusus untuk perangkat Android. Aksesori harus mematuhi protokol aksesori Android yang diuraikan dalam dokumentasi Android Accessory Development Kit. Hal ini memungkinkan perangkat Android yang tidak dapat bertindak sebagai host USB tetap berinteraksi dengan hardware USB. Saat perangkat Android berada dalam mode aksesori USB, aksesori USB Android yang terpasang akan berfungsi sebagai host, memberikan daya ke bus USB, dan memerinci perangkat yang terhubung. Android 3.1 (API level 12) mendukung mode aksesori USB dan fitur ini juga di-backport ke Android 2.3.4 (API level 10) untuk memungkinkan dukungan bagi berbagai perangkat yang lebih luas.
Memilih API aksesori USB yang tepat
Meskipun diperkenalkan ke platform di Android 3.1, API aksesori USB juga tersedia di Android 2.3.4 menggunakan library add-on Google API. Karena API ini di-backport menggunakan library eksternal, ada dua paket yang dapat diimpor untuk mendukung mode aksesori USB. Bergantung pada perangkat Android yang ingin didukung, Anda mungkin harus menggunakan salah satunya:
com.android.future.usb
: Untuk mendukung mode aksesori USB di Android 2.3.4, library add-on Google API menyertakan API aksesori USB yang di-backport dan terdapat dalam namespace ini. Android 3.1 juga mendukung pengimporan dan pemanggilan class dalam namespace ini untuk mendukung aplikasi yang ditulis dengan library add-on. Library add-on ini adalah wrapper tipis di seluruh API aksesoriandroid.hardware.usb
dan tidak mendukung mode host USB. Jika Anda ingin mendukung berbagai perangkat yang mendukung mode aksesori USB, gunakan library add-on dan impor paket ini. Penting untuk diperhatikan bahwa tidak semua perangkat Android 2.3.4 diperlukan untuk mendukung fitur aksesori USB. Setiap produsen perangkat memutuskan apakah akan mendukung kemampuan ini atau tidak. Oleh karena itu, Anda harus mendeklarasikannya dalam file manifes.android.hardware.usb
: Namespace ini berisi class yang mendukung mode aksesori USB di Android 3.1. Paket ini disertakan sebagai bagian dari API framework, sehingga Android 3.1 mendukung mode aksesori USB tanpa menggunakan library add-on. Gunakan paket ini jika Anda hanya ingin menggunakan Android 3.1 atau perangkat yang lebih baru yang memiliki dukungan hardware untuk mode aksesori USB, yang dapat dideklarasikan dalam file manifes.
Menginstal library add-on Google API
Jika ingin menginstal add-on, Anda dapat melakukannya dengan menginstal paket Google API Android API 10 dengan SDK Manager. Lihat Menginstal Add-on Google API untuk mengetahui informasi selengkapnya tentang cara menginstal library add-on.
Ringkasan API
Karena library add-on adalah wrapper untuk API framework, class yang mendukung
fitur aksesori USB akan serupa. Anda dapat menggunakan dokumentasi referensi untuk android.hardware.usb
meskipun Anda menggunakan library add-on.
Catatan: Namun, ada perbedaan penggunaan kecil antara library add-on dan API framework yang harus Anda ketahui.
Tabel berikut menjelaskan class yang mendukung API aksesori USB:
Class | Deskripsi |
---|---|
UsbManager |
Memungkinkan Anda memerinci dan berkomunikasi dengan aksesori USB yang tersambung. |
UsbAccessory |
Menunjukkan aksesori USB dan berisi metode untuk mengakses informasi identitasnya. |
Perbedaan penggunaan library add-on dan API platform
Ada dua perbedaan dalam penggunaan library add-on Google API dan API platform.
Jika menggunakan library add-on, Anda harus mendapatkan objek UsbManager
dengan cara berikut:
Kotlin
val manager = UsbManager.getInstance(this)
Java
UsbManager manager = UsbManager.getInstance(this);
Jika tidak menggunakan library add-on, Anda harus mendapatkan objek UsbManager
dengan cara berikut:
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
Saat memfilter aksesori yang terhubung dengan filter intent, objek UsbAccessory
dimuat di dalam intent yang diteruskan ke
aplikasi Anda. Jika menggunakan library add-on, Anda harus mendapatkan objek UsbAccessory
dengan cara berikut:
Kotlin
val accessory = UsbManager.getAccessory(intent)
Java
UsbAccessory accessory = UsbManager.getAccessory(intent);
Jika tidak menggunakan library add-on, Anda harus mendapatkan objek UsbAccessory
dengan cara berikut:
Kotlin
val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory
Java
UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
Persyaratan manifes Android
Daftar berikut menjelaskan item yang perlu Anda tambahkan ke file manifes aplikasi sebelum menggunakan API aksesori USB. Contoh file manifes dan resource menunjukkan cara mendeklarasikan item ini:
- Karena tidak semua perangkat Android dijamin mendukung API aksesori USB,
sertakan elemen
<uses-feature>
yang mendeklarasikan bahwa aplikasi Anda menggunakan fiturandroid.hardware.usb.accessory
. - Jika Anda menggunakan
library add-on,
tambahkan elemen
<uses-library>
yang menentukancom.android.future.usb.accessory
untuk library. - Tetapkan SDK minimum aplikasi ke API Level 10 jika Anda menggunakan library add-on
atau 12 jika Anda menggunakan paket
android.hardware.usb
. -
Jika ingin aplikasi Anda mendapatkan notifikasi tentang aksesori USB yang terpasang, tentukan pasangan elemen
<intent-filter>
dan<meta-data>
untuk intentandroid.hardware.usb.action.USB_ACCESSORY_ATTACHED
dalam aktivitas utama Anda. Elemen<meta-data>
mengarah ke file resource XML eksternal yang mendeklarasikan informasi identitas tentang aksesori yang ingin dideteksi.Dalam file resource XML, deklarasikan elemen
<usb-accessory>
untuk aksesori yang ingin difilter. Setiap<usb-accessory>
dapat memiliki atribut berikut:manufacturer
model
version
Pemfilteran di
version
tidak direkomendasikan. Aksesori atau perangkat mungkin tidak selalu menentukan string versi (secara sengaja atau tidak sengaja). Jika aplikasi Anda mendeklarasikan atribut versi yang akan difilter dan aksesori atau perangkat tidak menentukan string versi, hal ini akan menyebabkanNullPointerException
pada versi Android yang lebih lama. Masalah ini telah diperbaiki di Android 12.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 juga ditunjukkan 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.accessory" /> <uses-sdk android:minSdkVersion="<version>" /> ... <application> <uses-library android:name="com.android.future.usb.accessory" /> <activity ...> ... <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity> </application> </manifest>
Dalam hal ini, file resource berikut harus disimpan di
res/xml/accessory_filter.xml
dan menentukan bahwa aksesori apa pun yang memiliki
model, produsen, dan versi yang sesuai harus difilter. Aksesori mengirimkan
atribut berikut ke perangkat Android:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/> </resources>
Menggunakan aksesori
Saat pengguna menghubungkan aksesori USB ke perangkat Android, sistem Android dapat menentukan apakah aplikasi Anda tertarik dengan aksesori yang terhubung. Jika demikian, Anda dapat menyiapkan komunikasi dengan aksesori jika diinginkan. Untuk melakukannya, aplikasi Anda harus:
- Temukan aksesori yang terhubung dengan menggunakan filter intent yang memfilter peristiwa aksesori terhubung atau dengan memerinci aksesori yang terhubung dan menemukan aksesori yang sesuai.
- Meminta izin kepada pengguna untuk berkomunikasi dengan aksesori, jika belum diizinkan.
- Berkomunikasi dengan aksesori dengan membaca dan menulis data di endpoint antarmuka yang sesuai.
Menemukan aksesori
Aplikasi Anda dapat menemukan aksesori dengan menggunakan filter intent agar diberi tahu saat pengguna menyambungkan aksesori atau dengan memerinci aksesori yang telah tersambung. Penggunaan filter intent berguna jika ingin aplikasi Anda mendeteksi aksesori yang diinginkan secara otomatis. Memerinci aksesori yang terhubung akan berguna jika Anda ingin mendapatkan daftar semua aksesori yang terhubung atau jika aplikasi Anda tidak memfilter intent.
Menggunakan filter intent
Agar aplikasi menemukan aksesori USB tertentu, Anda dapat menentukan filter intent
untuk memfilter intent android.hardware.usb.action.USB_ACCESSORY_ATTACHED
. Bersama
dengan filter intent ini, Anda harus menentukan file resource yang menentukan properti aksesori
USB, seperti produsen, model, dan versi.
Contoh berikut menunjukkan cara mendeklarasikan filter intent:
<activity ...> ... <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity>
Contoh berikut menunjukkan cara mendeklarasikan file resource yang sesuai yang menentukan aksesori USB yang diinginkan:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" /> </resources>
Dalam aktivitas, Anda bisa mendapatkan UsbAccessory
yang mewakili
aksesori yang terpasang dari intent seperti ini (dengan library add-on):
Kotlin
val accessory = UsbManager.getAccessory(intent)
Java
UsbAccessory accessory = UsbManager.getAccessory(intent);
atau seperti ini (dengan API platform):
Kotlin
val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory
Java
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
Memerinci aksesori
Anda dapat meminta aplikasi menghitung aksesori yang telah mengidentifikasi dirinya sendiri saat aplikasi berjalan.
Gunakan metode getAccessoryList()
untuk mendapatkan array semua aksesori USB yang terhubung:
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager val accessoryList: Array<out UsbAccessory> = manager.accessoryList
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); UsbAccessory[] accessoryList = manager.getAccessoryList();
Catatan: Hanya satu aksesori terhubung yang didukung dalam satu waktu.
Mendapatkan izin untuk berkomunikasi dengan aksesori
Sebelum berkomunikasi dengan aksesori USB, aplikasi Anda harus mendapatkan izin dari pengguna.
Catatan: Jika aplikasi Anda menggunakan filter intent untuk menemukan aksesori saat terhubung, aplikasi akan otomatis menerima izin jika pengguna mengizinkan aplikasi Anda menangani intent. Jika tidak, Anda harus meminta izin secara eksplisit di aplikasi agar dapat menghubungkannya ke aksesori.
Meminta izin secara eksplisit mungkin diperlukan dalam beberapa situasi, seperti saat aplikasi Anda memerinci aksesori yang sudah terhubung, lalu ingin berkomunikasi dengan salah satunya. Anda harus memeriksa izin untuk mengakses aksesori sebelum mencoba berkomunikasi dengannya. Jika tidak, Anda akan menerima error runtime jika pengguna menolak izin untuk mengakses aksesori.
Untuk mendapatkan izin secara eksplisit, buat penerima siaran terlebih dahulu. Penerima ini memproses
intent yang disiarkan saat Anda memanggil requestPermission()
. Panggilan ke requestPermission()
akan menampilkan dialog kepada
pengguna untuk meminta izin untuk terhubung ke aksesori. 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 accessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { accessory?.apply { // call method to set up accessory communication } } else { Log.d(TAG, "permission denied for accessory $accessory") } } } } }
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) { UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if(accessory != null){ // call method to set up accessory communication } } else { Log.d(TAG, "permission denied for accessory " + accessory); } } } } };
Untuk mendaftarkan penerima siaran, masukkan 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), 0) 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), 0); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(usbReceiver, filter);
Untuk menampilkan dialog yang meminta izin kepada pengguna untuk terhubung ke aksesori, panggil
metode requestPermission()
:
Kotlin
lateinit var accessory: UsbAccessory ... usbManager.requestPermission(accessory, permissionIntent)
Java
UsbAccessory accessory; ... usbManager.requestPermission(accessory, 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 pada tambahan ini sebelum menyambungkan ke
aksesori.
Berkomunikasi dengan aksesori
Anda dapat berkomunikasi dengan aksesori menggunakan UsbManager
untuk
mendapatkan deskriptor file yang dapat disiapkan aliran input dan outputnya untuk membaca dan menulis data ke
deskriptor. Stream tersebut menunjukkan endpoint massal input dan output aksesori. Anda harus menyiapkan
komunikasi antara perangkat dan aksesori di thread lain agar UI thread utama
tidak terkunci. Contoh berikut menunjukkan cara membuka aksesori untuk berkomunikasi:
Kotlin
private lateinit var accessory: UsbAccessory private var fileDescriptor: ParcelFileDescriptor? = null private var inputStream: FileInputStream? = null private var outputStream: FileOutputStream? = null ... private fun openAccessory() { Log.d(TAG, "openAccessory: $mAccessory") fileDescriptor = usbManager.openAccessory(accessory) fileDescriptor?.fileDescriptor?.also { fd -> inputStream = FileInputStream(fd) outputStream = FileOutputStream(fd) val thread = Thread(null, this, "AccessoryThread") thread.start() } }
Java
UsbAccessory accessory; ParcelFileDescriptor fileDescriptor; FileInputStream inputStream; FileOutputStream outputStream; ... private void openAccessory() { Log.d(TAG, "openAccessory: " + accessory); fileDescriptor = usbManager.openAccessory(accessory); if (fileDescriptor != null) { FileDescriptor fd = fileDescriptor.getFileDescriptor(); inputStream = new FileInputStream(fd); outputStream = new FileOutputStream(fd); Thread thread = new Thread(null, this, "AccessoryThread"); thread.start(); } }
Dalam metode run()
thread, Anda dapat membaca dan menulis ke aksesori menggunakan
objek FileInputStream
atau FileOutputStream
. Saat membaca
data dari aksesori dengan objek FileInputStream
, pastikan buffer yang
Anda gunakan cukup besar untuk menyimpan data paket USB. Protokol aksesori Android mendukung
buffering paket hingga 16.384 byte, sehingga Anda dapat memilih untuk selalu mendeklarasikan buffer dengan
ukuran ini agar lebih mudah.
Catatan: Pada tingkat yang lebih rendah, paketnya adalah 64 byte untuk aksesori berkecepatan penuh USB dan 512 byte untuk aksesori berkecepatan tinggi USB. Demi kemudahan, protokol aksesori Android menggabungkan paket untuk kedua kecepatan tersebut menjadi satu paket logis.
Untuk mengetahui informasi selengkapnya tentang cara menggunakan thread di Android, lihat Proses dan Thread.
Menghentikan komunikasi dengan aksesori
Setelah selesai berkomunikasi dengan aksesori atau jika aksesori dilepas, tutup
deskriptor file yang telah dibuka dengan memanggil close()
.
Untuk memproses aktivitas 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_ACCESSORY_DETACHED == intent.action) { val accessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) accessory?.apply { // call your method that cleans up and closes communication with the accessory } } } }
Java
BroadcastReceiver usbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) { UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (accessory != null) { // call your method that cleans up and closes communication with the accessory } } } };
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.