Tryb akcesorium USB umożliwia użytkownikom Host USB zaprojektowany specjalnie dla urządzeń z Androidem. Akcesoria muszą spełniać wymagania z protokołem akcesoriów do Androida opisanym w dokumentacji pakietu Android Accessory Development Kit. Dzięki temu urządzenia z Androidem, które nie mogą działać jako host USB, mogą nadal wchodzić w interakcje z USB. sprzęt. Gdy urządzenie z Androidem działa w trybie akcesorium USB, podłączony port USB z Androidem akcesorium działa jako host, dostarcza zasilanie magistrali USB i wylicza połączone urządzenia. Android 3.1 (poziom interfejsu API 12) obsługuje tryb akcesoriów USB i funkcjonuje się również ponownie Androida 2.3.4 (poziom interfejsu API 10), aby zapewnić obsługę szerszej gamy urządzeń.
Wybierz odpowiednie interfejsy API akcesoriów USB
Chociaż interfejsy API akcesoriów USB zostały wprowadzone na platformie w Androidzie 3.1, są one również dostępne w Androidzie 2.3.4 przy użyciu biblioteki dodatku interfejsów API Google. Ponieważ te interfejsy API zostały z backportem przy użyciu zewnętrznej biblioteki. Są 2 pakiety, które możesz zaimportować, aby obsługiwać USB tryb akcesorium. W zależności od urządzeń z Androidem, które chcesz obsługiwać, konieczne może być używaj jednych i drugich:
com.android.future.usb
: aby zapewnić obsługę trybu akcesorium USB w Androidzie 2.3.4, Dodatek do interfejsów API Google obejmuje portowe interfejsy API akcesoriów USB, które znajdują się w przestrzeni nazw. Android 3.1 obsługuje również importowanie i wywoływanie klas w tej przestrzeni nazw, do obsługi aplikacji napisanych za pomocą biblioteki dodatków. Ta biblioteka dodatków jest cienkim otoczeniem wokół interfejsów API akcesoriówandroid.hardware.usb
i nie obsługuje trybu hosta USB. Jeśli Jeśli chcesz obsługiwać najszerszą gamę urządzeń obsługujących tryb akcesorium USB, użyj dodatku i zaimportuj ten pakiet. Należy pamiętać, że nie wszystkie urządzenia z Androidem 2.3.4 są wymagane do obsługi funkcji akcesorium USB. Każdy indywidualny producent urządzenia Ta funkcja jest obsługiwana, dlatego musisz zadeklarować ją w pliku manifestu. .android.hardware.usb
: ta przestrzeń nazw zawiera klasy obsługujące USB. trybu akcesorium w Androidzie 3.1. Ten pakiet wchodzi w skład interfejsów API platformy, dlatego Android 3.1 obsługuje tryb akcesorium USB bez konieczności korzystania z biblioteki dodatków. Użyj tego pakietu jeśli zależy Ci tylko na urządzeniach z Androidem 3.1 lub nowszym, które obsługują sprzętową obsługę USB trybu akcesorium, który można zadeklarować w pliku manifestu.
Instalowanie biblioteki dodatku do interfejsów API Google
Jeśli chcesz zainstalować dodatek, możesz to zrobić, instalując interfejsy API Google Android API 10 w pakiecie SDK w usłudze SDK Manager. Patrz: Instalowanie interfejsów API Google Dodatek, który zawiera więcej informacji o instalowaniu biblioteki dodatków.
Omówienie interfejsu API
Biblioteka dodatku jest otoką interfejsów API platformy, dlatego klasy, które obsługują
Funkcja akcesorium USB jest podobna. Nawet jeśli korzystasz z biblioteki dodatków, możesz skorzystać z dokumentacji referencyjnej dotyczącej android.hardware.usb
.
Uwaga: występuje jednak niewielkie użycie między biblioteką dodatku a interfejsami API platformy, o których warto wiedzieć.
W poniższej tabeli opisano klasy obsługujące interfejsy API akcesoriów USB:
Kategoria | Opis |
---|---|
UsbManager |
Umożliwia wyliczanie podłączonych akcesoriów USB i komunikowanie się z nimi. |
UsbAccessory |
Reprezentuje akcesorium USB i zawiera metody dostępu do jego identyfikacji i informacjami o nich. |
Różnice w wykorzystaniu biblioteki dodatku i interfejsów API platformy
Istnieją 2 różnice w sposobie użytkowania między biblioteką dodatku do interfejsów API Google a korzystaniem z platformy API.
Jeśli korzystasz z biblioteki dodatku, musisz uzyskać obiekt UsbManager
w ten sposób:
Kotlin
val manager = UsbManager.getInstance(this)
Java
UsbManager manager = UsbManager.getInstance(this);
Jeśli nie korzystasz z biblioteki dodatku, musisz uzyskać obiekt UsbManager
w ten sposób:
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
Gdy filtrujesz dane pod kątem połączonego akcesorium za pomocą filtra intencji, obiekt UsbAccessory
jest zawarty w intencji przekazywanej do
aplikacji. Jeśli korzystasz z biblioteki dodatku, musisz uzyskać obiekt UsbAccessory
w ten sposób:
Kotlin
val accessory = UsbManager.getAccessory(intent)
Java
UsbAccessory accessory = UsbManager.getAccessory(intent);
Jeśli nie korzystasz z biblioteki dodatku, musisz uzyskać obiekt UsbAccessory
w ten sposób:
Kotlin
val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory
Java
UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
Wymagania dotyczące pliku manifestu na Androida
Na poniższej liście opisaliśmy, co musisz dodać do pliku manifestu aplikacji, zanim z interfejsami API akcesoriów USB. Plik manifestu i plik zasobów Przykłady pokazują, jak zadeklarować te produkty:
- Nie wszystkie urządzenia z Androidem będą obsługiwać interfejsy API akcesoriów USB,
zawierać element
<uses-feature>
deklarujący, że aplikacja używa funkcjaandroid.hardware.usb.accessory
. - Jeśli używasz tagu
bibliotekę dodatków,
dodaj element
<uses-library>
określającycom.android.future.usb.accessory
. - Jeśli używasz biblioteki dodatku, ustaw minimalny pakiet SDK aplikacji na API poziomu 10
lub 12, jeśli używasz pakietu
android.hardware.usb
. -
Jeśli chcesz otrzymywać powiadomienia o podłączonych akcesorium USB, określ Para elementów
<intent-filter>
i<meta-data>
dlaandroid.hardware.usb.action.USB_ACCESSORY_ATTACHED
intencje w Twojej głównej aktywności. Element<meta-data>
wskazuje zewnętrzny plik zasobów XML, który deklaruje informacje identyfikujące akcesorium, które chcesz wykryć.W pliku zasobów XML zadeklaruj elementy
<usb-accessory>
dla akcesoria, które chcesz filtrować. Każdy element<usb-accessory>
może zawierać parametr następujące atrybuty:manufacturer
model
version
Nie zalecamy filtrowania według zakresu dat
version
. Akcesorium lub urządzenie nie zawsze może określać ciąg znaków z wersją (celowo lub przypadkowo). Gdy aplikacja deklaruje atrybut wersji, według którego ma być filtrowany produkt, oraz akcesorium lub urządzenie nie określa ciągu wersji, to powoduje, żeNullPointerException
jest włączone starszych wersji Androida. Ten problem został rozwiązany w Androidzie 12.Zapisz plik zasobów w katalogu
res/xml/
. Nazwa pliku zasobów (bez rozszerzenia .xml) musi być taki sam jak URL określony w<meta-data>
element. Format pliku zasobów XML jest też widoczny w przykład poniżej.
Przykłady plików manifestu i plików zasobów
Poniżej znajduje się przykładowy plik manifestu i odpowiadający mu plik zasobów:
<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>
W tym przypadku należy zapisać poniższy plik zasobów w
res/xml/accessory_filter.xml
i określa, że każde akcesorium zawierające atrybuty
należy odfiltrować odpowiedni model, producenta i wersję. Akcesorium wysyła te
określa urządzenie z systemem Android:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/> </resources>
Praca z akcesoriami
Gdy użytkownicy podłączają akcesoria USB do urządzenia z Androidem, system Android może określić, czy aplikacja jest zainteresowana połączonym akcesorium. Jeśli tak, możesz ustawić w razie potrzeby komunikuje się z akcesoriami. Aby to było możliwe, aplikacja musi:
- Odkryj połączone akcesoria za pomocą filtra intencji, który filtruje akcesoria powiązane z nim wydarzenia lub policzając połączone akcesoria i znajdując te, które Ci odpowiadają.
- W razie potrzeby poproś użytkownika o pozwolenie na skomunikowanie się z akcesoriami. uzyskane.
- Komunikuj się z akcesoriami, odczytując i zapisuj dane w odpowiednim interfejsie. i punktów końcowych.
Odkryj akcesorium
Aplikacja może wykrywać akcesoria, korzystając z filtra intencji, który będzie powiadamiany, gdy użytkownik podłącza akcesorium lub wymienia akcesoria, które są już połączone. Za pomocą jest przydatny, jeśli chcesz, aby aplikacja automatycznie wykrywała wybranego akcesorium. Wyliczanie połączonych akcesoriów przydaje się, gdy chcesz zobaczyć listę wszystkich połączonych akcesoriów lub jeśli aplikacja nie przefiltrowała danych pod kątem intencji.
Korzystanie z filtra intencji
Aby aplikacja wykrywała określone akcesorium USB, możesz określić filtr intencji
aby filtrować według intencji android.hardware.usb.action.USB_ACCESSORY_ATTACHED
. Wraz
z tym filtrem intencji, musisz określić plik zasobów określający właściwości dysku USB
akcesorium, takie jak producent, model i wersja.
Ten przykład pokazuje, jak zadeklarować filtr intencji:
<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>
Poniższy przykład pokazuje, jak zadeklarować odpowiedni plik zasobów, który określa Akcesoria USB, które Cię interesują:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" /> </resources>
W swojej aktywności możesz uzyskać UsbAccessory
, który reprezentuje
dołączone akcesorium z intencji podobnego do tego (z biblioteką dodatków):
Kotlin
val accessory = UsbManager.getAccessory(intent)
Java
UsbAccessory accessory = UsbManager.getAccessory(intent);
lub podobny (z interfejsami API platformy):
Kotlin
val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory
Java
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
Wyliczaj akcesoria
Możesz skonfigurować aplikację tak, aby wymieniała akcesoria, które zidentyfikowały się podczas aplikacja jest uruchomiona.
Użyj metody getAccessoryList()
aby uzyskać tablicę wszystkich podłączonych akcesoriów USB:
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();
Uwaga: obsługiwane jest tylko jedno połączone akcesorium za jednym razem.
Uzyskiwanie zgody na komunikację z akcesoriami
Przed komunikacją z akcesorium USB aplikacja musi mieć pozwolenie od użytkowników.
Uwaga: jeśli aplikacja korzysta z parametru , aby wykryć podłączone akcesoria, automatycznie otrzymują jeśli użytkownik zezwala aplikacji na obsługę intencji. Jeśli nie, w aplikacji przed nawiązaniem połączenia z akcesorium.
Wyraźne proszenie o zgodę może być konieczne w niektórych sytuacjach, na przykład gdy Aplikacja wymienia akcesoria, które są już połączone, a następnie chce się z nimi komunikować jeden. Zanim spróbujesz skomunikować się z akcesoriami, musisz sprawdzić uprawnienia dostępu. W przeciwnym razie, jeśli użytkownik odmówił dostępu do aplikacji, wyświetli się błąd czasu działania. akcesorium.
Aby bezpośrednio uzyskać odpowiednie uprawnienia, najpierw utwórz odbiornik. Ten odbiornik nasłuchuje przez
intencję, która ma być transmitowana, gdy zadzwonisz do: requestPermission()
. W wywołaniu requestPermission()
pojawi się okno
użytkownik prosi o pozwolenie na połączenie się z akcesoriami. Ten przykładowy kod pokazuje, jak
Utwórz odbiornik:
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); } } } } };
Aby zarejestrować odbiornik, umieść go w metodzie onCreate()
w
aktywność:
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);
Aby wyświetlić okno z prośbą o pozwolenie na połączenie się z akcesoriami, wywołaj funkcję
Metoda requestPermission()
:
Kotlin
lateinit var accessory: UsbAccessory ... usbManager.requestPermission(accessory, permissionIntent)
Java
UsbAccessory accessory; ... usbManager.requestPermission(accessory, permissionIntent);
Gdy użytkownik odpowie na okno, odbiornik wiadomości otrzyma intencję zawierającą
EXTRA_PERMISSION_GRANTED
dodatkowy, który jest wartością logiczną
reprezentująca odpowiedź. Sprawdź, czy ten dodatek ma wartość prawda, zanim połączysz się z
akcesorium.
Komunikacja z akcesoriami
Możesz komunikować się z akcesoriami za pomocą UsbManager
, aby:
uzyskać deskryptor pliku, w którym możesz skonfigurować strumienie wejściowe i wyjściowe do odczytu i zapisu danych;
deskryptor. Strumienie reprezentują zbiorcze wejściowe i wyjściowe punkty końcowe akcesorium. Należy ustawić
nawiązać komunikację między urządzeniem a akcesoriami w innym wątku, aby nie blokować
głównym wątku UI. Ten przykład pokazuje, jak otworzyć akcesorium, z którym chcesz się komunikować:
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(); } }
W metodzie run()
wątku możesz odczytywać i zapisywać w akcesorium za pomocą polecenia
obiekty FileInputStream
lub FileOutputStream
. Podczas czytania
z akcesorium z obiektem FileInputStream
, upewnij się, że bufor
jest wystarczająco duży, aby zapisać dane pakietów USB. Protokół akcesoriów z Androidem obsługuje
buforuje pakiety do 16 384 bajtów, możesz więc zadeklarować, że to ten bufor
i rozmiaru
dla prostoty.
Uwaga: na niższym poziomie pakiety mają 64 bajty w przypadku danych USB akcesorium zapewniające pełną prędkość i 512 bajtów w przypadku akcesoriów USB o dużej szybkości. Akcesorium z Androidem dla uproszczenia łączy pakiety dla obu tych szybkości w jeden pakiet logiczny.
Więcej informacji o używaniu wątków na Androidzie znajdziesz w artykule Procesy Wątki.
Zakończ komunikację z akcesoriami
Gdy skończysz komunikować się z akcesoriami lub jeśli zostało ono odłączone, zamknij
deskryptor pliku otwarty przez wywołanie funkcji close()
.
Aby nasłuchiwać odłączonego zdarzenia, utwórz odbiornik w ten sposób:
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 } } } };
Utworzenie odbiornika w aplikacji, a nie pliku manifestu, umożliwia do obsługi odłączonych zdarzeń tylko podczas działania aplikacji. Dzięki temu odłączone zdarzenia są wysyłane tylko do aktywnej aplikacji, a nie do wszystkich aplikacji.