Eigene Bedienungshilfe erstellen

Eine Bedienungshilfe ist eine App, die die Benutzeroberfläche verbessert, Nutzende mit Beeinträchtigungen oder Personen, die vorübergehend nicht in der Lage sind, mit einem Gerät. Zum Beispiel Nutzer, die Auto fahren, sich um ein Kleinkind kümmern, oder die Teilnahme an einer sehr lauten Party Feedback geben.

Android bietet standardmäßige Bedienungshilfen wie TalkBack und Entwickler können ihre eigenen Dienste erstellen und vertreiben. Dieses Dokument werden die Grundlagen der Erstellung einer Bedienungshilfe erläutert.

Eine Bedienungshilfe kann mit einer normalen App gebündelt oder als ein eigenständiges Android-Projekt erstellen. Die Schritte zum Erstellen des Dienstes sind dieselben in beiden Situationen.

Bedienungshilfe erstellen

Erstellen Sie innerhalb Ihres Projekts eine Klasse, die 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() {
    }

...
}

Sie erstellen ein neues Projekt für Service und möchten keine App haben verknüpft sind, können Sie die Starter-Klasse Activity aus Ihrem Quelle.

Manifestdeklarationen und Berechtigungen

Für Apps, die Bedienungshilfen anbieten, müssen bestimmte Erklärungen in ihre App-Manifeste so zu definieren, dass sie vom Android-Team als Bedienungshilfe behandelt werden. System. In diesem Abschnitt werden die erforderlichen und optionalen Einstellungen für Bedienungshilfen.

Erklärung zu Bedienungshilfen

Damit deine App als Bedienungshilfe behandelt werden kann, musst du einen service hinzufügen. statt des activity-Elements innerhalb von application. -Element in Ihrem Manifest. Fügen Sie außerdem im service-Element ein Intent-Filter für Bedienungshilfen. Das Manifest muss auch den Dienst schützen indem Sie den Parameter BIND_ACCESSIBILITY_SERVICE 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, die der Dienst verarbeitet, und zusätzliche Informationen zu für den Dienst. Die Konfiguration einer Bedienungshilfe ist in der AccessibilityServiceInfo . Ihr Dienst kann eine Konfiguration mithilfe einer Instanz dieses Klasse und setServiceInfo() während der Laufzeit. Allerdings sind damit nicht alle Konfigurationsoptionen verfügbar. .

Du kannst in dein Manifest ein <meta-data>-Element mit einem Verweis auf ein Konfigurationsdatei, mit der Sie alle Optionen für Ihre Bedienungshilfe 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 du in deinem im Ressourcenverzeichnis der Anwendung ein: <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 für Bedienungshilfen-Dienst (siehe folgende Referenz) Dokumentation:

Weitere Informationen dazu, welche Konfigurationseinstellungen dynamisch festgelegt werden können sehen Sie sich die AccessibilityServiceInfo in der Referenzdokumentation.

Bedienungshilfe konfigurieren

Beachten Sie beim Festlegen der Konfigurationsvariablen für Ihre Bedienungshilfe, um dem System mitzuteilen, wie und wann es ausgeführt werden soll:

  • Auf welche Ereignistypen soll die Funktion reagieren?
  • Muss der Dienst für alle Apps oder nur für ein bestimmtes Paket aktiv sein Namen?
  • Welche verschiedenen Feedbacktypen werden verwendet?

Sie haben zwei Möglichkeiten, diese Variablen festzulegen. Die abwärtskompatible Option im Code festlegen, indem Sie setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo) Dazu überschreiben Sie onServiceConnected() und konfigurieren Sie 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 Konfiguration Die Optionen aus dem vorherigen Beispiel sehen wie folgt 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 ein <meta-data>-Tag zu Ihrem Service-Deklaration, die auf die XML-Datei verweist. Wenn Sie Ihre XML-Datei in res/xml/serviceconfig.xml, 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

Eine Bedienungshilfe muss die AccessibilityService-Klasse und die folgenden Methoden dieser Klasse überschreiben. Diese Methoden werden in Die Reihenfolge, in der sie vom Android-System aufgerufen werden: ab dem Start des Dienstes (onServiceConnected()) bis während der Ausführung (onAccessibilityEvent(), onInterrupt()) bis zum Herunterfahren (onUnbind())

  • onServiceConnected() (optional): Das System ruft diese Methode auf, wenn sie eine Verbindung zu Ihrer Bedienungshilfe herstellen. Diese Methode für eine einmalige Einrichtung verwenden Schritte für Ihren Dienst, einschließlich der Verbindung mit dem Nutzerfeedbacksystem z. B. den Audio-Manager oder die Vibrator-App. Wenn Sie Konfiguration Ihres Dienstes während der Laufzeit oder nehmen Sie einmalige Anpassungen vor, Hier kannst du setServiceInfo() anrufen.

  • onAccessibilityEvent() (erforderlich): Das System ruft diese Methode zurück, wenn wird ein Fehler erkannt, AccessibilityEvent die den Parametern für die Ereignisfilterung entspricht, die Sie über die Bedienungshilfen festgelegt haben z. B. wenn Nutzende auf eine Schaltfläche tippen oder sich auf eine Benutzeroberfläche konzentrieren in einer App, für die Ihre Bedienungshilfe Feedback gibt. Wann? ruft das System diese Methode auf, übergibt es die zugehörige AccessibilityEvent, die der Dienst dann interpretieren und verwenden kann, um dem Nutzer. Diese Methode kann während des Lebenszyklus Ihrer .

  • onInterrupt() (erforderlich): Das System ruft diese Methode auf, wenn das System möchte das Feedback, das Ihr Dienst bereitstellt, unterbrechen. Dies geschieht normalerweise in Reaktion auf eine Nutzeraktion, z. B. das Verschieben des Fokus auf ein anderes Steuerelement Dieses kann im Lebenszyklus Ihres Dienstes mehrmals aufgerufen werden.

  • onUnbind() (optional): Diese Methode wird aufgerufen, wenn das System die Bedienungshilfe beenden wird. Mit dieser Methode können Sie einmaliges Herunterfahren, einschließlich Aufheben der Zuweisung von Nutzerfeedbacksystem z. B. den Audio-Manager oder die Vibrator-App.

Diese Callback-Methoden bieten die Grundstruktur für Bedienungshilfen . Sie können entscheiden, wie die vom Android-System bereitgestellten Daten verarbeitet werden. in Form von AccessibilityEvent-Objekten erstellen und dem Nutzer Feedback geben. Für Weitere Informationen zum Abrufen von Informationen aus Bedienungshilfen-Ereignissen finden Sie unter Getränke .

Für Veranstaltungen zur Barrierefreiheit registrieren

Eine der wichtigsten Funktionen der Konfiguration der Bedienungshilfen können Sie angeben, welche Arten von Bedienungshilfen-Ereignissen Ihr Dienst die Sie bewältigen können. Wenn Sie diese Informationen angeben, können Bedienungshilfen und können flexibel auf bestimmte Ereignisse aus bestimmten Apps. Das Filtern von Ereignissen kann Folgendes umfassen: Kriterien:

  • Paketnamen:Geben Sie die Paketnamen von Apps an, deren Bedienungshilfen Ereignisse, die Ihr Dienst verarbeiten soll. Falls Sie diesen Parameter nicht angeben, Bedienungshilfen gelten für jede App. Sie können diesen Parameter in der Bedienungshilfe Konfigurationsdateien mit dem Attribut android:packageNames als kommagetrennte Liste eingeben oder die Methode AccessibilityServiceInfo.packageNames Mitglied.

  • Ereignistypen:Geben Sie die Arten von Bedienungshilfen-Ereignissen an, die Ihre zu verwalten. Sie können diesen Parameter in der Bedienungshilfe Konfigurationsdateien mit dem Attribut android:accessibilityEventTypes als Eine Liste, die durch das Zeichen | getrennt ist, z. B. accessibilityEventTypes="typeViewClicked|typeViewFocused" Sie können auch mithilfe der AccessibilityServiceInfo.eventTypes Mitglied.

Überlegen Sie sich bei der Einrichtung Ihrer Bedienungshilfe genau, welche Ereignisse diese Ereignisse verarbeiten und nur registrieren können. Da Nutzer mehrere Bedienungshilfen gleichzeitig nutzen, darf Ihr Dienst keine die es nicht verarbeiten kann. Denken Sie daran, dass andere Dienste um die User Experience zu verbessern.

Lautstärke der Bedienungshilfen

Für Geräte mit Android 8.0 (API-Level 26) und höher ist die STREAM_ACCESSIBILITY Lautstärke, mit der Sie die Lautstärke Ihrer Bedienungshilfen Audioausgabe des Dienstes unabhängig von anderen Tönen auf dem Gerät.

Bedienungshilfen können diesen Streamtyp verwenden, indem sie die FLAG_ENABLE_ACCESSIBILITY_VOLUME Option. Anschließend kannst du die Audiolautstärke des Geräts für Bedienungshilfen ändern, indem du die adjustStreamVolume() auf der Geräteinstanz AudioManager

Das folgende Code-Snippet zeigt, wie eine Bedienungshilfe den Code STREAM_ACCESSIBILITY Volumenkategorie:

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 unter 06:35.

Kurzbefehl für Bedienungshilfen

Auf Geräten mit Android 8.0 (API-Level 26) und höher können Nutzer die bevorzugte Bedienungshilfe durch Drücken und und halten Sie beide Lautstärketasten gleichzeitig gedrückt. Obwohl diese Tastenkombination standardmäßig TalkBack deaktiviert, können Nutzer die Schaltfläche so konfigurieren, alle auf dem Gerät installierten Dienste zu deaktivieren.

Damit Nutzende über die Bedienungshilfen muss der Dienst die Funktion 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 unter 13:25.

Schaltfläche „Bedienungshilfen“

Auf Geräten mit einem von Software gerenderten Navigationsbereich und Android 8.0 (API-Ebene 26) oder höher enthält, befindet sich auf der rechten Seite der Navigationsleiste Schaltfläche „Bedienungshilfen“. Wenn Nutzer auf diese Schaltfläche klicken, können sie eine der folgenden Aktionen aufrufen: Bedienungshilfen und -Dienste aktiviert haben, je nach Inhalt die aktuell auf dem Bildschirm angezeigt werden.

Damit Nutzer eine bestimmte Bedienungshilfe mithilfe der muss der Dienst den Parameter FLAG_REQUEST_ACCESSIBILITY_BUTTON Flag im android:accessibilityFlags eines AccessibilityServiceInfo-Objekts. . Der Dienst kann dann Callbacks mithilfe von registerAccessibilityButtonCallback()

Im folgenden Code-Snippet sehen Sie, wie Sie Bedienungshilfen , um zu reagieren, wenn der Nutzer 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 zu den Neuerungen bei der Android-Barrierefreiheit im Internet von der Google I/O 2017, das unter 16:28.

Touch-Gesten auf dem Fin­gerabdrucksensor

Bedienungshilfen auf Geräten mit Android 8.0 (API-Level 26) oder höher auf Wischbewegungen (nach oben, unten, links und rechts) entlang des Fingerabdrucksensor verwenden. So konfigurieren Sie einen Dienst für den Empfang von Callbacks zu diesen -Interaktionen, führen Sie die folgende Sequenz aus:

  1. USE_BIOMETRIC deklarieren und die CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES
  2. Legen Sie die FLAG_REQUEST_FINGERPRINT_GESTURES fest. im Attribut android:accessibilityFlags.
  3. Registrieren Sie sich mit registerFingerprintGestureCallback() für Callbacks.

Denken Sie daran, dass nicht alle Geräte einen Fingerabdrucksensor haben. Zur Identifizierung ob ein Gerät den Sensor unterstützt, isHardwareDetected() . Auch auf einem Gerät mit Fingerabdrucksensor kann Ihr Dienst den Sensor zur Authentifizierung verwenden. Um zu ermitteln, wann wenn der Sensor verfügbar ist, rufen Sie isGestureDetectionAvailable() und implementieren die onGestureDetectionAvailabilityChanged() Callback des Nutzers an.

Das folgende Code-Snippet zeigt ein Beispiel für die Verwendung von auf einem virtuellen Spielfeld 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 zu den Neuerungen bei der Android-Barrierefreiheit im Internet von der Google I/O 2017, das unter 09:03.

Mehrsprachige Sprachausgabe

Ab Android 8.0 (API-Level 26) der Sprachausgabe-Dienst von Android kann Sätze in mehreren Sprachen innerhalb eines einzigen Blocks von Text. Um diese Funktion zum automatischen Sprachwechsel in einer Bedienungshilfe zu aktivieren, Service, packen Sie alle Zeichenfolgen in LocaleSpan-Objekte, wie gezeigt im folgenden Code-Snippet einfügen:

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 unter 22:59.

Im Namen von Nutzern handeln

Seit 2011 dürfen Bedienungshilfen im Namen von Nutzern handeln, darunter Ändern des Eingabefokus und Auswählen (Aktivieren) von Elementen der Benutzeroberfläche In 2012 wurde der Umfang der Aktionen um Scroll-Listen und Interaktionen erweitert. mit Textfeldern. Bedienungshilfen können auch globale Maßnahmen ergreifen, z. B. zum Startbildschirm navigieren, die Zurück-Taste drücken und die Benachrichtigungen und die Liste der zuletzt verwendeten Apps. Seit 2012 umfasst Android Fokus für Bedienungshilfen, bei dem alle sichtbaren Elemente Bedienungshilfe.

Mit diesen Funktionen können Entwickler von Bedienungshilfen wie die Bedienung über Gesten und ermöglichen es Nutzern mit Beeinträchtigungen, ihre Android-Geräte besser steuern können.

Auf Gesten achten

Bedienungshilfen können bestimmte Gesten erkennen und reagieren, im Namen eines Nutzers. Für diese Funktion muss Ihre Bedienungshilfeanfrage Aktivierung der Funktion "Tippen & Entdecken". Ihr Dienst kann dies anfordern aktivieren, indem Sie die flags Mitglied der Instanz AccessibilityServiceInfo des Dienstes, 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 angefordert hat, muss der Nutzer die Funktion aktiviert werden, falls sie noch nicht aktiv ist. Wenn diese Funktion aktiviert ist, erhält Ihr Dienst über Touch-Gesten für Bedienungshilfen Ihres Dienstes onGesture() und kann so antworten, indem er im Namen des Nutzers handelt.

Fortlaufende Touch-Gesten

Geräte mit Android 8.0 (API-Level 26) unterstützen fortlaufende Touch-Gesten oder programmatische Gesten, die mehrere Path-Objekt.

Beim Festlegen einer Abfolge von Strichen können Sie festlegen, dass sie zum programmatischer Geste durch Verwendung des letzten Arguments willContinue im 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 unter 15:47.

Aktionen für Bedienungshilfen verwenden

Bedienungshilfen können im Namen von Nutzern agieren, um die Interaktion mit und produktiver sein können. Die Fähigkeit von Bedienungshilfen, 2011 wurde das Tool zum Ausführen von Aktionen eingeführt und 2012 erheblich erweitert.

Damit Sie im Namen von Nutzern handeln können, muss die Bedienungshilfe registriert sein. um Ereignisse von Apps zu erhalten und die Berechtigung zum Ansehen der Inhalte anzufordern der Apps, indem Sie android:canRetrieveWindowContent auf true setzen Dienstkonfigurationsdatei. Wenn Ereignisse in Ihrem kann er die Daten abrufen, AccessibilityNodeInfo aus dem Ereignis aus, indem Sie getSource() Mit dem AccessibilityNodeInfo-Objekt kann Ihr Dienst dann die Ansicht erkunden um zu bestimmen, welche Aktion ausgeführt werden soll. 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();
    }
    ...
}

Mit der Methode performAction() kann Ihr Dienst Aktionen innerhalb eines Wenn Ihr Dienst eine globale Aktion ausführen muss, z. B. zum Startbildschirm navigieren, auf die Schaltfläche "Zurück" tippen oder die auf dem Benachrichtigungsbildschirm oder in der Liste der zuletzt verwendeten Apps performGlobalAction() .

Fokustypen verwenden

2012 wurde bei Android der Fokus auf der Benutzeroberfläche mit dem Namen Schwerpunkt auf Barrierefreiheit eingeführt. Bedienungshilfen können mit diesem Fokus jede sichtbare Benutzeroberfläche auswählen und auf das Element reagieren. Dieser Fokustyp unterscheidet sich vom Eingabefokus, mit dem welches Benutzeroberflächenelement auf dem Bildschirm eine Eingabe empfängt, gibt Zeichen ein, drückt die Eingabetaste auf einer Tastatur oder drückt die Mitte auf einem Steuerkreuz.

Es ist möglich, dass ein Element in einer Benutzeroberfläche den Eingabefokus hat, während ein anderes Element im Fokus steht. Der Zweck des Fokus auf Barrierefreiheit um Bedienungshilfen eine Methode zur Interaktion mit sichtbaren Elemente auf einem Bildschirm sichtbar sind, unabhängig davon, ob das Element aus einer Systemperspektive. Um sicherzustellen, dass die Bedienungshilfe mit mit der App richtig -Eingabeelemente verwenden, befolgen Sie die Richtlinien zum Testen der Zugänglichkeit, um deinen Dienst zu testen während der Nutzung einer typischen App.

Eine Bedienungshilfe kann festlegen, welches Benutzeroberflächenelement Eingaben enthält. oder Bedienungshilfen mithilfe der AccessibilityNodeInfo.findFocus() . Sie können auch nach Elementen suchen, die mit dem Eingabefokus ausgewählt werden können mithilfe der focusSearch() . Schließlich kann Ihre Bedienungshilfe den Fokus auf Barrierefreiheit mithilfe die performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS) .

Informationen sammeln

Bedienungshilfen haben Standardmethoden, um Schlüssel Einheiten mit von Nutzern bereitgestellten Informationen wie Ereignisdetails, Text und Zahlen

Details zu Fensteränderungen abrufen

Mit Android 9 (API-Level 28) und höher können Apps Fensterupdates nachverfolgen, in einer App mehrere Fenster gleichzeitig neu zeichnen. Wenn ein TYPE_WINDOWS_CHANGED Ereignis auftritt, verwenden Sie den getWindowChanges() API, um zu ermitteln, wie sich die Fenster ändern. Während eines Updates im Mehrfenstermodus wird jeder generiert einen eigenen Satz von Ereignissen. Die Methode getSource() gibt den Stamm zurück Ansicht des mit jedem Ereignis verknüpften Fensters.

Wenn eine App den Bereich für Bedienungshilfen für seine View-Objekten verwendet, kann Ihr Dienst erkennen, wird die Benutzeroberfläche der App aktualisiert. Wenn ein TYPE_WINDOW_STATE_CHANGED Ereignis auftritt, verwenden Sie die vom getContentChangeTypes() um zu bestimmen, wie sich das Fenster ändert. Beispielsweise kann das Framework erkennen, wenn ein Bereich einen neuen Titel hat oder wenn er ausgeblendet wird.

Termindetails abrufen

Android stellt Bedienungshilfen Informationen zur Benutzeroberfläche zur Verfügung. über AccessibilityEvent-Objekte interagieren. In früheren Android-Versionen die bei einer Veranstaltung zur Barrierefreiheit verfügbar sind, und bieten gleichzeitig Details zum von Nutzern ausgewählten Steuerelement auf der Benutzeroberfläche (eingeschränkt angeboten) Kontextinformationen. In vielen Fällen können diese fehlenden Kontextinformationen ist wichtig, 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 ein Tag im Planer. Wenn der Nutzer ein Zeitfenster von 16:00 Uhr in einer Liste mit Tagen von Montag bis Freitag auswählt und die Bedienungshilfe „16 Uhr“ ankündigt, aber nicht den Wochentag. Name, Tag des Monats oder Monatsnamen, ist das resultierende Feedback verwirrend sein. In diesem Fall ist der Kontext eines UI-Steuerelements entscheidend, Nutzende, die eine Besprechung planen möchten.

Seit 2011 erweitert Android die Menge an Informationen, die ein Informationen zu Interaktionen auf der Benutzeroberfläche erhalten, basierend auf der Ansichtshierarchie. Eine Ansichtshierarchie ist ein Satz Komponenten der Benutzeroberfläche, die die Komponente (ihre übergeordneten Elemente) und den Nutzer enthalten Oberflächenelemente, die in dieser Komponente (untergeordnete Elemente) enthalten sein können. In So kann Android ausführlichere Informationen zu Bedienungshilfen-Ereignissen liefern, Bedienungshilfen bieten den Nutzenden nützlicheres Feedback.

Eine Bedienungshilfe ruft Informationen zu einem Benutzeroberflächenereignis über eine AccessibilityEvent, die vom System an die Methode onAccessibilityEvent(). Dieses Objekt liefert Details zum Ereignis, einschließlich des Objekts, für das eine Aktion durchgeführt wird, seines Beschreibungstexts und weitere Details.

  • AccessibilityEvent.getRecordCount() und getRecord(int): Mit diesen Methoden können Sie AccessibilityRecord -Objekte, die zur AccessibilityEvent beitragen, die vom System. Diese Detailebene liefert mehr Kontext für das Ereignis, das die Bedienungshilfe auslöst.

  • AccessibilityRecord.getSource(): Diese Methode gibt ein AccessibilityNodeInfo-Objekt zurück. Mit diesem Objekt können Sie die Ansichtslayouthierarchie (über- und untergeordnete Elemente) der Komponente anfordern, das Bedienungshilfen-Ereignis. Mit dieser Funktion können Bedienungshilfen Dienst untersuchen den gesamten Kontext eines Ereignisses, einschließlich Inhalt und der einschließenden oder untergeordneten Ansichten angezeigt.

Auf der Android-Plattform kann ein AccessibilityService Abfragen ausführen Ansichtshierarchie. Dabei werden Informationen zur UI-Komponente erfasst, die einem Ereignis sowie dessen über- und untergeordnete Elemente. Legen Sie dazu folgende Zeile fest: in Ihrer XML-Konfiguration:

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, von dem das Ereignis stammt, immer noch 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:

  1. Greift sofort auf das übergeordnete Element der Ansicht zu, aus der das Ereignis stammt.
  2. In dieser Ansicht wird als untergeordnete Ansicht nach einem Label und einem Kästchen gesucht.
  3. Wenn sie gefunden werden, wird eine Zeichenfolge erstellt, die an den Nutzer gemeldet wird, die den und ob es aktiviert wurde.

Wenn beim Durchlaufen der Ansichtshierarchie an irgendeinem Punkt ein Nullwert zurückgegeben wird, die Methode leise aufgibt.

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. Versuchen Sie, die Methode zu konfigurieren Es interagiert mit dem Nutzer, indem es die Sprachausgabe-Funktion von Android Suchmaschine oder Vibrator für eine haptische Feedback geben.

Text verarbeiten

Geräte mit Android 8.0 (API-Level 26) und höher enthalten mehrere Textverarbeitungsfunktionen, die es Bedienungshilfen erleichtern, zur Identifizierung und Bearbeitung bestimmter Texteinheiten auf dem Bildschirm.

Kurzinfos

Android 9 (API-Level 28) bietet verschiedene Funktionen, Kurzinfos auf der Benutzeroberfläche einer App angezeigt. Verwenden Sie getTooltipText() um den Text einer Kurzinfo zu lesen, und verwenden Sie ACTION_SHOW_TOOLTIP und ACTION_HIDE_TOOLTIP an, um Instanzen von View anzuweisen, ihre Kurzinfos ein- oder auszublenden.

Hinweistext

Seit 2017 bietet Android mehrere Methoden zur Interaktion mit einem Hinweistext des textbasierten Objekts:

  • Die isShowingHintText() und setShowingHintText() -Methoden angeben bzw. festlegen, ob der aktuelle Text des Knotens content steht für den Hinweistext des Knotens.
  • getHintText() Zugriff auf den Hinweistext selbst. Auch wenn ein Objekt nicht Hinweistext: Das Aufrufen von getHintText() ist erfolgreich.

Positionen von Bildschirmtextzeichen

Auf Geräten mit Android 8.0 (API-Level 26) und höher: Bedienungshilfen kann die Bildschirmkoordinaten für den Begrenzungsrahmen jedes sichtbaren Zeichens bestimmen. in einem TextView-Widget Dienste ermitteln Sie diese Koordinaten, indem Sie refreshWithExtraData(), übergeben EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY als erstes Argument und ein Bundle-Objekt als zweites Argument ein. Bei Ausführung der Methode füllt das System Argument Bundle mit einem aparierbaren Array von Rect-Objekte. Jedes Rect-Objekt stellt den Begrenzungsrahmen eines bestimmten Zeichens dar.

Standardisierte einseitige Bereichswerte

Einige AccessibilityNodeInfo-Objekte verwenden eine Instanz von AccessibilityNodeInfo.RangeInfo um anzuzeigen, dass ein UI-Element einen Wertebereich annehmen kann. Beim Erstellen einer Bereich mithilfe von RangeInfo.obtain(), oder wenn Sie die Extremwerte des Bereichs mit getMin() und getMax(), Geräte mit Android 8.0 (API-Level 26) und höher einseitige Bereiche standardisiert werden:

Auf Bedienungshilfen reagieren

Ihr Dienst ist nun für die Ausführung und das Warten auf Ereignisse eingerichtet. Schreiben Sie nun Code, damit er weiß, was zu tun ist, wenn ein AccessibilityEvent ankommt. Überschreiben Sie zunächst den onAccessibilityEvent(AccessibilityEvent) . Bei dieser Methode verwenden Sie getEventType() um die Art des Ereignisses und getContentDescription() , um jeden 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:

Leitfäden

Codelabs