Tworzenie usługi ułatwień dostępu na Androida

1. Wprowadzenie

Usługi ułatwień dostępu to funkcja platformy Android, która ma na celu przekazywanie użytkownikowi alternatywnych informacji o nawigacji w imieniu aplikacji zainstalowanych na urządzeniach z Androidem. Usługa ułatwień dostępu może komunikować się z użytkownikiem w imieniu aplikacji, np. zamieniać tekst na mowę lub przekazywać reakcję haptyczną, gdy użytkownik najedzie kursorem na ważny obszar ekranu. Z tego ćwiczenia dowiesz się, jak utworzyć bardzo prostą usługę ułatwień dostępu.

Co to jest usługa ułatwień dostępu?

Usługa ułatwień dostępu pomaga osobom z niepełnosprawnościami w korzystaniu z urządzeń i aplikacji na Androida. Jest to długotrwała usługa z uprawnieniami, która pomaga użytkownikom przetwarzać informacje na ekranie i umożliwia im interakcję z urządzeniem.

Przykłady typowych usług ułatwień dostępu

  • Switch Access: umożliwia użytkownikom Androida z ograniczoną sprawnością ruchową sterowanie urządzeniami za pomocą co najmniej jednego przełącznika.
  • Voice Access (beta): umożliwia użytkownikom Androida z ograniczeniami ruchowymi sterowanie urządzeniem za pomocą poleceń głosowych.
  • TalkBack: czytnik ekranu powszechnie używany przez osoby niewidome lub osoby z wadą wzroku.

Tworzenie usługi ułatwień dostępu

Google udostępnia użytkownikom Androida usługi takie jak Switch Access, Voice Access i TalkBack, ale nie są one w stanie zaspokoić potrzeb wszystkich użytkowników z niepełnosprawnościami. Wielu użytkowników z niepełnosprawnościami ma wyjątkowe potrzeby, dlatego interfejsy API Androida do tworzenia usług ułatwień dostępu są otwarte, a deweloperzy mogą tworzyć takie usługi i dystrybuować je w Sklepie Play.

Co utworzysz

W tym ćwiczeniu z programowania utworzysz prostą usługę, która za pomocą interfejsu Accessibility API wykonuje kilka przydatnych czynności. Jeśli potrafisz napisać podstawową aplikację na Androida, możesz opracować podobną usługę.

Interfejs Accessibility API jest bardzo wydajny: kod usługi, którą utworzysz, znajduje się tylko w 4 plikach i zawiera około 200 wierszy kodu.

Użytkownik

Utworzysz usługę dla hipotetycznego użytkownika o tych cechach:

  • Użytkownik ma trudności z sięgnięciem do przycisków bocznych na urządzeniu.
  • Użytkownik ma trudności z przewijaniem lub przesuwaniem.

Szczegóły usługi

Usługa nałoży na ekran globalny pasek działań. Użytkownik może dotknąć przycisków na tym pasku, aby wykonać te czynności:

  1. Wyłącz urządzenie bez naciskania przycisku zasilania z boku telefonu.
  2. Dostosuj głośność bez dotykania przycisków głośności z boku telefonu.
  3. wykonywać czynności przewijania bez faktycznego przewijania;
  4. Wykonaj przesunięcie bez użycia gestu przesuwania.

Czego potrzebujesz

W tym ćwiczeniu założono, że będziesz używać tych narzędzi:

  1. Komputer z Android Studio.
  2. Terminal do wykonywania prostych poleceń powłoki.
  3. Urządzenie z Androidem 7.0 (Nougat) połączone z komputerem, na którym będziesz tworzyć aplikacje.

Zaczynajmy!

2. Przygotowania

Za pomocą terminala utwórz katalog, w którym będziesz pracować. Przejdź do tego katalogu.

Pobieranie kodu

Możesz sklonować repozytorium zawierające kod tego ćwiczenia:

git clone https://github.com/android/codelab-android-accessibility.git

Repozytorium zawiera kilka projektów Android Studio. W Android Studio otwórz GlobalActionBarService.

Uruchom Androida Studio, klikając ikonę Studio:

Logo używane do uruchamiania Androida Studio.

Wybierz opcję Import project (Eclipse ADT, Gradle, etc.) (Importuj projekt (Eclipse ADT, Gradle itp.)):

Ekran powitalny Androida Studio.

Przejdź do lokalizacji, w której sklonowano źródło, i wybierz GlobalActionBarService.

Następnie w terminalu przejdź do katalogu głównego.

3. Omówienie kodu początkowego

Przejrzyj otwarty projekt.

Szkielet usługi ułatwień dostępu został już utworzony. Cały kod, który napiszesz w tym ćwiczeniu, będzie ograniczony do tych 4 plików:

  1. app/src/main/AndroidManifest.xml
  2. app/src/main/res/layout/action_bar.xml
  3. app/src/main/res/xml/global_action_bar_service.xml
  4. app/src/main/java/com/example/android/globalactionbarservice/GlobalActionBarService.java

Poniżej znajdziesz opis zawartości każdego pliku.

AndroidManifest.xml

Informacje o usłudze ułatwień dostępu są zadeklarowane w pliku manifestu:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.android.globalactionbarservice">

   <application>
       <service
           android:name=".GlobalActionBarService"
           android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
           android:exported="true">
           <intent-filter>
               <action android:name="android.accessibilityservice.AccessibilityService" />
           </intent-filter>
           <meta-data
               android:name="android.accessibilityservice"
               android:resource="@xml/global_action_bar_service" />
       </service>
   </application>
</manifest>

W pliku AndroidManifest.xml zadeklarowano te 3 wymagane elementy:

  1. Uprawnienie do tworzenia powiązania z usługą ułatwień dostępu:
<service
    ...
    android:permission = "android.permission.BIND_ACCESSIBILITY_SERVICE">
    ...             
</service>
  1. Intencja AccessibilityService:
<intent-filter>
   <action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
  1. Lokalizacja pliku zawierającego metadane usługi, którą tworzysz:
<meta-data
       ...
       android:resource="@xml/global_action_bar_service" />
</service>

global_action_bar_service.xml

Ten plik zawiera metadane usługi.

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
   android:accessibilityFeedbackType="feedbackGeneric"
   android:accessibilityFlags="flagDefault"
   android:canPerformGestures="true"
   android:canRetrieveWindowContent="true" />

Za pomocą elementu <accessibility-service> zdefiniowano te metadane:

  1. Typ opinii dla tej usługi (w tym ćwiczeniu z programowania używamy typu feedbackGeneric, który jest dobrym domyślnym typem opinii).
  2. Flagi ułatwień dostępu dla usługi (w tym ćwiczeniu używane są flagi domyślne).
  3. Funkcje wymagane do korzystania z usługi:
  4. Aby można było przesuwać palcem, wartość atrybutu android:canPerformGestures musi być ustawiona na true.
  5. Aby pobrać zawartość okna, atrybut android:canRetrieveWindowContent musi mieć wartość true.

GlobalActionBarService.java

Większość kodu usługi ułatwień dostępu znajduje się w pliku GlobalActionBarService.java. Początkowo plik zawiera absolutne minimum kodu usługi ułatwień dostępu:

  1. Klasa, która rozszerza AccessibilityService.
  2. Kilka wymaganych zastąpionych metod (w tym ćwiczeniu są one puste).
public class GlobalActionBarService extends AccessibilityService {

   @Override
   public void onAccessibilityEvent(AccessibilityEvent event) {

   }

   @Override
   public void onInterrupt() {

   }
}

Podczas ćwiczenia dodasz do tego pliku kod.

action_bar.xml

Usługa udostępnia interfejs z 4 przyciskami, a plik układu action_bar.xml zawiera kod do wyświetlania tych przycisków:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="horizontal"
   android:layout_width="match_parent"
   android:layout_height="wrap_content">
</LinearLayout>

Ten plik zawiera obecnie pusty element LinearLayout. Podczas szkolenia dodasz znaczniki do przycisków.

Uruchamianie aplikacji

Sprawdź, czy urządzenie jest podłączone do komputera. Naciśnij zieloną ikonę Odtwórz Przycisk odtwarzania w Androidzie Studio służący do uruchamiania usługi na pasku menu u góry ekranu. Spowoduje to uruchomienie aplikacji, nad którą pracujesz.

Wybierz Ustawienia > Ułatwienia dostępu. Na urządzeniu jest zainstalowana usługa Global Action Bar Service.

Ekran ustawień ułatwień dostępu

Kliknij Global Action Bar Service i włącz tę usługę. Powinno pojawić się to okno z prośbą o przyznanie uprawnień:

Okno z prośbą o uprawnienia do usług ułatwień dostępu.

Usługa ułatwień dostępu prosi o uprawnienia do obserwowania działań użytkownika, pobierania zawartości okna i wykonywania gestów w jego imieniu. Jeśli korzystasz z usługi ułatwień dostępu innej firmy, upewnij się, że źródło jest godne zaufania.

Uruchomienie usługi nie przynosi większych efektów, ponieważ nie dodaliśmy jeszcze żadnych funkcji. Zacznijmy to robić.

4. Tworzenie przycisków

Otwórz plik action_bar.xml w folderze res/layout. Dodaj kod w pustym elemencie LinearLayout:

<LinearLayout ...>
    <Button
        android:id="@+id/power"
        android:text="@string/power"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/volume_up"
        android:text="@string/volume"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/scroll"
        android:text="@string/scroll"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/swipe"
        android:text="@string/swipe"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

Tworzy to przyciski, które użytkownik będzie naciskać, aby wywoływać działania na urządzeniu.

Otwórz plik GlobalActionBarService.java i dodaj zmienną do przechowywania układu paska działań:

public class GlobalActionBarService extends AccessibilityService {
    FrameLayout mLayout;
    ...
}

Teraz dodaj metodę onServiceStarted():

public class GlobalActionBarService extends AccessibilityService {
   FrameLayout mLayout;

   @Override
   protected void onServiceConnected() {
       // Create an overlay and display the action bar
       WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
       mLayout = new FrameLayout(this);
       WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
       lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
       lp.format = PixelFormat.TRANSLUCENT;
       lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
       lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
       lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
       lp.gravity = Gravity.TOP;
       LayoutInflater inflater = LayoutInflater.from(this);
       inflater.inflate(R.layout.action_bar, mLayout);
       wm.addView(mLayout, lp);
   }
}

Kod powiększa układ i dodaje pasek działań u góry ekranu.

Metoda onServiceConnected() jest uruchamiana po nawiązaniu połączenia z usługą. Usługa ułatwień dostępu ma obecnie wszystkie uprawnienia niezbędne do działania. Kluczowym uprawnieniem, którego będziesz tu używać, jest WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY. To uprawnienie umożliwia rysowanie bezpośrednio na ekranie nad istniejącą zawartością bez konieczności przechodzenia przez skomplikowany proces przyznawania uprawnień.

Cykl życia usługi ułatwień dostępu

Cykl życia usługi ułatwień dostępu jest zarządzany wyłącznie przez system i jest zgodny z ustalonym cyklem życia usługi.

  • Usługa ułatwień dostępu uruchamia się, gdy użytkownik włączy ją w ustawieniach urządzenia.
  • Gdy system powiąże się z usługą, wywołuje metodę onServiceConnected(). Usługi, które chcą przeprowadzić konfigurację po powiązaniu, mogą zastąpić tę metodę.
  • Usługa ułatwień dostępu zatrzymuje się, gdy użytkownik wyłączy ją w ustawieniach urządzenia lub gdy wywoła funkcję disableSelf().

Uruchamianie usługi

Zanim uruchomisz usługę za pomocą Android Studio, musisz się upewnić, że ustawienia uruchamiania są prawidłowo skonfigurowane.

Edytuj konfigurację uruchamiania (w menu u góry kliknij Uruchom i wybierz Edytuj konfiguracje). Następnie w menu zmień opcję uruchamiania z „Domyślna aktywność” na „Nic”.

Rozwiń menu, aby skonfigurować ustawienia uruchamiania i uruchomić usługę za pomocą Android Studio.

Usługę można teraz uruchomić za pomocą Androida Studio.

Naciśnij zieloną ikonę Odtwórz Przycisk odtwarzania w Androidzie Studio służący do uruchamiania usługi na pasku menu u góry ekranu. Następnie otwórz Ustawienia > Ułatwienia dostępu i włącz Globalny pasek działań.

Na treści wyświetlane na ekranie powinny być nałożone 4 przyciski, które tworzą interfejs usługi.

overlay.png

Teraz dodasz funkcje do 4 przycisków, aby użytkownik mógł ich dotknąć i wykonać przydatne działania.

5. Konfigurowanie przycisku zasilania

Dodaj metodę configurePowerButton() do pliku GlobalActionBarService.java:

private void configurePowerButton() {
   Button powerButton = (Button) mLayout.findViewById(R.id.power);
   powerButton.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View view) {
           performGlobalAction(GLOBAL_ACTION_POWER_DIALOG);
       }
   });
}

Aby uzyskać dostęp do menu przycisku zasilania, funkcja configurePowerButton() korzysta z metody performGlobalAction(), która jest udostępniana przez AccessibilityService. Dodany kod jest prosty: kliknięcie przycisku wywołuje onClickListener(). Ta funkcja wywołuje performGlobalAction(GLOBAL_ACTION_POWER_DIALOG) i wyświetla użytkownikowi okno zasilania.

Pamiętaj, że czynności globalne nie są powiązane z żadnymi widokami. Naciśnięcie przycisku Wstecz, przycisku ekranu głównego lub przycisku Ostatnie to inne przykłady działań globalnych.

Teraz dodaj configurePowerButton() na końcu metody onServiceConnected():

@Override
protected void onServiceConnected() {
   ...
   configurePowerButton();
}

Naciśnij zieloną ikonę Odtwórz Przycisk odtwarzania w Androidzie Studio służący do uruchamiania usługi na pasku menu u góry ekranu. Następnie wybierz Ustawienia > Ułatwienia dostępu i uruchom usługę globalnego paska działań.

Naciśnij przycisk zasilania, aby wyświetlić okno zasilania.

6. Konfigurowanie przycisku głośności

Dodaj metodę configureVolumeButton() do pliku GlobalActionBarService.java:

private void configureVolumeButton() {
   Button volumeUpButton = (Button) mLayout.findViewById(R.id.volume_up);
   volumeUpButton.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View view) {
           AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
           audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
                   AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
       }
   });
}

Metoda configureVolumeButton() dodaje onClickListener(), który jest wywoływany, gdy użytkownik naciśnie przycisk głośności. W tym detektorze funkcja configureVolumeButton() używa AudioManager do dostosowywania głośności strumienia.

Pamiętaj, że każdy może sterować głośnością (nie musisz być usługą ułatwień dostępu).

Teraz dodaj configureVolumeButton() na końcu metody onServiceConnected():

@Override
protected void onServiceConnected() {
   ...

   configureVolumeButton();
}

Naciśnij zieloną ikonę Odtwórz Przycisk odtwarzania w Androidzie Studio służący do uruchamiania usługi na pasku menu u góry ekranu. Następnie otwórz Ustawienia > Ułatwienia dostępu i uruchom Global Action Bar Service.

Aby zmienić głośność, naciśnij przycisk głośności.

Użytkownik, który nie może dosięgnąć przycisków głośności z boku urządzenia, może teraz użyć usługi globalnego paska działań, aby zmienić (zwiększyć) głośność.

7. Konfigurowanie przycisku przewijania

Ta sekcja obejmuje kodowanie 2 metod. Pierwsza metoda wyszukuje węzeł, który można przewijać, a druga wykonuje przewijanie w imieniu użytkownika.

Dodaj metodę findScrollableNode do pliku GlobalActionBarService.java:

private AccessibilityNodeInfo findScrollableNode(AccessibilityNodeInfo root) {
   Deque<AccessibilityNodeInfo> deque = new ArrayDeque<>();
   deque.add(root);
   while (!deque.isEmpty()) {
       AccessibilityNodeInfo node = deque.removeFirst();
       if (node.getActionList().contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD)) {
           return node;
       }
       for (int i = 0; i < node.getChildCount(); i++) {
           deque.addLast(node.getChild(i));
       }
   }
   return null;
}

Usługa ułatwień dostępu nie ma dostępu do rzeczywistych widoków na ekranie. Zamiast tego widzi odbicie tego, co jest na ekranie, w postaci drzewa składającego się z obiektów AccessibilityNodeInfo. Obiekty te zawierają informacje o reprezentowanym przez nie widoku (lokalizacja widoku, tekst powiązany z widokiem, metadane dodane z myślą o ułatwieniach dostępu, działania obsługiwane przez widok itp.). Metoda findScrollableNode() wykonuje przeszukiwanie wszerz tego drzewa, zaczynając od węzła głównego. Jeśli znajdzie węzeł, który można przewijać (tzn. węzeł obsługujący działanie AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD)), zwraca go. W przeciwnym razie zwraca wartość null.

Teraz dodaj metodę configureScrollButton() do pliku GlobalActionBarService.java:

private void configureScrollButton() {
   Button scrollButton = (Button) mLayout.findViewById(R.id.scroll);
   scrollButton.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View view) {
           AccessibilityNodeInfo scrollable = findScrollableNode(getRootInActiveWindow());
           if (scrollable != null) {
               scrollable.performAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId());
           }
       }
   });
}

Ta metoda tworzy onClickListener(), który uruchamia się po kliknięciu przycisku przewijania. Próbuje znaleźć węzeł, który można przewijać, a jeśli mu się to uda, wykonuje działanie przewijania.

Teraz dodaj configureScrollButton() do onServiceConnected():

@Override
protected void onServiceConnected() {
   ...

   configureScrollButton();
}

Naciśnij zieloną ikonę Odtwórz Przycisk odtwarzania w Androidzie Studio służący do uruchamiania usługi na pasku menu u góry ekranu. Następnie otwórz Ustawienia > Ułatwienia dostępu i uruchom Global Action Bar Service.

Naciśnij przycisk Wstecz, aby przejść do Ustawienia > Ułatwienia dostępu. Elementy na ekranie ustawień ułatwień dostępu można przewijać, a kliknięcie przycisku przewijania powoduje przewinięcie. Nasz hipotetyczny użytkownik, który ma trudności z przewijaniem, może teraz użyć przycisku Przewiń, aby przewinąć listę elementów.

8. Konfigurowanie przycisku przesuwania

Dodaj metodę configureSwipeButton() do pliku GlobalActionBarService.java:

private void configureSwipeButton() {
   Button swipeButton = (Button) mLayout.findViewById(R.id.swipe);
   swipeButton.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View view) {
           Path swipePath = new Path();
           swipePath.moveTo(1000, 1000);
           swipePath.lineTo(100, 1000);
           GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
           gestureBuilder.addStroke(new GestureDescription.StrokeDescription(swipePath, 0, 500));
           dispatchGesture(gestureBuilder.build(), null, null);
       }
   });
}

Metoda configureSwipeButton() korzysta z nowego interfejsu API dodanego w wersji N, który wykonuje gesty w imieniu użytkownika. Kod używa obiektu GestureDescription do określenia ścieżki, po której ma zostać wykonany gest (w tych ćwiczeniach z programowania używane są wartości zakodowane na stałe), a następnie wysyła gest przesunięcia w imieniu użytkownika za pomocą metody dispatchGesture() klasy AccessibilityService.

Teraz dodaj configureSwipeButton() do onServiceConnected():

@Override
protected void onServiceConnected() {
   ...
   configureSwipeButton();
}

Naciśnij zieloną ikonę Odtwórz Przycisk odtwarzania w Androidzie Studio służący do uruchamiania usługi na pasku menu u góry ekranu. Następnie otwórz Ustawienia > Ułatwienia dostępu i uruchom Global Action Bar Service.

Najprostszym sposobem sprawdzenia funkcji przesuwania jest otwarcie aplikacji Mapy zainstalowanej na telefonie. Po wczytaniu mapy kliknięcie przycisku Przesuń spowoduje przesunięcie ekranu w prawo.

9. Podsumowanie

Gratulacje! Masz prostą, funkcjonalną usługę ułatwień dostępu.

Możesz rozszerzyć tę usługę na różne sposoby. Na przykład:

  1. Umożliwienie przenoszenia paska działań (obecnie jest on umieszczony u góry ekranu).
  2. Zezwól użytkownikowi na zwiększanie i zmniejszanie głośności.
  3. Umożliwia użytkownikowi przesuwanie palcem w lewo i w prawo.
  4. Dodano obsługę dodatkowych gestów, na które może reagować pasek działań.

Ten przewodnik obejmuje tylko niewielki podzbiór funkcji udostępnianych przez interfejsy API ułatwień dostępu. Interfejs API obejmuje też te funkcje (lista niepełna):

  • Obsługa wielu okien.
  • Obsługa zdarzeń AccessibilityEvent. Gdy interfejs ulegnie zmianie, usługi ułatwień dostępu są o tym powiadamiane za pomocą obiektów AccessibilityEvent. Usługa może wtedy odpowiednio reagować na zmiany w interfejsie.
  • Możliwość kontrolowania powiększenia.

Z tego ćwiczenia dowiesz się, jak napisać usługę ułatwień dostępu. Jeśli znasz użytkownika z konkretnymi problemami z dostępnością, możesz teraz utworzyć usługę, która mu pomoże.