แนวคิดและการใช้งาน Jetpack Compose
บริการการช่วยเหลือพิเศษคือแอปที่ปรับปรุงอินเทอร์เฟซผู้ใช้เพื่อช่วยเหลือ ผู้ใช้ที่มีความบกพร่องหรือผู้ที่อาจไม่สามารถโต้ตอบกับอุปกรณ์ได้อย่างเต็มที่ เป็นการชั่วคราว เช่น ผู้ใช้ที่ขับรถ ดูแลเด็กเล็ก หรือเข้าร่วมปาร์ตี้ที่มีเสียงดังมากอาจต้องการความคิดเห็นเพิ่มเติมหรือทางเลือกอื่น เกี่ยวกับอินเทอร์เฟซ
Android มีบริการการช่วยเหลือพิเศษมาตรฐาน ซึ่งรวมถึง TalkBack และ นักพัฒนาแอปสามารถสร้างและเผยแพร่บริการของตนเองได้ เอกสารนี้อธิบาย พื้นฐานของการสร้างบริการการช่วยเหลือพิเศษ
คุณสามารถรวมบริการการช่วยเหลือพิเศษไว้กับแอปปกติหรือสร้างเป็น โปรเจ็กต์ Android แบบสแตนด์อโลนก็ได้ ขั้นตอนในการสร้างบริการจะเหมือนกันในทั้ง 2 กรณี
สร้างบริการการช่วยเหลือพิเศษ
สร้างคลาสที่ขยาย 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 ที่ใช้ในไฟล์การกำหนดค่าบริการการช่วยเหลือพิเศษได้ที่เอกสารอ้างอิงต่อไปนี้
android:descriptionandroid:packageNamesandroid:accessibilityEventTypesandroid:accessibilityFlagsandroid:accessibilityFeedbackTypeandroid:notificationTimeoutandroid:canRetrieveWindowContentandroid:settingsActivity
ดูข้อมูลเพิ่มเติมเกี่ยวกับการตั้งค่าการกำหนดค่าที่ตั้งค่าแบบไดนามิกได้
ในรันไทม์ได้ที่เอกสารอ้างอิงของ 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ที่เชื่อมโยงมาด้วย ซึ่งบริการจะ ตีความและใช้เพื่อแสดงความคิดเห็นแก่ผู้ใช้ได้ เรียกใช้เมธอดนี้ได้หลายครั้งตลอดวงจรของบริการonInterrupt(): (ต้องระบุ) ระบบจะเรียกใช้เมธอดนี้เมื่อระบบ ต้องการขัดจังหวะความคิดเห็นที่บริการของคุณแสดง โดยปกติจะเป็น การตอบสนองต่อการกระทำของผู้ใช้ เช่น การย้ายโฟกัสไปยังตัวควบคุมอื่น คุณเรียกใช้เมธอดนี้ได้หลายครั้งตลอดวงจรของบริการonUnbind(): (ไม่บังคับ) ระบบจะเรียกใช้เมธอดนี้เมื่อระบบกำลังจะปิดบริการการช่วยเหลือพิเศษ ใช้วิธีนี้เพื่อดำเนินการตามขั้นตอนการปิดระบบแบบครั้งเดียว ซึ่งรวมถึงการยกเลิกการจัดสรรบริการระบบความคิดเห็นของผู้ใช้ เช่น ตัวจัดการเสียงหรือเครื่องสั่นของอุปกรณ์
วิธีการเรียกกลับเหล่านี้มีโครงสร้างพื้นฐานสำหรับบริการการช่วยเหลือพิเศษ
คุณเลือกวิธีประมวลผลข้อมูลที่ระบบ 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 จากนั้นบริการจะลงทะเบียนฟังก์ชันเรียกกลับได้โดยใช้
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) ขึ้นไป สามารถตอบสนองต่อการปัดตามทิศทาง (ขึ้น ลง ซ้าย และขวา) ตามเซ็นเซอร์ลายนิ้วมือของอุปกรณ์ หากต้องการกำหนดค่าบริการให้รับการเรียกกลับเกี่ยวกับการโต้ตอบเหล่านี้ ให้ทำตามลำดับต่อไปนี้
- ประกาศสิทธิ์
USE_BIOMETRICและความสามารถCAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES - ตั้งค่าสถานะ
FLAG_REQUEST_FINGERPRINT_GESTURESภายในแอตทริบิวต์android:accessibilityFlags - ลงทะเบียนรับสายโทรกลับโดยใช้
registerFingerprintGestureCallback())
โปรดทราบว่าอุปกรณ์บางรุ่นไม่มีเซ็นเซอร์ลายนิ้วมือ หากต้องการระบุว่าอุปกรณ์รองรับเซ็นเซอร์หรือไม่ ให้ใช้วิธี isHardwareDetected()
แม้ในอุปกรณ์ที่มีเซ็นเซอร์ลายนิ้วมือ บริการของคุณก็ไม่สามารถ
ใช้เซ็นเซอร์ดังกล่าวเมื่อมีการใช้เพื่อวัตถุประสงค์ในการตรวจสอบสิทธิ์ หากต้องการระบุเวลาที่เซ็นเซอร์พร้อมใช้งาน ให้เรียกใช้เมธอด isGestureDetectionAvailable()
และใช้การเรียกกลับ onGestureDetectionAvailabilityChanged()
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างการใช้ท่าทางสัมผัสด้วยลายนิ้วมือเพื่อ ไปยังส่วนต่างๆ ของกระดานเกมเสมือน
// 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; } ... }
หลังจากที่บริการของคุณขอเปิดใช้งานฟีเจอร์แตะเพื่อสำรวจแล้ว ผู้ใช้ต้องอนุญาตให้เปิดฟีเจอร์นี้ หากยังไม่ได้เปิดใช้งาน เมื่อฟีเจอร์นี้ ทำงานอยู่ บริการของคุณจะได้รับการแจ้งเตือนเกี่ยวกับท่าทางสัมผัสเพื่อการช่วยเหลือพิเศษผ่านเมธอด Callback onGesture() ของบริการ และสามารถตอบสนองโดยดำเนินการในนามของผู้ใช้ได้
ท่าทางสัมผัสต่อเนื่อง
อุปกรณ์ที่ใช้ Android 8.0 (ระดับ API 26) ขึ้นไปรองรับท่าทางสัมผัสต่อเนื่องหรือท่าทางสัมผัสแบบเป็นโปรแกรมที่มีออบเจ็กต์ Path มากกว่า 1 รายการ
เมื่อระบุลำดับการลาก คุณจะระบุได้ว่าการลากเหล่านั้นเป็นท่าทางสัมผัสแบบเป็นโปรแกรมเดียวกันโดยใช้อาร์กิวเมนต์สุดท้าย 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 ดังนั้นให้ดำเนินการตามนั้น
ในตัวอย่างต่อไปนี้ โค้ดจะทําสิ่งต่อไปนี้เมื่อได้รับเหตุการณ์
- รับองค์ประกอบหลักของมุมมองที่เกิดเหตุการณ์ขึ้นทันที
- ในมุมมองนั้น ให้มองหาป้ายกำกับและช่องทำเครื่องหมายเป็นมุมมองย่อย
- หากพบ ระบบจะสร้างสตริงเพื่อรายงานให้ผู้ใช้ทราบ โดยระบุป้ายกำกับและระบุว่ามีการตรวจสอบหรือไม่
หากมีการส่งคืนค่า Null ในขณะที่ข้ามผ่านลำดับชั้นการแสดงผล เมธอดจะหยุดทำงานโดยไม่มีการแจ้งเตือน
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()จะระบุและตั้งค่าตามลำดับว่าเนื้อหาข้อความปัจจุบันของโหนด แสดงข้อความคำแนะนำของโหนดหรือไม่ getHintText()ให้สิทธิ์เข้าถึงข้อความคำใบ้ แม้ว่าออบเจ็กต์จะไม่แสดงข้อความคำแนะนำ แต่การเรียกใช้getHintText()จะสำเร็จ
ตำแหน่งของอักขระข้อความบนหน้าจอ
ในอุปกรณ์ที่ใช้ Android 8.0 (ระดับ API 26) ขึ้นไป บริการการช่วยเหลือพิเศษจะกำหนดพิกัดหน้าจอสำหรับกล่องขอบเขตของอักขระที่มองเห็นได้แต่ละตัวภายในวิดเจ็ต TextView ได้ บริการจะค้นหาพิกัดเหล่านี้โดยการเรียกใช้
refreshWithExtraData() โดยส่ง
EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY เป็นอาร์กิวเมนต์แรกและออบเจ็กต์
Bundle เป็นอาร์กิวเมนต์ที่สอง ขณะที่เมธอดทำงาน ระบบจะ
ป้อนข้อมูลอาร์กิวเมนต์ 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); ... }
แหล่งข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมได้ที่แหล่งข้อมูลต่อไปนี้