Membuat layanan aksesibilitas Anda sendiri

Layanan aksesibilitas adalah aplikasi yang meningkatkan kualitas antarmuka pengguna untuk membantu pengguna yang menyandang disabilitas atau yang untuk sementara mungkin tidak dapat berinteraksi sepenuhnya dengan suatu perangkat. Misalnya, pengguna yang sedang mengemudi, merawat anak kecil, atau menghadiri pesta yang sangat ramai mungkin memerlukan antarmuka tambahan atau alternatif masukan.

Android menyediakan layanan aksesibilitas standar, termasuk TalkBack , lalu developer dapat membuat dan mendistribusikan layanan mereka sendiri. Dokumen ini menjelaskan dasar-dasar membangun layanan aksesibilitas.

Layanan aksesibilitas dapat dipaketkan dengan aplikasi biasa atau dibuat sebagai project Android mandiri. Langkah-langkah untuk membuat layanan sama dengan kedua situasi tersebut.

Membuat layanan aksesibilitas Anda

Dalam project, buat class yang memperluas 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() {
    }

...
}

Jika Anda membuat project baru untuk Service ini dan tidak berencana memiliki aplikasi yang terkait dengannya, Anda dapat menghapus class Activity awal dari sumber.

Izin dan deklarasi manifes

Aplikasi yang menyediakan layanan aksesibilitas harus menyertakan deklarasi spesifik di manifes aplikasi mereka agar diperlakukan sebagai layanan aksesibilitas oleh Android sistem file. Bagian ini menjelaskan setelan wajib dan opsional untuk aksesibilitas.

Deklarasi layanan aksesibilitas

Agar aplikasi Anda diperlakukan sebagai layanan aksesibilitas, sertakan service —bukan elemen activity—dalam application dalam manifes Anda. Selain itu, dalam elemen service, sertakan elemen filter intent layanan aksesibilitas. Manifes juga harus melindungi layanan dengan menambahkan BIND_ACCESSIBILITY_SERVICE izin akses untuk memastikan bahwa hanya sistem yang dapat mengikatnya. Berikut contohnya:

  <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>

Konfigurasi layanan aksesibilitas

Layanan aksesibilitas harus menyediakan konfigurasi yang menentukan jenis peristiwa aksesibilitas yang ditangani layanan dan informasi tambahan tentang layanan tersebut. Konfigurasi layanan aksesibilitas terdapat dalam AccessibilityServiceInfo . Layanan Anda dapat membangun dan mengatur konfigurasi menggunakan kelas dan setServiceInfo() pada runtime. Namun, tidak semua opsi konfigurasi tersedia dengan .

Anda dapat menyertakan elemen <meta-data> dalam manifes dengan referensi ke file konfigurasi, yang memungkinkan Anda menetapkan berbagai opsi untuk layanan aksesibilitas, seperti yang ditunjukkan dalam contoh berikut:

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

Elemen <meta-data> ini merujuk ke file XML yang Anda buat di direktori resource aplikasi Anda: <project_dir>/res/xml/accessibility_service_config.xml>. Kode berikut menunjukkan contoh konten file konfigurasi layanan:

<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"
/>

Untuk informasi selengkapnya tentang atribut XML yang dapat digunakan dalam file konfigurasi layanan aksesibilitas, lihat referensi berikut dokumentasi:

Untuk informasi selengkapnya tentang setelan konfigurasi yang dapat disetel secara dinamis saat runtime, lihat AccessibilityServiceInfo dokumentasi referensi.

Mengonfigurasi layanan aksesibilitas

Pertimbangkan hal berikut saat menetapkan variabel konfigurasi untuk layanan aksesibilitas untuk memberi tahu sistem bagaimana dan kapan harus menjalankan:

  • Jenis peristiwa apa yang ingin Anda respons?
  • Apakah layanan harus aktif untuk semua aplikasi, atau hanya paket tertentu nama?
  • Jenis masukan apa yang digunakan?

Anda memiliki dua opsi untuk menetapkan variabel ini. Opsi kompatibilitas mundur adalah mengaturnya dalam kode, menggunakan setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo) Untuk melakukannya, ganti onServiceConnected() dan konfigurasikan layanan Anda di sana, seperti yang ditunjukkan pada contoh berikut:

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);

}

Opsi kedua adalah mengonfigurasi layanan menggunakan file XML. Tertentu opsi konfigurasi, seperti canRetrieveWindowContent, hanya tersedia jika Anda mengonfigurasi layanan menggunakan XML. Konfigurasi opsi dari contoh sebelumnya akan terlihat seperti ini jika ditentukan menggunakan 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"
/>

Jika Anda menggunakan XML, referensikan dalam manifes dengan menambahkan elemen <meta-data> ke deklarasi layanan yang menunjuk ke file XML. Jika Anda menyimpan file XML di res/xml/serviceconfig.xml, tag baru akan terlihat seperti ini:

<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>

Metode layanan aksesibilitas

Layanan aksesibilitas harus memperluas class AccessibilityService dan akan mengganti metode berikut dari class tersebut. Metode ini disajikan dalam urutan pemanggilan sistem Android: dari saat layanan dimulai (onServiceConnected()), hingga saat dijalankan (onAccessibilityEvent(), onInterrupt()), sampai saat dimatikan (onUnbind()).

  • onServiceConnected(): (opsional) sistem memanggil metode ini saat terhubung ke layanan aksesibilitas Anda. Gunakan metode ini untuk melakukan penyiapan satu kali langkah-langkah untuk layanan Anda, termasuk menghubungkan ke sistem umpan balik pengguna layanan, seperti pengelola audio atau penggetar perangkat. Jika Anda ingin menetapkan konfigurasi layanan Anda saat {i>runtime<i} atau membuat penyesuaian satu kali, lokasi ini mudah untuk memanggil setServiceInfo().

  • onAccessibilityEvent(): (diperlukan) sistem memanggil kembali metode ini saat perangkat tersebut mendeteksi AccessibilityEvent yang cocok dengan parameter pemfilteran peristiwa yang ditentukan oleh aksesibilitas Anda layanan, seperti saat pengguna mengetuk tombol atau berfokus pada antarmuka pengguna mengontrol di aplikasi yang diberikan masukan{i> <i}oleh layanan aksesibilitas Anda. Kapan sistem memanggil metode ini, sistem akan meneruskan AccessibilityEvent yang terkait, yang kemudian dapat ditafsirkan dan digunakan oleh layanan untuk memberikan umpan balik kepada . Metode ini dapat dipanggil beberapa kali selama siklus proses layanan.

  • onInterrupt(): (wajib) sistem memanggil metode ini saat sistem ingin mengganggu umpan balik yang diberikan layanan Anda, biasanya dalam terhadap tindakan pengguna seperti memindahkan fokus ke kontrol yang berbeda. Ini dapat dipanggil beberapa kali selama siklus proses layanan Anda.

  • onUnbind(): (opsional) sistem memanggil metode ini saat sistem akan mematikan layanan aksesibilitas. Gunakan metode ini untuk melakukan prosedur penonaktifan satu kali, termasuk membatalkan alokasi sistem masukan pengguna layanan, seperti pengelola audio atau penggetar perangkat.

Metode callback ini menyediakan struktur dasar untuk aksesibilitas Anda layanan. Anda dapat memutuskan cara memproses data yang disediakan oleh sistem Android dengan bentuk objek AccessibilityEvent dan memberikan masukan kepada pengguna. Sebagai informasi selengkapnya tentang mendapatkan informasi dari peristiwa aksesibilitas, lihat Mendapatkan detail peristiwa.

Mendaftar untuk peristiwa aksesibilitas

Salah satu fungsi terpenting dari konfigurasi layanan aksesibilitas adalah memungkinkan Anda menentukan jenis peristiwa aksesibilitas yang digunakan oleh layanan Anda dapat ditangani. Menentukan informasi ini memungkinkan layanan aksesibilitas bekerja sama satu sama lain dan memberi Anda fleksibilitas untuk menangani peristiwa tertentu saja jenis aplikasi tertentu. Pemfilteran peristiwa dapat mencakup hal berikut kriteria:

  • Package names: menentukan nama paket aplikasi yang aksesibilitasnya peristiwa yang perlu ditangani oleh layanan Anda. Jika parameter ini dihilangkan, layanan aksesibilitas dianggap tersedia untuk aksesibilitas layanan untuk aplikasi apa pun. Anda dapat menetapkan parameter ini di layanan aksesibilitas file konfigurasi dengan atribut android:packageNames sebagai daftar yang dipisahkan koma atau gunakan AccessibilityServiceInfo.packageNames anggota.

  • Jenis peristiwa: tentukan jenis peristiwa aksesibilitas yang Anda inginkan layanan apa pun yang harus ditangani. Anda dapat menetapkan parameter ini di layanan aksesibilitas file konfigurasi dengan atribut android:accessibilityEventTypes sebagai daftar yang dipisahkan oleh karakter |—misalnya, accessibilityEventTypes="typeViewClicked|typeViewFocused". Atau, Anda bisa menyetel menggunakan AccessibilityServiceInfo.eventTypes anggota.

Saat menyiapkan layanan aksesibilitas, pertimbangkan dengan cermat peristiwa yang dapat menangani dan hanya mendaftar untuk peristiwa tersebut. Karena pengguna dapat mengaktifkan lebih dari satu layanan aksesibilitas sekaligus, layanan Anda tidak boleh menggunakan data yang tidak dapat ditanganinya. Perlu diingat bahwa layanan lain mungkin menangani {i>event<i} untuk meningkatkan pengalaman pengguna.

Volume aksesibilitas

Perangkat yang menjalankan Android 8.0 (API level 26) dan yang lebih baru menyertakan STREAM_ACCESSIBILITY kategori volume, yang memungkinkan Anda mengontrol volume aksesibilitas output audio layanan independen dari suara lain pada perangkat.

Layanan aksesibilitas dapat menggunakan jenis streaming ini dengan menyetel FLAG_ENABLE_ACCESSIBILITY_VOLUME sebelumnya. Anda kemudian dapat mengubah volume audio aksesibilitas perangkat dengan memanggil tindakan adjustStreamVolume() pada instance perangkat AudioManager.

Cuplikan kode berikut menunjukkan cara layanan aksesibilitas menggunakan Kategori volume STREAM_ACCESSIBILITY:

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);
        }
    }
}

Untuk informasi selengkapnya, lihat video sesi Yang baru di aksesibilitas Android dari Google I/O 2017, mulai dari 6:35.

Pintasan aksesibilitas

Pada perangkat yang menjalankan Android 8.0 (API level 26) dan yang lebih tinggi, pengguna dapat mengaktifkan dan menonaktifkan layanan aksesibilitas yang mereka inginkan dari layar mana pun dengan menekan dan sambil menahan kedua tombol volume secara bersamaan. Meskipun pintasan ini memungkinkan dan menonaktifkan Talkback secara {i>default<i}, pengguna dapat mengkonfigurasi tombol untuk mengaktifkan dan menonaktifkan layanan apa pun yang terinstal di perangkat mereka.

Bagi pengguna untuk mengakses layanan aksesibilitas tertentu dari aksesibilitas , layanan harus meminta fitur pada runtime.

Untuk informasi selengkapnya, lihat video sesi Yang baru di aksesibilitas Android dari Google I/O 2017, mulai dari 13:25.

Tombol aksesibilitas

Pada perangkat yang menggunakan area navigasi yang dirender software dan menjalankan Android 8.0 (API level 26) atau yang lebih tinggi, di sisi kanan bilah navigasi terdapat tombol aksesibilitas. Ketika pengguna menekan tombol ini, mereka dapat memanggil salah satu beberapa fitur dan layanan aksesibilitas yang diaktifkan, tergantung pada kontennya yang saat ini ditampilkan di layar.

Untuk memungkinkan pengguna memanggil layanan aksesibilitas tertentu menggunakan aksesibilitas , layanan perlu menambahkan FLAG_REQUEST_ACCESSIBILITY_BUTTON flag di android:accessibilityFlags objek AccessibilityServiceInfo . Layanan kemudian bisa mendaftarkan callback menggunakan registerAccessibilityButtonCallback()

Cuplikan kode berikut menunjukkan cara mengonfigurasi aksesibilitas layanan untuk merespons pengguna dengan menekan tombol aksesibilitas:

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);
    }
}

Untuk informasi selengkapnya, lihat video sesi Yang baru di aksesibilitas Android dari Google I/O 2017, mulai dari 16:28.

Gestur sidik jari

Layanan aksesibilitas di perangkat yang menjalankan Android 8.0 (level API 26) atau yang lebih baru bisa merespons geser terarah (atas, bawah, kiri, dan kanan) di sepanjang sensor sidik jari. Untuk mengonfigurasi layanan guna menerima callback tentang ini interaksi, selesaikan urutan berikut:

  1. Mendeklarasikan USE_BIOMETRIC izin dan CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES kemampuan IT mereka.
  2. Setel FLAG_REQUEST_FINGERPRINT_GESTURES flag dalam atribut android:accessibilityFlags.
  3. Daftarkan callback menggunakan registerFingerprintGestureCallback().

Ingatlah bahwa tidak semua perangkat menyertakan sensor sidik jari. Untuk mengidentifikasi apakah perangkat mendukung sensor, gunakan isHardwareDetected() . Bahkan di perangkat yang menyertakan sensor sidik jari, layanan Anda tidak dapat menggunakan sensor saat digunakan untuk tujuan otentikasi. Untuk mengidentifikasi kapan sensor tersedia, panggil metode isGestureDetectionAvailable() dan mengimplementasikan metode onGestureDetectionAvailabilityChanged() .

Cuplikan kode berikut akan menunjukkan contoh penggunaan gestur sidik jari untuk memilih opsi navigasi di papan game virtual:

// 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);
        }
    }
}

Untuk informasi selengkapnya, lihat video sesi Yang baru di aksesibilitas Android dari Google I/O 2017, mulai dari 9:03.

Text to speech multibahasa

Mulai dari Android 8.0 (API level 26), layanan text-to-speech (TTS) Android dapat mengidentifikasi dan mengucapkan frasa dalam berbagai bahasa dalam satu blok teks. Untuk mengaktifkan kemampuan pengalihan bahasa otomatis ini pada aksesibilitas {i>service<i}, menggabungkan semua {i>string<i} Objek LocaleSpan, seperti yang ditunjukkan dalam cuplikan kode berikut:

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;
}

Untuk informasi selengkapnya, lihat video sesi Yang baru di aksesibilitas Android dari Google I/O 2017, mulai dari 10:59.

Bertindak atas nama pengguna

Mulai tahun 2011, layanan aksesibilitas dapat bertindak atas nama pengguna, termasuk mengubah fokus input dan memilih (mengaktifkan) elemen antarmuka pengguna. Di beberapa tahun 2012, rentang tindakan diperluas untuk mencakup daftar scroll dan interaksi dengan kolom teks. Layanan aksesibilitas juga dapat mengambil tindakan global, seperti menavigasi ke layar beranda, menekan tombol Kembali, dan membuka layar notifikasi dan daftar aplikasi terbaru. Sejak 2012, Android menyertakan fokus aksesibilitas, yang membuat semua elemen yang terlihat dapat dipilih oleh aksesibilitas.

Kemampuan ini memungkinkan developer layanan aksesibilitas membuat mode navigasi, seperti navigasi {i>gesture<i}, dan memberikan pengguna penyandang disabilitas kendali yang lebih baik atas perangkat yang didukung Android.

Memproses gestur

Layanan aksesibilitas dapat memproses gestur tertentu dan merespons dengan menindaklanjuti nama pengguna. Fitur ini mengharuskan permintaan layanan aksesibilitas Anda aktivasi fitur Jelajahi dengan Sentuhan. Layanan Anda dapat memintanya aktivasi dengan mengatur flags anggota instance AccessibilityServiceInfo layanan untuk FLAG_REQUEST_TOUCH_EXPLORATION_MODE, seperti yang ditunjukkan dalam contoh berikut.

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;
    }
    ...
}

Setelah layanan Anda meminta aktivasi Jelajahi dengan Sentuhan, pengguna harus mengizinkan fitur diaktifkan, jika belum aktif. Jika fitur ini aktif, layanan Anda akan menerima notifikasi dari {i>gesture <i}aksesibilitas melalui layanan Anda onGesture() dan dapat merespons dengan bertindak atas nama pengguna.

Gestur berkelanjutan

Perangkat yang menjalankan Android 8.0 (level API 26) mendukung gestur berkelanjutan, atau gestur terprogram yang berisi lebih dari satu Objek Path.

Ketika menetapkan urutan goresan, Anda dapat menetapkan bahwa garis itu termasuk gestur terprogram yang sama dengan menggunakan argumen akhir willContinue dalam GestureDescription.StrokeDescription seperti yang ditampilkan dalam cuplikan kode berikut:

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);
}

Untuk informasi selengkapnya, lihat video sesi Yang baru di aksesibilitas Android dari Google I/O 2017, mulai dari 15:47.

Menggunakan tindakan aksesibilitas

Layanan aksesibilitas dapat bertindak atas nama pengguna untuk menyederhanakan interaksi dengan aplikasi dan menjadi lebih produktif. Kemampuan layanan aksesibilitas untuk melakukan tindakan ditambahkan pada tahun 2011 dan berkembang secara signifikan pada 2012.

Untuk bertindak atas nama pengguna, layanan aksesibilitas Anda harus mendaftar untuk menerima peristiwa dari aplikasi dan meminta izin untuk melihat konten aplikasi dengan menyetel android:canRetrieveWindowContent ke true di file konfigurasi layanan Google Cloud. Saat peristiwa diterima oleh layanan tersebut, kemudian dapat mengambil AccessibilityNodeInfo dari peristiwa dengan menggunakan getSource(). Dengan objek AccessibilityNodeInfo, layanan Anda kemudian dapat menjelajahi tampilan hierarki untuk menentukan tindakan apa yang harus diambil dan kemudian bertindak untuk pengguna menggunakan 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();
    }
    ...
}

Metode performAction() memungkinkan layanan Anda mengambil tindakan dalam . Jika layanan Anda perlu melakukan tindakan global, seperti menavigasi ke layar beranda, mengetuk tombol Kembali, atau membuka layar notifikasi atau daftar aplikasi terbaru, lalu gunakan performGlobalAction() .

Menggunakan jenis fokus

Pada 2012, Android memperkenalkan fokus antarmuka pengguna yang disebut fokus aksesibilitas. Layanan aksesibilitas dapat menggunakan fokus ini untuk memilih antarmuka pengguna yang terlihat itu dan mengambil tindakan. Jenis fokus ini berbeda dengan fokus input, yang menentukan elemen antarmuka pengguna di layar apa yang menerima input saat pengguna mengetik karakter, menekan Enter pada keyboard, atau menekan bagian tengah tombol D-pad.

Ada kemungkinan satu elemen di antarmuka pengguna memiliki fokus input sementara elemen lain memiliki fokus aksesibilitas. Tujuan dari fokus aksesibilitas adalah untuk menyediakan layanan aksesibilitas dengan metode interaksi dengan elemen pada layar, terlepas dari apakah elemen itu dapat difokuskan input atau tidak perspektif sistem. Untuk membantu memastikan bahwa layanan aksesibilitas Anda berinteraksi menggunakan aplikasi elemen input, ikuti pedoman untuk menguji aksesibilitas untuk menguji layanan Anda saat menggunakan aplikasi biasa.

Layanan aksesibilitas dapat menentukan elemen antarmuka pengguna apa yang memiliki input atau fokus aksesibilitas menggunakan AccessibilityNodeInfo.findFocus() . Anda juga dapat menelusuri elemen yang dapat dipilih dengan fokus input menggunakan focusSearch() . Terakhir, layanan aksesibilitas Anda bisa mengatur fokus aksesibilitas menggunakan tindakan performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS) .

Mengumpulkan informasi

Layanan aksesibilitas memiliki metode standar untuk mengumpulkan dan menampilkan informasi kunci unit informasi yang diberikan pengguna, seperti detail acara, teks, dan nomor.

Mendapatkan detail perubahan jendela

Android 9 (level API 28) dan yang lebih baru memungkinkan aplikasi melacak update periode sebuah aplikasi menggambar ulang beberapa jendela secara bersamaan. Ketika seorang TYPE_WINDOWS_CHANGED yang terjadi, gunakan getWindowChanges() API untuk menentukan cara jendela berubah. Selama update multi-aplikasi, setiap menghasilkan kumpulan peristiwanya sendiri. Metode getSource() akan menampilkan root jendela yang terkait dengan setiap peristiwa.

Jika aplikasi menentukan panel aksesibilitas judul untuk Objek View, layanan Anda dapat mengenali kapan UI aplikasi akan diupdate. Ketika seorang TYPE_WINDOW_STATE_CHANGED yang terjadi, gunakan jenis yang dikembalikan oleh getContentChangeTypes() untuk menentukan perubahan jendela. Misalnya, kerangka kerja dapat mendeteksi kapan panel memiliki judul baru atau saat panel menghilang.

Mendapatkan detail peristiwa

Android menyediakan informasi ke layanan aksesibilitas tentang antarmuka pengguna interaksi melalui objek AccessibilityEvent. Di versi Android sebelumnya, informasi yang tersedia dalam peristiwa aksesibilitas, sekaligus memberikan detail tentang kontrol antarmuka pengguna yang dipilih oleh pengguna, ditawarkan secara terbatas informasi kontekstual. Di banyak kasus, informasi konteks yang hilang ini mungkin penting untuk memahami arti kontrol yang dipilih.

Contoh antarmuka yang konteksnya sangat penting adalah kalender atau hari perencana proyek. Jika pengguna memilih slot waktu 16.00 dalam daftar hari Senin hingga Jumat dan layanan aksesibilitas mengumumkan "jam 4 sore", tetapi tidak mengumumkan hari kerja nama, hari dalam sebulan, atau nama bulan, {i>feedback<i} yang dihasilkan membingungkan. Dalam hal ini, konteks dari kontrol antarmuka pengguna sangat penting untuk pengguna yang ingin menjadwalkan rapat.

Sejak tahun 2011, Android secara signifikan memperluas jumlah informasi yang layanan aksesibilitas bisa memperoleh tentang interaksi antarmuka pengguna dengan menulis peristiwa aksesibilitas berdasarkan hierarki tampilan. Hierarki tampilan adalah rangkaian komponen antarmuka pengguna yang berisi komponen (induknya) dan pengguna elemen antarmuka yang mungkin terdapat dalam komponen itu (turunannya). Di beberapa dengan cara ini, Android bisa memberikan detail yang lebih lengkap tentang peristiwa aksesibilitas, memungkinkan layanan aksesibilitas memberikan masukan yang lebih berguna bagi pengguna.

Layanan aksesibilitas mendapatkan informasi tentang peristiwa antarmuka pengguna melalui AccessibilityEvent yang diteruskan oleh sistem ke metode Metode callback onAccessibilityEvent(). Objek ini memberikan detail tentang peristiwa, termasuk jenis objek yang sedang ditindaklanjuti, teks deskriptifnya, dan detail lainnya.

  • AccessibilityEvent.getRecordCount() dan getRecord(int): metode ini memungkinkan Anda mengambil kumpulan AccessibilityRecord objek yang berkontribusi pada AccessibilityEvent yang diteruskan kepada Anda oleh sistem file. Tingkat detail ini memberikan lebih banyak konteks untuk peristiwa yang akan memicu layanan aksesibilitas Anda.

  • AccessibilityRecord.getSource(): metode ini akan menampilkan objek AccessibilityNodeInfo. Objek ini memungkinkan Anda meminta hierarki tata letak tampilan (induk dan turunan) dari komponen yang akan memulai peristiwa aksesibilitas. Fitur ini memungkinkan aksesibilitas menyelidiki konteks penuh dari suatu peristiwa, termasuk konten dan dari setiap tampilan yang mencakup atau tampilan turunan.

Platform Android menyediakan kemampuan bagi AccessibilityService untuk membuat kueri hierarki tampilan, yang mengumpulkan informasi tentang komponen UI yang menghasilkan suatu peristiwa serta orang tua dan turunannya. Untuk melakukannya, setel baris berikut dalam konfigurasi XML Anda:

android:canRetrieveWindowContent="true"

Setelah selesai, dapatkan objek AccessibilityNodeInfo menggunakan getSource(). Panggilan ini hanya menampilkan objek jika jendela tempat peristiwa berasal jendela yang masih aktif. Jika tidak, metode ini akan menghasilkan nilai null, jadi lakukanlah hal yang sama.

Dalam contoh berikut, kode melakukan hal berikut saat peristiwa diterima:

  1. Segera meraih induk tampilan tempat peristiwa berasal.
  2. Dalam tampilan tersebut, cari label dan kotak centang sebagai tampilan turunan.
  3. Jika menemukannya, buat string untuk dilaporkan kepada pengguna, yang menunjukkan label dan apakah label telah dicentang.

Jika pada suatu saat nilai {i>null <i}ditampilkan saat melintasi hierarki tampilan, metode tersebut akan menyerah dengan tenang.

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);
}

Kini Anda memiliki layanan aksesibilitas yang lengkap dan berfungsi. Coba konfigurasikan cara berinteraksi dengan pengguna dengan menambahkan fitur text-to-speech Android mesin atau menggunakan Vibrator untuk memberikan sentuhan masukan.

Memproses teks

Perangkat yang menjalankan Android 8.0 (API level 26) dan yang lebih tinggi menyertakan beberapa fitur pemrosesan teks yang mempermudah layanan aksesibilitas untuk mengidentifikasi dan mengoperasikan unit teks tertentu yang muncul di layar.

Tooltip

Android 9 (level API 28) memperkenalkan beberapa kemampuan yang memberi Anda akses ke tooltip di UI aplikasi. Gunakan getTooltipText() untuk membaca teks tooltip, dan menggunakan ACTION_SHOW_TOOLTIP dan ACTION_HIDE_TOOLTIP untuk menginstruksikan instance View agar menampilkan atau menyembunyikan tooltip.

Teks petunjuk

Mulai tahun 2017, Android menyertakan beberapa metode untuk berinteraksi dengan teks petunjuk objek berbasis teks:

  • Tujuan isShowingHintText() dan setShowingHintText() menunjukkan dan menyetel, masing-masing, apakah teks node saat ini konten mewakili teks petunjuk node.
  • getHintText() menyediakan akses ke teks petunjuk itu sendiri. Bahkan jika objek tidak ditampilkan teks petunjuk, memanggil getHintText() akan berhasil.

Lokasi karakter teks di layar

Pada perangkat yang menjalankan Android 8.0 (API level 26) dan yang lebih tinggi, layanan aksesibilitas dapat menentukan koordinat layar untuk setiap kotak pembatas karakter yang terlihat dalam widget TextView. Layanan temukan koordinat ini dengan memanggil refreshWithExtraData(), meneruskan EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY sebagai argumen pertama dan objek Bundle sebagai argumen kedua. Saat metode dieksekusi, sistem akan mengisi Argumen Bundle dengan array yang dapat dibagi-bagi dari Objek Rect. Setiap objek Rect merepresentasikan kotak pembatas karakter tertentu.

Nilai rentang satu sisi standar

Beberapa objek AccessibilityNodeInfo menggunakan instance AccessibilityNodeInfo.RangeInfo untuk menunjukkan bahwa elemen UI bisa menggunakan sebuah rentang nilai. Saat membuat rentang menggunakan RangeInfo.obtain(), atau saat mengambil nilai ekstrem dari rentang menggunakan getMin() dan getMax(), perlu diingat bahwa perangkat yang menjalankan Android 8.0 (API level 26) dan yang lebih tinggi mewakili rentang satu sisi dengan cara yang terstandardisasi:

Merespons peristiwa aksesibilitas

Setelah layanan Anda siap menjalankan dan memproses peristiwa, tulis kode agar tahu apa yang harus dilakukan saat AccessibilityEvent tiba. Mulailah dengan mengganti onAccessibilityEvent(AccessibilityEvent) . Dalam metode tersebut, gunakan getEventType() untuk menentukan jenis peristiwa dan getContentDescription() untuk mengekstrak teks label apa pun yang terkait dengan tampilan yang mengaktifkan peristiwa:

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);
    ...
}

Referensi lainnya

Untuk mempelajari lebih lanjut, lihat referensi berikut:

Panduan

Codelab