Panoramica degli accessori USB

La modalità accessorio USB consente agli utenti di connettersi Hardware host USB progettato appositamente per i dispositivi Android. Gli accessori devono rispettare al protocollo degli accessori Android descritto nella documentazione relativa al kit di sviluppo accessori Android. Ciò consente ai dispositivi Android che non possono fungere da host USB di interagire comunque con USB hardware. Quando un dispositivo Android è in modalità accessorio USB, il token USB Android collegato l'accessorio funge da host, fornisce l'alimentazione al bus USB ed elenca i dispositivi connessi. Android 3.1 (livello API 12) supporta la modalità accessorio USB ed è inoltre eseguito il backporting della funzione in Android 2.3.4 (livello API 10) per consentire il supporto di una gamma più ampia di dispositivi.

Scegli le API per accessori USB adatte

Anche se le API accessorie USB sono state introdotte sulla piattaforma in Android 3.1, sono disponibile in Android 2.3.4 con la libreria dei componenti aggiuntivi delle API di Google. Poiché queste API erano con una libreria esterna, ci sono due pacchetti che puoi importare per supportare modalità accessorio. A seconda dei dispositivi Android che vuoi supportare, potresti dover utilizzale una sull'altra:

  • com.android.future.usb. Per supportare la modalità accessorio USB in Android 2.3.4, Componente aggiuntivo API di Google include le API per gli accessori USB con backporting, che sono contenute nello spazio dei nomi. Android 3.1 supporta anche l'importazione e la chiamata delle classi all'interno di questo spazio dei nomi per supportare applicazioni scritte con la libreria dei componenti aggiuntivi. La raccolta di componenti aggiuntivi è un wrapper sottile le API accessorie di android.hardware.usb e non supporta la modalità host USB. Se Se vuoi supportare la più vasta gamma di dispositivi che supportano la modalità accessori USB, usa libreria e importa questo pacchetto. È importante notare che non tutti i dispositivi Android 2.3.4 sono dotati necessaria per supportare la funzionalità dell'accessorio USB. Ogni singolo produttore di dispositivi decide se supportare o meno questa funzionalità, motivo per cui devi dichiararla nel tuo file manifest .
  • android.hardware.usb: questo spazio dei nomi contiene le classi che supportano USB modalità accessorio in Android 3.1. Questo pacchetto fa parte delle API del framework, quindi Android 3.1 supporta la modalità accessorio USB senza utilizzare una libreria di componenti aggiuntivi. Utilizza questo pacchetto se ti interessano solo i dispositivi Android 3.1 o versioni successive che supportano hardware per USB accessori, che puoi dichiarare nel file manifest.

Installa la libreria dei componenti aggiuntivi delle API di Google

Se vuoi installare il componente aggiuntivo, puoi farlo installando l'API Android 10 delle API di Google con SDK Manager. Consulta Installazione delle API di Google Componente aggiuntivo per ulteriori informazioni sull'installazione della libreria dei componenti aggiuntivi.

Panoramica dell'API

Poiché la libreria dei componenti aggiuntivi è un wrapper per le API del framework, le classi che supportano Le funzionalità degli accessori USB sono simili. Puoi utilizzare la documentazione di riferimento per android.hardware.usb anche se usi la libreria dei componenti aggiuntivi.

Nota: vi è, tuttavia, un lieve utilizzo la differenza di cui dovresti essere a conoscenza tra la libreria dei componenti aggiuntivi e le API del framework.

La tabella seguente descrive le classi che supportano le API degli accessori USB:

Classe Descrizione
UsbManager Consente di enumerare e comunicare con gli accessori USB collegati.
UsbAccessory Rappresenta un accessorio USB e contiene metodi per accedere al suo informazioni.

Differenze di utilizzo tra la libreria dei componenti aggiuntivi e le API della piattaforma

Esistono due differenze di utilizzo tra l'uso della libreria dei componenti aggiuntivi delle API di Google e la piattaforma su quelle di livello inferiore.

Se utilizzi la libreria di componenti aggiuntivi, devi ottenere l'oggetto UsbManager nel seguente modo:

Kotlin

val manager = UsbManager.getInstance(this)

Java

UsbManager manager = UsbManager.getInstance(this);

Se non utilizzi la libreria dei componenti aggiuntivi, devi ottenere l'oggetto UsbManager nel seguente modo:

Kotlin

val manager = getSystemService(Context.USB_SERVICE) as UsbManager

Java

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);

Quando filtri un accessorio connesso con un filtro per intent, l'oggetto UsbAccessory è contenuto nell'intent trasmesso al tuo un'applicazione. Se utilizzi la libreria di componenti aggiuntivi, devi ottenere l'oggetto UsbAccessory nel seguente modo:

Kotlin

val accessory = UsbManager.getAccessory(intent)

Java

UsbAccessory accessory = UsbManager.getAccessory(intent);

Se non utilizzi la libreria dei componenti aggiuntivi, devi ottenere l'oggetto UsbAccessory nel seguente modo:

Kotlin

val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory

Java

UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);

Requisiti per il file manifest di Android

Nell'elenco seguente viene descritto ciò che è necessario aggiungere al file manifest della tua applicazione prima che lavora con le API degli accessori USB. Il file manifest e le risorse esempi mostrano come dichiarare questi articoli:

  • Poiché non è garantito che tutti i dispositivi Android supportino le API degli accessori USB, includi un elemento <uses-feature> che dichiara che l'applicazione utilizza la funzionalità android.hardware.usb.accessory.
  • Se utilizzi raccolta di componenti aggiuntivi, aggiungi l'elemento <uses-library> specificando com.android.future.usb.accessory per la raccolta.
  • Imposta l'SDK minimo dell'applicazione sul livello API 10 se utilizzi la libreria dei componenti aggiuntivi. o 12 se utilizzi il pacchetto android.hardware.usb.
  • Se desideri che la tua applicazione riceva una notifica relativa a un accessorio USB collegato, specifica Coppia di elementi <intent-filter> e <meta-data> per android.hardware.usb.action.USB_ACCESSORY_ATTACHED intent nell'attività principale. L'elemento <meta-data> rimanda a un file di risorse XML esterno che dichiara le informazioni identificative sull'accessorio che vuoi rilevare.

    Nel file di risorse XML, dichiara gli elementi <usb-accessory> per gli accessori che vuoi filtrare. Ogni <usb-accessory> può avere i seguenti attributi:

    • manufacturer
    • model
    • version

    L'applicazione di filtri in base a version non è consigliata. Un accessorio o il dispositivo potrebbe non specificare sempre una stringa di versione (intenzionalmente o involontariamente). Quando la tua app dichiara un attributo versione a cui applicare il filtro e l'accessorio o il dispositivo non specifica una stringa di versione, questo determina un NullPointerException con le versioni precedenti di Android. Il problema è stato risolto in Android 12.

    Salva il file della risorsa nella directory res/xml/. Il nome del file della risorsa (senza l'estensione .xml) deve essere uguale a quello specificato nel Elemento <meta-data>. Il formato per il file di risorse XML è mostrato anche in nell'esempio riportato di seguito.

Esempi di file manifest e di risorse

L'esempio seguente mostra un manifest di esempio e il file di risorse corrispondente:

<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>

In questo caso, il seguente file di risorse deve essere salvato res/xml/accessory_filter.xml e specifica che tutti gli accessori il modello, il produttore e la versione corrispondenti devono essere filtrati. L'accessorio invia questi dati attribuisce il dispositivo Android:

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

<resources>
    <usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/>
</resources>

Utilizzare gli accessori

Quando gli utenti collegano accessori USB a un dispositivo Android, il sistema Android può determinare se la tua applicazione è interessata all'accessorio connesso. In tal caso, puoi impostare comunicare con l'accessorio, se lo desideri. Per farlo, la tua applicazione deve:

  1. Scopri gli accessori connessi usando un filtro per intent che filtra in base agli accessori eventi collegati o enumerando gli accessori collegati per trovare quello appropriato.
  2. Chiedi all'utente l'autorizzazione a comunicare con l'accessorio, se non lo è già ottenuto.
  3. Comunica con l'accessorio leggendo e scrivendo i dati nell'interfaccia appropriata endpoint.

Scopri un accessorio

La tua applicazione può rilevare gli accessori utilizzando un filtro per intent per ricevere una notifica quando l'utente connette un accessorio o elenca gli accessori già collegati. L'utilizzo di un è utile se vuoi che la tua applicazione rilevi automaticamente l'accessorio desiderato. L'enumerazione degli accessori collegati è utile se vuoi ottenere un elenco di tutti accessori connessi o se la tua applicazione non ha filtrato in base a un intent.

Utilizzare un filtro per intent

Per fare in modo che la tua applicazione rilevi un particolare accessorio USB, puoi specificare un filtro per intent per filtrare in base all'intent android.hardware.usb.action.USB_ACCESSORY_ATTACHED. Lungo con questo filtro per intent, devi specificare un file di risorse che specifichi le proprietà come produttore, modello e versione.

L'esempio seguente mostra come dichiarare il filtro per 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>

L'esempio seguente mostra come dichiarare il file di risorse corrispondente che specifica Accessori USB che ti interessano:

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

<resources>
    <usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" />
</resources>

Nella tua attività, puoi ottenere il UsbAccessory che rappresenta l'accessorio collegato in questo modo (con la raccolta dei componenti aggiuntivi):

Kotlin

val accessory = UsbManager.getAccessory(intent)

Java

UsbAccessory accessory = UsbManager.getAccessory(intent);

o in questo modo (con le API della piattaforma):

Kotlin

val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory

Java

UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);

Enumera gli accessori

Puoi fare in modo che la tua applicazione evidenzi gli accessori che si sono identificati mentre dell'applicazione è in esecuzione.

Usa il metodo getAccessoryList() per ottenere un array di tutti gli accessori USB collegati:

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();

Nota: è supportato un solo accessorio connesso su una volta.

Ottenere l'autorizzazione per comunicare con un accessorio

Prima di comunicare con l'accessorio USB, l'applicazione deve avere l'autorizzazione del tuo utenti.

Nota: se la tua applicazione utilizza una filtro per intent per scoprire gli accessori quando sono collegati, riceve automaticamente se l'utente consente alla tua applicazione di gestire l'intent. In caso contrario, devi richiedere esplicitamente nella tua applicazione prima di connetterti all'accessorio.

Potrebbe essere necessario richiedere esplicitamente l'autorizzazione in alcune situazioni, ad esempio quando applicazione elenca gli accessori che sono già connessi e che poi vuole comunicare uno. Devi verificare l'autorizzazione per accedere a un accessorio prima di tentare di comunicare con quell'accessorio. In caso contrario, riceverai un errore di runtime se l'utente ha negato l'autorizzazione ad accedere al accessorio.

Per ottenere l'autorizzazione esplicitamente, crea prima un broadcast receiver. Questo ricevitore è in ascolto l'intent che viene trasmesso quando chiami requestPermission(). La chiamata a requestPermission() mostra una finestra di dialogo al utente che chiede l'autorizzazione per connettersi all'accessorio. Il seguente codice di esempio mostra come crea il broadcast receiver:

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);
                }
            }
        }
    }
};

Per registrare il broadcast receiver, inserisci questo nel metodo onCreate() nella tua attività:

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);

Per visualizzare la finestra di dialogo che chiede agli utenti l'autorizzazione per connettersi all'accessorio, chiama il Metodo requestPermission():

Kotlin

lateinit var accessory: UsbAccessory
...
usbManager.requestPermission(accessory, permissionIntent)

Java

UsbAccessory accessory;
...
usbManager.requestPermission(accessory, permissionIntent);

Quando gli utenti rispondono alla finestra di dialogo, il tuo broadcast receiver riceve l'intent che contiene la EXTRA_PERMISSION_GRANTED extra, che è un valore booleano che rappresentano la risposta. Controlla questo extra per verificare se è presente il valore true prima di eseguire la connessione al accessorio.

Comunicare con un accessorio

Puoi comunicare con l'accessorio utilizzando UsbManager per ottenere un descrittore di file in cui impostare flussi di input e output per leggere e scrivere dati descrittore. I flussi rappresentano gli endpoint collettivi di input e output dell'accessorio. Dovresti impostare la comunicazione tra il dispositivo e l'accessorio in un altro thread, così non blocchi thread principale della UI. L'esempio seguente mostra come aprire un accessorio con cui comunicare:

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();
    }
}

Nel metodo run() del thread, puoi leggere e scrivere sull'accessorio utilizzando gli oggetti FileInputStream o FileOutputStream. Durante la lettura dati da un accessorio con un oggetto FileInputStream, assicurati che il buffer che utilizzi sia abbastanza grande da memorizzare i dati del pacchetto USB. Il protocollo accessori Android supporta buffer di pacchetti fino a 16.384 byte, quindi si può scegliere di dichiarare sempre che il buffer è di questo dimensioni per la semplicità.

Nota:a un livello inferiore, i pacchetti sono di 64 byte per le porte USB e 512 byte per accessori USB ad alta velocità. Accessorio Android raggruppa i pacchetti per entrambe le velocità in un unico pacchetto logico per semplicità.

Per ulteriori informazioni sull'utilizzo dei thread in Android, consulta Processi e Thread.

Terminare la comunicazione con un accessorio

Quando hai finito di comunicare con un accessorio o se l'accessorio è stato scollegato, chiudi la che hai aperto chiamando close(). Per ascoltare gli eventi scollegati, crea un broadcast receiver come quello seguente:

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
            }
        }
    }
};

La creazione del broadcast receiver all'interno dell'applicazione, non del manifest, consente per gestire gli eventi scollegati solo mentre è in esecuzione. In questo modo, gli eventi scollegati vengono inviate solo all'applicazione attualmente in esecuzione e non trasmesse a tutte le applicazioni.