Utwórz własną usługę ułatwień dostępu

Usługa ułatwień dostępu to aplikacja, która stanowi ulepszenie interfejsu użytkownika, aby ułatwić użytkownicy z niepełnosprawnościami lub którzy mogą tymczasowo nie być w stanie w pełni korzystać z aplikacji z urządzeniem. Na przykład są to użytkownicy, którzy prowadzą samochód, opiekują się małymi dziećmi, lub udział w bardzo głośnej imprezie może wymagać dodatkowego lub alternatywnego interfejsu opinie.

Android oferuje standardowe usługi ułatwień dostępu, takie jak TalkBack , a deweloperzy mogą tworzyć i rozpowszechniać własne usługi. Ten dokument zawiera omówienie podstaw tworzenia usługi ułatwień dostępu.

Usługę ułatwień dostępu można połączyć w pakiet ze standardową aplikacją lub utworzyć samodzielnym projekcie Androida. Etapy tworzenia usługi są takie same w w każdej z tych sytuacji.

Utwórz swoją usługę ułatwień dostępu

W projekcie utwórz zajęcia, które obejmują zakres AccessibilityService:

Kotlin

package com.example.android.apis.accessibility

import android.accessibilityservice.AccessibilityService
import android.view.accessibility.AccessibilityEvent

class MyAccessibilityService : AccessibilityService() {
...
    override fun onInterrupt() {}

    override fun onAccessibilityEvent(event: AccessibilityEvent?) {}
...
}

Java

package com.example.android.apis.accessibility;

import android.accessibilityservice.AccessibilityService;
import android.view.accessibility.AccessibilityEvent;

public class MyAccessibilityService extends AccessibilityService {
...
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
    }

    @Override
    public void onInterrupt() {
    }

...
}

Jeśli tworzysz dla tego elementu (Service) nowy projekt i nie planujesz mieć aplikacji możesz usunąć początkową klasę Activity ze swojej źródła.

Deklaracje i uprawnienia w pliku manifestu

Aplikacje udostępniające usługi ułatwień dostępu muszą zawierać określone deklaracje w sekcji i manifest aplikacji, aby był traktowany przez Androida jako usługa ułatwień dostępu. systemu. W tej sekcji opisano wymagane i opcjonalne ustawienia dla usług ułatwień dostępu.

Deklaracja dotycząca usługi ułatwień dostępu

Aby Twoja aplikacja była traktowana jako usługa ułatwień dostępu, dodaj atrybut service w elemencie application, a nie activity. w pliku manifestu. Dodatkowo w elemencie service umieść filtr intencji związanych z usługą ułatwień dostępu. Plik manifestu musi też chronić usługę dodając BIND_ACCESSIBILITY_SERVICE aby mieć pewność, że tylko system może z nim powiązać. Oto przykład:

  <application>
    <service android:name=".MyAccessibilityService"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
        android:label="@string/accessibility_service_label">
      <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
      </intent-filter>
    </service>
  </application>

Konfiguracja usługi ułatwień dostępu

Usługi ułatwień dostępu muszą zawierać konfigurację określającą typy zdarzenia ułatwień dostępu obsługiwane przez usługę i dodatkowe informacje o nich i z usługami. Konfiguracja usługi ułatwień dostępu znajduje się w sekcji AccessibilityServiceInfo zajęcia. Twoja usługa może skompilować i ustawić konfigurację przy użyciu instancji tego typu klasa i setServiceInfo() w czasie działania aplikacji. Jednak nie wszystkie opcje konfiguracji są dostępne w przypadku tego .

Możesz uwzględnić w pliku manifestu element <meta-data> z odwołaniem do który pozwala ustawić wszystkie opcje zgodnie z tym przykładem:

<service android:name=".MyAccessibilityService">
  ...
  <meta-data
    android:name="android.accessibilityservice"
    android:resource="@xml/accessibility_service_config" />
</service>

Ten element <meta-data> odnosi się do pliku XML utworzonego w katalog zasobów aplikacji: <project_dir>/res/xml/accessibility_service_config.xml> Następujący kod: Poniżej znajdziesz przykład zawartości pliku konfiguracji usługi:

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
    android:packageNames="com.example.android.apis"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFlags="flagDefault"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity"
/>

Więcej informacji o atrybutach XML, których można użyć w pliku plik konfiguracji usługi ułatwień dostępu, patrz poniższe informacje. dokumentacja:

Więcej informacji o tym, które ustawienia konfiguracji można ustawiać dynamicznie w czasie działania, zapoznaj się z AccessibilityServiceInfo dokumentacji referencyjnej.

Skonfiguruj usługę ułatwień dostępu

Podczas ustawiania zmiennych konfiguracyjnych dla środowiska należy wziąć pod uwagę następujące kwestie: usługi ułatwień dostępu, aby poinformować system, jak i kiedy uruchamiać:

  • Na jakie typy zdarzeń ma odpowiadać?
  • Czy usługa musi być aktywna dla wszystkich aplikacji, czy tylko dla określonego pakietu? nazwy?
  • Jakiego typu opinii używa?

Te zmienne możesz konfigurować na 2 sposoby. Opcja zgodności wstecznej jest umieszczenie ich w kodzie, setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo) Aby to zrobić, zastąp onServiceConnected() i skonfiguruj w niej swoją usługę, jak pokazano w poniższym przykładzie:

Kotlin

override fun onServiceConnected() {
    info.apply {
        // Set the type of events that this service wants to listen to. Others
        // aren't passed to this service.
        eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED or AccessibilityEvent.TYPE_VIEW_FOCUSED

        // If you only want this service to work with specific apps, set their
        // package names here. Otherwise, when the service is activated, it
        // listens to events from all apps.
        packageNames = arrayOf("com.example.android.myFirstApp", "com.example.android.mySecondApp")

        // Set the type of feedback your service provides.
        feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN

        // Default services are invoked only if no package-specific services are
        // present for the type of AccessibilityEvent generated. This service is
        // app-specific, so the flag isn't necessary. For a general-purpose
        // service, consider setting the DEFAULT flag.

        // flags = AccessibilityServiceInfo.DEFAULT;

        notificationTimeout = 100
    }

    this.serviceInfo = info

}

Java

@Override
public void onServiceConnected() {
    // Set the type of events that this service wants to listen to. Others
    // aren't passed to this service.
    info.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED |
            AccessibilityEvent.TYPE_VIEW_FOCUSED;

    // If you only want this service to work with specific apps, set their
    // package names here. Otherwise, when the service is activated, it listens
    // to events from all apps.
    info.packageNames = new String[]
            {"com.example.android.myFirstApp", "com.example.android.mySecondApp"};

    // Set the type of feedback your service provides.
    info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN;

    // Default services are invoked only if no package-specific services are
    // present for the type of AccessibilityEvent generated. This service is
    // app-specific, so the flag isn't necessary. For a general-purpose service,
    // consider setting the DEFAULT flag.

    // info.flags = AccessibilityServiceInfo.DEFAULT;

    info.notificationTimeout = 100;

    this.setServiceInfo(info);

}

Drugą opcją jest skonfigurowanie usługi za pomocą pliku XML. Tak opcje konfiguracji, takie jak canRetrieveWindowContent są dostępne tylko wtedy, gdy skonfigurujesz usługę przy użyciu kodu XML. Konfiguracja opcje z poprzedniego przykładu wyglądają następująco po zdefiniowaniu przy użyciu pliku XML:

<accessibility-service
     android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
     android:packageNames="com.example.android.myFirstApp, com.example.android.mySecondApp"
     android:accessibilityFeedbackType="feedbackSpoken"
     android:notificationTimeout="100"
     android:settingsActivity="com.example.android.apis.accessibility.TestBackActivity"
     android:canRetrieveWindowContent="true"
/>

Jeśli używasz formatu XML, odwołaj się do niego w pliku manifestu, dodając <meta-data> na deklaracji usługi wskazującą plik XML. Jeśli przechowujesz plik XML w res/xml/serviceconfig.xml, nowy tag wygląda tak:

<service android:name=".MyAccessibilityService">
     <intent-filter>
         <action android:name="android.accessibilityservice.AccessibilityService" />
     </intent-filter>
     <meta-data android:name="android.accessibilityservice"
     android:resource="@xml/serviceconfig" />
</service>

Metody usługi ułatwień dostępu

Usługa ułatwień dostępu musi stanowić rozszerzenie klasy AccessibilityService i zastąpić poniższe metody z tej klasy. Metody te są opisane w w kolejności ich wywoływania przez system Android: od momentu uruchomienia usługi (onServiceConnected()) na uruchomiony (onAccessibilityEvent(), onInterrupt()), na czas wyłączenia (onUnbind()).

  • onServiceConnected(): (opcjonalnie) system wywołuje tę metodę, gdy łączy się z usługą ułatwień dostępu. Użyj tej metody, aby przeprowadzić konfigurację jednorazową czynności związane z Twoją usługą, w tym łączenie się z systemem przesyłania opinii użytkowników takich jak menedżer dźwięku czy wibracja urządzenia. Jeśli chcesz ustawić konfigurowania usługi w czasie działania lub wprowadzania jednorazowych zmian, to dogodne miejsce, by zadzwonić pod numer setServiceInfo().

  • onAccessibilityEvent(): (wymagane) system wywołuje tę metodę, gdy: wykrywa AccessibilityEvent. zgodne z parametrami filtrowania zdarzeń określonymi w ustawieniach ułatwień dostępu. usługa, np. kliknięcie przycisku lub zaznaczenie przez użytkownika interfejsu element sterujący w aplikacji, dla której usługa ułatwień dostępu przekazuje opinię. Kiedy system wywołuje tę metodę, przekazuje powiązane AccessibilityEvent, które usługa może zinterpretować i wykorzystać w celu przekazywania użytkownika. Metodę tę można wywoływać wiele razy w cyklu życia posprzedażna.

  • onInterrupt(): (wymagane) system wywołuje tę metodę, gdy system. chce przerwać przesyłanie opinii przez Twoją usługę, zwykle w reakcja na działanie użytkownika, np. przeniesienie zaznaczenia na inny element sterujący. Ten może być wywoływana wiele razy w cyklu życia usługi.

  • onUnbind(): (opcjonalnie) system wywołuje tę metodę, gdy system jest wyłączyć usługę ułatwień dostępu. Użyj tej metody, aby: procedury jednorazowego wyłączania, w tym usunięcie przydziału systemu przesyłania opinii użytkowników. takich jak menedżer dźwięku czy wibracja urządzenia.

Te metody wywołania zwrotnego zapewniają podstawową strukturę ułatwień dostępu posprzedażna. Możesz zdecydować, jak przetwarzać dane dostarczone przez system Android na jako obiekty AccessibilityEvent i przekazywać użytkownikowi opinię. Dla: więcej informacji na temat uzyskiwania informacji ze zdarzeń związanych z ułatwieniami dostępu znajdziesz w artykule o uzyskiwaniu szczegóły wydarzenia.

Zarejestruj na potrzeby zdarzeń ułatwień dostępu

Jedna z najważniejszych funkcji konfiguracji usługi ułatwień dostępu pozwala określić, jakiego typu zdarzenia ułatwień dostępu mają być wykorzystywane który sobie radzi. Podanie tych informacji umożliwia współpracę usług ułatwień dostępu ze sobą nawzajem i daje elastyczność również w obsłudze tylko konkretnych wydarzeń typy z konkretnych aplikacji. Filtrowanie zdarzeń może obejmować następujące opcje: kryteria:

  • Nazwy pakietów: określ nazwy pakietów aplikacji, których ułatwienia dostępu mają miejsce. zdarzenia, które ma obsługiwać Twoja usługa. Jeśli pominiesz ten parametr, usługa ułatwień dostępu jest uznawana za dostępną dla ułatwień dostępu w usłudze zdarzeń w dowolnej aplikacji. Ten parametr można ustawić w usłudze ułatwień dostępu plików konfiguracji z atrybutem android:packageNames jako oddzieloną przecinkami albo AccessibilityServiceInfo.packageNames. użytkownika.

  • Typy zdarzeń: określ typy zdarzeń ułatwień dostępu, które chcesz uwzględnić. do obsługi reklam. Ten parametr można ustawić w usłudze ułatwień dostępu plików konfiguracji z atrybutem android:accessibilityEventTypes o wartości listę rozdzielaną znakiem |, na przykład accessibilityEventTypes="typeViewClicked|typeViewFocused" Możesz też ustawić za pomocą AccessibilityServiceInfo.eventTypes użytkownika.

Podczas konfigurowania usługi ułatwień dostępu zastanów się, jakie zdarzenia może obsługiwać i rejestrować tylko te zdarzenia. Ponieważ użytkownicy mogą aktywować więcej niż jedną usługę ułatwień dostępu jednocześnie, usługa nie może korzystać które nie są w stanie obsłużyć. Pamiętaj, że inne usługi mogą je obsługiwać zdarzeń, by zwiększyć wygodę użytkowników.

Głośność przy ułatwieniach dostępu

Urządzenia z Androidem 8.0 (poziom interfejsu API 26) lub nowszym zawierają STREAM_ACCESSIBILITY kategorię głośności, która pozwala kontrolować głośność ułatwień dostępu. na wyjściu audio usługi niezależnie od innych dźwięków urządzenia.

Usługi ułatwień dostępu mogą korzystać z tego typu strumienia, ustawiając FLAG_ENABLE_ACCESSIBILITY_VOLUME . Następnie możesz zmienić głośność dźwięku przy ułatwieniach dostępu na urządzeniu, dzwoniąc adjustStreamVolume() w instancji urządzenia AudioManager

Ten fragment kodu pokazuje, jak usługa ułatwień dostępu może korzystać z funkcji STREAM_ACCESSIBILITY kategoria woluminów:

Kotlin

import android.media.AudioManager.*

class MyAccessibilityService : AccessibilityService() {

    private val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager

    override fun onAccessibilityEvent(accessibilityEvent: AccessibilityEvent) {
        if (accessibilityEvent.source.text == "Increase volume") {
            audioManager.adjustStreamVolume(AudioManager.STREAM_ACCESSIBILITY, ADJUST_RAISE, 0)
        }
    }
}

Java

import static android.media.AudioManager.*;

public class MyAccessibilityService extends AccessibilityService {
    private AudioManager audioManager =
            (AudioManager) getSystemService(AUDIO_SERVICE);

    @Override
    public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
        AccessibilityNodeInfo interactedNodeInfo =
                accessibilityEvent.getSource();
        if (interactedNodeInfo.getText().equals("Increase volume")) {
            audioManager.adjustStreamVolume(AudioManager.STREAM_ACCESSIBILITY,
                ADJUST_RAISE, 0);
        }
    }
}

Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 6:35.

Skrót ułatwień dostępu

Na urządzeniach z Androidem 8.0 (poziom interfejsu API 26) lub nowszym użytkownicy mogą włączać wyłączyć preferowaną usługę ułatwień dostępu na dowolnym ekranie, naciskając przytrzymując jednocześnie oba przyciski głośności. Mimo że ten skrót umożliwia domyślnie wyłącza TalkBack, użytkownicy mogą skonfigurować przycisk w taki sposób, aby wyłączyć dowolną usługę zainstalowaną na urządzeniu.

Aby użytkownicy mieli dostęp do konkretnej usługi ułatwień dostępu z poziomu ułatwień dostępu usługa musi poprosić o dostęp do danej funkcji w czasie działania.

Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 13:25.

Przycisk ułatwień dostępu

Na urządzeniach korzystających z wyrenderowanego programowo obszaru nawigacji z Androidem 8.0 (poziom interfejsu API 26) lub wyższym po prawej stronie paska nawigacyjnego znajduje się przycisk ułatwień dostępu. Po naciśnięciu tego przycisku użytkownik może wywołać jedną z tych opcji: kilka włączonych funkcji i usług ułatwień dostępu, w zależności od treści widoczne na ekranie.

Aby umożliwić użytkownikom wywoływanie danej usługi ułatwień dostępu za pomocą ułatwień dostępu , usługa musi dodać atrybut FLAG_REQUEST_ACCESSIBILITY_BUTTON flaga w android:accessibilityFlags obiektu AccessibilityServiceInfo . Usługa może następnie rejestrować wywołania zwrotne za pomocą registerAccessibilityButtonCallback()

Fragment kodu poniżej pokazuje, jak skonfigurować ułatwienia dostępu reakcja użytkownika na naciśnięcie przycisku ułatwień dostępu:

Kotlin

private var mAccessibilityButtonController: AccessibilityButtonController? = null
private var accessibilityButtonCallback:
        AccessibilityButtonController.AccessibilityButtonCallback? = null
private var mIsAccessibilityButtonAvailable: Boolean = false

override fun onServiceConnected() {
    mAccessibilityButtonController = accessibilityButtonController
    mIsAccessibilityButtonAvailable =
            mAccessibilityButtonController?.isAccessibilityButtonAvailable ?: false

    if (!mIsAccessibilityButtonAvailable) return

    serviceInfo = serviceInfo.apply {
        flags = flags or AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON
    }

    accessibilityButtonCallback =
        object : AccessibilityButtonController.AccessibilityButtonCallback() {
            override fun onClicked(controller: AccessibilityButtonController) {
                Log.d("MY_APP_TAG", "Accessibility button pressed!")

                // Add custom logic for a service to react to the
                // accessibility button being pressed.
            }

            override fun onAvailabilityChanged(
                    controller: AccessibilityButtonController,
                    available: Boolean
            ) {
                if (controller == mAccessibilityButtonController) {
                    mIsAccessibilityButtonAvailable = available
                }
            }
    }

    accessibilityButtonCallback?.also {
        mAccessibilityButtonController?.registerAccessibilityButtonCallback(it, null)
    }
}

Java

private AccessibilityButtonController accessibilityButtonController;
private AccessibilityButtonController
        .AccessibilityButtonCallback accessibilityButtonCallback;
private boolean mIsAccessibilityButtonAvailable;

@Override
protected void onServiceConnected() {
    accessibilityButtonController = getAccessibilityButtonController();
    mIsAccessibilityButtonAvailable =
            accessibilityButtonController.isAccessibilityButtonAvailable();

    if (!mIsAccessibilityButtonAvailable) {
        return;
    }

    AccessibilityServiceInfo serviceInfo = getServiceInfo();
    serviceInfo.flags
            |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
    setServiceInfo(serviceInfo);

    accessibilityButtonCallback =
        new AccessibilityButtonController.AccessibilityButtonCallback() {
            @Override
            public void onClicked(AccessibilityButtonController controller) {
                Log.d("MY_APP_TAG", "Accessibility button pressed!");

                // Add custom logic for a service to react to the
                // accessibility button being pressed.
            }

            @Override
            public void onAvailabilityChanged(
              AccessibilityButtonController controller, boolean available) {
                if (controller.equals(accessibilityButtonController)) {
                    mIsAccessibilityButtonAvailable = available;
                }
            }
        };

    if (accessibilityButtonCallback != null) {
        accessibilityButtonController.registerAccessibilityButtonCallback(
                accessibilityButtonCallback, null);
    }
}

Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 16:28.

Gesty związane z odciskiem palca

usługi ułatwień dostępu na urządzeniach z Androidem 8.0 (poziom interfejsu API 26) lub nowszym; może reagować na przesunięcia kierunkowe (w górę, w dół, w lewo i w prawo) po ekranie urządzenia czytnik linii papilarnych. Aby skonfigurować usługę do otrzymywania wywołań zwrotnych na ich temat: należy wykonać następującą sekwencję:

  1. Zadeklaruj USE_BIOMETRIC uprawnienia i CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES działania.
  2. Ustawianie FLAG_REQUEST_FINGERPRINT_GESTURES flagę w atrybucie android:accessibilityFlags.
  3. Zarejestruj się na wywołania zwrotne za pomocą registerFingerprintGestureCallback().
.

Pamiętaj, że nie wszystkie urządzenia mają czujniki linii papilarnych. Aby zidentyfikować czy urządzenie obsługuje czujnik, użyj funkcji isHardwareDetected() . Nawet na urządzeniu wyposażonym w czytnik linii papilarnych usługa nie może korzystać z czujnika, gdy jest on używany do uwierzytelniania. Aby określić, kiedy czujnik jest dostępny, wywołaj funkcję isGestureDetectionAvailable() i zaimplementuj funkcję onGestureDetectionAvailabilityChanged() oddzwanianie.

Ten fragment kodu pokazuje przykład użycia gestów odcisku palca do: poruszać się po wirtualnej planszy:

// AndroidManifest.xml
<manifest ... >
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
    ...
    <application>
        <service android:name="com.example.MyFingerprintGestureService" ... >
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/myfingerprintgestureservice" />
        </service>
    </application>
</manifest>
// myfingerprintgestureservice.xml
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:accessibilityFlags=" ... |flagRequestFingerprintGestures"
    android:canRequestFingerprintGestures="true"
    ... />

Kotlin

// MyFingerprintGestureService.kt
import android.accessibilityservice.FingerprintGestureController.*

class MyFingerprintGestureService : AccessibilityService() {

    private var gestureController: FingerprintGestureController? = null
    private var fingerprintGestureCallback:
            FingerprintGestureController.FingerprintGestureCallback? = null
    private var mIsGestureDetectionAvailable: Boolean = false

    override fun onCreate() {
        gestureController = fingerprintGestureController
        mIsGestureDetectionAvailable = gestureController?.isGestureDetectionAvailable ?: false
    }

    override fun onServiceConnected() {
        if (mFingerprintGestureCallback != null || !mIsGestureDetectionAvailable) return

        fingerprintGestureCallback =
                object : FingerprintGestureController.FingerprintGestureCallback() {
                    override fun onGestureDetected(gesture: Int) {
                        when (gesture) {
                            FINGERPRINT_GESTURE_SWIPE_DOWN -> moveGameCursorDown()
                            FINGERPRINT_GESTURE_SWIPE_LEFT -> moveGameCursorLeft()
                            FINGERPRINT_GESTURE_SWIPE_RIGHT -> moveGameCursorRight()
                            FINGERPRINT_GESTURE_SWIPE_UP -> moveGameCursorUp()
                            else -> Log.e(MY_APP_TAG, "Error: Unknown gesture type detected!")
                        }
                    }

                    override fun onGestureDetectionAvailabilityChanged(available: Boolean) {
                        mIsGestureDetectionAvailable = available
                    }
                }

        fingerprintGestureCallback?.also {
            gestureController?.registerFingerprintGestureCallback(it, null)
        }
    }
}

Java

// MyFingerprintGestureService.java
import static android.accessibilityservice.FingerprintGestureController.*;

public class MyFingerprintGestureService extends AccessibilityService {
    private FingerprintGestureController gestureController;
    private FingerprintGestureController
            .FingerprintGestureCallback fingerprintGestureCallback;
    private boolean mIsGestureDetectionAvailable;

    @Override
    public void onCreate() {
        gestureController = getFingerprintGestureController();
        mIsGestureDetectionAvailable =
                gestureController.isGestureDetectionAvailable();
    }

    @Override
    protected void onServiceConnected() {
        if (fingerprintGestureCallback != null
                || !mIsGestureDetectionAvailable) {
            return;
        }

        fingerprintGestureCallback =
               new FingerprintGestureController.FingerprintGestureCallback() {
            @Override
            public void onGestureDetected(int gesture) {
                switch (gesture) {
                    case FINGERPRINT_GESTURE_SWIPE_DOWN:
                        moveGameCursorDown();
                        break;
                    case FINGERPRINT_GESTURE_SWIPE_LEFT:
                        moveGameCursorLeft();
                        break;
                    case FINGERPRINT_GESTURE_SWIPE_RIGHT:
                        moveGameCursorRight();
                        break;
                    case FINGERPRINT_GESTURE_SWIPE_UP:
                        moveGameCursorUp();
                        break;
                    default:
                        Log.e(MY_APP_TAG,
                                  "Error: Unknown gesture type detected!");
                        break;
                }
            }

            @Override
            public void onGestureDetectionAvailabilityChanged(boolean available) {
                mIsGestureDetectionAvailable = available;
            }
        };

        if (fingerprintGestureCallback != null) {
            gestureController.registerFingerprintGestureCallback(
                    fingerprintGestureCallback, null);
        }
    }
}

Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 9:03.

Zamiana tekstu na mowę w wielu językach

Usługa zamiany tekstu na mowę (TTS) w Androidzie 8.0 (poziom interfejsu API 26) rozpoznawać i mówić wyrażenia w wielu językach w jednym bloku tekstu. Aby włączyć tę funkcję automatycznego przełączania języka w ułatwieniach dostępu , umieść wszystkie ciągi w LocaleSpan obiektów widocznych na ilustracji w tym fragmencie kodu:

Kotlin

val localeWrappedTextView = findViewById<TextView>(R.id.my_french_greeting_text).apply {
    text = wrapTextInLocaleSpan("Bonjour!", Locale.FRANCE)
}

private fun wrapTextInLocaleSpan(originalText: CharSequence, loc: Locale): SpannableStringBuilder {
    return SpannableStringBuilder(originalText).apply {
        setSpan(LocaleSpan(loc), 0, originalText.length - 1, 0)
    }
}

Java

TextView localeWrappedTextView = findViewById(R.id.my_french_greeting_text);
localeWrappedTextView.setText(wrapTextInLocaleSpan("Bonjour!", Locale.FRANCE));

private SpannableStringBuilder wrapTextInLocaleSpan(
        CharSequence originalText, Locale loc) {
    SpannableStringBuilder myLocaleBuilder =
            new SpannableStringBuilder(originalText);
    myLocaleBuilder.setSpan(new LocaleSpan(loc), 0,
            originalText.length() - 1, 0);
    return myLocaleBuilder;
}

Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 10:59.

Działanie w imieniu użytkowników

Od 2011 roku usługi ułatwień dostępu mogą działać w imieniu użytkowników, w tym zmienianie fokusu wprowadzania i wybieranie (aktywowanie) elementów interfejsu użytkownika. W W 2012 r. rozszerzyliśmy zakres działań o listy przewijane i interakcje z polami tekstowymi. Usługi ułatwień dostępu mogą też wykonywać działania globalne, na przykład: przejdź do ekranu głównego, naciśnij przycisk Wstecz i otwórz ekranu powiadomień i listy ostatnio używanych aplikacji. Od 2012 roku Android obejmuje ułatwienia dostępu, dzięki któremu wszystkie widoczne elementy można zaznaczyć w usłudze ułatwień dostępu.

Te możliwości pozwalają programistom usług ułatwień dostępu tworzyć alternatywne rozwiązania, w trybach nawigacji, takich jak nawigacja przy użyciu gestów, oraz dla użytkowników z niepełnosprawnościami. lepsze sterowanie urządzeniami z Androidem.

Nasłuchuj gestów

Usługi ułatwień dostępu mogą nasłuchiwać określonych gestów i reagować na nie użytkownika. Ta funkcja wymaga wysłania żądania o usługę ułatwień dostępu. aktywować funkcję Czytania dotykiem. Twoja usługa może o to poprosić aktywacji przez ustawienie flags należąca do instancji AccessibilityServiceInfo usługi, FLAG_REQUEST_TOUCH_EXPLORATION_MODE, jak w poniższym przykładzie.

Kotlin

class MyAccessibilityService : AccessibilityService() {

    override fun onCreate() {
        serviceInfo.flags = AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE
    }
    ...
}

Java

public class MyAccessibilityService extends AccessibilityService {
    @Override
    public void onCreate() {
        getServiceInfo().flags = AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
    }
    ...
}

Gdy Twoja usługa poprosi o aktywację Czytania dotykiem, użytkownik musi wyrazić zgodę funkcja musi być włączona, jeśli nie jest jeszcze aktywna. Gdy ta funkcja jest będzie aktywna, Twoja usługa będzie otrzymywać powiadomienia o gestach ułatwień dostępu przez Twojej usługi onGesture() wywołanie zwrotne i może odpowiedzieć, działając w imieniu użytkownika.

Ciągłe gesty

Urządzenia z Androidem 8.0 (poziom interfejsu API 26) obsługują ciągłe gesty lub automatyczne gesty zawierające więcej niż jeden Path.

Przy określaniu sekwencji kresek możesz określić, że należą one do ten sam gest zautomatyzowany przy użyciu ostatniego argumentu willContinue w GestureDescription.StrokeDescription. jak w tym fragmencie kodu:

Kotlin

// Simulates an L-shaped drag path: 200 pixels right, then 200 pixels down.
private fun doRightThenDownDrag() {
    val dragRightPath = Path().apply {
        moveTo(200f, 200f)
        lineTo(400f, 200f)
    }
    val dragRightDuration = 500L // 0.5 second

    // The starting point of the second path must match
    // the ending point of the first path.
    val dragDownPath = Path().apply {
        moveTo(400f, 200f)
        lineTo(400f, 400f)
    }
    val dragDownDuration = 500L
    val rightThenDownDrag = GestureDescription.StrokeDescription(
            dragRightPath,
            0L,
            dragRightDuration,
            true
    ).apply {
        continueStroke(dragDownPath, dragRightDuration, dragDownDuration, false)
    }
}

Java

// Simulates an L-shaped drag path: 200 pixels right, then 200 pixels down.
private void doRightThenDownDrag() {
    Path dragRightPath = new Path();
    dragRightPath.moveTo(200, 200);
    dragRightPath.lineTo(400, 200);
    long dragRightDuration = 500L; // 0.5 second

    // The starting point of the second path must match
    // the ending point of the first path.
    Path dragDownPath = new Path();
    dragDownPath.moveTo(400, 200);
    dragDownPath.lineTo(400, 400);
    long dragDownDuration = 500L;
    GestureDescription.StrokeDescription rightThenDownDrag =
            new GestureDescription.StrokeDescription(dragRightPath, 0L,
            dragRightDuration, true);
    rightThenDownDrag.continueStroke(dragDownPath, dragRightDuration,
            dragDownDuration, false);
}

Więcej informacji znajdziesz w filmie z sesji Co nowego w ułatwieniach dostępu w Androidzie przygotowanym przez Google I/O 2017. Zaczynamy od 15:47.

Korzystanie z ułatwień dostępu

Usługi ułatwień dostępu mogą działać w imieniu użytkowników, aby uprościć interakcje z aplikacji i pracować wydajniej. Możliwości ułatwień dostępu Funkcja wykonywania działań została dodana w 2011 r., a w 2012 – znacznie rozszerzona.

Aby można było działać w imieniu użytkowników, usługa ułatwień dostępu musi się zarejestrować. na otrzymywanie zdarzeń z aplikacji i wysyłanie próśb o zgodę na wyświetlanie treści aplikacji przez ustawienie android:canRetrieveWindowContent na true w plik konfiguracji usługi. Po odebraniu zdarzeń przez może następnie pobrać AccessibilityNodeInfo ze zdarzenia za pomocą funkcji getSource() Dzięki obiektowi AccessibilityNodeInfo usługa może badać widok. w hierarchii użytkowników, aby określić, jakie działania należy podjąć, performAction()

Kotlin

class MyAccessibilityService : AccessibilityService() {

    override fun onAccessibilityEvent(event: AccessibilityEvent) {
        // Get the source node of the event.
        event.source?.apply {

            // Use the event and node information to determine what action to
            // take.

            // Act on behalf of the user.
            performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)

            // Recycle the nodeInfo object.
            recycle()
        }
    }
    ...
}

Java

public class MyAccessibilityService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        // Get the source node of the event.
        AccessibilityNodeInfo nodeInfo = event.getSource();

        // Use the event and node information to determine what action to take.

        // Act on behalf of the user.
        nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);

        // Recycle the nodeInfo object.
        nodeInfo.recycle();
    }
    ...
}

Metoda performAction() umożliwia usłudze podjęcie działania w obrębie . Jeśli usługa musi wykonać działanie globalne, takie jak przejście do ekranu głównego, kliknięcie przycisku Wstecz lub otwarcie ekranu powiadomień lub listy ostatnio używanych aplikacji, a następnie użyj performGlobalAction(). .

Użyj typów skupienia

W 2012 roku w interfejsie Androida pojawiła się nowa funkcja: accessibility. Usługi ułatwień dostępu mogą użyć tego fokusu, aby wybrać dowolny widoczny interfejs użytkownika i wykonać na nim działania. Ten typ zaznaczenia różni się od fokusu wejściowego, który określa, który element interfejsu na ekranie otrzymuje dane wejściowe, gdy użytkownik wpisze znaki, naciśnij Enter na klawiaturze lub naciśnij środek przycisku na padzie kierunkowym.

Może się zdarzyć, że jeden element interfejsu użytkownika będzie zaznaczony podczas Inny element koncentruje się na ułatwieniach dostępu. Głównym celem korzystania z ułatwień dostępu aby zapewnić usługom ułatwień dostępu metodę interakcji z widocznymi elementów na ekranie niezależnie od tego, czy można ich aktywować w z perspektywy systemu. Aby zapewnić współdziałanie usługi ułatwień dostępu z aplikacjami elementów wejściowych, postępuj zgodnie z wytycznymi dotyczącymi testowania ułatwień dostępu, aby przetestować usługę podczas używania typowej aplikacji.

Usługa ułatwień dostępu może określić, który element interfejsu użytkownika ma dane wejściowe lub ułatwienia dostępu za pomocą AccessibilityNodeInfo.findFocus() . Możesz też wyszukiwać elementy, które można wybierać za pomocą wprowadzania za pomocą focusSearch() . Usługa ułatwień dostępu może też ustawić fokus przy użyciu performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS) .

Zbieranie informacji

Usługi ułatwień dostępu korzystają ze standardowych metod gromadzenia i reprezentowania jednostki informacji przekazywanych przez użytkowników, takie jak szczegóły wydarzeń, tekst i liczby.

Pobieranie szczegółów zmiany okna

Android 9 (poziom interfejsu API 28) i nowsze umożliwiają aplikacjom śledzenie aktualizacji okien, gdy aplikacja pobiera ponownie wiele okien jednocześnie. Gdy TYPE_WINDOWS_CHANGED zachodzi zdarzenie, użyj funkcji getWindowChanges() API do określania, jak zmieniają się okna. Podczas aktualizacji w trybie wielu okien każda generuje własny zestaw zdarzeń. Metoda getSource() zwraca pierwiastek w widoku okien powiązanych z poszczególnymi zdarzeniami.

Jeśli aplikacja określa okienko ułatwień dostępu View, usługa może rozpoznać, kiedy interfejs aplikacji zostanie zaktualizowany. Gdy TYPE_WINDOW_STATE_CHANGED użyj typów zwróconych przez getContentChangeTypes() aby określić, jak zmienia się okno. Platforma może na przykład wykryć, kiedy panel ma nowy tytuł lub zniknie.

Pobieranie szczegółów wydarzenia

Android dostarcza usługom ułatwień dostępu informacje o interfejsie użytkownika interakcji za pomocą AccessibilityEvent obiektów. W poprzednich wersjach Androida informacji dostępnych w przypadku ułatwień dostępu, a jednocześnie zapewnić szczegóły na temat ustawień interfejsu wybranych przez użytkowników, dostępne z ograniczeniami informacji kontekstowych. W wielu przypadkach brak informacji kontekstowych jest kluczowe dla zrozumienia znaczenia wybranego elementu sterującego.

Przykładem interfejsu, w którym kontekst ma kluczowe znaczenie, to kalendarz lub dzień w kalendarzu. Jeśli użytkownik wybierze przedział czasu o godzinie 16:00 na liście dni od poniedziałku do piątku a usługa ułatwień dostępu informuje o godzinie 16:00, ale nie ogłasza dnia tygodnia. „name”, „dzień miesiąca” lub „nazwa miesiąca” – otrzymana opinia będzie miała postać są niejasne. W takim przypadku kontekst elementu sterującego interfejsu użytkownika ma kluczowe znaczenie użytkownika, który chce zaplanować spotkanie.

Od 2011 roku Android znacznie rozszerza ilość informacji przekazywanych usługa ułatwień dostępu może uzyskać informacje o interakcji z interfejsem użytkownika zdarzeń związanych z ułatwieniami dostępu na podstawie hierarchii widoków. Hierarchia widoków to zbiór Komponenty interfejsu, które zawierają komponent (jego elementy nadrzędne) i użytkownika elementów interfejsu, które mogą zawierać ten komponent (jego elementy podrzędne). W Dzięki temu Android może dostarczyć więcej informacji o zdarzeniach związanych z ułatwieniami dostępu, usługi ułatwień dostępu zapewniają użytkownikom bardziej przydatne informacje zwrotne.

Usługa ułatwień dostępu pobiera informacje o zdarzeniach w interfejsie przez: obiekt AccessibilityEvent przekazany przez system do usługi Metoda wywołania zwrotnego onAccessibilityEvent(). Ten obiekt dostarcza szczegółowe informacje o rodzaj zdarzenia, w tym typ obiektu, którego dotyczy działanie, jego opis inne szczegóły.

  • AccessibilityEvent.getRecordCount() oraz getRecord(int): które pozwalają pobrać zestaw AccessibilityRecord obiekty należące do kategorii AccessibilityEvent przekazane Ci przez systemu. Ten poziom szczegółowości zapewnia więcej kontekstu dla zdarzenia, które uruchamia usługę ułatwień dostępu.

  • AccessibilityRecord.getSource(): ta metoda zwraca obiekt AccessibilityNodeInfo. Ten obiekt umożliwia: zażądać hierarchii układu widoku (elementy nadrzędne i podrzędne) komponentu, który jest początkiem zdarzenia ułatwień dostępu. Dzięki tej funkcji ułatwienia dostępu badanie całego kontekstu zdarzenia, w tym treści żadnych połączonych widoków lub widoków podrzędnych.

.

Platforma Androida umożliwia AccessibilityService wykonywanie zapytań hierarchię widoków, zbierając informacje o komponencie UI, który generuje wydarzenia, a także jego elementu nadrzędnego i elementu podrzędnego. W tym celu ustaw następujący wiersz: w konfiguracji XML:

android:canRetrieveWindowContent="true"

Potem pobierz obiekt AccessibilityNodeInfo za pomocą getSource(). To wywołanie zwraca obiekt tylko wtedy, gdy okno, w którym zainicjowano zdarzenie, to aktywne okno. Jeśli nie, zwraca wartość null, więc musisz się zachować.

W tym przykładzie po otrzymaniu zdarzenia kod wykonuje takie działania:

  1. Natychmiast pobiera element nadrzędny widoku, w którym zaczyna się zdarzenie.
  2. W tym widoku szuka etykiety i pola wyboru w widoku treści podrzędnych.
  3. Jeśli je znajdzie, tworzy ciąg znaków do zgłoszenia użytkownikowi, który wskazuje i informacje o tym, czy została zaznaczona.

Jeśli w którymkolwiek momencie podczas przemierzania hierarchii widoku zostanie zwrócona wartość null, metody dyskretnie poddaje się.

Kotlin

// Alternative onAccessibilityEvent that uses AccessibilityNodeInfo.

override fun onAccessibilityEvent(event: AccessibilityEvent) {

    val source: AccessibilityNodeInfo = event.source ?: return

    // Grab the parent of the view that fires the event.
    val rowNode: AccessibilityNodeInfo = getListItemNodeInfo(source) ?: return

    // Using this parent, get references to both child nodes, the label, and the
    // checkbox.
    val taskLabel: CharSequence = rowNode.getChild(0)?.text ?: run {
        rowNode.recycle()
        return
    }

    val isComplete: Boolean = rowNode.getChild(1)?.isChecked ?: run {
        rowNode.recycle()
        return
    }

    // Determine what the task is and whether it's complete based on the text
    // inside the label, and the state of the checkbox.
    if (rowNode.childCount < 2 || !rowNode.getChild(1).isCheckable) {
        rowNode.recycle()
        return
    }

    val completeStr: String = if (isComplete) {
        getString(R.string.checked)
    } else {
        getString(R.string.not_checked)
    }
    val reportStr = "$taskLabel$completeStr"
    speakToUser(reportStr)
}

Java

// Alternative onAccessibilityEvent that uses AccessibilityNodeInfo.

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {

    AccessibilityNodeInfo source = event.getSource();
    if (source == null) {
        return;
    }

    // Grab the parent of the view that fires the event.
    AccessibilityNodeInfo rowNode = getListItemNodeInfo(source);
    if (rowNode == null) {
        return;
    }

    // Using this parent, get references to both child nodes, the label, and the
    // checkbox.
    AccessibilityNodeInfo labelNode = rowNode.getChild(0);
    if (labelNode == null) {
        rowNode.recycle();
        return;
    }

    AccessibilityNodeInfo completeNode = rowNode.getChild(1);
    if (completeNode == null) {
        rowNode.recycle();
        return;
    }

    // Determine what the task is and whether it's complete based on the text
    // inside the label, and the state of the checkbox.
    if (rowNode.getChildCount() < 2 || !rowNode.getChild(1).isCheckable()) {
        rowNode.recycle();
        return;
    }

    CharSequence taskLabel = labelNode.getText();
    final boolean isComplete = completeNode.isChecked();
    String completeStr = null;

    if (isComplete) {
        completeStr = getString(R.string.checked);
    } else {
        completeStr = getString(R.string.not_checked);
    }
    String reportStr = taskLabel + completeStr;
    speakToUser(reportStr);
}

Dzięki temu zyskujesz kompletną, działającą usługę ułatwień dostępu. Spróbuj skonfigurować sposób Wchodzi w interakcje z użytkownikiem za pomocą funkcji zamiana tekstu na mowę Androida wyszukiwarka lub za pomocą Vibrator w celu wywołania reakcji haptycznej opinie.

Przetwórz tekst

Urządzenia z Androidem 8.0 (poziom interfejsu API 26) lub nowszym obejmują kilka funkcji przetwarzania tekstu, które ułatwiają usługom ułatwień dostępu identyfikować określone jednostki tekstu pojawiającego się na ekranie i wykonywać związane z nimi działania.

Etykietki

Android 9 (poziom interfejsu API 28) wprowadza kilka funkcji, które dają dostęp do etykietek w interfejsie aplikacji. Używaj getTooltipText() aby odczytać tekst etykietki, i użyj ACTION_SHOW_TOOLTIP oraz ACTION_HIDE_TOOLTIP aby instruować instancje View, że mają wyświetlać lub ukrywać ich etykietki.

Tekst podpowiedzi

Od 2017 roku Android udostępnia kilka metod interakcji z tekst podpowiedzi obiektu tekstowego:

  • isShowingHintText() oraz setShowingHintText() wskazują i ustawiają, czy bieżący tekst węzła to tekst podpowiedzi węzła.
  • getHintText() zapewnia dostęp do samego tekstu podpowiedzi. Nawet jeśli obiekt się nie wyświetla tekstu podpowiedzi, wywołanie getHintText() powiodło się.

Lokalizacje znaków tekstu na ekranie

Na urządzeniach z Androidem 8.0 (poziom interfejsu API 26) lub nowszym usługi ułatwień dostępu może określić współrzędne ekranu dla ramki ograniczającej każdej widocznej postaci w widżecie TextView. Usługi można podać te współrzędne, dzwoniąc refreshWithExtraData() zaliczanie EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY jako pierwszy argument i obiekt Bundle jako drugiego argumentu. W miarę działania metody system wypełnia pole Bundle argument z tablicą o wartości umożliwiającej parowanie Rect obiektów. Każdy obiekt Rect reprezentuje ramkę ograniczającą konkretnego znaku.

Ujednolicone jednostronne wartości zakresu

Niektóre obiekty AccessibilityNodeInfo korzystają z instancji AccessibilityNodeInfo.RangeInfo. wskazuje, że element interfejsu może przyjmować różne wartości. Podczas tworzenia zakresu za pomocą RangeInfo.obtain() lub podczas pobierania skrajnych wartości zakresu za pomocą funkcji getMin() oraz getMax(), pamiętaj, że urządzenia z Androidem 8.0 (poziom interfejsu API 26) lub nowszym zakresy jednostronne w ustandaryzowany sposób:

Odpowiadanie na zdarzenia związane z ułatwieniami dostępu

Skoro usługa jest skonfigurowana do uruchamiania i nasłuchiwania zdarzeń, napisz kod wie, co zrobić, gdy nadejdzie AccessibilityEvent. Zacznij od zastąpienia onAccessibilityEvent(AccessibilityEvent) . W tej metodzie użyj parametru getEventType() aby określić rodzaj zdarzenia getContentDescription() aby wyodrębnić tekst etykiety powiązany z widokiem, który uruchamia zdarzenie:

Kotlin

override fun onAccessibilityEvent(event: AccessibilityEvent) {
    var eventText: String = when (event.eventType) {
        AccessibilityEvent.TYPE_VIEW_CLICKED -> "Clicked: "
        AccessibilityEvent.TYPE_VIEW_FOCUSED -> "Focused: "
        else -> ""
    }

    eventText += event.contentDescription

    // Do something nifty with this text, like speak the composed string back to
    // the user.
    speakToUser(eventText)
    ...
}

Java

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    final int eventType = event.getEventType();
    String eventText = null;
    switch(eventType) {
        case AccessibilityEvent.TYPE_VIEW_CLICKED:
            eventText = "Clicked: ";
            break;
        case AccessibilityEvent.TYPE_VIEW_FOCUSED:
            eventText = "Focused: ";
            break;
    }

    eventText = eventText + event.getContentDescription();

    // Do something nifty with this text, like speak the composed string back to
    // the user.
    speakToUser(eventText);
    ...
}

Dodatkowe materiały

Więcej informacji znajdziesz w tych materiałach:

Przewodniki

Ćwiczenia z programowania