سرویس دسترس‌پذیری خودتان را ایجاد کنید (نماها)

مفاهیم و پیاده‌سازی Jetpack Compose

سرویس دسترس‌پذیری برنامه‌ای است که میانای کاربر را برای کمک به کاربران دارای ناتوانی یا کاربرانی که ممکن است به‌طور موقت نتوانند به‌طور کامل با دستگاه تعامل داشته باشند بهبود می‌بخشد. برای مثال، کاربرانی که درحال رانندگی هستند، از کودک خردسالی مراقبت می‌کنند، یا در مهمانی بسیار پرسروصدایی حضور دارند ممکن است به بازخورد واسط اضافی یا جایگزین نیاز داشته باشند.

Android سرویس‌های دسترس‌پذیری استانداردی ازجمله TalkBack ارائه می‌دهد و توسعه‌دهندگان می‌توانند سرویس‌های خودشان را ایجاد و توزیع کنند. این سند اصول اولیه ساختن سرویس دسترس‌پذیری را توضیح می‌دهد.

سرویس دسترس‌پذیری را می‌توان با یک برنامه عادی همراه کرد یا به‌عنوان یک پروژه Android مستقل ایجاد کرد. مراحل ایجاد سرویس در هر دو وضعیت یکسان است.

ایجاد سرویس دسترس‌پذیری

در پروژه‌تان، کلاسی ایجاد کنید که AccessibilityService را گسترش دهد:

کاتلین

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?) {}
...
}

جاوا

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 را از منبعتان بردارید.

اظهارنامه‌ها و اجازه‌های مانیفست

برنامه‌هایی که خدمات دسترس‌پذیری ارائه می‌دهند باید اظهارنامه‌های خاصی را در مانیفست برنامه خود بگنجانند تا سیستم Android آن‌ها را به‌عنوان خدمات دسترس‌پذیری درنظر بگیرد. این بخش تنظیمات الزامی و اختیاری را برای سرویس‌های دسترس‌پذیری توضیح می‌دهد.

اظهارنامه خدمات دسترس‌پذیری

برای اینکه با برنامه شما به‌عنوان سرویس دسترس‌پذیری رفتار شود، به‌جای عنصر activity، عنصر service را در عنصر application در مانیفست خود اضافه کنید. به‌علاوه، در عنصر service، فیلتر قصد سرویس دسترس‌پذیری را اضافه کنید. مانیفست باید با افزودن اجازه 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> را در مانیفست خود با ارجاع به فایل پیکربندی اضافه کنید، که به شما امکان می‌دهد طیف کاملی از گزینه‌ها را برای سرویس دسترس‌پذیری خود تنظیم کنید، همان‌طور که در مثال زیر نشان داده شده است:

<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 مراجعه کنید.

پیکربندی سرویس دسترس‌پذیری

هنگام تنظیم متغیرهای پیکربندی برای سرویس دسترس‌پذیری خود، موارد زیر را درنظر بگیرید تا به سیستم بگویید چگونه و چه زمانی اجرا شود:

  • می‌خواهید به کدام نوع رویدادها پاسخ دهد؟
  • آیا این سرویس باید برای همه برنامه‌ها فعال باشد یا فقط برای نام‌های بسته خاص؟
  • از چه نوع بازخوردهای متفاوتی استفاده می‌کند؟

دو گزینه برای تنظیم این متغیرها دارید. گزینه سازگار با نسخه قدیمی این است که آن‌ها را در کد، بااستفاده از setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo) تنظیم کنید. برای انجام این کار، روش onServiceConnected() را لغو کنید و سرویس خود را در آنجا پیکربندی کنید، همان‌طور که در مثال زیر نشان داده شده است:

کاتلین

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

}

جاوا

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

}

گزینه دوم پیکربندی سرویس بااستفاده از فایل 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 استفاده می‌کنید، با افزودن برچسب <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 تنظیم کنید.

هنگام راه‌اندازی سرویس دسترس‌پذیری، با دقت بررسی کنید که سرویس شما چه رویدادهایی را می‌تواند مدیریت کند و فقط برای آن رویدادها ثبت‌نام کنید. ازآنجایی‌که کاربران می‌توانند بیش‌از یک سرویس دسترس‌پذیری را به‌طور هم‌زمان فعال کنند، سرویس شما نباید رویدادهایی را که نمی‌تواند مدیریت کند مصرف کند. به‌خاطر داشته باشید که سرویس‌های دیگر ممکن است آن رویدادها را برای بهبود تجربه کاربری مدیریت کنند.

میزان دسترس‌پذیری

دستگاه‌هایی که Android نسخه ۸.۰ (سطح میانای برنامه‌سازی کاربردی ۲۶) و بالاتر را اجرا می‌کنند، شامل دسته میزان صدای STREAM_ACCESSIBILITY هستند که به شما امکان می‌دهد میزان صدای خروجی صوتی سرویس دسترس‌پذیری را مستقل از سایر صداهای دستگاه کنترل کنید.

سرویس‌های دسترس‌پذیری می‌توانند با تنظیم گزینه FLAG_ENABLE_ACCESSIBILITY_VOLUME از این نوع جاری‌سازی استفاده کنند. سپس می‌توانید با فراخوانی روش adjustStreamVolume() در نمونه AudioManager دستگاه، میزان صدای دسترس‌پذیری دستگاه را تغییر دهید.

تکه‌کد زیر نشان می‌دهد که چگونه سرویس دسترس‌پذیری می‌تواند از دسته میزان صدای STREAM_ACCESSIBILITY استفاده کند:

کاتلین

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

جاوا

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 را از دقیقه ۶:۳۵ ببینید.

میان‌برهای دسترس‌پذیری

در دستگاه‌هایی که Android نسخه ۸.۰ (سطح میانای برنامه‌سازی کاربردی ۲۶) و بالاتر دارند، کاربران می‌توانند با فشار دادن و نگه داشتن هم‌زمان هر دو کلید میزان صدا، سرویس دسترس‌پذیری دلخواهشان را از هر صفحه‌ای فعال و غیرفعال کنند. اگرچه این میان‌بر به‌طور پیش‌فرض Talkback را فعال و غیرفعال می‌کند، کاربران می‌توانند این دکمه را برای فعال و غیرفعال کردن هر سرویسی که در دستگاهشان نصب شده است پیکربندی کنند.

برای اینکه کاربران بتوانند از میان‌بر دسترس‌پذیری به سرویس دسترس‌پذیری خاصی دسترسی پیدا کنند، سرویس باید این ویژگی را در زمان اجرا درخواست کند.

برای اطلاعات بیشتر، ویدیو جلسه تازه‌ها در دسترس‌پذیری Android از Google I/O 2017 را از دقیقه ۱۳:۲۵ ببینید.

دکمه دسترس‌پذیری

در دستگاه‌هایی که از ناحیه پیمایش نرم‌افزار-پردازش‌شده استفاده می‌کنند و Android نسخه ۸.۰ (سطح میانای برنامه‌سازی کاربردی ۲۶) و بالاتر دارند، سمت راست نوار پیمایش شامل دکمه دسترس‌پذیری است. وقتی کاربران این دکمه را فشار می‌دهند، می‌توانند یکی از چندین ویژگی و سرویس دسترس‌پذیری فعال‌شده را، بسته به محتوایی که درحال‌حاضر در صفحه نشان داده می‌شود، فراخوانی کنند.

برای اینکه کاربران بتوانند بااستفاده از دکمه دسترس‌پذیری، سرویس دسترس‌پذیری خاصی را فراخوانی کنند، سرویس باید پرچم FLAG_REQUEST_ACCESSIBILITY_BUTTON را در ویژگی android:accessibilityFlags شیء AccessibilityServiceInfo اضافه کند. سپس سرویس می‌تواند بااستفاده از registerAccessibilityButtonCallback()، تماس‌های برگشتی را ثبت کند.

تکه‌کد زیر نشان می‌دهد که چگونه می‌توانید سرویس دسترس‌پذیری را پیکربندی کنید تا به فشار دادن دکمه دسترس‌پذیری توسط کاربر پاسخ دهد:

کاتلین

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

جاوا

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 را ببینید که از دقیقه ۱۶:۲۸ شروع می‌شود.

اشاره‌های اثر انگشت

سرویس‌های دسترس‌پذیری در دستگاه‌هایی که Android نسخه ۸.۰ (سطح میانای برنامه‌سازی کاربردی ۲۶) و بالاتر دارند می‌توانند به تند کشیدن‌های جهتی (بالا، پایین، چپ، و راست) درطول حسگر اثر انگشت دستگاه پاسخ دهند. برای پیکربندی سرویسی جهت دریافت تماس‌های برگشتی درباره این تعاملات، توالی زیر را تکمیل کنید:

  1. اجازه USE_BIOMETRIC و قابلیت CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES را اعلام کنید.
  2. پرچم FLAG_REQUEST_FINGERPRINT_GESTURES را در مشخصه android:accessibilityFlags تنظیم کنید.
  3. بااستفاده از 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"
    ... />

کاتلین

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

جاوا

// 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‏ ۲۶) به بعد، سرویس نوشتار به گفتار (TTS) در Android می‌تواند عبارت‌ها را به چندین زبان در یک بلوک نوشتاری شناسایی کند و بخواند. برای فعال کردن این قابلیت تعویض خودکار زبان در سرویس دسترس‌پذیری، همه رشته‌ها را در اشیاء LocaleSpan قرار دهید، همان‌طور که در تکه‌کد زیر نشان داده شده است:

کاتلین

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

جاوا

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 را از دقیقه ۱۰:۵۹ ببینید.

اقدام ازطرف کاربران

از سال ۲۰۱۱، سرویس‌های دسترس‌پذیری می‌توانند ازطرف کاربران اقدام کنند، ازجمله تغییر تمرکز ورودی و انتخاب (فعال کردن) عناصر میانای کاربر. در سال ۲۰۱۲، دامنه کنش‌ها گسترش یافت و پیمایش فهرست‌ها و تعامل با فیلدهای نوشتاری را نیز دربرگرفت. سرویس‌های دسترس‌پذیری می‌توانند کنش‌های عمومی نیز انجام دهند، مثلاً پیمایش به صفحه اصلی، فشار دادن دکمه «برگشت»، و باز کردن صفحه اعلان‌ها و فهرست برنامه‌های اخیر. از سال ۲۰۱۲، Android شامل تمرکز دسترس‌پذیری است که باعث می‌شود همه عناصر قابل‌مشاهده توسط سرویس دسترس‌پذیری قابل‌انتخاب باشند.

این قابلیت‌ها به توسعه‌دهندگان سرویس‌های دسترس‌پذیری امکان می‌دهد حالت‌های ناوبری جایگزین، مثل ناوبری اشاره‌ای، ایجاد کنند و به کاربران دارای ناتوانی امکان می‌دهد کنترل بهتری بر دستگاه‌های مجهز به Android خود داشته باشند.

گوش دادن به اشاره‌ها

سرویس‌های دسترس‌پذیری می‌توانند به اشاره‌های خاص گوش دهند و با اقدام کردن ازطرف کاربر، پاسخ دهند. این ویژگی مستلزم آن است که سرویس دسترس‌پذیری شما فعال‌سازی ویژگی «کاوش با لمس» را درخواست کند. سرویس شما می‌تواند این فعال‌سازی را با تنظیم عضو flags نمونه AccessibilityServiceInfoسرویس روی FLAG_REQUEST_TOUCH_EXPLORATION_MODE درخواست کند، همان‌طور که در مثال زیر نشان داده شده است.

کاتلین

class MyAccessibilityService : AccessibilityService() {

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

جاوا

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

پس‌از اینکه سرویس شما فعال‌سازی «کاوش با لمس» را درخواست کرد، کاربر باید اجازه دهد این ویژگی روشن شود، اگر قبلاً فعال نشده باشد. وقتی این ویژگی فعال باشد، سرویس شما ازطریق روش بازخوانی onGesture() سرویس شما، اعلان اشاره‌های دسترس‌پذیری را دریافت می‌کند و می‌تواند با اقدام ازطرف کاربر پاسخ دهد.

اشاره‌های ادامه‌دار

دستگاه‌های دارای Android نسخه ۸.۰ (سطح میانای برنامه‌سازی کاربردی ۲۶) و بالاتر از اشاره‌های ادامه‌دار یا اشاره‌های برنامه‌نویسی‌شده حاوی بیش‌از یک شیء Path پشتیبانی می‌کنند.

هنگام مشخص کردن توالی ضربه‌ها، می‌توانید بااستفاده از آرگومان نهایی willContinue در سازنده GestureDescription.StrokeDescription مشخص کنید که آن‌ها به یک اشاره برنامه‌ای تعلق دارند، همان‌طور که در قطعه کد زیر نشان داده شده است:

کاتلین

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

جاوا

// 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 را ببینید، که از دقیقه ۱۵:۴۷ شروع می‌شود.

استفاده از کنش‌های دسترس‌پذیری

سرویس‌های دسترس‌پذیری می‌توانند ازطرف کاربران اقدام کنند تا تعامل با برنامه‌ها را ساده‌تر کنند و بهره‌وری را افزایش دهند. توانایی سرویس‌های دسترس‌پذیری برای انجام کنش‌ها در سال ۲۰۱۱ اضافه شد و در سال ۲۰۱۲ به‌طور قابل‌توجهی گسترش یافت.

برای اقدام ازطرف کاربران، سرویس دسترس‌پذیری شما باید ثبت‌نام کند تا رویدادها را از برنامه‌ها دریافت کند و با تنظیم android:canRetrieveWindowContent روی true در فایل پیکربندی سرویس، اجازه مشاهده محتوای برنامه‌ها را درخواست کند. وقتی رویدادها توسط سرویس شما دریافت می‌شود، سپس می‌تواند شیء AccessibilityNodeInfo را بااستفاده از getSource() از رویداد بازیابی کند. با شیء AccessibilityNodeInfo، سرویس شما می‌تواند سلسله‌مراتب نما را کاوش کند تا تعیین کند چه کنشی باید انجام شود و سپس بااستفاده از performAction() ازطرف کاربر اقدام کند.

کاتلین

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

جاوا

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() استفاده کنید.

استفاده از انواع تمرکز

در سال ۲۰۱۲، Android یک تمرکز واسط کاربر به‌نام تمرکز دسترس‌پذیری معرفی کرد. سرویس‌های دسترس‌پذیری می‌توانند از این تمرکز برای انتخاب هر عنصر میانای کاربر قابل‌مشاهده و اقدام روی آن استفاده کنند. این نوع تمرکز با تمرکز ورودی متفاوت است، که تعیین می‌کند وقتی کاربر نویسه تایپ می‌کند، کلید Enter را روی صفحه‌کلید فشار می‌دهد، یا دکمه مرکزی پد کنترل را فشار می‌دهد، کدام عنصر میانای کاربر روی صفحه ورودی را دریافت می‌کند.

ممکن است یک عنصر در واسط کاربر دارای تمرکز ورودی باشد درحالی‌که عنصر دیگری دارای تمرکز دسترس‌پذیری باشد. هدف از تمرکز دسترس‌پذیری این است که روشی برای تعامل با عناصر قابل‌مشاهده در صفحه‌نمایش برای سرویس‌های دسترس‌پذیری فراهم شود، صرف‌نظر از اینکه عنصر از دیدگاه سیستم قابل‌تمرکز ورودی باشد یا نه. برای کمک به اطمینان از اینکه سرویس دسترس‌پذیری شما به‌درستی با عناصر ورودی برنامه‌ها تعامل دارد، دستورالعمل‌های آزمایش دسترس‌پذیری برنامه را دنبال کنید تا سرویس خود را هنگام استفاده از یک برنامه معمولی آزمایش کنید.

سرویس دسترس‌پذیری می‌تواند بااستفاده از روش AccessibilityNodeInfo.findFocus() تعیین کند کدام عنصر میانای کاربر دارای تمرکز ورودی یا تمرکز دسترس‌پذیری است. همچنین می‌توانید عناصری را که می‌توانند با تمرکز ورودی انتخاب شوند بااستفاده از روش focusSearch() جستجو کنید. درنهایت، سرویس دسترس‌پذیری شما می‌تواند بااستفاده از روش performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS) تمرکز دسترس‌پذیری را تنظیم کند.

جمع‌آوری اطلاعات

سرویس‌های دسترس‌پذیری روش‌های استانداردی برای جمع‌آوری و نمایش واحدهای کلیدی اطلاعات ارائه‌شده توسط کاربر دارند، مانند جزئیات رویداد، نوشتار، و اعداد.

دریافت جزئیات تغییر پنجره

Android نسخه ۹ (سطح میانای برنامه‌سازی کاربردی ۲۸) و بالاتر به برنامه‌ها اجازه می‌دهد به‌روزرسانی‌های پنجره را زمانی‌که برنامه چندین پنجره را به‌طور هم‌زمان بازترسیم می‌کند ردیابی کنند. وقتی رویداد TYPE_WINDOWS_CHANGED رخ می‌دهد، از getWindowChanges() API برای تعیین نحوه تغییر پنجره‌ها استفاده کنید. درطول به‌روزرسانی چندپنجره‌ای، هر پنجره مجموعه رویدادهای خودش را تولید می‌کند. روش getSource() نمای ریشه پنجره مرتبط با هر رویداد را برمی‌گرداند.

اگر برنامه‌ای عنوان‌های قاب دسترس‌پذیری را برای اشیاء View خود تعریف کند، سرویس شما می‌تواند زمان به‌روزرسانی واسط کاربر برنامه را تشخیص دهد. وقتی رویداد TYPE_WINDOW_STATE_CHANGED رخ می‌دهد، از انواع برگردانده‌شده توسط getContentChangeTypes() برای تعیین نحوه تغییر پنجره استفاده کنید. برای مثال، چارچوب می‌تواند تشخیص دهد که قاب عنوان جدیدی دارد یا قاب ناپدید شده است.

دریافت جزئیات رویداد

Android ازطریق اشیاء AccessibilityEvent اطلاعاتی درباره تعامل میانای کاربر به سرویس‌های دسترس‌پذیری ارائه می‌دهد. در نسخه‌های قبلی Android، اطلاعات موجود در رویداد دسترس‌پذیری، ضمن ارائه جزئیات قابل‌توجه درباره کنترل میانای کاربر که توسط کاربران انتخاب شده است، اطلاعات زمینه‌ای محدودی ارائه می‌داد. در بسیاری از موارد، این اطلاعات بافت گم‌شده ممکن است برای درک معنی کنترل انتخاب‌شده حیاتی باشد.

نمونه‌ای از واسطی که بافت در آن بسیار مهم است، تقویم یا برنامه‌ریز روزانه است. اگر کاربر بازه زمانی ۴:۰۰ بعدازظهر را در فهرست روزهای دوشنبه تا جمعه انتخاب کند و سرویس دسترس‌پذیری «۴ بعدازظهر» را اعلام کند، اما نام روز هفته، روز ماه، یا نام ماه را اعلام نکند، بازخورد حاصل گیج‌کننده خواهد بود. در این مورد، بافت کنترل واسط کاربر برای کاربری که می‌خواهد جلسه‌ای را زمان‌بندی کند بسیار مهم است.

از سال ۲۰۱۱، Android با ترکیب کردن رویدادهای دسترس‌پذیری براساس سلسله‌مراتب نما، میزان اطلاعاتی را که سرویس دسترس‌پذیری می‌تواند درباره تعامل میانای کاربر به‌دست آورد به‌طور قابل‌توجهی گسترش می‌دهد. سلسله‌مراتب نما مجموعه‌ای از مؤلفه‌های میانای کاربر است که حاوی مؤلفه (والدین آن) و عناصر میانای کاربر است که ممکن است در آن مؤلفه (فرزندان آن) وجود داشته باشد. به این ترتیب، Android می‌تواند جزئیات غنی‌تری درباره رویدادهای دسترس‌پذیری ارائه دهد و به سرویس‌های دسترس‌پذیری اجازه دهد بازخورد مفیدتری به کاربران ارائه دهند.

سرویس دسترس‌پذیری اطلاعات مربوط به رویداد میانای کاربر را ازطریق AccessibilityEvent که سیستم به روش فراخوانی برگشتی onAccessibilityEvent() سرویس ارسال کرده است دریافت می‌کند. این شیء جزئیاتی درباره رویداد ارائه می‌دهد، ازجمله نوع شیء مورد اقدام، نوشتار توصیفی آن، و جزئیات دیگر.

  • AccessibilityEvent.getRecordCount() و getRecord(int): این روش‌ها به شما امکان می‌دهند مجموعه اشیای AccessibilityRecord را که در AccessibilityEvent ارسال‌شده ازسوی سیستم به شما مشارکت دارند بازیابی کنید. این سطح از جزئیات، بافت بیشتری برای رویدادی که سرویس دسترس‌پذیری شما را راه‌اندازی می‌کند ارائه می‌دهد.

  • AccessibilityRecord.getSource(): این روش یک شیء AccessibilityNodeInfo را برمی‌گرداند. این شیء به شما امکان می‌دهد سلسله‌مراتب چیدمان نمای (والدین و فرزندان) مؤلفه‌ای را که رویداد دسترس‌پذیری از آن منشأ می‌گیرد درخواست کنید. این ویژگی به سرویس دسترس‌پذیری اجازه می‌دهد تا زمینه کامل رویداد را بررسی کند، ازجمله محتوا و وضعیت هرکدام از نماهای محصور یا نماهای فرعی.

پلاتفرم Android این امکان را برای AccessibilityService فراهم می‌کند که سلسله‌مراتب نما را پُرسمان کند و اطلاعات مربوط به مؤلفه واسط کاربری را که رویداد و همچنین والد و فرزندان آن را تولید می‌کند جمع‌آوری کند. برای انجام این کار، خط زیر را در پیکربندی XML خود تنظیم کنید:

android:canRetrieveWindowContent="true"

پس‌از انجام این کار، بااستفاده از getSource()، شیء AccessibilityNodeInfo را دریافت کنید. این فراخوانی فقط درصورتی شیء را برمی‌گرداند که پنجره‌ای که رویداد از آن منشأ می‌گیرد همچنان پنجره فعال باشد. اگر نه، مقدار null را برمی‌گرداند، بنابراین مطابق با آن رفتار کنید.

در مثال زیر، کد هنگام دریافت رویداد کارهای زیر را انجام می‌دهد:

  1. فوراً والد نمایی را که رویداد از آن نشئت گرفته است می‌گیرد.
  2. در آن نما، به‌دنبال برچسب و چارگوش انتخاب به‌عنوان نماهای فرزند می‌گردد.
  3. اگر آن‌ها را پیدا کند، رشته‌ای برای گزارش به کاربر ایجاد می‌کند که برچسب و اینکه آیا علامت زده شده است یا نه را نشان می‌دهد.

اگر در هر نقطه‌ای مقدار تهی درحین پیمایش سلسله‌مراتب نما برگردانده شود، روش بی‌سروصدا متوقف می‌شود.

کاتلین

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

جاوا

// 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 (سطح میانای برنامه‌سازی کاربردی ۲۶) و بالاتر شامل چندین ویژگی پردازش نوشتار هستند که شناسایی و کار کردن با واحدهای نوشتاری خاصی را که در صفحه ظاهر می‌شوند برای سرویس‌های دسترس‌پذیری آسان‌تر می‌کنند.

نکته‌ابزارها

Android 9 (سطح میانای برنامه‌سازی کاربردی ۲۸) چندین قابلیت را معرفی می‌کند که به شما امکان می‌دهد به نکته‌ابزارها در میانای کاربری برنامه دسترسی داشته باشید. از getTooltipText() برای خواندن نوشتار نکته‌ابزار استفاده کنید، و از ACTION_SHOW_TOOLTIP و ACTION_HIDE_TOOLTIP برای دستور دادن به نمونه‌های View برای نمایش یا پنهان کردن نکته‌ابزارهایشان استفاده کنید.

نوشتار راهنمایی

از سال ۲۰۱۷، Android شامل چندین روش برای تعامل با نوشتار راهنمای شیء نوشتارمحور است:

  • روش‌های isShowingHintText() و setShowingHintText() به‌ترتیب نشان می‌دهند و تنظیم می‌کنند که آیا محتوای نوشتاری فعلی گره نوشتار راهنمای گره را نشان می‌دهد یا نه.
  • getHintText() دسترسی به خود نوشتار راهنما را فراهم می‌کند. حتی اگر شیئی نوشتار راهنما را نمایش ندهد، فراخوانی getHintText() موفقیت‌آمیز است.

مکان نویسه‌های نوشتار روی صفحه

در دستگاه‌های دارای Android 8.0 (سطح میانای برنامه‌سازی کاربردی ۲۶) و بالاتر، سرویس‌های دسترس‌پذیری می‌توانند مختصات صفحه را برای کادر محدودکننده هر نویسه قابل‌مشاهده در ابزاره TextView تعیین کنند. سرویس‌ها این مختصات را با فراخوانی refreshWithExtraData()، ارسال EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY به‌عنوان آرگومان اول و یک شیء Bundle به‌عنوان آرگومان دوم پیدا می‌کنند. با اجرای روش، سیستم آرگومان Bundle را با آرایه قابل‌بسته‌بندی از اشیاء Rect پر می‌کند. هر شیء Rect نشان‌دهنده کادر محدودکننده یک نویسه خاص است.

مقادیر محدوده یک‌طرفه استانداردشده

برخی‌از اشیای AccessibilityNodeInfo از نمونه‌ای از AccessibilityNodeInfo.RangeInfo استفاده می‌کنند تا نشان دهند که عنصر میانای کاربر می‌تواند طیفی از مقادیر را داشته باشد. هنگام ایجاد محدوده بااستفاده از RangeInfo.obtain()، یا هنگام بازیابی مقادیر حداکثر و حداقل محدوده بااستفاده از getMin() و getMax()، به‌خاطر داشته باشید که دستگاه‌های دارای Android نسخه ۸.۰ (سطح میانای برنامه‌سازی کاربردی ۲۶) و بالاتر محدوده‌های یک‌طرفه را به‌صورت استاندارد نشان می‌دهند:

  • برای محدوده‌هایی که حداقل ندارند، Float.NEGATIVE_INFINITY نشان‌دهنده حداقل مقدار است.
  • برای محدوده‌هایی که حداکثر ندارند، Float.POSITIVE_INFINITY نشان‌دهنده حداکثر مقدار است.

پاسخ دادن به رویدادهای دسترس‌پذیری

اکنون که سرویس شما برای اجرا و گوش دادن به رویدادها راه‌اندازی شده است، کدی بنویسید تا بداند وقتی AccessibilityEvent می‌رسد چه کاری باید انجام دهد. با لغو کردن روش onAccessibilityEvent(AccessibilityEvent) شروع کنید. در آن روش، از getEventType() برای تعیین نوع رویداد و از getContentDescription() برای استخراج هرگونه نوشتار برچسب مرتبط با نمایی که رویداد را فعال می‌کند استفاده کنید:

کاتلین

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

جاوا

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

منابع بیشتر

برای اطلاعات بیشتر، منابع زیر را ببینید:

راهنماها

Codelabs