Ein Bedienungshilfen-Dienst ist eine App zur Optimierung der Benutzeroberfläche, um Nutzer mit Behinderungen oder Nutzern, die vorübergehend nicht vollständig mit einem Gerät interagieren können, zu unterstützen. Beispielsweise benötigen Nutzer, die Auto fahren, sich um ein Kleinkind kümmern oder an einer lauten Party teilnehmen, möglicherweise zusätzliches oder alternatives Feedback über die Benutzeroberfläche.
Android bietet standardmäßige Bedienungshilfen wie TalkBack. Entwickler können ihre eigenen Dienste erstellen und vertreiben. In diesem Dokument werden die Grundlagen zum Erstellen einer Bedienungshilfe erläutert.
Eine Bedienungshilfe kann mit einer normalen App gebündelt oder als eigenständiges Android-Projekt erstellt werden. Die Schritte zum Erstellen des Dienstes sind in beiden Fällen identisch.
Bedienungshilfe erstellen
Erstellen Sie in Ihrem Projekt eine Klasse, die AccessibilityService
erweitert:
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() { } ... }
Wenn Sie für diese Service
ein neues Projekt erstellen und damit keine Anwendung verknüpfen möchten, können Sie die Startklasse Activity
aus der Quelle entfernen.
Manifestdeklarationen und Berechtigungen
Apps, die Bedienungshilfen anbieten, müssen im App-Manifest bestimmte Deklarationen enthalten, damit sie vom Android-System als Bedienungshilfe behandelt werden. In diesem Abschnitt werden die erforderlichen und optionalen Einstellungen für Bedienungshilfen beschrieben.
Erklärung zum Dienst „Barrierefreiheit im Internet“
Damit Ihre App als Bedienungshilfe behandelt wird, muss ein service
-Element anstelle des activity
-Elements in das application
-Element Ihres Manifests eingefügt werden. Fügen Sie außerdem innerhalb des service
-Elements einen Intent-Filter für den Bedienungshilfendienst hinzu. Das Manifest muss den Dienst außerdem schützen. Dazu wird die Berechtigung BIND_ACCESSIBILITY_SERVICE
hinzugefügt, damit nur das System eine Bindung an ihn vornehmen kann. Beispiel:
<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>
Konfiguration der Bedienungshilfen
Bedienungshilfen müssen eine Konfiguration bereitstellen, in der die Arten von Bedienungshilfen-Ereignissen, die der Dienst verarbeitet, sowie zusätzliche Informationen zum Dienst angegeben sind. Die Konfiguration einer Bedienungshilfe ist in der Klasse AccessibilityServiceInfo
enthalten. Ihr Dienst kann eine Konfiguration mithilfe einer Instanz dieser Klasse und setServiceInfo()
zur Laufzeit erstellen und festlegen. Bei dieser Methode sind jedoch nicht alle Konfigurationsoptionen verfügbar.
Sie können in Ihr Manifest ein <meta-data>
-Element mit einem Verweis auf eine Konfigurationsdatei einfügen, mit der Sie alle Optionen für den Bedienungshilfen-Dienst festlegen können, wie im folgenden Beispiel gezeigt:
<service android:name=".MyAccessibilityService"> ... <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" /> </service>
Dieses <meta-data>
-Element verweist auf eine XML-Datei, die Sie im Ressourcenverzeichnis Ihrer Anwendung erstellen: <project_dir>/res/xml/accessibility_service_config.xml>
. Der folgende Code zeigt ein Beispiel für den Inhalt der Dienstkonfigurationsdatei:
<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" />
Weitere Informationen zu den XML-Attributen, die in der Konfigurationsdatei des Bedienungshilfendiensts verwendet werden können, finden Sie in der folgenden Referenzdokumentation:
android:description
android:packageNames
android:accessibilityEventTypes
android:accessibilityFlags
android:accessibilityFeedbackType
android:notificationTimeout
android:canRetrieveWindowContent
android:settingsActivity
Weitere Informationen dazu, welche Konfigurationseinstellungen zur Laufzeit dynamisch festgelegt werden können, finden Sie in der Referenzdokumentation zu AccessibilityServiceInfo
.
Bedienungshilfe konfigurieren
Beachten Sie Folgendes, wenn Sie die Konfigurationsvariablen für den Bedienungshilfendienst festlegen, um dem System mitzuteilen, wie und wann es ausgeführt werden soll:
- Auf welche Ereignistypen soll er reagieren?
- Muss der Dienst für alle Anwendungen oder nur für bestimmte Paketnamen aktiv sein?
- Welche verschiedenen Feedbacktypen werden dabei verwendet?
Sie haben zwei Möglichkeiten, diese Variablen festzulegen. Die abwärtskompatible Option besteht darin, sie im Code mit setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
festzulegen. Überschreiben Sie dazu die Methode onServiceConnected()
und konfigurieren Sie den Dienst dort, wie im folgenden Beispiel gezeigt:
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); }
Die zweite Möglichkeit besteht darin, den Dienst mithilfe einer XML-Datei zu konfigurieren. Bestimmte Konfigurationsoptionen wie canRetrieveWindowContent
sind nur verfügbar, wenn Sie Ihren Dienst mit XML konfigurieren. Die Konfigurationsoptionen aus dem vorherigen Beispiel sehen bei der Definition mit XML so aus:
<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" />
Wenn Sie XML verwenden, verweisen Sie in Ihrem Manifest darauf, indem Sie in Ihre Dienstdeklaration ein <meta-data>
-Tag einfügen, das auf die XML-Datei verweist. Wenn du deine XML-Datei in res/xml/serviceconfig.xml
speicherst, sieht das neue Tag so aus:
<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>
Methoden für Bedienungshilfen-Dienste
Eine Bedienungshilfe muss die Klasse AccessibilityService
erweitern und die folgenden Methoden aus dieser Klasse überschreiben. Diese Methoden werden in der Reihenfolge angezeigt, in der sie vom Android-System aufgerufen werden: vom Start des Dienstes (onServiceConnected()
) über seine Ausführung (onAccessibilityEvent()
, onInterrupt()
) bis zum Zeitpunkt seiner Beendigung (onUnbind()
).
onServiceConnected()
: (optional) Das System ruft diese Methode auf, wenn eine Verbindung zu Ihrer Bedienungshilfe hergestellt wird. Verwenden Sie diese Methode, um einmalige Einrichtungsschritte für Ihren Dienst auszuführen, einschließlich der Verbindung mit Nutzerfeedback-Systemdiensten wie dem Audiomanager oder der Gerätevibrator. Wenn Sie die Konfiguration Ihres Dienstes zur Laufzeit festlegen oder einmalige Anpassungen vornehmen möchten, ist dies ein geeigneter Ort, umsetServiceInfo()
aufzurufen.onAccessibilityEvent()
(erforderlich): Das System ruft diese Methode zurück, wenn es eineAccessibilityEvent
erkennt, die den von Ihrem Bedienungshilfendienst angegebenen Ereignisfilterparametern entspricht, z. B. wenn der Nutzer auf eine Schaltfläche tippt oder den Fokus auf eine UI-Steuerung in einer App legt, für die die Bedienungshilfe Feedback gibt. Wenn das System diese Methode aufruft, wird das zugehörigeAccessibilityEvent
-Element übergeben, das der Dienst dann interpretieren und verwenden kann, um dem Nutzer Feedback zu geben. Diese Methode kann während des Lebenszyklus Ihres Dienstes mehrmals aufgerufen werden.onInterrupt()
(erforderlich): Das System ruft diese Methode auf, wenn das Feedback vom Dienst unterbrochen werden soll, in der Regel als Reaktion auf eine Nutzeraktion wie das Verschieben des Fokus auf ein anderes Steuerelement. Diese Methode kann während des Lebenszyklus Ihres Dienstes mehrmals aufgerufen werden.onUnbind()
: (optional) Das System ruft diese Methode auf, wenn das System die Bedienungshilfe herunterfährt. Verwenden Sie diese Methode, um ein einmaliges Herunterfahren auszuführen, einschließlich des Aufhebens der Zuweisung von Nutzerfeedback-Systemdiensten wie dem Audio-Manager oder der Gerätevibratorfunktion.
Diese Callback-Methoden stellen die Grundstruktur für Ihren Bedienungshilfedienst bereit. Du kannst entscheiden, wie die vom Android-System in Form von AccessibilityEvent
-Objekten bereitgestellten Daten verarbeitet werden sollen, und dem Nutzer Feedback geben. Weitere Informationen zum Abrufen von Informationen zu Bedienungshilfen-Terminen finden Sie unter Termindetails abrufen.
Für Veranstaltungen zur Barrierefreiheit registrieren
Eine der wichtigsten Funktionen der Konfigurationsparameter des Bedienungshilfendienstes besteht darin, anzugeben, welche Arten von Bedienungshilfen-Ereignissen Ihr Dienst verarbeiten kann. Wenn Sie diese Informationen angeben, können Bedienungshilfen miteinander zusammenarbeiten und Sie können flexibel nur bestimmte Ereignistypen aus bestimmten Apps verarbeiten. Die Ereignisfilterung kann die folgenden Kriterien umfassen:
Paketnamen:Geben Sie die Paketnamen der Apps an, deren Bedienungshilfen-Ereignisse Ihr Dienst verarbeiten soll. Wenn Sie diesen Parameter nicht angeben, wird der Bedienungshilfendienst für Bedienungshilfen-Ereignisse aller Apps als verfügbar angesehen. Sie können diesen Parameter in den Konfigurationsdateien des Bedienungshilfendiensts mit dem Attribut
android:packageNames
als durch Kommas getrennte Liste festlegen oder das MitgliedAccessibilityServiceInfo.packageNames
verwenden.Ereignistypen:Geben Sie die Typen von Bedienungshilfen an, die der Dienst verarbeiten soll. Sie können diesen Parameter in den Konfigurationsdateien des Bedienungshilfendiensts mit dem Attribut
android:accessibilityEventTypes
als Liste festlegen, die durch das Zeichen|
getrennt ist, z. B.accessibilityEventTypes="typeViewClicked|typeViewFocused"
. Alternativ können Sie ihn mit dem ElementAccessibilityServiceInfo.eventTypes
festlegen.
Überlegen Sie sich beim Einrichten der Bedienungshilfe genau, welche Ereignisse Ihr Dienst verarbeiten kann, und registrieren Sie sich nur für diese Ereignisse. Da Nutzer mehrere Bedienungshilfen gleichzeitig aktivieren können, darf der Dienst keine Ereignisse verarbeiten, die er nicht verarbeiten kann. Denken Sie daran, dass andere Dienste diese Ereignisse verarbeiten können, um die User Experience zu verbessern.
Lautstärke der Bedienungshilfen
Geräte mit Android 8.0 (API-Level 26) und höher enthalten die Lautstärkekategorie STREAM_ACCESSIBILITY
. Damit kannst du die Lautstärke der Audioausgabe deines Bedienungshilfendienstes unabhängig von anderen Tönen auf dem Gerät steuern.
Bedienungshilfen können diesen Streamtyp durch Festlegen der Option FLAG_ENABLE_ACCESSIBILITY_VOLUME
verwenden. Anschließend können Sie die Lautstärke der Bedienungshilfen des Geräts ändern, indem Sie die Methode adjustStreamVolume()
in der AudioManager
-Instanz des Geräts aufrufen.
Das folgende Code-Snippet zeigt, wie eine Bedienungshilfe die Volume-Kategorie STREAM_ACCESSIBILITY
verwenden kann:
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); } } }
Weitere Informationen finden Sie im Video der Session What's new in Android Accessibility von der Google I/O 2017 ab 6:35 Uhr.
Kurzbefehl für Bedienungshilfen
Auf Geräten mit Android 8.0 (API-Level 26) und höher können Nutzer ihre bevorzugte Bedienungshilfe auf jedem Bildschirm aktivieren und deaktivieren, indem sie beide Lautstärketasten gleichzeitig gedrückt halten. Durch diese Verknüpfung wird TalkBack standardmäßig aktiviert und deaktiviert. Nutzer können die Schaltfläche jedoch so konfigurieren, dass alle auf ihrem Gerät installierten Dienste aktiviert und deaktiviert werden.
Damit Nutzer über die Bedienungshilfenverknüpfung auf eine bestimmte Bedienungshilfe zugreifen können, muss der Dienst die Funktion zur Laufzeit anfordern.
Weitere Informationen finden Sie im Video der Session What's new in Android Accessibility von der Google I/O 2017 ab 13:25 Uhr.
Schaltfläche „Bedienungshilfen“
Auf Geräten mit einem als Software gerenderten Navigationsbereich und Android 8.0 (API-Level 26) oder höher enthält die rechte Seite der Navigationsleiste eine Schaltfläche für Bedienungshilfen. Wenn Nutzer auf diese Schaltfläche klicken, können sie eine von mehreren aktivierten Bedienungshilfen und -diensten aufrufen, je nachdem, welche Inhalte gerade auf dem Bildschirm angezeigt werden.
Damit Nutzer eine bestimmte Bedienungshilfe über die entsprechende Schaltfläche aufrufen können, muss der Dienst das Flag FLAG_REQUEST_ACCESSIBILITY_BUTTON
in das Attribut android:accessibilityFlags
des AccessibilityServiceInfo
-Objekts einfügen. Der Dienst kann dann Callbacks mit registerAccessibilityButtonCallback()
registrieren.
Das folgende Code-Snippet zeigt, wie Sie eine Bedienungshilfe konfigurieren können, die reagiert, wenn der Nutzer auf die Schaltfläche „Bedienungshilfen“ drückt:
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); } }
Weitere Informationen finden Sie im Video der Session What's new in Android Accessibility von der Google I/O 2017 ab 16:28 Uhr.
Gesten auf dem Fingerabdrucksensor
Auf Geräten mit Android 8.0 (API-Level 26) und höher können Bedienungshilfen auf Wischbewegungen (nach oben, unten, links und rechts) entlang des Fingerabdrucksensors eines Geräts reagieren. Führen Sie die folgende Reihenfolge aus, um einen Dienst für den Empfang von Callbacks zu diesen Interaktionen zu konfigurieren:
- Deklarieren Sie die Berechtigung
USE_BIOMETRIC
und die FunktionCAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES
. - Legen Sie das Flag
FLAG_REQUEST_FINGERPRINT_GESTURES
im Attributandroid:accessibilityFlags
fest. - Registrieren Sie sich mit
registerFingerprintGestureCallback()
für Rückrufe.
Bitte beachte, dass nicht alle Geräte Fingerabdrucksensoren haben. Mit der Methode isHardwareDetected()
kannst du feststellen, ob ein Gerät den Sensor unterstützt. Selbst auf einem Gerät mit Fingerabdrucksensor kann Ihr Dienst den Sensor nicht verwenden, wenn er zu Authentifizierungszwecken verwendet wird. Wenn Sie wissen möchten, wann der Sensor verfügbar ist, rufen Sie die Methode isGestureDetectionAvailable()
auf und implementieren Sie den onGestureDetectionAvailabilityChanged()
-Callback.
Das folgende Code-Snippet zeigt ein Beispiel für die Verwendung von Fingerabdruckgesten, um ein virtuelles Spielbrett zu navigieren:
// 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); } } }
Weitere Informationen finden Sie im Video der Session What's new in Android Accessibility von der Google I/O 2017 ab 9:03 Uhr.
Mehrsprachige Sprachausgabe
Ab Android 8.0 (API-Ebene 26) kann der Sprachausgabe-Dienst (TTS) von Android Wortgruppen in mehreren Sprachen in einem einzigen Textblock identifizieren und sprechen. Um diese Funktion zur automatischen Sprachwechselfunktion in einem Bedienungshilfedienst zu aktivieren, umschließen Sie alle Strings in LocaleSpan
-Objekten, wie im folgenden Code-Snippet gezeigt:
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; }
Weitere Informationen finden Sie im Video der Session What's new in Android Accessibility von der Google I/O 2017 ab 10:59 Uhr.
Im Namen von Nutzern handeln
Seit 2011 können Bedienungshilfen im Namen von Nutzern agieren. Dazu gehören das Ändern des Eingabefokus und das Auswählen (Aktivieren) von Elementen der Benutzeroberfläche. 2012 wurde der Aktionsbereich um das Scrollen von Listen und das Interagieren mit Textfeldern erweitert. Bedienungshilfen können auch globale Aktionen ausführen, z. B. den Startbildschirm aufrufen, die Schaltfläche „Zurück“ drücken und den Benachrichtigungsbildschirm und die Liste der zuletzt verwendeten Apps öffnen. Seit 2012 hat Android den Schwerpunkt für Barrierefreiheit, sodass alle sichtbaren Elemente über einen Bedienungshilfendienst ausgewählt werden können.
Mit diesen Funktionen können Entwickler von Bedienungshilfen alternative Navigationsmodi wie die Bedienung über Gesten erstellen und Nutzer mit Behinderungen können ihre Android-Mobilgeräte besser steuern.
Auf Gesten achten
Bedienungshilfen können auf bestimmte Gesten reagieren und im Namen eines Nutzers reagieren. Für diese Funktion muss die Bedienungshilfe die Funktion „Tippen & Entdecken“ aktivieren. Ihr Dienst kann diese Aktivierung anfordern. Dazu setzt er das Mitglied flags
der AccessibilityServiceInfo
-Instanz des Dienstes auf FLAG_REQUEST_TOUCH_EXPLORATION_MODE
, wie im folgenden Beispiel gezeigt.
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; } ... }
Nachdem Ihr Dienst die Aktivierung von Tippen & Entdecken anfordert, muss der Nutzer die Aktivierung der Funktion zulassen, falls sie noch nicht aktiv ist. Wenn diese Funktion aktiv ist, erhält der Dienst über die Callback-Methode onGesture()
des Dienstes Benachrichtigungen über Touch-Gesten für Bedienungshilfen und kann im Namen des Nutzers reagieren.
Fortlaufende Touch-Gesten
Geräte mit Android 8.0 (API-Level 26) unterstützen fortlaufende Touch-Gesten oder programmatische Gesten, die mehr als ein Path
-Objekt enthalten.
Wenn Sie eine Abfolge von Strichen angeben, können Sie festlegen, dass sie zu derselben programmatischen Geste gehören. Verwenden Sie dazu das letzte Argument willContinue
im Konstruktor GestureDescription.StrokeDescription
, wie im folgenden Code-Snippet gezeigt:
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); }
Weitere Informationen finden Sie im Video der Session What's new in Android Accessibility von der Google I/O 2017 ab 15:47 Uhr.
Aktionen für Bedienungshilfen verwenden
Bedienungshilfen können im Namen von Nutzern die Interaktion mit Apps vereinfachen und produktiver sein. Bedienungshilfen wurden 2011 hinzugefügt und 2012 deutlich ausgeweitet.
Wenn Sie im Namen von Nutzern handeln möchten, muss sich die Bedienungshilfe registrieren, um Ereignisse von Apps zu erhalten und die Berechtigung zum Ansehen von App-Inhalten anzufordern. Dazu setzen Sie android:canRetrieveWindowContent
in der Dienstkonfigurationsdatei auf true
. Wenn Ihr Dienst Ereignisse empfängt, kann er das Objekt AccessibilityNodeInfo
aus dem Ereignis mit getSource()
abrufen.
Mit dem AccessibilityNodeInfo
-Objekt kann der Dienst dann die Ansichtshierarchie untersuchen, um zu bestimmen, welche Aktion ausgeführt werden soll, und dann performAction()
für den Nutzer verwenden.
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(); } ... }
Mit der Methode performAction()
kann der Dienst Aktionen innerhalb einer App ausführen. Wenn Ihr Dienst eine globale Aktion ausführen muss, z. B. den Startbildschirm aufrufen, auf die Schaltfläche „Zurück“ tippen oder den Benachrichtigungsbildschirm oder die Liste mit den zuletzt verwendeten Apps öffnen, verwenden Sie die Methode performGlobalAction()
.
Fokustypen verwenden
2012 wurde der Schwerpunkt von Android auf die Benutzeroberfläche Barrierefreiheit im Internet eingeführt. Bedienungshilfen können diesen Fokus verwenden, um beliebige sichtbare Elemente der Benutzeroberfläche auszuwählen und darauf zu reagieren. Dieser Fokustyp unterscheidet sich vom Eingabefokus, der festlegt, welches Bildschirmelement der Benutzeroberfläche eine Eingabe erhält, wenn ein Nutzer Zeichen eingibt, die Eingabetaste auf einer Tastatur drückt oder die mittlere Taste eines Steuerkreuzes drückt.
Es ist möglich, dass ein Element in einer Benutzeroberfläche einen Eingabefokus hat, während ein anderes Element auf Barrierefreiheit ausgerichtet ist. Der Zweck der Barrierefreiheit besteht darin, Bedienungshilfen eine Methode zur Interaktion mit sichtbaren Elementen auf einem Bildschirm bereitzustellen, unabhängig davon, ob das Element aus Systemperspektive eingabefokussierbar ist. Damit die Bedienungshilfe korrekt mit den Eingabeelementen einer App interagiert, folgen Sie den Richtlinien zum Testen der Barrierefreiheit einer App, um den Dienst in einer typischen App zu testen.
Eine Bedienungshilfe kann mithilfe der Methode AccessibilityNodeInfo.findFocus()
bestimmen, welches Element der Benutzeroberfläche den Eingabefokus oder Barrierefreiheitsfokus hat. Mit der Methode focusSearch()
können Sie auch nach Elementen suchen, die mit Eingabefokus ausgewählt werden können. Schließlich kann der Bedienungshilfendienst den Fokus auf die Barrierefreiheit mit der Methode performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS)
festlegen.
Informationen sammeln
Bedienungshilfen verwenden Standardmethoden zum Erfassen und Darstellen von Schlüsseleinheiten für von Nutzern bereitgestellte Informationen wie Ereignisdetails, Text und Zahlen.
Details zu Fensteränderungen abrufen
Mit Android 9 (API-Level 28) und höher können Apps Fensteraktualisierungen erfassen, wenn eine App mehrere Fenster gleichzeitig neu erstellt. Wenn ein TYPE_WINDOWS_CHANGED
-Ereignis eintritt, verwende die getWindowChanges()
API, um festzustellen, wie sich die Fenster ändern. Während einer Aktualisierung mit mehreren Fenstern generiert jedes Fenster eine eigene Reihe von Ereignissen. Die Methode getSource()
gibt die Stammansicht des Fensters zurück, das jedem Ereignis zugeordnet ist.
Wenn eine App Titel für den Bedienungshilfenbereich für ihre View
-Objekte definiert, kann der Dienst erkennen, wenn die UI der App aktualisiert wird. Wenn ein TYPE_WINDOW_STATE_CHANGED
-Ereignis eintritt, verwenden Sie die von getContentChangeTypes()
zurückgegebenen Typen, um zu bestimmen, wie sich das Fenster ändert. Das Framework kann beispielsweise erkennen, wenn ein Bereich einen neuen Titel hat oder ein Bereich verschwindet.
Termindetails abrufen
Android stellt Bedienungshilfen mithilfe von AccessibilityEvent
-Objekten Informationen zur Interaktion mit der Benutzeroberfläche zur Verfügung. In früheren Android-Versionen boten die in einem Ereignis zur Barrierefreiheit verfügbaren Informationen nur begrenzte Kontextinformationen, obwohl sie viele Details zur von den Nutzern ausgewählten Benutzeroberflächensteuerung enthielten. In vielen Fällen können diese fehlenden Kontextinformationen entscheidend sein, um die Bedeutung des ausgewählten Steuerelements zu verstehen.
Ein Beispiel für eine Schnittstelle, bei der der Kontext von entscheidender Bedeutung ist, ist ein Kalender oder ein Tagesplaner. Wenn der Nutzer in einer Liste mit einem Montag bis Freitag ein Zeitfenster von 16:00 Uhr auswählt und die Bedienungshilfe „16:00 Uhr“ ankündigt, den Wochentag, den Tag des Monats oder den Monatsnamen jedoch nicht ankündigt, ist das resultierende Feedback verwirrend. In diesem Fall ist der Kontext einer UI-Steuerung für einen Nutzer, der eine Besprechung planen möchte, von entscheidender Bedeutung.
Seit 2011 erweitert Android die Menge an Informationen, die ein Bedienungshilfendienst zu einer Interaktion auf der Benutzeroberfläche erhalten kann, indem Barrierefreiheitsereignisse basierend auf der Ansichtshierarchie zusammengestellt werden. Eine Ansichtshierarchie besteht aus Komponenten der Benutzeroberfläche, die die Komponente (ihre übergeordneten Elemente) und die Elemente der Benutzeroberfläche enthalten, die in der jeweiligen Komponente enthalten sein können (ihre untergeordneten Elemente). Auf diese Weise kann Android mehr Details zu Ereignissen für Bedienungshilfen liefern, sodass Bedienungshilfen nützliches Feedback für Nutzer geben können.
Eine Bedienungshilfe ruft Informationen zu einem Ereignis auf der Benutzeroberfläche über ein AccessibilityEvent
ab, das vom System an die Callback-Methode onAccessibilityEvent()
des Dienstes übergeben wird. Dieses Objekt liefert Details zum Ereignis, einschließlich des Objekttyps, auf den reagiert wird, der Beschreibung des Objekts und andere Details.
AccessibilityEvent.getRecordCount()
undgetRecord(int)
: Mit diesen Methoden können Sie die Gruppe vonAccessibilityRecord
-Objekten abrufen, die zu den vom System übergebenenAccessibilityEvent
beitragen. Diese Detailebene bietet mehr Kontext für das Ereignis, das die Bedienungshilfe auslöst.AccessibilityRecord.getSource()
: Diese Methode gibt einAccessibilityNodeInfo
-Objekt zurück. Mit diesem Objekt können Sie die Layouthierarchie (über- und untergeordnete Elemente) der Komponente anfordern, aus der das Bedienungshilfen-Ereignis stammt. Mit dieser Funktion kann eine Bedienungshilfe den vollständigen Kontext eines Ereignisses untersuchen, einschließlich des Inhalts und des Status von einschließenden Ansichten oder untergeordneten Ansichten.
Die Android-Plattform bietet die Möglichkeit, mit einem AccessibilityService
die Ansichtshierarchie abzufragen. Dabei werden Informationen zu der UI-Komponente, die ein Ereignis generiert, sowie zu dessen übergeordneten und untergeordneten Elementen erfasst. Dazu legen Sie die folgende Zeile in Ihrer XML-Konfiguration fest:
android:canRetrieveWindowContent="true"
Anschließend können Sie mit getSource()
ein AccessibilityNodeInfo
-Objekt abrufen.
Bei diesem Aufruf wird ein Objekt nur zurückgegeben, wenn das Fenster, von dem das Ereignis stammt, noch das aktive Fenster ist. Andernfalls wird null zurückgegeben, verhalten Sie sich also entsprechend.
Im folgenden Beispiel bewirkt der Code Folgendes, wenn ein Ereignis empfangen wird:
- Sofort das übergeordnete Element der Ansicht erfassen, von der das Ereignis stammt.
- In dieser Ansicht wird nach einem Label und einem Kästchen als untergeordnete Ansichten gesucht.
- Wenn sie gefunden werden, wird ein String erstellt, der an den Nutzer gemeldet werden soll. Dieser gibt das Label an und gibt an, ob es überprüft wurde.
Wenn beim Durchlaufen der Ansichtshierarchie ein Nullwert zurückgegeben wird, wird die Methode stillschweigend aufgegeben.
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); }
Jetzt haben Sie einen vollständigen, funktionierenden Bedienungshilfedienst. Konfigurieren Sie die Interaktion mit dem Nutzer, indem Sie das Sprachausgabe-Modul von Android hinzufügen oder ein Vibrator
für haptisches Feedback verwenden.
Text verarbeiten
Geräte mit Android 8.0 (API-Level 26) und höher enthalten mehrere Textverarbeitungsfunktionen, mit denen Bedienungshilfen bestimmte Texteinheiten, die auf dem Bildschirm angezeigt werden, leichter erkennen und bearbeiten können.
Kurzinfos
Android 9 (API-Level 28) bietet verschiedene Funktionen, mit denen du Zugriff auf Kurzinfos in der Benutzeroberfläche einer App erhältst. Verwenden Sie getTooltipText()
, um den Text einer Kurzinfo zu lesen, und ACTION_SHOW_TOOLTIP
und ACTION_HIDE_TOOLTIP
, um Instanzen von View
anzuweisen, ihre Kurzinfos ein- oder auszublenden.
Hinweistext
Seit 2017 bietet Android mehrere Methoden für die Interaktion mit dem Hinweistext eines textbasierten Objekts:
- Mit den Methoden
isShowingHintText()
undsetShowingHintText()
wird angegeben und festgelegt, ob der aktuelle Textinhalt des Knotens den Hinweistext des Knotens darstellt. getHintText()
bietet Zugriff auf den Hinweistext selbst. Auch wenn ein Objekt keinen Hinweistext anzeigt, ist der Aufruf vongetHintText()
erfolgreich.
Position von Bildschirmtextzeichen
Auf Geräten mit Android 8.0 (API-Level 26) und höher können Bedienungshilfen die Bildschirmkoordinaten für die Begrenzungsrahmen jedes sichtbaren Zeichens in einem TextView
-Widget ermitteln. Dienste ermitteln diese Koordinaten, indem sie refreshWithExtraData()
aufrufen und dabei EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
als erstes Argument und ein Bundle
-Objekt als zweites Argument übergeben. Bei Ausführung der Methode füllt das System das Argument Bundle
mit einem Parcelable-Array von Rect
-Objekten auf. Jedes Rect
-Objekt stellt den Begrenzungsrahmen eines bestimmten Zeichens dar.
Standardisierte einseitige Bereichswerte
Einige AccessibilityNodeInfo
-Objekte verwenden eine Instanz von AccessibilityNodeInfo.RangeInfo
, um anzugeben, dass ein UI-Element einen Wertebereich annehmen kann. Beachten Sie beim Erstellen eines Bereichs mit RangeInfo.obtain()
oder beim Abrufen der Extremwerte mit getMin()
und getMax()
, dass Geräte mit Android 8.0 (API-Level 26) und höher einseitige Bereiche standardisiert darstellen:
- Bei Bereichen ohne Minimum stellt
Float.NEGATIVE_INFINITY
den Minimalwert dar. - Bei Bereichen ohne Höchstwert stellt
Float.POSITIVE_INFINITY
den Höchstwert dar.
Auf Ereignisse zur Barrierefreiheit reagieren
Ihr Dienst ist nun so eingerichtet, dass er ausgeführt wird und auf Ereignisse wartet. Schreiben Sie nun Code, damit er weiß, was zu tun ist, wenn ein AccessibilityEvent
eintrifft. Überschreiben Sie zuerst die Methode onAccessibilityEvent(AccessibilityEvent)
. Verwenden Sie dabei getEventType()
, um den Ereignistyp zu bestimmen, und getContentDescription()
, um den Labeltext zu extrahieren, der mit der Ansicht verknüpft ist, die das Ereignis auslöst:
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); ... }
Weitere Informationen
Weitere Informationen finden Sie in den folgenden Ressourcen: