สร้างบริการการช่วยเหลือพิเศษของคุณเอง

บริการการช่วยเหลือพิเศษคือแอปที่ปรับปรุงอินเทอร์เฟซผู้ใช้เพื่อช่วยเหลือ ผู้ใช้ที่มีความพิการหรืออาจไม่สามารถโต้ตอบได้อย่างสมบูรณ์แบบชั่วคราว ด้วยอุปกรณ์ เช่น ผู้ใช้ที่ขับรถและดูแลเด็กเล็ก หรือไปงานปาร์ตี้ที่มีเสียงดังมากๆ อาจต้องใช้อินเทอร์เฟซเพิ่มเติมหรืออินเทอร์เฟซอื่น ความคิดเห็น

Android ให้บริการการช่วยเหลือพิเศษแบบมาตรฐาน ซึ่งรวมถึง TalkBack และนักพัฒนาแอปจะสร้างและเผยแพร่บริการของตนเองได้อย่างไร เอกสารนี้ อธิบายพื้นฐานในการสร้างบริการการช่วยเหลือพิเศษ

บริการการช่วยเหลือพิเศษอาจมาพร้อมกับแอปทั่วไปหรือสร้างเป็น Android แบบสแตนด์อโลน โดยมีขั้นตอนในการสร้างบริการเหมือนกัน สถานการณ์ใดสถานการณ์หนึ่ง

สร้างบริการการช่วยเหลือพิเศษ

สร้างชั้นเรียนแบบขยายภายในโปรเจ็กต์ของคุณ 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() {
    }

...
}

หากคุณสร้างโปรเจ็กต์ใหม่สำหรับ Service นี้และไม่ได้วางแผนที่จะมีแอป ที่เกี่ยวข้อง คุณสามารถนำคลาส Activity เริ่มต้นออกจาก แหล่งที่มา

การประกาศและสิทธิ์ในไฟล์ Manifest

แอปที่ให้บริการการช่วยเหลือพิเศษต้องมีประกาศเฉพาะใน ไฟล์ Manifest ของแอปจะถือเป็นบริการช่วยเหลือพิเศษโดย Android ระบบ ส่วนนี้จะอธิบายการตั้งค่าที่บังคับและไม่บังคับสำหรับ บริการการช่วยเหลือพิเศษ

การประกาศบริการการช่วยเหลือพิเศษ

หากต้องการให้แอปของคุณถือเป็นบริการช่วยเหลือพิเศษ ให้ใส่ service แทนที่จะเป็นองค์ประกอบ activity ภายใน application ในไฟล์ Manifest นอกจากนี้ ภายในองค์ประกอบ service ให้ใส่ ตัวกรอง Intent ของบริการการช่วยเหลือพิเศษ ไฟล์ Manifest ต้องปกป้องบริการด้วย โดยเพิ่ม BIND_ACCESSIBILITY_SERVICE เพื่อให้มั่นใจว่ามีเพียงระบบเท่านั้นที่สามารถเชื่อมโยงกับระบบได้ ตัวอย่างเช่น

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

การกำหนดค่าบริการการช่วยเหลือพิเศษ

บริการการช่วยเหลือพิเศษต้องมีการกำหนดค่าที่ระบุประเภทของ เหตุการณ์การช่วยเหลือพิเศษที่บริการจัดการและข้อมูลเพิ่มเติม บริการ การกำหนดค่าของบริการการเข้าถึงจะอยู่ใน AccessibilityServiceInfo บริการของคุณสามารถสร้างและตั้งค่าการกำหนดค่าโดยใช้อินสแตนซ์นี้ ชั้นเรียนและ setServiceInfo() ขณะรันไทม์ อย่างไรก็ตาม ตัวเลือกการกำหนดค่าบางอย่างอาจใช้ไม่ได้เมื่อใช้

คุณใส่เอลิเมนต์ <meta-data> ลงในไฟล์ Manifest เพื่ออ้างอิง ซึ่งทำให้คุณสามารถตั้งค่าตัวเลือกทั้งหมดสำหรับ บริการการเข้าถึงดังที่ปรากฏในตัวอย่างต่อไปนี้

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

องค์ประกอบ <meta-data> นี้หมายถึงไฟล์ XML ที่คุณสร้างขึ้นในไฟล์ ไดเรกทอรีทรัพยากรของแอป: <project_dir>/res/xml/accessibility_service_config.xml> รหัสต่อไปนี้ แสดงตัวอย่างเนื้อหาของไฟล์การกำหนดค่าบริการ

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

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับแอตทริบิวต์ XML ที่สามารถใช้ใน ไฟล์การกำหนดค่าบริการการช่วยเหลือพิเศษ โปรดดูข้อมูลอ้างอิงต่อไปนี้ เอกสารประกอบ:

ดูข้อมูลเพิ่มเติมเกี่ยวกับการตั้งค่าการกําหนดค่าแบบไดนามิกได้ ที่รันไทม์ โปรดดู AccessibilityServiceInfo เอกสารอ้างอิง

กำหนดค่าบริการการช่วยเหลือพิเศษ

คำนึงถึงสิ่งต่อไปนี้เมื่อตั้งค่าตัวแปรการกำหนดค่าสำหรับ บริการการช่วยเหลือพิเศษเพื่อบอกระบบว่าจะทำงานอย่างไรและเมื่อใด ดังนี้

  • คุณต้องการให้กิจกรรมตอบสนองต่อเหตุการณ์ประเภทใด
  • ต้องมีการเปิดใช้บริการดังกล่าวในทุกแอปหรือเฉพาะบางแพ็กเกจ ชื่ออะไร
  • ความคิดเห็นประเภทต่างๆ ที่ใช้

คุณมี 2 ตัวเลือกสำหรับการตั้งค่าตัวแปรเหล่านี้ ตัวเลือกที่เข้ากันได้แบบย้อนหลัง คือการตั้งค่าในโค้ดโดยใช้ setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo) ในการดำเนินการนี้ ให้แทนที่ onServiceConnected() และกำหนดค่าบริการของคุณ ดังที่ปรากฏในตัวอย่างต่อไปนี้:

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

}

ตัวเลือกที่ 2 คือการกำหนดค่าบริการโดยใช้ไฟล์ XML บางประเภท ตัวเลือกการกำหนดค่า เช่น canRetrieveWindowContent จะใช้ได้เมื่อคุณกำหนดค่าบริการโดยใช้ XML เท่านั้น การกำหนดค่า ตัวเลือกจากตัวอย่างก่อนหน้านี้มีลักษณะดังนี้เมื่อกำหนดโดยใช้ 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"
/>

หากคุณใช้ XML ให้อ้างถึงไฟล์ในไฟล์ Manifest โดยเพิ่ม <meta-data> ต่อท้าย การประกาศบริการซึ่งชี้ไปที่ไฟล์ XML หากเก็บไฟล์ XML ไว้ใน res/xml/serviceconfig.xml แท็กใหม่จะมีลักษณะดังนี้

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

วิธีการให้บริการการช่วยเหลือพิเศษ

บริการการช่วยเหลือพิเศษต้องขยายคลาส AccessibilityService และ ลบล้างเมธอดต่อไปนี้จากคลาสดังกล่าว วิธีการเหล่านี้จะแสดงใน ลำดับที่ระบบ Android เรียกผู้ใช้: ตั้งแต่เริ่มบริการ (onServiceConnected()) จนถึงขณะที่วิดีโอทำงานอยู่ (onAccessibilityEvent() onInterrupt()) จนถึงตอนปิดตัว (onUnbind())

  • onServiceConnected(): (ไม่บังคับ) ระบบจะเรียกใช้เมธอดนี้เมื่อ เชื่อมต่อกับบริการการช่วยเหลือพิเศษ ใช้วิธีนี้เพื่อตั้งค่าแบบครั้งเดียว ขั้นตอนสำหรับบริการของคุณ รวมถึงการเชื่อมต่อกับระบบความคิดเห็นของผู้ใช้ เช่น โปรแกรมจัดการเสียง หรือการสั่นของอุปกรณ์ หากต้องการตั้งค่า การกำหนดค่าของบริการขณะรันไทม์ หรือทำการปรับเปลี่ยนแบบครั้งเดียว ตำแหน่งนี้ทำให้โทรหา setServiceInfo() ได้สะดวก

  • onAccessibilityEvent(): (ต้องระบุ) ระบบจะโทรกลับวิธีนี้เมื่อ ตรวจพบ AccessibilityEvent ที่ตรงกับพารามิเตอร์การกรองเหตุการณ์ที่การช่วยเหลือพิเศษระบุไว้ เช่น เมื่อผู้ใช้แตะปุ่มหรือโฟกัสที่อินเทอร์เฟซผู้ใช้ ควบคุมในแอปที่บริการการช่วยเหลือพิเศษของคุณแสดงความคิดเห็นให้ วันและเวลา ระบบเรียกใช้เมธอดนี้ ซึ่งส่งผ่าน AccessibilityEvent ที่เกี่ยวข้อง ซึ่งบริการสามารถตีความและใช้เพื่อแสดงความคิดเห็นแก่ ผู้ใช้ วิธีการนี้สามารถเรียกใช้ได้หลายครั้งตลอดวงจร service.

  • onInterrupt(): (ต้องระบุ) ระบบเรียกใช้เมธอดนี้เมื่อระบบ ต้องการขัดขวางความคิดเห็นที่คุณได้รับจากบริการ ซึ่งมักอยู่ใน การตอบสนองต่อการดำเนินการของผู้ใช้ เช่น การย้ายโฟกัสไปยังตัวควบคุมอื่น ช่วงเวลานี้ สามารถเรียกใช้ได้หลายครั้งตลอดวงจรของบริการของคุณ

  • onUnbind(): (ไม่บังคับ) ระบบจะเรียกใช้เมธอดนี้เมื่อระบบ กำลังจะปิดบริการการช่วยเหลือพิเศษ ใช้วิธีการนี้เพื่อทำสิ่งต่างๆ ขั้นตอนการปิดระบบแบบครั้งเดียว รวมถึงระบบการจัดสรรความคิดเห็นของผู้ใช้ เช่น โปรแกรมจัดการเสียง หรือการสั่นของอุปกรณ์

เมธอด Callback เหล่านี้ให้โครงสร้างพื้นฐานสำหรับการช่วยเหลือพิเศษ service. คุณสามารถเลือกวิธีประมวลผลข้อมูลที่ได้รับจากระบบ Android ใน รูปแบบของออบเจ็กต์ AccessibilityEvent และให้ความคิดเห็นแก่ผู้ใช้ สำหรับ หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับการรับข้อมูลจากกิจกรรมการช่วยเหลือพิเศษ โปรดดูรับ รายละเอียดกิจกรรม

ลงทะเบียนเข้าร่วมกิจกรรมการช่วยเหลือพิเศษ

ฟังก์ชันที่สำคัญที่สุดอย่างหนึ่งของการกำหนดค่าบริการการช่วยเหลือพิเศษ ช่วยให้คุณระบุประเภทของเหตุการณ์การช่วยเหลือพิเศษของบริการได้ สามารถจัดการได้ การระบุข้อมูลนี้จะช่วยให้บริการการช่วยเหลือพิเศษทำงานร่วมกัน ระหว่างกัน และช่วยให้จัดการเฉพาะเหตุการณ์หนึ่งๆ ได้อย่างยืดหยุ่น จากแอปบางแอป การกรองเหตุการณ์อาจประกอบด้วยสิ่งต่อไปนี้ เกณฑ์:

  • ชื่อแพ็กเกจ: ระบุชื่อแพ็กเกจของแอปที่มีความสามารถในการเข้าถึง เหตุการณ์ที่คุณต้องการให้บริการจัดการ หากไม่ระบุพารามิเตอร์นี้ บริการการช่วยเหลือพิเศษจะถือว่าพร้อมใช้งานสำหรับการช่วยเหลือพิเศษของบริการ เหตุการณ์ของแอปใดๆ คุณตั้งค่าพารามิเตอร์นี้ในบริการการช่วยเหลือพิเศษได้ ที่มีแอตทริบิวต์ android:packageNames เป็น รายการที่คั่นด้วยคอมมาหรือใช้ AccessibilityServiceInfo.packageNames

  • ประเภทเหตุการณ์: ระบุประเภทของเหตุการณ์การช่วยเหลือพิเศษที่คุณต้องการให้ ที่ต้องจัดการ คุณตั้งค่าพารามิเตอร์นี้ในบริการการช่วยเหลือพิเศษได้ ที่มีแอตทริบิวต์ android:accessibilityEventTypes เป็น รายการที่คั่นด้วยอักขระ | ตัวอย่างเช่น accessibilityEventTypes="typeViewClicked|typeViewFocused" หรือคุณสามารถตั้งค่า โดยใช้ AccessibilityServiceInfo.eventTypes

เมื่อตั้งค่าบริการการช่วยเหลือพิเศษ โปรดพิจารณาอย่างรอบคอบว่าเหตุการณ์ใดที่คุณ บริการจะจัดการและลงทะเบียนสำหรับกิจกรรมเหล่านั้นได้เท่านั้น เนื่องจากผู้ใช้เปิดใช้งานได้ บริการการเข้าถึงมากกว่า 1 บริการพร้อมกัน บริการของคุณจะต้องไม่ใช้ ที่ไม่สามารถรับมือได้ โปรดทราบว่าบริการอื่นๆ อาจจัดการกับ กิจกรรมเพื่อปรับปรุงประสบการณ์ของผู้ใช้

ระดับเสียงการช่วยเหลือพิเศษ

อุปกรณ์ที่ใช้ Android 8.0 (API ระดับ 26) ขึ้นไปประกอบด้วย STREAM_ACCESSIBILITY หมวดหมู่ระดับเสียง ซึ่งช่วยให้คุณควบคุมการช่วยเหลือพิเศษได้ เอาต์พุตเสียงของบริการแยกจากเสียงอื่นๆ ในอุปกรณ์

บริการการช่วยเหลือพิเศษสามารถใช้สตรีมประเภทนี้โดยการตั้งค่า FLAG_ENABLE_ACCESSIBILITY_VOLUME ตัวเลือก จากนั้นคุณจะเปลี่ยนระดับเสียงสำหรับการช่วยเหลือพิเศษของอุปกรณ์ได้ด้วยการโทร เวลา adjustStreamVolume() ในอินสแตนซ์ของอุปกรณ์ AudioManager

ตัวอย่างข้อมูลโค้ดต่อไปนี้แสดงให้เห็นว่าบริการการช่วยเหลือพิเศษสามารถใช้ หมวดหมู่หนังสือชุด 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);
        }
    }
}

สำหรับข้อมูลเพิ่มเติม โปรดดูวิดีโอเซสชันมีอะไรใหม่ในการช่วยเหลือพิเศษของ Android จาก Google I/O 2017 โดยเริ่มตั้งแต่ 6:35

ทางลัดสำหรับการช่วยเหลือพิเศษ

สำหรับอุปกรณ์ที่ใช้ Android 8.0 (API ระดับ 26) ขึ้นไป ผู้ใช้สามารถเปิดใช้ และ ปิดใช้บริการการช่วยเหลือพิเศษที่ต้องการจากหน้าจอใดก็ได้โดยกดและ กดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มพร้อมกัน แม้ว่าทางลัดนี้จะเปิดใช้และ จะปิดใช้ TalkBack โดยค่าเริ่มต้น ผู้ใช้สามารถกำหนดค่าปุ่มเพื่อเปิดใช้และ ปิดใช้บริการทั้งหมดที่ติดตั้งในอุปกรณ์

เพื่อให้ผู้ใช้เข้าถึงบริการการช่วยเหลือพิเศษบางอย่างได้จากการช่วยเหลือพิเศษ บริการจะต้องขอฟีเจอร์ขณะรันไทม์

สำหรับข้อมูลเพิ่มเติม โปรดดูวิดีโอเซสชันมีอะไรใหม่ในการช่วยเหลือพิเศษของ Android จาก Google I/O 2017 โดยเริ่มตั้งแต่ 13:25

ปุ่มการช่วยเหลือพิเศษ

ในอุปกรณ์ที่ใช้พื้นที่การนำทางที่แสดงผลด้วยซอฟต์แวร์และใช้ Android 8.0 (API ระดับ 26) ขึ้นไป ที่ด้านขวาของแถบนำทางจะมีองค์ประกอบ ปุ่มการช่วยเหลือพิเศษ เมื่อกดปุ่มนี้ ผู้ใช้จะเรียกใช้รายการใดรายการหนึ่ง ฟีเจอร์และบริการการช่วยเหลือพิเศษที่เปิดใช้หลายรายการ ขึ้นอยู่กับเนื้อหา ที่กำลังแสดงอยู่บนหน้าจอ

เพื่อให้ผู้ใช้เรียกใช้บริการการช่วยเหลือพิเศษโดยใช้การช่วยเหลือพิเศษ บริการต้องเพิ่ม FLAG_REQUEST_ACCESSIBILITY_BUTTON ธงในandroid:accessibilityFlagsของออบเจ็กต์ AccessibilityServiceInfo จากนั้น บริการจะสามารถลงทะเบียน Callback โดยใช้ registerAccessibilityButtonCallback()

ข้อมูลโค้ดต่อไปนี้แสดงวิธีกำหนดค่าการช่วยเหลือพิเศษ เพื่อตอบสนองผู้ใช้ที่กดปุ่มการช่วยเหลือพิเศษ:

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

สำหรับข้อมูลเพิ่มเติม โปรดดูวิดีโอเซสชันมีอะไรใหม่ในการช่วยเหลือพิเศษของ Android จาก Google I/O 2017 โดยเริ่มตั้งแต่ 16:28

ท่าทางสัมผัสลายนิ้วมือ

บริการช่วยเหลือพิเศษในอุปกรณ์ที่ใช้ Android 8.0 (API ระดับ 26) ขึ้นไป สามารถตอบสนองต่อการปัดตามทิศทาง (ขึ้น ลง ซ้าย และขวา) ตามแนวของอุปกรณ์ เซ็นเซอร์ลายนิ้วมือ ในการกำหนดค่าบริการเพื่อรับ Callback เกี่ยวกับ การโต้ตอบ ให้กรอกลำดับต่อไปนี้

  1. ประกาศUSE_BIOMETRIC และ CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES แบบพื้นฐาน
  2. ตั้งค่าFLAG_REQUEST_FINGERPRINT_GESTURES แฟล็กภายในแอตทริบิวต์ android:accessibilityFlags
  3. ลงทะเบียนสำหรับการติดต่อกลับโดยใช้ registerFingerprintGestureCallback()

โปรดทราบว่าบางอุปกรณ์อาจไม่มีเซ็นเซอร์ลายนิ้วมือ เพื่อระบุ อุปกรณ์รองรับเซ็นเซอร์หรือไม่ ให้ใช้ isHardwareDetected() แม้ในอุปกรณ์ที่มีเซ็นเซอร์ลายนิ้วมือ บริการของคุณก็ไม่สามารถ ใช้เซ็นเซอร์เมื่อใช้เพื่อตรวจสอบสิทธิ์ เพื่อระบุว่าเมื่อใด เซ็นเซอร์พร้อมใช้งาน เรียกใช้ isGestureDetectionAvailable() และนำเมตริก onGestureDetectionAvailabilityChanged() Callback

ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างของการใช้ท่าทางสัมผัสลายนิ้วมือเพื่อ ไปยังส่วนต่างๆ ของกระดานเกมเสมือนจริง

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

สำหรับข้อมูลเพิ่มเติม โปรดดูวิดีโอเซสชันมีอะไรใหม่ในการช่วยเหลือพิเศษของ Android จาก Google I/O 2017 โดยเริ่มตั้งแต่ 9:03

การอ่านออกเสียงข้อความหลายภาษา

ตั้งแต่ Android 8.0 (API ระดับ 26) ไปจนถึงบริการอ่านออกเสียงข้อความ (TTS) ของ Android สามารถระบุและพูดวลีในภาษาต่างๆ ภายในบล็อกเดียว ข้อความ เพื่อเปิดใช้ความสามารถในการเปลี่ยนภาษาอัตโนมัตินี้ในฟีเจอร์การช่วยเหลือพิเศษ บริการ รวมสตริงทั้งหมดไว้ใน LocaleSpan ออบเจ็กต์ตามที่แสดง ในข้อมูลโค้ดต่อไปนี้

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

สำหรับข้อมูลเพิ่มเติม โปรดดูวิดีโอเซสชันมีอะไรใหม่ในการช่วยเหลือพิเศษของ Android จาก Google I/O 2017 โดยเริ่มตั้งแต่ 10:59

ดำเนินการในนามของผู้ใช้

ตั้งแต่ปี 2011 บริการการเข้าถึงสามารถดำเนินการในนามของผู้ใช้ได้ ซึ่งรวมถึง การเปลี่ยนโฟกัสอินพุตและการเลือก (เปิดใช้งาน) องค์ประกอบอินเทอร์เฟซผู้ใช้ ใน ในปี 2012 ได้ขยายช่วงการดําเนินการให้ครอบคลุมรายการแบบเลื่อนและการโต้ตอบ ด้วยช่องข้อความ บริการช่วยเหลือพิเศษยังดำเนินการต่างๆ ได้ทั่วโลก เช่น ไปยังหน้าจอหลัก กดปุ่มย้อนกลับ และเปิด หน้าจอการแจ้งเตือนและรายการแอปล่าสุด ตั้งแต่ปี 2012 เป็นต้นมา Android มี โฟกัสการช่วยเหลือพิเศษ ซึ่งทำให้เลือกองค์ประกอบที่มองเห็นได้ทั้งหมดด้วย บริการการช่วยเหลือพิเศษ

ความสามารถเหล่านี้ช่วยให้นักพัฒนาบริการการช่วยเหลือพิเศษสร้างทางเลือก โหมดการไปยังส่วนต่างๆ เช่น การนำทางด้วยท่าทางสัมผัส และให้ผู้ใช้ที่มีความพิการ ที่ปรับปรุงการควบคุมอุปกรณ์ที่ใช้ Android

ฟังท่าทางสัมผัส

บริการการช่วยเหลือพิเศษจะฟังท่าทางสัมผัสที่เจาะจงและตอบสนองได้โดยการดำเนินการตาม แทนผู้ใช้ คุณต้องส่งคำขอบริการการช่วยเหลือพิเศษเพื่อใช้ฟีเจอร์นี้ การเปิดใช้งานฟีเจอร์สำรวจด้วยการแตะ บริการของคุณสามารถขอข้อมูลนี้ได้ การเปิดใช้งานได้โดยการตั้งค่า flags สมาชิกของอินสแตนซ์ AccessibilityServiceInfo ของบริการให้กับ FLAG_REQUEST_TOUCH_EXPLORATION_MODE, ดังที่ปรากฏในตัวอย่างต่อไปนี้

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

หลังจากบริการของคุณขอเปิดใช้งานการสำรวจด้วยการแตะ ผู้ใช้ต้องอนุญาต ฟีเจอร์จะเปิดขึ้นหากยังไม่ได้ใช้งานอยู่ เมื่อฟีเจอร์นี้ ทำงานอยู่ บริการของคุณจะได้รับการแจ้งเตือนเกี่ยวกับท่าทางสัมผัสการช่วยเหลือพิเศษผ่าน onGesture() เมธอด Callback และสามารถตอบกลับโดยการดำเนินการในนามของผู้ใช้

ท่าทางสัมผัสต่อ

อุปกรณ์ที่ใช้ Android 8.0 (API ระดับ 26) รองรับท่าทางสัมผัสอย่างต่อเนื่อง หรือ ท่าทางสัมผัสแบบเป็นโปรแกรมที่มีมากกว่า 1 ท่าทางสัมผัส Path

เมื่อระบุลำดับของเส้นโครงร่าง คุณสามารถระบุได้ว่าเส้นโครงร่างเป็นของ ท่าทางสัมผัสแบบเป็นโปรแกรมเดียวกันโดยใช้อาร์กิวเมนต์สุดท้าย willContinue ใน GestureDescription.StrokeDescription เครื่องมือสร้าง ตามที่ปรากฏในข้อมูลโค้ดต่อไปนี้

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

สำหรับข้อมูลเพิ่มเติม โปรดดูวิดีโอเซสชันมีอะไรใหม่ในการช่วยเหลือพิเศษของ Android จาก Google I/O 2017 โดยเริ่มตั้งแต่ 15:47

ใช้การดำเนินการช่วยเหลือพิเศษ

บริการการช่วยเหลือพิเศษสามารถดำเนินการในนามของผู้ใช้เพื่อลดความซับซ้อนในการโต้ตอบกับ และทำงานได้อย่างมีประสิทธิภาพมากขึ้น ความสามารถของบริการการช่วยเหลือพิเศษเพื่อ มีการดำเนินการเพิ่มขึ้นในปี 2011 และเพิ่มขึ้นอย่างมากในปี 2012

ในการดำเนินการในนามของผู้ใช้ บริการการช่วยเหลือพิเศษของคุณต้องลงทะเบียน เพื่อรับกิจกรรมจากแอปและขอสิทธิ์ดูเนื้อหา โดยการตั้งค่า android:canRetrieveWindowContent เป็น true ในส่วน ไฟล์การกำหนดค่าบริการ เมื่อกิจกรรมของคุณได้รับเหตุการณ์ บริการ โมเดลก็สามารถเรียก AccessibilityNodeInfo จากเหตุการณ์โดยใช้ getSource() เมื่อใช้ออบเจ็กต์ AccessibilityNodeInfo บริการจะสำรวจมุมมองได้ ลำดับชั้นในการพิจารณาว่าควรดำเนินการใด แล้วดำเนินการแทนผู้ใช้โดยใช้ 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();
    }
    ...
}

เมธอด performAction() ช่วยให้บริการดำเนินการภายใน แอป หากบริการของคุณจำเป็นต้องดำเนินการส่วนกลาง เช่น การไปยังหน้าจอหลัก แตะปุ่มย้อนกลับ หรือเปิด หน้าจอการแจ้งเตือนหรือรายการแอปล่าสุด ให้ใช้ performGlobalAction()

ใช้ประเภทโฟกัส

ในปี 2012 Android ได้เปิดตัวโฟกัสของอินเทอร์เฟซผู้ใช้ที่เรียกว่าโฟกัสการช่วยเหลือพิเศษ บริการการช่วยเหลือพิเศษสามารถใช้การโฟกัสนี้เพื่อเลือกอินเทอร์เฟซผู้ใช้ที่มองเห็นได้ องค์ประกอบและดำเนินการกับสิ่งนั้น การโฟกัสประเภทนี้แตกต่างจากโฟกัสอินพุตซึ่ง กำหนดองค์ประกอบอินเทอร์เฟซผู้ใช้บนหน้าจอที่จะได้รับข้อมูลเมื่อผู้ใช้ พิมพ์อักขระ กด Enter บนแป้นพิมพ์ หรือกดตรงกลาง ของ D-pad

องค์ประกอบหนึ่งๆ ในอินเทอร์เฟซผู้ใช้จะโฟกัสการป้อนข้อมูลได้ในขณะที่ อีกองค์ประกอบหนึ่งมีโฟกัสการช่วยเหลือพิเศษ วัตถุประสงค์ของการมุ่งเน้นการช่วยเหลือพิเศษคือ เพื่อให้บริการการช่วยเหลือพิเศษโดยมีวิธีโต้ตอบกับ องค์ประกอบบนหน้าจอ โดยไม่คำนึงว่าองค์ประกอบนั้นสามารถโฟกัสข้อมูลจาก เกี่ยวกับมุมมองของระบบ เพื่อช่วยตรวจสอบว่าบริการการช่วยเหลือพิเศษของคุณโต้ตอบ ได้อย่างถูกต้อง องค์ประกอบอินพุตต่างๆ ให้ปฏิบัติตามหลักเกณฑ์ในการทดสอบ การช่วยเหลือพิเศษเพื่อทดสอบบริการของคุณ ขณะใช้แอปทั่วไป

บริการการช่วยเหลือพิเศษระบุได้ว่าองค์ประกอบอินเทอร์เฟซผู้ใช้ใดมีข้อมูล โฟกัสหรือการช่วยเหลือพิเศษโดยใช้ AccessibilityNodeInfo.findFocus() คุณยังค้นหาองค์ประกอบที่สามารถเลือกโดยโฟกัสการป้อนข้อมูลได้ด้วย โดยใช้ focusSearch() สุดท้าย บริการการช่วยเหลือพิเศษสามารถตั้งค่าโฟกัสการช่วยเหลือพิเศษโดยใช้ เวลา performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS)

รวบรวมข้อมูล

บริการการช่วยเหลือพิเศษมีวิธีมาตรฐานในการรวบรวมและแสดงคีย์ หน่วยข้อมูลที่ได้จากผู้ใช้ เช่น รายละเอียดเหตุการณ์ ข้อความ และตัวเลข

ดูรายละเอียดการเปลี่ยนแปลงหน้าต่าง

Android 9 (API ระดับ 28) ขึ้นไปจะช่วยให้แอปติดตามการอัปเดตกรอบเวลาได้ในกรณีที่ แอปหนึ่งวาดหน้าต่างหลายหน้าต่างซ้ำพร้อมกัน เมื่อ TYPE_WINDOWS_CHANGED เกิดเหตุการณ์ ให้ใช้ getWindowChanges() API เพื่อกำหนดการเปลี่ยนแปลงของหน้าต่าง ในระหว่างการอัปเดตหลายหน้าต่าง จะสร้างชุดเหตุการณ์ของตัวเอง เมธอด getSource() จะแสดงรูท หน้าต่างที่เชื่อมโยงกับแต่ละเหตุการณ์

หากแอปกำหนดแผงการช่วยเหลือพิเศษ ชื่อ ออบเจ็กต์ View บริการของคุณจะรับรู้ได้เมื่อ อัปเดต UI ของแอปแล้ว เมื่อ TYPE_WINDOW_STATE_CHANGED เกิดเหตุการณ์ ให้ใช้ประเภทที่แสดงผลตาม getContentChangeTypes() เพื่อดูว่าหน้าต่างจะเปลี่ยนแปลงไปอย่างไร เช่น เฟรมเวิร์กจะตรวจหาว่า แผงมีชื่อใหม่หรือเมื่อแผงหายไป

ดูรายละเอียดกิจกรรม

Android ให้ข้อมูลแก่บริการการช่วยเหลือพิเศษเกี่ยวกับอินเทอร์เฟซผู้ใช้ การโต้ตอบผ่านออบเจ็กต์ AccessibilityEvent รายการ ใน Android เวอร์ชันก่อนหน้า ข้อมูลที่มีอยู่ในเหตุการณ์การช่วยเหลือพิเศษ ในขณะเดียวกันก็ให้ รายละเอียดเกี่ยวกับการควบคุมอินเทอร์เฟซผู้ใช้ที่ผู้ใช้เลือก เสนอแบบจำกัด ข้อมูลบริบท ในหลายกรณี ข้อมูลบริบทที่ขาดหายไป สำคัญอย่างยิ่งต่อการทำความเข้าใจความหมายของตัวควบคุมที่เลือก

ตัวอย่างอินเทอร์เฟซที่บริบทเป็นสิ่งสําคัญคือปฏิทินหรือวัน เครื่องมือวางแผนประสิทธิภาพ หากผู้ใช้เลือกช่วงเวลา 16:00 น. ในรายการวันจันทร์ถึงศุกร์ และบริการการช่วยเหลือพิเศษประกาศว่า "16:00 น." แต่ไม่ได้ประกาศวันธรรมดา วันของเดือน หรือชื่อเดือน ความคิดเห็นที่ได้คือ ทำให้เกิดความสับสน ในกรณีนี้ บริบทของการควบคุมอินเทอร์เฟซผู้ใช้จะมีความสำคัญอย่างยิ่ง ผู้ใช้ที่ต้องการกำหนดเวลาการประชุม

ตั้งแต่ปี 2011 เป็นต้นมา Android ได้ขยายขอบเขตของข้อมูลที่ บริการการช่วยเหลือพิเศษสามารถรับข้อมูลเกี่ยวกับการโต้ตอบกับอินเทอร์เฟซผู้ใช้ได้โดยการเขียน เหตุการณ์การช่วยเหลือพิเศษตามลำดับชั้นการดู ลำดับชั้นการดูคือชุดของ คอมโพเนนต์อินเทอร์เฟซผู้ใช้ที่มีคอมโพเนนต์ (คอมโพเนนต์หลัก) และผู้ใช้ องค์ประกอบของอินเทอร์เฟซที่อาจอยู่ภายในคอมโพเนนต์นั้น (องค์ประกอบย่อย) ใน ด้วยวิธีนี้ Android จะสามารถแสดงรายละเอียดเกี่ยวกับกิจกรรมการเข้าถึงที่ครบถ้วนยิ่งขึ้น ซึ่งช่วยให้ บริการการช่วยเหลือพิเศษจะให้ความคิดเห็นที่เป็นประโยชน์มากขึ้นแก่ผู้ใช้

บริการการช่วยเหลือพิเศษจะได้รับข้อมูลเกี่ยวกับเหตุการณ์อินเทอร์เฟซผู้ใช้ผ่าน AccessibilityEvent ที่ระบบส่งไปยังบริการของ เมธอด Callback onAccessibilityEvent() รายการ ออบเจ็กต์นี้ให้รายละเอียดเกี่ยวกับ รวมถึงประเภทของออบเจ็กต์ที่มีการดำเนินการ ข้อความอธิบาย และ รายละเอียดอื่นๆ

  • AccessibilityEvent.getRecordCount() และ getRecord(int): วิธีการเหล่านี้จะช่วยให้คุณสามารถดึงชุด AccessibilityRecord ที่มีส่วนให้ข้อมูล AccessibilityEvent ที่ส่งให้คุณโดย ระบบ รายละเอียดระดับนี้จะให้บริบทเพิ่มเติมเกี่ยวกับเหตุการณ์ที่ เรียกใช้บริการการช่วยเหลือพิเศษ

  • AccessibilityRecord.getSource(): เมธอดนี้จะแสดงผลออบเจ็กต์ AccessibilityNodeInfo ออบเจ็กต์นี้ช่วยให้คุณ ขอลำดับชั้นเลย์เอาต์การดู (หลักและย่อย) ของคอมโพเนนต์ที่ จะเริ่มต้นเหตุการณ์การช่วยเหลือพิเศษ ฟีเจอร์นี้ช่วยให้การช่วยเหลือพิเศษ จะตรวจสอบบริบททั้งหมดของกิจกรรม รวมถึงเนื้อหาและ สถานะของมุมมองใดๆ ที่แนบมาหรือการดูของเด็ก

แพลตฟอร์ม Android ช่วยให้ AccessibilityService ทำการค้นหาได้ ลำดับชั้นการดู โดยรวบรวมข้อมูลเกี่ยวกับคอมโพเนนต์ UI ที่สร้าง รวมถึงผู้ปกครองและบุตรหลาน โดยให้กำหนดบรรทัดต่อไปนี้ ในการกำหนดค่า XML ของคุณ:

android:canRetrieveWindowContent="true"

เมื่อเสร็จแล้ว รับออบเจ็กต์ AccessibilityNodeInfo โดยใช้ getSource() การเรียกนี้จะส่งคืนอ็อบเจกต์ก็ต่อเมื่อหน้าต่างที่เกิดเหตุการณ์เกิดขึ้นคือ จะยังคงเป็นหน้าต่างที่ใช้งานอยู่ หากไม่ จะแสดงเป็นค่า Null ดังนั้นโปรดดำเนินการตามความเหมาะสม

ในตัวอย่างต่อไปนี้ โค้ดจะดำเนินการต่อไปนี้เมื่อได้รับเหตุการณ์

  1. ดึงมุมมองระดับบนสุดของตำแหน่งที่เกิดเหตุการณ์ขึ้นทันที
  2. ในมุมมองดังกล่าว ให้มองหาป้ายกำกับและช่องทำเครื่องหมายเมื่อเป็นมุมมองย่อย
  3. หากพบเจอผู้ใช้ ให้สร้างสตริงที่จะรายงานไปยังผู้ใช้ ซึ่งระบุถึง ว่ามีการตรวจสอบหรือไม่

หากมีการส่งคืนค่าว่าง ณ จุดใดก็ตามขณะข้ามลำดับชั้นการแสดงผล แต่วิธีนี้ก็ยอมแพ้อย่างเงียบๆ

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

ตอนนี้คุณมีบริการการช่วยเหลือพิเศษที่ใช้งานได้เต็มรูปแบบแล้ว ลองกำหนดค่าวิธี แอปโต้ตอบกับผู้ใช้ด้วยการเพิ่มการอ่านออกเสียงข้อความ" ของ Android เครื่องมือ หรือใช้ Vibrator เพื่อการตอบสนองแบบรู้สึกได้ ความคิดเห็น

ประมวลผลข้อความ

อุปกรณ์ที่ใช้ Android 8.0 (API ระดับ 26) ขึ้นไปจะมีส่วนประกอบหลายอย่าง การประมวลผลข้อความ ซึ่งช่วยให้บริการ การเข้าถึงต่างๆ ทำได้ง่ายขึ้น ระบุและดำเนินการในหน่วยข้อความเฉพาะที่ปรากฏบนหน้าจอ

เคล็ดลับเครื่องมือ

Android 9 (API ระดับ 28) มาพร้อมกับความสามารถหลายอย่างที่ช่วยให้คุณเข้าถึง เคล็ดลับเครื่องมือใน UI ของแอป ใช้ getTooltipText() เพื่ออ่านข้อความของเคล็ดลับเครื่องมือ และใช้ ACTION_SHOW_TOOLTIP และ ACTION_HIDE_TOOLTIP เพื่อสั่งให้อินสแตนซ์ View แสดงหรือซ่อนเคล็ดลับเครื่องมือ

ข้อความคำใบ้

ตั้งแต่ปี 2017 เป็นต้นไป Android มีวิธีโต้ตอบกับ ข้อความแนะนำของออบเจ็กต์แบบข้อความ:

  • isShowingHintText() และ setShowingHintText() ระบุและตั้งค่าตามลำดับว่าข้อความปัจจุบันของโหนดหรือไม่ content จะแสดงข้อความแนะนำของโหนด
  • getHintText() ให้การเข้าถึงข้อความแนะนำ แม้ว่าวัตถุจะไม่แสดง ข้อความบอกใบ้ การเรียก getHintText() สำเร็จแล้ว

ตำแหน่งของอักขระบนหน้าจอ

สำหรับอุปกรณ์ที่ใช้ Android 8.0 (API ระดับ 26) ขึ้นไป บริการการช่วยเหลือพิเศษ สามารถระบุพิกัดหน้าจอสำหรับกรอบล้อมรอบของอักขระที่ปรากฏแต่ละตัว ภายในวิดเจ็ต TextView บริการต่างๆ ค้นหาพิกัดเหล่านี้ได้โดยโทร refreshWithExtraData() กำลังผ่านใน EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY เป็นอาร์กิวเมนต์แรกและออบเจ็กต์ Bundle เป็นอาร์กิวเมนต์ที่ 2 ขณะที่เมธอดดำเนินการ ระบบจะป้อนข้อมูล อาร์กิวเมนต์ Bundle ที่มีอาร์เรย์แบบพาร์เซลของ ออบเจ็กต์ Rect รายการ ออบเจ็กต์ Rect แต่ละรายการ หมายถึงกรอบล้อมรอบของอักขระหนึ่งๆ

ค่าของช่วงด้านเดียวที่เป็นมาตรฐาน

ออบเจ็กต์ AccessibilityNodeInfo บางรายการใช้อินสแตนซ์ของ AccessibilityNodeInfo.RangeInfo เพื่อระบุว่าองค์ประกอบ UI สามารถรับช่วงของค่าได้ เมื่อสร้าง ช่วงโดยใช้ RangeInfo.obtain() หรือเมื่อดึงค่าที่สูงมากของช่วงโดยใช้ getMin() และ getMax(), โปรดทราบว่าอุปกรณ์ที่ใช้ Android 8.0 (API ระดับ 26) ขึ้นไป ช่วงด้านเดียวในลักษณะมาตรฐาน:

  • สำหรับช่วงที่ไม่มีค่าขั้นต่ำ Float.NEGATIVE_INFINITY แสดงถึงค่าต่ำสุด
  • สำหรับช่วงที่ไม่มีขีดจำกัดสูงสุด Float.POSITIVE_INFINITY แสดงค่าสูงสุด

ตอบกลับกิจกรรมการช่วยเหลือพิเศษ

เมื่อตั้งค่าบริการเพื่อเรียกใช้และรอเหตุการณ์แล้ว ให้เขียนโค้ดเพื่อเขียน รู้ว่าต้องทำอะไรเมื่อ AccessibilityEvent มาถึง เริ่มต้นด้วยการลบล้าง onAccessibilityEvent(AccessibilityEvent) ในวิธีการดังกล่าว ให้ใช้ getEventType() เพื่อกำหนดประเภทของเหตุการณ์และ getContentDescription() เพื่อดึงข้อความป้ายกํากับที่เชื่อมโยงกับมุมมองที่ทําให้เหตุการณ์เริ่มทํางาน

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

แหล่งข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมได้ในแหล่งข้อมูลต่อไปนี้

เส้นนำ

Codelab