Eine Bedienungshilfe ist eine App, die die Benutzeroberfläche verbessert, um Nutzer mit Behinderungen oder Personen, 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 kleines Kind kümmern oder an einer sehr lauten Party teilnehmen, möglicherweise zusätzliches oder alternatives Feedback zur Benutzeroberfläche benötigen.
Android bietet standardmäßige Bedienungshilfen, einschließlich TalkBack, und Entwickler können ihre eigenen Dienste erstellen und vertreiben. In diesem Dokument werden die Grundlagen der Erstellung 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 du ein neues Projekt für diese Service
erstellst und nicht beabsichtigst, eine App damit verknüpft zu haben, kannst du die Starter-Activity
-Klasse aus der Quelle entfernen.
Manifestdeklarationen und Berechtigungen
Apps, die Bedienungshilfen anbieten, müssen bestimmte Deklarationen in ihrem App-Manifest enthalten, damit sie vom Android-System als Bedienungshilfe behandelt werden. In diesem Abschnitt werden die erforderlichen und optionalen Einstellungen für Bedienungshilfen erläutert.
Erklärung zu Bedienungshilfen
Damit deine App als Bedienungshilfe behandelt werden kann, musst du in deinem Manifest in das application
-Element ein service
-Element anstelle des activity
-Elements einfügen. Fügen Sie außerdem im Element service
einen Intent-Filter für Bedienungshilfen ein. Außerdem muss das Manifest den Dienst durch Hinzufügen der Berechtigung BIND_ACCESSIBILITY_SERVICE
schützen, damit nur das System eine Bindung daran 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 angegeben sind, die der Dienst verarbeitet, sowie zusätzliche Informationen zum Dienst. Die Konfiguration eines Bedienungshilfendiensts ist in der Klasse AccessibilityServiceInfo
enthalten. Der Dienst kann mithilfe einer Instanz dieser Klasse und setServiceInfo()
zur Laufzeit eine Konfiguration erstellen und festlegen. Bei dieser Methode sind jedoch nicht alle Konfigurationsoptionen verfügbar.
Du kannst deinem Manifest ein <meta-data>
-Element mit einem Verweis auf eine Konfigurationsdatei hinzufügen. So kannst du die gesamte Palette der Optionen für die Bedienungshilfe festlegen, 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 Barrierefreiheitsdienstes 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 beim Festlegen der Konfigurationsvariablen für Ihre Bedienungshilfe Folgendes, damit das System weiß, wie und wann es ausgeführt werden soll:
- Auf welche Ereignistypen soll die Funktion reagieren?
- Muss der Dienst für alle Anwendungen oder nur für bestimmte Paketnamen aktiv sein?
- Welche verschiedenen Feedbacktypen werden verwendet?
Sie haben zwei Möglichkeiten, diese Variablen festzulegen. Die abwärtskompatible Option besteht darin, sie im Code mit setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
festzulegen. Dazu überschreiben Sie die Methode onServiceConnected()
und konfigurieren dort Ihren Dienst, 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 so aus, wenn sie mit XML definiert wurden:
<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 Ihrer Dienstdeklaration ein <meta-data>
-Tag hinzufügen, das auf die XML-Datei verweist. Wenn Sie Ihre XML-Datei in res/xml/serviceconfig.xml
speichern, 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
Ein Bedienungshilfendienst muss die AccessibilityService
-Klasse erweitern und die folgenden Methoden aus dieser Klasse überschreiben. Diese Methoden werden in der Reihenfolge dargestellt, in der sie vom Android-System aufgerufen werden: vom Start des Dienstes (onServiceConnected()
) über die Ausführung (onAccessibilityEvent()
, onInterrupt()
) bis zum Herunterfahren (onUnbind()
).
onServiceConnected()
(optional): Diese Methode wird vom System aufgerufen, wenn eine Verbindung zu Ihrer Bedienungshilfe hergestellt wird. Verwenden Sie diese Methode für einmalige Einrichtungsschritte für Ihren Dienst, einschließlich der Verbindung zu Diensten für Nutzerfeedbacksysteme wie dem Audiomanager oder dem 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, wennAccessibilityEvent
erkannt wird, die den von Ihrer Bedienungshilfe angegebenen Ereignisfilterparametern entspricht, z. B. wenn der Nutzer auf eine Schaltfläche tippt oder sich auf ein UI-Steuerelement in einer App konzentriert, zu der Ihre Bedienungshilfe Feedback gibt. Wenn das System diese Methode aufruft, übergibt es die zugehörigeAccessibilityEvent
, die 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 von Ihrem Dienst bereitgestellte Feedback unterbrochen werden möchte. Dies geschieht normalerweise als Reaktion auf eine Nutzeraktion, z. B. wenn der Fokus auf ein anderes Steuerelement verschoben wird. Diese Methode kann während des Lebenszyklus Ihres Dienstes mehrmals aufgerufen werden.onUnbind()
(optional): Diese Methode wird vom System aufgerufen, wenn die Bedienungshilfe heruntergefahren wird. Verwenden Sie diese Methode, um ein einmaliges Herunterfahren durchzuführen. Dazu gehört auch die Aufhebung der Zuweisung von Diensten für Nutzerfeedbacksysteme wie Audiomanager oder Gerätevibrator.
Diese Callback-Methoden bieten die Grundstruktur für die Bedienungshilfe. Sie können entscheiden, wie Daten verarbeitet werden, die vom Android-System in Form von AccessibilityEvent
-Objekten bereitgestellt werden, und dem Nutzer Feedback geben. Weitere Informationen zum Abrufen von Informationen aus einem Bedienungshilfen-Ereignis finden Sie unter Ereignisdetails abrufen.
Für Veranstaltungen zur Barrierefreiheit registrieren
Eine der wichtigsten Funktionen der Konfigurationsparameter des Bedienungshilfendiensts besteht darin, anzugeben, welche Arten von Bedienungshilfenereignissen Ihr Dienst verarbeiten kann. Wenn Sie diese Informationen angeben, können Bedienungshilfen miteinander zusammenarbeiten. Außerdem haben Sie die Möglichkeit, nur bestimmte Ereignistypen aus bestimmten Anwendungen zu verarbeiten. Die Ereignisfilterung kann die folgenden Kriterien umfassen:
Paketnamen:Geben Sie die Paketnamen der Apps an, deren Bedienungshilfenereignisse Ihr Dienst verarbeiten soll. Wenn Sie diesen Parameter nicht angeben, wird die Bedienungshilfe als verfügbar für Bedienungshilfen-Ereignisse für alle Anwendungen betrachtet. Sie können diesen Parameter in den Konfigurationsdateien des Bedienungshilfendiensts mit dem Attribut
android:packageNames
als kommagetrennte Liste festlegen oder das MitgliedAccessibilityServiceInfo.packageNames
verwenden.Ereignistypen:Geben Sie die Arten von Bedienungshilfenereignissen an, die Ihr Dienst verarbeiten soll. Sie können diesen Parameter in den Konfigurationsdateien des Bedienungshilfendienstes mit dem Attribut
android:accessibilityEventTypes
als durch das Zeichen|
getrennte Liste festlegen, z. B.accessibilityEventTypes="typeViewClicked|typeViewFocused"
. Alternativ können Sie sie mit dem MitgliedAccessibilityServiceInfo.eventTypes
festlegen.
Überlegen Sie sich beim Einrichten der Bedienungshilfe sorgfältig, welche Ereignisse er verarbeiten kann, und registrieren Sie sich nur für diese Ereignisse. Da Nutzer mehrere Bedienungshilfen gleichzeitig aktivieren können, darf Ihr Dienst keine Ereignisse verarbeiten, die er nicht verarbeiten kann. Denken Sie daran, dass andere Dienste diese Ereignisse verarbeiten können, um die Nutzererfahrung 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 können Sie die Lautstärke der Audioausgabe Ihrer Bedienungshilfe unabhängig von anderen Tönen auf dem Gerät steuern.
Bedienungshilfen können diesen Streamtyp verwenden, indem sie die Option FLAG_ENABLE_ACCESSIBILITY_VOLUME
festlegen. Anschließend kannst du die Audiolautstärke des Geräts für Bedienungshilfen ändern, indem du auf der Geräteinstanz von AudioManager
die Methode adjustStreamVolume()
aufrufst.
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 zu den Neuerungen bei der Android-Barrierefreiheit im Internet von der Google I/O 2017, das um 6:35 Uhr startet.
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. Obwohl durch diese Tastenkombination standardmäßig TalkBack aktiviert und deaktiviert wird, können Nutzer die Schaltfläche so konfigurieren, dass alle auf ihrem Gerät installierten Dienste aktiviert und deaktiviert werden.
Damit Nutzer über den Kurzbefehl für Bedienungshilfen auf einen bestimmten Bedienungshilfe-Dienst zugreifen können, muss der Dienst das Feature zur Laufzeit anfordern.
Weitere Informationen finden Sie im Video zu den Neuerungen bei der Android-Barrierefreiheit im Internet von der Google I/O 2017, das um 13:25 Uhr startet.
Schaltfläche „Bedienungshilfen“
Auf Geräten mit einem von Software gerenderten Navigationsbereich und Android 8.0 (API-Level 26) oder höher befindet sich auf der rechten Seite der Navigationsleiste die Schaltfläche „Bedienungshilfen“. Wenn Nutzer auf diese Schaltfläche klicken, können sie abhängig vom aktuell auf dem Bildschirm angezeigten Inhalt eine von mehreren aktivierten Bedienungshilfen und -diensten aufrufen.
Damit Nutzer einen bestimmten Bedienungshilfendienst über die Schaltfläche „Bedienungshilfen“ aufrufen können, muss der Dienst das Flag FLAG_REQUEST_ACCESSIBILITY_BUTTON
im android:accessibilityFlags
-Attribut eines AccessibilityServiceInfo
-Objekts hinzufügen. Der Dienst kann dann Callbacks mit registerAccessibilityButtonCallback()
registrieren.
Im folgenden Code-Snippet sehen Sie, wie Sie einen Bedienungshilfedienst so konfigurieren können, dass er auf das Drücken der Schaltfläche für Bedienungshilfen reagiert:
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 zu den Neuerungen bei der Android-Barrierefreiheit im Internet von der Google I/O 2017, das um 16:28 Uhr gestartet wurde.
Gesten auf dem Fingerabdrucksensor
Bedienungshilfen auf Geräten mit Android 8.0 (API-Level 26) oder höher können auf Wischen (nach oben, unten, links und rechts) entlang des Fingerabdrucksensors eines Geräts reagieren. Führen Sie die folgende Sequenz 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 Callbacks.
Denken Sie daran, dass nicht alle Geräte einen Fingerabdrucksensor haben. Mit der Methode isHardwareDetected()
können Sie feststellen, ob ein Gerät den Sensor unterstützt. Auch auf einem Gerät mit Fingerabdrucksensor kann Ihr Dienst den Sensor nicht verwenden, wenn er zur Authentifizierung genutzt wird. Wenn Sie herausfinden 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 Fingerabdruck-Gesten zum Navigieren auf einem virtuellen Spielbrett:
// 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 zu den Neuerungen bei der Android-Barrierefreiheit im Internet von der Google I/O 2017, das um 9:03 Uhr beginnt.
Mehrsprachige Sprachausgabe
Ab Android 8.0 (API-Level 26) kann der Text-in-Sprache-Dienst (TTS) von Android Wortgruppen in mehreren Sprachen innerhalb eines einzigen Textblocks erkennen und sprechen. Um diesen automatischen Sprachwechsel in einer Bedienungshilfe zu ermöglichen, verpacken Sie alle Strings in LocaleSpan
-Objekte, 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 zu den Neuerungen bei der Android-Barrierefreiheit im Internet von der Google I/O 2017, das um 10:59 Uhr startet.
Im Namen von Nutzern handeln
Ab 2011 können Bedienungshilfen im Namen von Nutzern agieren, unter anderem den Eingabefokus ändern und Elemente der Benutzeroberfläche auswählen (aktivieren). Im Jahr 2012 wurde der Bereich der Aktionen um Scrolllisten und die Interaktion mit Textfeldern erweitert. Bedienungshilfen können auch globale Aktionen ausführen, z. B. zum Startbildschirm gehen, die Schaltfläche „Zurück“ drücken und den Benachrichtigungsbildschirm und die Liste der zuletzt verwendeten Apps öffnen. Seit 2012 umfasst Android den Schwerpunkt auf Bedienungshilfen, d. h., alle sichtbaren Elemente können von Bedienungshilfen ausgewählt werden.
Mit diesen Funktionen können Entwickler von Bedienungshilfen alternative Navigationsmodi wie die Gestensteuerung erstellen und Nutzern mit Behinderungen eine bessere Steuerung ihrer Android-Geräte ermöglichen.
Auf Gesten achten
Bedienungshilfen können bestimmte Gesten erkennen und im Auftrag eines Nutzers reagieren. Für diese Funktion muss Ihre Bedienungshilfe die Aktivierung der Funktion „Tippen & Entdecken“ anfordern. Ihr Dienst kann diese Aktivierung anfordern, indem er das Mitglied flags
der AccessibilityServiceInfo
-Instanz des Dienstes auf FLAG_REQUEST_TOUCH_EXPLORATION_MODE
setzt, 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 angefordert hat, muss der Nutzer die Aktivierung der Funktion zulassen, falls sie nicht bereits aktiv ist. Wenn diese Funktion aktiviert 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 Touch-Gesten mit mehr als einem Path
-Objekt.
Beim Angeben einer Abfolge von Strichen können Sie angeben, dass sie zu derselben programmatischen Geste gehören. Dazu verwenden Sie das abschließende 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 zu den Neuerungen bei der Android-Barrierefreiheit im Internet von der Google I/O 2017, das um 15:47 Uhr startet.
Aktionen für Bedienungshilfen verwenden
Bedienungshilfen können im Namen der Nutzer agieren, um Interaktionen mit Apps zu vereinfachen und produktiver zu sein. Die Bedienungshilfen für Aktionen wurden 2011 hinzugefügt und 2012 erheblich erweitert.
Wenn Sie im Namen von Nutzern handeln möchten, muss Ihre Bedienungshilfe registrieren, damit Ereignisse von Apps empfangen werden können. Außerdem muss die Berechtigung zum Ansehen der App-Inhalte angefordert werden. Dazu setzen Sie android:canRetrieveWindowContent
in der Dienstkonfigurationsdatei auf true
. Wenn der Dienst Ereignisse empfängt, kann er mit getSource()
das Objekt AccessibilityNodeInfo
aus dem Ereignis abrufen.
Mit dem AccessibilityNodeInfo
-Objekt kann Ihr Dienst dann die Ansichtshierarchie untersuchen, um zu bestimmen, welche Aktion ausgeführt werden soll, und dann mit performAction()
für den Nutzer handeln.
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 Ihr Dienst Aktionen innerhalb einer App ausführen. Wenn Ihr Dienst eine globale Aktion ausführen muss, z. B. zum Startbildschirm, auf die Schaltfläche „Zurück“ tippen oder den Benachrichtigungsbildschirm oder die Liste der zuletzt verwendeten Apps öffnen muss, verwenden Sie die Methode performGlobalAction()
.
Fokustypen verwenden
2012 wurde bei Android der Fokus auf der Benutzeroberfläche mit dem Namen Schwerpunkt auf Barrierefreiheit 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, mit dem festgelegt wird, welches Benutzeroberflächenelement auf dem Bildschirm eine Eingabe empfängt, wenn ein Nutzer Zeichen eingibt, die Eingabetaste auf der Tastatur drückt oder die mittlere Taste eines Steuerkreuzes drückt.
Es ist möglich, dass ein Element in einer Benutzeroberfläche den Eingabefokus hat, während ein anderes Element den Fokus auf die Barrierefreiheit hat. Der Zweck des Fokus auf Bedienungshilfen besteht darin, Bedienungshilfen eine Methode zur Interaktion mit sichtbaren Elementen auf einem Bildschirm zu bieten, unabhängig davon, ob das Element aus Systemperspektive eingabefokussierbar ist. Damit deine Bedienungshilfe korrekt mit den Eingabeelementen der App interagiert, folge den Richtlinien zum Testen der Barrierefreiheit einer App. So kannst du deinen Dienst testen, während du eine typische App verwendest.
Eine Bedienungshilfe kann mithilfe der Methode AccessibilityNodeInfo.findFocus()
bestimmen, welches Benutzeroberflächenelement den Eingabe- oder Bedienungshilfenfokus hat. Sie können auch nach Elementen suchen, die mit dem Eingabefokus ausgewählt werden können. Verwenden Sie dazu die Methode focusSearch()
. Schließlich kann der Bedienungshilfenfokus mithilfe der Methode performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS)
festgelegt werden.
Informationen sammeln
Bedienungshilfen haben Standardmethoden, um Schlüsseleinheiten der von Nutzern bereitgestellten Informationen wie Ereignisdetails, Text und Zahlen zu erfassen und darzustellen.
Details zu Fensteränderungen abrufen
Mit Android 9 (API-Level 28) und höher können Apps Fensterupdates verfolgen, wenn eine App mehrere Fenster gleichzeitig neu zieht. Wenn ein TYPE_WINDOWS_CHANGED
-Ereignis eintritt, können Sie mit der getWindowChanges()
API bestimmen, wie sich die Fenster ändern. Während einer Aktualisierung im Mehrfenstermodus erzeugt jedes Fenster seine eigenen Ereignisse. Die Methode getSource()
gibt die Stammansicht des Fensters zurück, das mit jedem Ereignis verknüpft ist.
Wenn eine App Titel des Bereichs für Bedienungshilfen 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. Beispielsweise kann das Framework erkennen, wenn ein Bereich einen neuen Titel hat oder wenn ein Bereich ausgeblendet wird.
Termindetails abrufen
Android stellt Bedienungshilfen Informationen zur Interaktion der Benutzeroberfläche über AccessibilityEvent
-Objekte bereit. In früheren Android-Versionen boten die in einem Bedienungshilfen-Ereignis verfügbaren Informationen und wichtige Details zur Steuerung der Benutzeroberfläche, die von Nutzern ausgewählt wurden, begrenzte Kontextinformationen. In vielen Fällen können diese fehlenden Kontextinformationen entscheidend sein, um die Bedeutung der ausgewählten Einstellung zu verstehen.
Ein Beispiel für eine Schnittstelle, bei der der Kontext entscheidend ist, ist ein Kalender oder Tagesplaner. Wenn der Nutzer in einer Liste von Montag bis Freitag ein Zeitfenster von 16:00 Uhr auswählt und die Bedienungshilfe „16 Uhr“ ansagt, aber weder den Wochentag- noch den Tag des Monats oder den Monat angibt, ist das daraus resultierende Feedback verwirrend. In diesem Fall ist der Kontext einer Steuerung auf der Benutzeroberfläche für einen Nutzer, der eine Besprechung planen möchte, von entscheidender Bedeutung.
Seit 2011 erweitert Android die Menge an Informationen, die ein Bedienungshilfedienst zu einer Interaktion auf der Benutzeroberfläche erhalten kann, indem Bedienungshilfen basierend auf der Ansichtshierarchie erstellt werden. Eine Ansichtshierarchie besteht aus einer Gruppe von Benutzeroberflächenkomponenten, die die Komponente (ihre übergeordneten Elemente) enthalten, sowie den Benutzeroberflächenelementen, die diese Komponente (untergeordnete Elemente) enthalten könnte. Auf diese Weise kann Android umfassendere Details zu Bedienungshilfen-Ereignissen bereitstellen, sodass Bedienungshilfen den Nutzern nützlicheres Feedback geben.
Eine Bedienungshilfe ruft Informationen zu einem Benutzeroberflächenereignis ü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 Typs des Objekts, auf das reagiert wird, des Beschreibungstexts und weiterer Details.
AccessibilityEvent.getRecordCount()
undgetRecord(int)
: Mit diesen Methoden können Sie eine Gruppe vonAccessibilityRecord
-Objekten abrufen, die zu dem vom System übergebenenAccessibilityEvent
-Objekt 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 Ansichts-Layout-Hierarchie (über- und untergeordnete Elemente) der Komponente anfordern, von der das Bedienungshilfen-Ereignis stammt. Mit dieser Funktion kann eine Bedienungshilfe den vollständigen Kontext eines Ereignisses untersuchen, einschließlich des Inhalts und Status der zugehörigen Ansichten oder untergeordneten Ansichten.
Auf der Android-Plattform kann ein AccessibilityService
die Ansichtshierarchie abfragen und Daten zur UI-Komponente, die ein Ereignis generiert, sowie zu den übergeordneten und untergeordneten Elementen erfassen. Legen Sie dazu die folgende Zeile in Ihrer XML-Konfiguration fest:
android:canRetrieveWindowContent="true"
Anschließend rufen Sie mit getSource()
ein AccessibilityNodeInfo
-Objekt ab.
Bei diesem Aufruf wird nur dann ein Objekt zurückgegeben, wenn das Fenster, aus dem das Ereignis stammt, noch immer das aktive Fenster ist. Wenn nicht, wird null zurückgegeben. Gehen Sie also entsprechend vor.
Im folgenden Beispiel führt der Code folgende Schritte aus, wenn ein Ereignis empfangen wird:
- Greift sofort auf das übergeordnete Element der Ansicht zu, aus der das Ereignis stammt.
- In dieser Ansicht wird als untergeordnete Ansicht nach einem Label und einem Kästchen gesucht.
- Wenn sie gefunden werden, wird ein String für den Bericht an den Nutzer erstellt, der das Label angibt und angibt, ob es geprüft wurde.
Wenn beim Durchlaufen der Ansichtshierarchie an irgendeinem Punkt 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 eine vollständige, funktionierende Bedienungshilfe. Konfiguriere die Interaktionen mit dem Nutzer. Füge dazu das Sprachausgabe-Engine von Android hinzu oder verwende Vibrator
für haptisches Feedback.
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
Mit Android 9 (API-Level 28) werden mehrere Funktionen eingeführt, mit denen Sie auf der Benutzeroberfläche einer App auf Kurzinfos zugreifen können. 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 zur Interaktion mit dem Hinweistext eines textbasierten Objekts:
- Die Methoden
isShowingHintText()
undsetShowingHintText()
geben bzw. legen fest, 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.
Positionen von Bildschirmtextzeichen
Auf Geräten mit Android 8.0 (API-Level 26) und höher können Bedienungshilfen die Bildschirmkoordinaten für den Begrenzungsrahmen jedes sichtbaren Zeichens in einem TextView
-Widget bestimmen. Dienste finden diese Koordinaten, indem sie refreshWithExtraData()
aufrufen und EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
als erstes Argument und ein Bundle
-Objekt als zweites Argument übergeben. Bei der Ausführung der Methode füllt das System das Argument Bundle
mit einem aggregierbaren Array von Rect
-Objekten. 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. Wenn Sie einen Bereich mit RangeInfo.obtain()
erstellen oder die Extremwerte des Bereichs mit getMin()
und getMax()
abrufen, beachten Sie, dass Geräte mit Android 8.0 (API-Level 26) und höher einseitige Bereiche auf standardisierte Weise darstellen:
- Bei Bereichen ohne Mindestwert stellt
Float.NEGATIVE_INFINITY
den Mindestwert dar. - Bei Bereichen ohne Maximalwert stellt
Float.POSITIVE_INFINITY
den Maximalwert dar.
Auf Bedienungshilfen reagieren
Nachdem Ihr Dienst nun ausgeführt und auf Ereignisse überwacht wird, sollten Sie Code schreiben, damit er weiß, was zu tun ist, wenn ein AccessibilityEvent
eintrifft. Überschreiben Sie zuerst die Methode onAccessibilityEvent(AccessibilityEvent)
. Verwenden Sie in dieser Methode getEventType()
, um den Ereignistyp zu bestimmen, und getContentDescription()
, um den Labeltext zu extrahieren, der mit der Ansicht verknüpft ist, durch die das Ereignis ausgelöst wird:
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); ... }
Zusätzliche Ressourcen
Weitere Informationen finden Sie in den folgenden Ressourcen: