Usługa ułatwień dostępu to aplikacja, która stanowi ulepszenie interfejsu użytkownika, aby ułatwić użytkownicy z niepełnosprawnościami lub którzy mogą tymczasowo nie być w stanie w pełni korzystać z aplikacji z urządzeniem. Na przykład są to użytkownicy, którzy prowadzą samochód, opiekują się małymi dziećmi, lub udział w bardzo głośnej imprezie może wymagać dodatkowego lub alternatywnego interfejsu opinie.
Android oferuje standardowe usługi ułatwień dostępu, takie jak TalkBack , a deweloperzy mogą tworzyć i rozpowszechniać własne usługi. Ten dokument zawiera omówienie podstaw tworzenia usługi ułatwień dostępu.
Usługę ułatwień dostępu można połączyć w pakiet ze standardową aplikacją lub utworzyć samodzielnym projekcie Androida. Etapy tworzenia usługi są takie same w w każdej z tych sytuacji.
Utwórz swoją usługę ułatwień dostępu
W projekcie utwórz zajęcia, które obejmują zakres
AccessibilityService
:
Kotlin
package com.example.android.apis.accessibility import android.accessibilityservice.AccessibilityService import android.view.accessibility.AccessibilityEvent class MyAccessibilityService : AccessibilityService() { ... override fun onInterrupt() {} override fun onAccessibilityEvent(event: AccessibilityEvent?) {} ... }
Java
package com.example.android.apis.accessibility; import android.accessibilityservice.AccessibilityService; import android.view.accessibility.AccessibilityEvent; public class MyAccessibilityService extends AccessibilityService { ... @Override public void onAccessibilityEvent(AccessibilityEvent event) { } @Override public void onInterrupt() { } ... }
Jeśli tworzysz dla tego elementu (Service
) nowy projekt i nie planujesz mieć aplikacji
możesz usunąć początkową klasę Activity
ze swojej
źródła.
Deklaracje i uprawnienia w pliku manifestu
Aplikacje udostępniające usługi ułatwień dostępu muszą zawierać określone deklaracje w sekcji i manifest aplikacji, aby był traktowany przez Androida jako usługa ułatwień dostępu. systemu. W tej sekcji opisano wymagane i opcjonalne ustawienia dla usług ułatwień dostępu.
Deklaracja dotycząca usługi ułatwień dostępu
Aby Twoja aplikacja była traktowana jako usługa ułatwień dostępu, dodaj atrybut service
w elemencie application
, a nie activity
.
w pliku manifestu. Dodatkowo w elemencie service
umieść
filtr intencji związanych z usługą ułatwień dostępu. Plik manifestu musi też chronić usługę
dodając
BIND_ACCESSIBILITY_SERVICE
aby mieć pewność, że tylko system może z nim powiązać. Oto przykład:
<application> <service android:name=".MyAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" android:label="@string/accessibility_service_label"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> </service> </application>
Konfiguracja usługi ułatwień dostępu
Usługi ułatwień dostępu muszą zawierać konfigurację określającą typy
zdarzenia ułatwień dostępu obsługiwane przez usługę i dodatkowe informacje o nich
i z usługami. Konfiguracja usługi ułatwień dostępu znajduje się w sekcji
AccessibilityServiceInfo
zajęcia. Twoja usługa może skompilować i ustawić konfigurację przy użyciu instancji tego typu
klasa i
setServiceInfo()
w czasie działania aplikacji. Jednak nie wszystkie opcje konfiguracji są dostępne w przypadku tego
.
Możesz uwzględnić w pliku manifestu element <meta-data>
z odwołaniem do
który pozwala ustawić wszystkie opcje
zgodnie z tym przykładem:
<service android:name=".MyAccessibilityService"> ... <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" /> </service>
Ten element <meta-data>
odnosi się do pliku XML utworzonego w
katalog zasobów aplikacji:
<project_dir>/res/xml/accessibility_service_config.xml>
Następujący kod:
Poniżej znajdziesz przykład zawartości pliku konfiguracji usługi:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/accessibility_service_description" android:packageNames="com.example.android.apis" android:accessibilityEventTypes="typeAllMask" android:accessibilityFlags="flagDefault" android:accessibilityFeedbackType="feedbackSpoken" android:notificationTimeout="100" android:canRetrieveWindowContent="true" android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity" />
Więcej informacji o atrybutach XML, których można użyć w pliku plik konfiguracji usługi ułatwień dostępu, patrz poniższe informacje. dokumentacja:
android:description
android:packageNames
android:accessibilityEventTypes
android:accessibilityFlags
android:accessibilityFeedbackType
android:notificationTimeout
android:canRetrieveWindowContent
android:settingsActivity
Więcej informacji o tym, które ustawienia konfiguracji można ustawiać dynamicznie
w czasie działania, zapoznaj się z
AccessibilityServiceInfo
dokumentacji referencyjnej.
Skonfiguruj usługę ułatwień dostępu
Podczas ustawiania zmiennych konfiguracyjnych dla środowiska należy wziąć pod uwagę następujące kwestie: usługi ułatwień dostępu, aby poinformować system, jak i kiedy uruchamiać:
- Na jakie typy zdarzeń ma odpowiadać?
- Czy usługa musi być aktywna dla wszystkich aplikacji, czy tylko dla określonego pakietu? nazwy?
- Jakiego typu opinii używa?
Te zmienne możesz konfigurować na 2 sposoby. Opcja zgodności wstecznej
jest umieszczenie ich w kodzie,
setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
Aby to zrobić, zastąp
onServiceConnected()
i skonfiguruj w niej swoją usługę, jak pokazano w poniższym przykładzie:
Kotlin
override fun onServiceConnected() { info.apply { // Set the type of events that this service wants to listen to. Others // aren't passed to this service. eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED or AccessibilityEvent.TYPE_VIEW_FOCUSED // If you only want this service to work with specific apps, set their // package names here. Otherwise, when the service is activated, it // listens to events from all apps. packageNames = arrayOf("com.example.android.myFirstApp", "com.example.android.mySecondApp") // Set the type of feedback your service provides. feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN // Default services are invoked only if no package-specific services are // present for the type of AccessibilityEvent generated. This service is // app-specific, so the flag isn't necessary. For a general-purpose // service, consider setting the DEFAULT flag. // flags = AccessibilityServiceInfo.DEFAULT; notificationTimeout = 100 } this.serviceInfo = info }
Java
@Override public void onServiceConnected() { // Set the type of events that this service wants to listen to. Others // aren't passed to this service. info.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED; // If you only want this service to work with specific apps, set their // package names here. Otherwise, when the service is activated, it listens // to events from all apps. info.packageNames = new String[] {"com.example.android.myFirstApp", "com.example.android.mySecondApp"}; // Set the type of feedback your service provides. info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN; // Default services are invoked only if no package-specific services are // present for the type of AccessibilityEvent generated. This service is // app-specific, so the flag isn't necessary. For a general-purpose service, // consider setting the DEFAULT flag. // info.flags = AccessibilityServiceInfo.DEFAULT; info.notificationTimeout = 100; this.setServiceInfo(info); }
Drugą opcją jest skonfigurowanie usługi za pomocą pliku XML. Tak
opcje konfiguracji, takie jak
canRetrieveWindowContent
są dostępne tylko wtedy, gdy skonfigurujesz usługę przy użyciu kodu XML. Konfiguracja
opcje z poprzedniego przykładu wyglądają następująco po zdefiniowaniu przy użyciu pliku XML:
<accessibility-service android:accessibilityEventTypes="typeViewClicked|typeViewFocused" android:packageNames="com.example.android.myFirstApp, com.example.android.mySecondApp" android:accessibilityFeedbackType="feedbackSpoken" android:notificationTimeout="100" android:settingsActivity="com.example.android.apis.accessibility.TestBackActivity" android:canRetrieveWindowContent="true" />
Jeśli używasz formatu XML, odwołaj się do niego w pliku manifestu, dodając
<meta-data>
na
deklaracji usługi wskazującą plik XML. Jeśli przechowujesz plik XML w
res/xml/serviceconfig.xml
, nowy tag wygląda tak:
<service android:name=".MyAccessibilityService"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/serviceconfig" /> </service>
Metody usługi ułatwień dostępu
Usługa ułatwień dostępu musi stanowić rozszerzenie klasy AccessibilityService
i
zastąpić poniższe metody z tej klasy. Metody te są opisane w
w kolejności ich wywoływania przez system Android: od momentu uruchomienia usługi
(onServiceConnected()
) na uruchomiony
(onAccessibilityEvent()
,
onInterrupt()
),
na czas wyłączenia
(onUnbind()
).
onServiceConnected()
: (opcjonalnie) system wywołuje tę metodę, gdy łączy się z usługą ułatwień dostępu. Użyj tej metody, aby przeprowadzić konfigurację jednorazową czynności związane z Twoją usługą, w tym łączenie się z systemem przesyłania opinii użytkowników takich jak menedżer dźwięku czy wibracja urządzenia. Jeśli chcesz ustawić konfigurowania usługi w czasie działania lub wprowadzania jednorazowych zmian, to dogodne miejsce, by zadzwonić pod numersetServiceInfo()
.onAccessibilityEvent()
: (wymagane) system wywołuje tę metodę, gdy: wykrywaAccessibilityEvent
. zgodne z parametrami filtrowania zdarzeń określonymi w ustawieniach ułatwień dostępu. usługa, np. kliknięcie przycisku lub zaznaczenie przez użytkownika interfejsu element sterujący w aplikacji, dla której usługa ułatwień dostępu przekazuje opinię. Kiedy system wywołuje tę metodę, przekazuje powiązaneAccessibilityEvent
, które usługa może zinterpretować i wykorzystać w celu przekazywania użytkownika. Metodę tę można wywoływać wiele razy w cyklu życia posprzedażna.onInterrupt()
: (wymagane) system wywołuje tę metodę, gdy system. chce przerwać przesyłanie opinii przez Twoją usługę, zwykle w reakcja na działanie użytkownika, np. przeniesienie zaznaczenia na inny element sterujący. Ten może być wywoływana wiele razy w cyklu życia usługi.onUnbind()
: (opcjonalnie) system wywołuje tę metodę, gdy system jest wyłączyć usługę ułatwień dostępu. Użyj tej metody, aby: procedury jednorazowego wyłączania, w tym usunięcie przydziału systemu przesyłania opinii użytkowników. takich jak menedżer dźwięku czy wibracja urządzenia.
Te metody wywołania zwrotnego zapewniają podstawową strukturę ułatwień dostępu
posprzedażna. Możesz zdecydować, jak przetwarzać dane dostarczone przez system Android na
jako obiekty AccessibilityEvent
i przekazywać użytkownikowi opinię. Dla:
więcej informacji na temat uzyskiwania informacji ze zdarzeń związanych z ułatwieniami dostępu znajdziesz w artykule o uzyskiwaniu
szczegóły wydarzenia.
Zarejestruj na potrzeby zdarzeń ułatwień dostępu
Jedna z najważniejszych funkcji konfiguracji usługi ułatwień dostępu pozwala określić, jakiego typu zdarzenia ułatwień dostępu mają być wykorzystywane który sobie radzi. Podanie tych informacji umożliwia współpracę usług ułatwień dostępu ze sobą nawzajem i daje elastyczność również w obsłudze tylko konkretnych wydarzeń typy z konkretnych aplikacji. Filtrowanie zdarzeń może obejmować następujące opcje: kryteria:
Nazwy pakietów: określ nazwy pakietów aplikacji, których ułatwienia dostępu mają miejsce. zdarzenia, które ma obsługiwać Twoja usługa. Jeśli pominiesz ten parametr, usługa ułatwień dostępu jest uznawana za dostępną dla ułatwień dostępu w usłudze zdarzeń w dowolnej aplikacji. Ten parametr można ustawić w usłudze ułatwień dostępu plików konfiguracji z atrybutem
android:packageNames
jako oddzieloną przecinkami alboAccessibilityServiceInfo.packageNames
. użytkownika.Typy zdarzeń: określ typy zdarzeń ułatwień dostępu, które chcesz uwzględnić. do obsługi reklam. Ten parametr można ustawić w usłudze ułatwień dostępu plików konfiguracji z atrybutem
android:accessibilityEventTypes
o wartości listę rozdzielaną znakiem|
, na przykładaccessibilityEventTypes="typeViewClicked|typeViewFocused"
Możesz też ustawić za pomocąAccessibilityServiceInfo.eventTypes
użytkownika.
Podczas konfigurowania usługi ułatwień dostępu zastanów się, jakie zdarzenia może obsługiwać i rejestrować tylko te zdarzenia. Ponieważ użytkownicy mogą aktywować więcej niż jedną usługę ułatwień dostępu jednocześnie, usługa nie może korzystać które nie są w stanie obsłużyć. Pamiętaj, że inne usługi mogą je obsługiwać zdarzeń, by zwiększyć wygodę użytkowników.
Głośność przy ułatwieniach dostępu
Urządzenia z Androidem 8.0 (poziom interfejsu API 26) lub nowszym zawierają
STREAM_ACCESSIBILITY
kategorię głośności, która pozwala kontrolować głośność ułatwień dostępu.
na wyjściu audio usługi niezależnie od innych dźwięków urządzenia.
Usługi ułatwień dostępu mogą korzystać z tego typu strumienia, ustawiając
FLAG_ENABLE_ACCESSIBILITY_VOLUME
. Następnie możesz zmienić głośność dźwięku przy ułatwieniach dostępu na urządzeniu, dzwoniąc
adjustStreamVolume()
w instancji urządzenia
AudioManager
Ten fragment kodu pokazuje, jak usługa ułatwień dostępu może korzystać z funkcji
STREAM_ACCESSIBILITY
kategoria woluminów:
Kotlin
import android.media.AudioManager.* class MyAccessibilityService : AccessibilityService() { private val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager override fun onAccessibilityEvent(accessibilityEvent: AccessibilityEvent) { if (accessibilityEvent.source.text == "Increase volume") { audioManager.adjustStreamVolume(AudioManager.STREAM_ACCESSIBILITY, ADJUST_RAISE, 0) } } }
Java
import static android.media.AudioManager.*; public class MyAccessibilityService extends AccessibilityService { private AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE); @Override public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) { AccessibilityNodeInfo interactedNodeInfo = accessibilityEvent.getSource(); if (interactedNodeInfo.getText().equals("Increase volume")) { audioManager.adjustStreamVolume(AudioManager.STREAM_ACCESSIBILITY, ADJUST_RAISE, 0); } } }
Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 6:35.
Skrót ułatwień dostępu
Na urządzeniach z Androidem 8.0 (poziom interfejsu API 26) lub nowszym użytkownicy mogą włączać wyłączyć preferowaną usługę ułatwień dostępu na dowolnym ekranie, naciskając przytrzymując jednocześnie oba przyciski głośności. Mimo że ten skrót umożliwia domyślnie wyłącza TalkBack, użytkownicy mogą skonfigurować przycisk w taki sposób, aby wyłączyć dowolną usługę zainstalowaną na urządzeniu.
Aby użytkownicy mieli dostęp do konkretnej usługi ułatwień dostępu z poziomu ułatwień dostępu usługa musi poprosić o dostęp do danej funkcji w czasie działania.
Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 13:25.
Przycisk ułatwień dostępu
Na urządzeniach korzystających z wyrenderowanego programowo obszaru nawigacji z Androidem 8.0 (poziom interfejsu API 26) lub wyższym po prawej stronie paska nawigacyjnego znajduje się przycisk ułatwień dostępu. Po naciśnięciu tego przycisku użytkownik może wywołać jedną z tych opcji: kilka włączonych funkcji i usług ułatwień dostępu, w zależności od treści widoczne na ekranie.
Aby umożliwić użytkownikom wywoływanie danej usługi ułatwień dostępu za pomocą ułatwień dostępu
, usługa musi dodać atrybut
FLAG_REQUEST_ACCESSIBILITY_BUTTON
flaga w android:accessibilityFlags
obiektu AccessibilityServiceInfo
. Usługa może następnie rejestrować wywołania zwrotne za pomocą
registerAccessibilityButtonCallback()
Fragment kodu poniżej pokazuje, jak skonfigurować ułatwienia dostępu reakcja użytkownika na naciśnięcie przycisku ułatwień dostępu:
Kotlin
private var mAccessibilityButtonController: AccessibilityButtonController? = null private var accessibilityButtonCallback: AccessibilityButtonController.AccessibilityButtonCallback? = null private var mIsAccessibilityButtonAvailable: Boolean = false override fun onServiceConnected() { mAccessibilityButtonController = accessibilityButtonController mIsAccessibilityButtonAvailable = mAccessibilityButtonController?.isAccessibilityButtonAvailable ?: false if (!mIsAccessibilityButtonAvailable) return serviceInfo = serviceInfo.apply { flags = flags or AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON } accessibilityButtonCallback = object : AccessibilityButtonController.AccessibilityButtonCallback() { override fun onClicked(controller: AccessibilityButtonController) { Log.d("MY_APP_TAG", "Accessibility button pressed!") // Add custom logic for a service to react to the // accessibility button being pressed. } override fun onAvailabilityChanged( controller: AccessibilityButtonController, available: Boolean ) { if (controller == mAccessibilityButtonController) { mIsAccessibilityButtonAvailable = available } } } accessibilityButtonCallback?.also { mAccessibilityButtonController?.registerAccessibilityButtonCallback(it, null) } }
Java
private AccessibilityButtonController accessibilityButtonController; private AccessibilityButtonController .AccessibilityButtonCallback accessibilityButtonCallback; private boolean mIsAccessibilityButtonAvailable; @Override protected void onServiceConnected() { accessibilityButtonController = getAccessibilityButtonController(); mIsAccessibilityButtonAvailable = accessibilityButtonController.isAccessibilityButtonAvailable(); if (!mIsAccessibilityButtonAvailable) { return; } AccessibilityServiceInfo serviceInfo = getServiceInfo(); serviceInfo.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; setServiceInfo(serviceInfo); accessibilityButtonCallback = new AccessibilityButtonController.AccessibilityButtonCallback() { @Override public void onClicked(AccessibilityButtonController controller) { Log.d("MY_APP_TAG", "Accessibility button pressed!"); // Add custom logic for a service to react to the // accessibility button being pressed. } @Override public void onAvailabilityChanged( AccessibilityButtonController controller, boolean available) { if (controller.equals(accessibilityButtonController)) { mIsAccessibilityButtonAvailable = available; } } }; if (accessibilityButtonCallback != null) { accessibilityButtonController.registerAccessibilityButtonCallback( accessibilityButtonCallback, null); } }
Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 16:28.
Gesty związane z odciskiem palca
usługi ułatwień dostępu na urządzeniach z Androidem 8.0 (poziom interfejsu API 26) lub nowszym; może reagować na przesunięcia kierunkowe (w górę, w dół, w lewo i w prawo) po ekranie urządzenia czytnik linii papilarnych. Aby skonfigurować usługę do otrzymywania wywołań zwrotnych na ich temat: należy wykonać następującą sekwencję:
- Zadeklaruj
USE_BIOMETRIC
uprawnienia iCAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES
działania. - Ustawianie
FLAG_REQUEST_FINGERPRINT_GESTURES
flagę w atrybucieandroid:accessibilityFlags
. - Zarejestruj się na wywołania zwrotne za pomocą
registerFingerprintGestureCallback()
.
Pamiętaj, że nie wszystkie urządzenia mają czujniki linii papilarnych. Aby zidentyfikować
czy urządzenie obsługuje czujnik, użyj funkcji
isHardwareDetected()
. Nawet na urządzeniu wyposażonym w czytnik linii papilarnych usługa nie może
korzystać z czujnika, gdy jest on używany do uwierzytelniania. Aby określić, kiedy
czujnik jest dostępny, wywołaj funkcję
isGestureDetectionAvailable()
i zaimplementuj funkcję
onGestureDetectionAvailabilityChanged()
oddzwanianie.
Ten fragment kodu pokazuje przykład użycia gestów odcisku palca do: poruszać się po wirtualnej planszy:
// AndroidManifest.xml <manifest ... > <uses-permission android:name="android.permission.USE_FINGERPRINT" /> ... <application> <service android:name="com.example.MyFingerprintGestureService" ... > <meta-data android:name="android.accessibilityservice" android:resource="@xml/myfingerprintgestureservice" /> </service> </application> </manifest>
// myfingerprintgestureservice.xml <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" ... android:accessibilityFlags=" ... |flagRequestFingerprintGestures" android:canRequestFingerprintGestures="true" ... />
Kotlin
// MyFingerprintGestureService.kt import android.accessibilityservice.FingerprintGestureController.* class MyFingerprintGestureService : AccessibilityService() { private var gestureController: FingerprintGestureController? = null private var fingerprintGestureCallback: FingerprintGestureController.FingerprintGestureCallback? = null private var mIsGestureDetectionAvailable: Boolean = false override fun onCreate() { gestureController = fingerprintGestureController mIsGestureDetectionAvailable = gestureController?.isGestureDetectionAvailable ?: false } override fun onServiceConnected() { if (mFingerprintGestureCallback != null || !mIsGestureDetectionAvailable) return fingerprintGestureCallback = object : FingerprintGestureController.FingerprintGestureCallback() { override fun onGestureDetected(gesture: Int) { when (gesture) { FINGERPRINT_GESTURE_SWIPE_DOWN -> moveGameCursorDown() FINGERPRINT_GESTURE_SWIPE_LEFT -> moveGameCursorLeft() FINGERPRINT_GESTURE_SWIPE_RIGHT -> moveGameCursorRight() FINGERPRINT_GESTURE_SWIPE_UP -> moveGameCursorUp() else -> Log.e(MY_APP_TAG, "Error: Unknown gesture type detected!") } } override fun onGestureDetectionAvailabilityChanged(available: Boolean) { mIsGestureDetectionAvailable = available } } fingerprintGestureCallback?.also { gestureController?.registerFingerprintGestureCallback(it, null) } } }
Java
// MyFingerprintGestureService.java import static android.accessibilityservice.FingerprintGestureController.*; public class MyFingerprintGestureService extends AccessibilityService { private FingerprintGestureController gestureController; private FingerprintGestureController .FingerprintGestureCallback fingerprintGestureCallback; private boolean mIsGestureDetectionAvailable; @Override public void onCreate() { gestureController = getFingerprintGestureController(); mIsGestureDetectionAvailable = gestureController.isGestureDetectionAvailable(); } @Override protected void onServiceConnected() { if (fingerprintGestureCallback != null || !mIsGestureDetectionAvailable) { return; } fingerprintGestureCallback = new FingerprintGestureController.FingerprintGestureCallback() { @Override public void onGestureDetected(int gesture) { switch (gesture) { case FINGERPRINT_GESTURE_SWIPE_DOWN: moveGameCursorDown(); break; case FINGERPRINT_GESTURE_SWIPE_LEFT: moveGameCursorLeft(); break; case FINGERPRINT_GESTURE_SWIPE_RIGHT: moveGameCursorRight(); break; case FINGERPRINT_GESTURE_SWIPE_UP: moveGameCursorUp(); break; default: Log.e(MY_APP_TAG, "Error: Unknown gesture type detected!"); break; } } @Override public void onGestureDetectionAvailabilityChanged(boolean available) { mIsGestureDetectionAvailable = available; } }; if (fingerprintGestureCallback != null) { gestureController.registerFingerprintGestureCallback( fingerprintGestureCallback, null); } } }
Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 9:03.
Zamiana tekstu na mowę w wielu językach
Usługa zamiany tekstu na mowę (TTS) w Androidzie 8.0 (poziom interfejsu API 26)
rozpoznawać i mówić wyrażenia w wielu językach w jednym bloku
tekstu. Aby włączyć tę funkcję automatycznego przełączania języka w ułatwieniach dostępu
, umieść wszystkie ciągi w
LocaleSpan
obiektów widocznych na ilustracji
w tym fragmencie kodu:
Kotlin
val localeWrappedTextView = findViewById<TextView>(R.id.my_french_greeting_text).apply { text = wrapTextInLocaleSpan("Bonjour!", Locale.FRANCE) } private fun wrapTextInLocaleSpan(originalText: CharSequence, loc: Locale): SpannableStringBuilder { return SpannableStringBuilder(originalText).apply { setSpan(LocaleSpan(loc), 0, originalText.length - 1, 0) } }
Java
TextView localeWrappedTextView = findViewById(R.id.my_french_greeting_text); localeWrappedTextView.setText(wrapTextInLocaleSpan("Bonjour!", Locale.FRANCE)); private SpannableStringBuilder wrapTextInLocaleSpan( CharSequence originalText, Locale loc) { SpannableStringBuilder myLocaleBuilder = new SpannableStringBuilder(originalText); myLocaleBuilder.setSpan(new LocaleSpan(loc), 0, originalText.length() - 1, 0); return myLocaleBuilder; }
Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 10:59.
Działanie w imieniu użytkowników
Od 2011 roku usługi ułatwień dostępu mogą działać w imieniu użytkowników, w tym zmienianie fokusu wprowadzania i wybieranie (aktywowanie) elementów interfejsu użytkownika. W W 2012 r. rozszerzyliśmy zakres działań o listy przewijane i interakcje z polami tekstowymi. Usługi ułatwień dostępu mogą też wykonywać działania globalne, na przykład: przejdź do ekranu głównego, naciśnij przycisk Wstecz i otwórz ekranu powiadomień i listy ostatnio używanych aplikacji. Od 2012 roku Android obejmuje ułatwienia dostępu, dzięki któremu wszystkie widoczne elementy można zaznaczyć w usłudze ułatwień dostępu.
Te możliwości pozwalają programistom usług ułatwień dostępu tworzyć alternatywne rozwiązania, w trybach nawigacji, takich jak nawigacja przy użyciu gestów, oraz dla użytkowników z niepełnosprawnościami. lepsze sterowanie urządzeniami z Androidem.
Nasłuchuj gestów
Usługi ułatwień dostępu mogą nasłuchiwać określonych gestów i reagować na nie
użytkownika. Ta funkcja wymaga wysłania żądania o usługę ułatwień dostępu.
aktywować funkcję Czytania dotykiem. Twoja usługa może o to poprosić
aktywacji przez ustawienie
flags
należąca do instancji AccessibilityServiceInfo
usługi,
FLAG_REQUEST_TOUCH_EXPLORATION_MODE
,
jak w poniższym przykładzie.
Kotlin
class MyAccessibilityService : AccessibilityService() { override fun onCreate() { serviceInfo.flags = AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE } ... }
Java
public class MyAccessibilityService extends AccessibilityService { @Override public void onCreate() { getServiceInfo().flags = AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE; } ... }
Gdy Twoja usługa poprosi o aktywację Czytania dotykiem, użytkownik musi wyrazić zgodę
funkcja musi być włączona, jeśli nie jest jeszcze aktywna. Gdy ta funkcja jest
będzie aktywna, Twoja usługa będzie otrzymywać powiadomienia o gestach ułatwień dostępu przez
Twojej usługi
onGesture()
wywołanie zwrotne i może odpowiedzieć, działając w imieniu użytkownika.
Ciągłe gesty
Urządzenia z Androidem 8.0 (poziom interfejsu API 26) obsługują ciągłe gesty lub
automatyczne gesty zawierające więcej niż jeden
Path
.
Przy określaniu sekwencji kresek możesz określić, że należą one do
ten sam gest zautomatyzowany przy użyciu ostatniego argumentu willContinue
w
GestureDescription.StrokeDescription
.
jak w tym fragmencie kodu:
Kotlin
// Simulates an L-shaped drag path: 200 pixels right, then 200 pixels down. private fun doRightThenDownDrag() { val dragRightPath = Path().apply { moveTo(200f, 200f) lineTo(400f, 200f) } val dragRightDuration = 500L // 0.5 second // The starting point of the second path must match // the ending point of the first path. val dragDownPath = Path().apply { moveTo(400f, 200f) lineTo(400f, 400f) } val dragDownDuration = 500L val rightThenDownDrag = GestureDescription.StrokeDescription( dragRightPath, 0L, dragRightDuration, true ).apply { continueStroke(dragDownPath, dragRightDuration, dragDownDuration, false) } }
Java
// Simulates an L-shaped drag path: 200 pixels right, then 200 pixels down. private void doRightThenDownDrag() { Path dragRightPath = new Path(); dragRightPath.moveTo(200, 200); dragRightPath.lineTo(400, 200); long dragRightDuration = 500L; // 0.5 second // The starting point of the second path must match // the ending point of the first path. Path dragDownPath = new Path(); dragDownPath.moveTo(400, 200); dragDownPath.lineTo(400, 400); long dragDownDuration = 500L; GestureDescription.StrokeDescription rightThenDownDrag = new GestureDescription.StrokeDescription(dragRightPath, 0L, dragRightDuration, true); rightThenDownDrag.continueStroke(dragDownPath, dragRightDuration, dragDownDuration, false); }
Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 15:47.
Korzystanie z ułatwień dostępu
Usługi ułatwień dostępu mogą działać w imieniu użytkowników, aby uprościć interakcje z aplikacji i pracować wydajniej. Możliwości ułatwień dostępu Funkcja wykonywania działań została dodana w 2011 r., a w 2012 – znacznie rozszerzona.
Aby można było działać w imieniu użytkowników, usługa ułatwień dostępu musi się zarejestrować.
na otrzymywanie zdarzeń z aplikacji i wysyłanie próśb o zgodę na wyświetlanie treści
aplikacji przez ustawienie android:canRetrieveWindowContent
na true
w
plik konfiguracji usługi. Po odebraniu zdarzeń przez
może następnie pobrać
AccessibilityNodeInfo
ze zdarzenia za pomocą funkcji
getSource()
Dzięki obiektowi AccessibilityNodeInfo
usługa może badać widok.
w hierarchii użytkowników, aby określić, jakie działania należy podjąć,
performAction()
Kotlin
class MyAccessibilityService : AccessibilityService() { override fun onAccessibilityEvent(event: AccessibilityEvent) { // Get the source node of the event. event.source?.apply { // Use the event and node information to determine what action to // take. // Act on behalf of the user. performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) // Recycle the nodeInfo object. recycle() } } ... }
Java
public class MyAccessibilityService extends AccessibilityService { @Override public void onAccessibilityEvent(AccessibilityEvent event) { // Get the source node of the event. AccessibilityNodeInfo nodeInfo = event.getSource(); // Use the event and node information to determine what action to take. // Act on behalf of the user. nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); // Recycle the nodeInfo object. nodeInfo.recycle(); } ... }
Metoda performAction()
umożliwia usłudze podjęcie działania w obrębie
. Jeśli usługa musi wykonać działanie globalne, takie jak
przejście do ekranu głównego, kliknięcie przycisku Wstecz lub otwarcie
ekranu powiadomień lub listy ostatnio używanych aplikacji, a następnie użyj
performGlobalAction()
.
.
Użyj typów skupienia
W 2012 roku w interfejsie Androida pojawiła się nowa funkcja: accessibility. Usługi ułatwień dostępu mogą użyć tego fokusu, aby wybrać dowolny widoczny interfejs użytkownika i wykonać na nim działania. Ten typ zaznaczenia różni się od fokusu wejściowego, który określa, który element interfejsu na ekranie otrzymuje dane wejściowe, gdy użytkownik wpisze znaki, naciśnij Enter na klawiaturze lub naciśnij środek przycisku na padzie kierunkowym.
Może się zdarzyć, że jeden element interfejsu użytkownika będzie zaznaczony podczas Inny element koncentruje się na ułatwieniach dostępu. Głównym celem korzystania z ułatwień dostępu aby zapewnić usługom ułatwień dostępu metodę interakcji z widocznymi elementów na ekranie niezależnie od tego, czy można ich aktywować w z perspektywy systemu. Aby zapewnić współdziałanie usługi ułatwień dostępu z aplikacjami elementów wejściowych, postępuj zgodnie z wytycznymi dotyczącymi testowania ułatwień dostępu, aby przetestować usługę podczas używania typowej aplikacji.
Usługa ułatwień dostępu może określić, który element interfejsu użytkownika ma dane wejściowe
lub ułatwienia dostępu za pomocą
AccessibilityNodeInfo.findFocus()
. Możesz też wyszukiwać elementy, które można wybierać za pomocą wprowadzania
za pomocą
focusSearch()
. Usługa ułatwień dostępu może też ustawić fokus przy użyciu
performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS)
.
Zbieranie informacji
Usługi ułatwień dostępu korzystają ze standardowych metod gromadzenia i reprezentowania jednostki informacji przekazywanych przez użytkowników, takie jak szczegóły wydarzeń, tekst i liczby.
Pobieranie szczegółów zmiany okna
Android 9 (poziom interfejsu API 28) i nowsze umożliwiają aplikacjom śledzenie aktualizacji okien, gdy
aplikacja pobiera ponownie wiele okien jednocześnie. Gdy
TYPE_WINDOWS_CHANGED
zachodzi zdarzenie, użyj funkcji
getWindowChanges()
API do określania, jak zmieniają się okna. Podczas aktualizacji w trybie wielu okien każda
generuje własny zestaw zdarzeń. Metoda getSource()
zwraca pierwiastek
w widoku okien powiązanych z poszczególnymi zdarzeniami.
Jeśli aplikacja określa okienko ułatwień dostępu
View
, usługa może rozpoznać, kiedy
interfejs aplikacji zostanie zaktualizowany. Gdy
TYPE_WINDOW_STATE_CHANGED
użyj typów zwróconych przez
getContentChangeTypes()
aby określić, jak zmienia się okno. Platforma może na przykład wykryć, kiedy
panel ma nowy tytuł lub zniknie.
Pobieranie szczegółów wydarzenia
Android dostarcza usługom ułatwień dostępu informacje o interfejsie użytkownika
interakcji za pomocą AccessibilityEvent
obiektów. W poprzednich wersjach Androida
informacji dostępnych w przypadku ułatwień dostępu, a jednocześnie zapewnić
szczegóły na temat ustawień interfejsu wybranych przez użytkowników, dostępne z ograniczeniami
informacji kontekstowych. W wielu przypadkach brak informacji kontekstowych
jest kluczowe dla zrozumienia znaczenia wybranego elementu sterującego.
Przykładem interfejsu, w którym kontekst ma kluczowe znaczenie, to kalendarz lub dzień w kalendarzu. Jeśli użytkownik wybierze przedział czasu o godzinie 16:00 na liście dni od poniedziałku do piątku a usługa ułatwień dostępu informuje o godzinie 16:00, ale nie ogłasza dnia tygodnia. „name”, „dzień miesiąca” lub „nazwa miesiąca” – otrzymana opinia będzie miała postać są niejasne. W takim przypadku kontekst elementu sterującego interfejsu użytkownika ma kluczowe znaczenie użytkownika, który chce zaplanować spotkanie.
Od 2011 roku Android znacznie rozszerza ilość informacji przekazywanych usługa ułatwień dostępu może uzyskać informacje o interakcji z interfejsem użytkownika zdarzeń związanych z ułatwieniami dostępu na podstawie hierarchii widoków. Hierarchia widoków to zbiór Komponenty interfejsu, które zawierają komponent (jego elementy nadrzędne) i użytkownika elementów interfejsu, które mogą zawierać ten komponent (jego elementy podrzędne). W Dzięki temu Android może dostarczyć więcej informacji o zdarzeniach związanych z ułatwieniami dostępu, usługi ułatwień dostępu zapewniają użytkownikom bardziej przydatne informacje zwrotne.
Usługa ułatwień dostępu pobiera informacje o zdarzeniach w interfejsie przez:
obiekt AccessibilityEvent
przekazany przez system do usługi
Metoda wywołania zwrotnego onAccessibilityEvent()
. Ten obiekt dostarcza szczegółowe informacje o
rodzaj zdarzenia, w tym typ obiektu, którego dotyczy działanie, jego opis
inne szczegóły.
AccessibilityEvent.getRecordCount()
orazgetRecord(int)
: które pozwalają pobrać zestawAccessibilityRecord
obiekty należące do kategoriiAccessibilityEvent
przekazane Ci przez systemu. Ten poziom szczegółowości zapewnia więcej kontekstu dla zdarzenia, które uruchamia usługę ułatwień dostępu.AccessibilityRecord.getSource()
: ta metoda zwraca obiektAccessibilityNodeInfo
. Ten obiekt umożliwia: zażądać hierarchii układu widoku (elementy nadrzędne i podrzędne) komponentu, który jest początkiem zdarzenia ułatwień dostępu. Dzięki tej funkcji ułatwienia dostępu badanie całego kontekstu zdarzenia, w tym treści żadnych połączonych widoków lub widoków podrzędnych.
Platforma Androida umożliwia AccessibilityService
wykonywanie zapytań
hierarchię widoków, zbierając informacje o komponencie UI, który generuje
wydarzenia, a także jego elementu nadrzędnego i elementu podrzędnego. W tym celu ustaw następujący wiersz:
w konfiguracji XML:
android:canRetrieveWindowContent="true"
Potem pobierz obiekt AccessibilityNodeInfo
za pomocą getSource()
.
To wywołanie zwraca obiekt tylko wtedy, gdy okno, w którym zainicjowano zdarzenie, to
aktywne okno. Jeśli nie, zwraca wartość null, więc musisz się zachować.
W tym przykładzie po otrzymaniu zdarzenia kod wykonuje takie działania:
- Natychmiast pobiera element nadrzędny widoku, w którym zaczyna się zdarzenie.
- W tym widoku szuka etykiety i pola wyboru w widoku treści podrzędnych.
- Jeśli je znajdzie, tworzy ciąg znaków do zgłoszenia użytkownikowi, który wskazuje i informacje o tym, czy została zaznaczona.
Jeśli w którymkolwiek momencie podczas przemierzania hierarchii widoku zostanie zwrócona wartość null, metody dyskretnie poddaje się.
Kotlin
// Alternative onAccessibilityEvent that uses AccessibilityNodeInfo. override fun onAccessibilityEvent(event: AccessibilityEvent) { val source: AccessibilityNodeInfo = event.source ?: return // Grab the parent of the view that fires the event. val rowNode: AccessibilityNodeInfo = getListItemNodeInfo(source) ?: return // Using this parent, get references to both child nodes, the label, and the // checkbox. val taskLabel: CharSequence = rowNode.getChild(0)?.text ?: run { rowNode.recycle() return } val isComplete: Boolean = rowNode.getChild(1)?.isChecked ?: run { rowNode.recycle() return } // Determine what the task is and whether it's complete based on the text // inside the label, and the state of the checkbox. if (rowNode.childCount < 2 || !rowNode.getChild(1).isCheckable) { rowNode.recycle() return } val completeStr: String = if (isComplete) { getString(R.string.checked) } else { getString(R.string.not_checked) } val reportStr = "$taskLabel$completeStr" speakToUser(reportStr) }
Java
// Alternative onAccessibilityEvent that uses AccessibilityNodeInfo. @Override public void onAccessibilityEvent(AccessibilityEvent event) { AccessibilityNodeInfo source = event.getSource(); if (source == null) { return; } // Grab the parent of the view that fires the event. AccessibilityNodeInfo rowNode = getListItemNodeInfo(source); if (rowNode == null) { return; } // Using this parent, get references to both child nodes, the label, and the // checkbox. AccessibilityNodeInfo labelNode = rowNode.getChild(0); if (labelNode == null) { rowNode.recycle(); return; } AccessibilityNodeInfo completeNode = rowNode.getChild(1); if (completeNode == null) { rowNode.recycle(); return; } // Determine what the task is and whether it's complete based on the text // inside the label, and the state of the checkbox. if (rowNode.getChildCount() < 2 || !rowNode.getChild(1).isCheckable()) { rowNode.recycle(); return; } CharSequence taskLabel = labelNode.getText(); final boolean isComplete = completeNode.isChecked(); String completeStr = null; if (isComplete) { completeStr = getString(R.string.checked); } else { completeStr = getString(R.string.not_checked); } String reportStr = taskLabel + completeStr; speakToUser(reportStr); }
Dzięki temu zyskujesz kompletną, działającą usługę ułatwień dostępu. Spróbuj skonfigurować sposób
Wchodzi w interakcje z użytkownikiem za pomocą funkcji zamiana tekstu na mowę Androida
wyszukiwarka
lub za pomocą Vibrator
w celu wywołania reakcji haptycznej
opinie.
Przetwórz tekst
Urządzenia z Androidem 8.0 (poziom interfejsu API 26) lub nowszym obejmują kilka funkcji przetwarzania tekstu, które ułatwiają usługom ułatwień dostępu identyfikować określone jednostki tekstu pojawiającego się na ekranie i wykonywać związane z nimi działania.
Etykietki
Android 9 (poziom interfejsu API 28) wprowadza kilka funkcji, które dają dostęp do
etykietek w interfejsie aplikacji. Używaj
getTooltipText()
aby odczytać tekst etykietki, i użyj
ACTION_SHOW_TOOLTIP
oraz
ACTION_HIDE_TOOLTIP
aby instruować instancje View
, że mają wyświetlać lub ukrywać ich etykietki.
Tekst podpowiedzi
Od 2017 roku Android udostępnia kilka metod interakcji z tekst podpowiedzi obiektu tekstowego:
-
isShowingHintText()
orazsetShowingHintText()
wskazują i ustawiają, czy bieżący tekst węzła to tekst podpowiedzi węzła. getHintText()
zapewnia dostęp do samego tekstu podpowiedzi. Nawet jeśli obiekt się nie wyświetla tekstu podpowiedzi, wywołaniegetHintText()
powiodło się.
Lokalizacje znaków tekstu na ekranie
Na urządzeniach z Androidem 8.0 (poziom interfejsu API 26) lub nowszym usługi ułatwień dostępu
może określić współrzędne ekranu dla ramki ograniczającej każdej widocznej postaci
w widżecie TextView
. Usługi
można podać te współrzędne, dzwoniąc
refreshWithExtraData()
zaliczanie
EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
jako pierwszy argument i obiekt Bundle
jako drugiego argumentu. W miarę działania metody system wypełnia pole
Bundle
argument z tablicą o wartości umożliwiającej parowanie
Rect
obiektów. Każdy obiekt Rect
reprezentuje ramkę ograniczającą konkretnego znaku.
Ujednolicone jednostronne wartości zakresu
Niektóre obiekty AccessibilityNodeInfo
korzystają z instancji
AccessibilityNodeInfo.RangeInfo
.
wskazuje, że element interfejsu może przyjmować różne wartości. Podczas tworzenia
zakresu za pomocą
RangeInfo.obtain()
lub podczas pobierania skrajnych wartości zakresu za pomocą funkcji
getMin()
oraz
getMax()
,
pamiętaj, że urządzenia z Androidem 8.0 (poziom interfejsu API 26) lub nowszym
zakresy jednostronne w ustandaryzowany sposób:
- W przypadku zakresów bez wartości minimalnej
Float.NEGATIVE_INFINITY
reprezentuje wartość minimalną. - Dla zakresów bez wartości maksymalnej
Float.POSITIVE_INFINITY
reprezentuje wartość maksymalną.
Odpowiadanie na zdarzenia związane z ułatwieniami dostępu
Skoro usługa jest skonfigurowana do uruchamiania i nasłuchiwania zdarzeń, napisz kod
wie, co zrobić, gdy nadejdzie AccessibilityEvent
. Zacznij od zastąpienia
onAccessibilityEvent(AccessibilityEvent)
. W tej metodzie użyj parametru
getEventType()
aby określić rodzaj zdarzenia
getContentDescription()
aby wyodrębnić tekst etykiety powiązany z widokiem, który uruchamia zdarzenie:
Kotlin
override fun onAccessibilityEvent(event: AccessibilityEvent) { var eventText: String = when (event.eventType) { AccessibilityEvent.TYPE_VIEW_CLICKED -> "Clicked: " AccessibilityEvent.TYPE_VIEW_FOCUSED -> "Focused: " else -> "" } eventText += event.contentDescription // Do something nifty with this text, like speak the composed string back to // the user. speakToUser(eventText) ... }
Java
@Override public void onAccessibilityEvent(AccessibilityEvent event) { final int eventType = event.getEventType(); String eventText = null; switch(eventType) { case AccessibilityEvent.TYPE_VIEW_CLICKED: eventText = "Clicked: "; break; case AccessibilityEvent.TYPE_VIEW_FOCUSED: eventText = "Focused: "; break; } eventText = eventText + event.getContentDescription(); // Do something nifty with this text, like speak the composed string back to // the user. speakToUser(eventText); ... }
Dodatkowe materiały
Więcej informacji znajdziesz w tych materiałach: