Ringkasan host USB

Saat berada dalam mode host USB, perangkat Android akan bertindak sebagai host USB, menyalakan bus, dan menyebutkan perangkat USB yang tersambung. 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. Tujuan tabel berikut menjelaskan API host USB dalam paket android.hardware.usb.

Tabel 1. API Host USB

Class Deskripsi
UsbManager Memungkinkan Anda memerinci dan berkomunikasi dengan perangkat USB yang tersambung.
UsbDevice Menunjukkan perangkat USB yang terhubung dan berisi metode untuk mengakses informasi, antarmuka, dan endpoint.
UsbInterface Menunjukkan antarmuka perangkat USB, yang mendefinisikan serangkaian fungsi untuk perangkat seluler. Perangkat dapat memiliki satu atau beberapa antarmuka yang dapat digunakan untuk berkomunikasi.
UsbEndpoint Menunjukkan antarmuka endpoint, yang merupakan saluran komunikasi untuk antarmuka ini. Channel antarmuka dapat memiliki satu atau lebih {i>endpoint<i}, dan biasanya memiliki titik akhir input dan {i>output<i} untuk komunikasi dua arah dengan perangkat.
UsbDeviceConnection Menunjukkan koneksi ke perangkat, yang mentransfer data pada endpoint. Kelas ini memungkinkan Anda mengirim data bolak-balik secara sinkron atau asinkron.
UsbRequest Menunjukkan konten asinkron untuk berkomunikasi dengan perangkat melalui UsbDeviceConnection.
UsbConstants Mendefinisikan konstanta USB yang sesuai dengan definisi di linux/usb/ch9.h Linux {i>kernel<i}.

Dalam sebagian besar situasi, 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 berkomunikasi. Setelah mendapatkan endpoint yang benar, buka UsbDeviceConnection untuk berkomunikasi dengan perangkat USB.

Persyaratan manifes Android

Daftar berikut menjelaskan apa saja yang perlu Anda tambahkan ke file manifes aplikasi sebelum menggunakan API host USB:

  • Karena tidak semua perangkat Android dijamin mendukung API {i>host<i} USB, menyertakan elemen <uses-feature> yang mendeklarasikan bahwa aplikasi Anda menggunakan fitur android.hardware.usb.host.
  • Tetapkan SDK minimum aplikasi ke API Level 12 atau yang lebih tinggi. API host USB tidak ada di level API sebelumnya.
  • Jika ingin aplikasi Anda diberi tahu tentang perangkat USB yang terpasang, tentukan Pasangan elemen <intent-filter> dan <meta-data> untuk android.hardware.usb.action.USB_DEVICE_ATTACHED dalam aktivitas utama Anda. Tujuan Elemen <meta-data> mengarah ke file resource XML eksternal yang mendeklarasikan pengidentifikasian informasi tentang perangkat yang ingin Anda deteksi.

    Dalam file resource XML, deklarasikan elemen <usb-device> untuk USB yang ingin difilter. Daftar berikut ini menjelaskan atribut <usb-device>. Secara umum, gunakan ID vendor dan produk jika Anda ingin memfilter untuk perangkat tertentu, dan gunakan class, subclass, serta protokol jika ingin memfilter grup perangkat USB, seperti perangkat penyimpanan massal atau kamera digital. Anda dapat menentukan tidak ada atau semua atribut ini. Menentukan tidak ada atribut yang cocok dengan setiap perangkat USB, jadi hanya lakukan 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 di Elemen <meta-data>. Format untuk file resource XML ada dalam contoh di bawah ini.

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 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 menyambungkan perangkat USB ke perangkat Android, sistem Android dapat menentukan apakah aplikasi tertarik pada perangkat yang terhubung. Jika demikian, Anda dapat menyiapkan komunikasi dengan perangkat jika diinginkan. Untuk melakukannya, aplikasi Anda harus:

  1. Menemukan perangkat USB yang terhubung dengan menggunakan filter intent agar diberi tahu saat pengguna menyambungkan perangkat USB atau dengan menghitung perangkat USB yang telah tersambung.
  2. Meminta izin kepada pengguna untuk tersambung ke perangkat USB, jika belum diizinkan.
  3. Berkomunikasi dengan perangkat USB dengan membaca dan menulis data pada antarmuka yang sesuai endpoint.

Menemukan perangkat

Aplikasi Anda bisa menemukan perangkat USB baik dengan menggunakan filter intent agar diberi tahu saat pengguna menghubungkan perangkat atau dengan menghitung perangkat USB yang sudah terhubung. Menggunakan filter intent berguna jika ingin agar aplikasi Anda dapat secara otomatis mendeteksi perangkat yang diinginkan. Memerinci perangkat USB yang tersambung berguna jika Anda ingin mendapatkan daftar semua perangkat yang terhubung atau jika aplikasi Anda tidak memfilter intent.

Menggunakan filter intent

Agar aplikasi Anda menemukan perangkat USB tertentu, Anda bisa menetapkan filter intent untuk filter untuk intent android.hardware.usb.action.USB_DEVICE_ATTACHED. Bersama dengan filter intent ini, Anda harus menetapkan file sumber daya yang menetapkan properti USB seperti ID produk dan vendor. Saat pengguna menghubungkan perangkat yang cocok dengan perangkat Anda , sistem akan menampilkan dialog yang menanyakan apakah mereka ingin memulai aplikasi Anda. Jika pengguna menerimanya, aplikasi Anda secara otomatis memiliki izin untuk mengakses perangkat hingga 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 atribut Perangkat USB yang perlu diperhatikan:

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <usb-device vendor-id="1234" product-id="5678" />
</resources>

Dalam aktivitas, Anda dapat memperoleh 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 aplikasi Anda tertarik untuk memeriksa semua perangkat USB yang saat ini tersambung ketika aplikasi sedang berjalan, aplikasi dapat menghitung perangkat di bus. Gunakan metode getDeviceList() untuk mendapatkan peta hash dari semua perangkat USB yang terhubung. Peta {i>hash <i}dikunci oleh nama perangkat USB jika Anda ingin untuk 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 bisa mendapatkan iterator dari peta hash dan memproses setiap perangkat dengan 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 memiliki izin dari pelanggan.

Catatan: Jika aplikasi Anda menggunakan filter intent untuk menemukan perangkat USB saat terhubung, perangkat tersebut akan otomatis menerima jika pengguna mengizinkan aplikasi Anda menangani intent tersebut. Jika tidak, Anda harus meminta secara eksplisit di aplikasi Anda sebelum menyambungkan ke perangkat.

Meminta izin secara eksplisit mungkin diperlukan dalam beberapa situasi, seperti saat aplikasi menghitung perangkat USB yang sudah terhubung dan kemudian ingin berkomunikasi dengan satu. Anda harus memeriksa izin untuk mengakses perangkat sebelum mencoba berkomunikasi dengannya. Jika tidak, Anda akan menerima pesan {i>error<i} runtime jika pengguna menolak izin untuk mengakses perangkat.

Untuk mendapatkan izin secara eksplisit, buat penerima siaran terlebih dahulu. Penerima ini mendengarkan intent yang akan disiarkan saat Anda memanggil requestPermission(). Panggilan ke requestPermission() menampilkan dialog ke pengguna yang meminta izin untuk terhubung ke perangkat. Kode contoh berikut menunjukkan cara buat 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() Anda aktivitas:

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 merupakan boolean merepresentasikan jawaban. Periksa nilai true (benar) tambahan ini sebelum menyambungkan ke perangkat seluler.

Berkomunikasi dengan perangkat

Komunikasi dengan perangkat USB dapat bersifat tersinkron atau asinkron. Dalam kedua kasus tersebut, Anda harus membuat utas baru untuk melakukan semua transmisi data, jadi Anda tidak memblokir Thread UI. Untuk mengatur komunikasi dengan perangkat secara benar, Anda perlu mendapatkan UsbInterface dan UsbEndpoint dari perangkat yang ingin digunakan untuk berkomunikasi dan mengirim permintaan di endpoint ini dengan UsbDeviceConnection. Secara umum, kode Anda harus:

  • Periksa atribut objek UsbDevice, seperti ID produk, ID vendor, atau kelas perangkat untuk mengetahui apakah Anda ingin berkomunikasi dengan perangkat seluler.
  • Apabila Anda yakin ingin berkomunikasi dengan perangkat, temukan UsbInterface yang ingin Anda gunakan untuk berkomunikasi bersama UsbEndpoint yang sesuai dari antarmuka tersebut. Antarmuka dapat memiliki satu atau lebih endpoint, dan umumnya akan memiliki endpoint input dan output komunikasi antarlayanan.
  • Setelah menemukan endpoint yang benar, buka UsbDeviceConnection pada endpoint tersebut.
  • Sediakan metode bulkTransfer() atau controlTransfer() untuk data yang ingin dikirim pada endpoint. Anda seharusnya melakukan langkah ini di thread lain untuk mencegah pemblokiran thread UI utama. Untuk selengkapnya informasi tentang penggunaan thread di Android, lihat Proses dan Rangkaian pesan.

Cuplikan kode berikut menunjukkan cara mudah untuk melakukan transfer data sinkron. Kode Anda harus memiliki lebih banyak logika untuk menemukan antarmuka dan endpoint yang benar dengan benar untuk berkomunikasi dan juga harus melakukan transfer data di thread yang berbeda dengan thread UI 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 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 apa pun untuk hanya menangani peristiwa terpisah saat sedang berjalan. Dengan cara ini, peristiwa terpisah menjadi hanya dikirim ke aplikasi yang sedang berjalan dan tidak disiarkan ke semua aplikasi.