إنشاء خدمة تسهيل الاستخدام الخاصة بك

خدمة تسهيل الاستخدام هي تطبيق يحسّن واجهة المستخدم لمساعدة المستخدمين الذين يعانون من عجز أو الذين قد يكونون غير قادرين مؤقتًا على التفاعل بشكل كامل مع الأجهزة. على سبيل المثال، قد يحتاج المستخدمون الذين يقودون أو يرعون طفلاً صغيرًا أو يحضرون حفلة صاخبة جدًا إلى ملاحظات إضافية أو بديلة عن الواجهة.

يوفّر 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 لإجراءات التفعيل من المصدر.

بيانات البيان والأذونات

إنّ التطبيقات التي تقدِّم خدمات لتسهيل الاستخدام يجب أن تتضمّن بيانات محدّدة في بيانات التطبيقات لكي يتعامل نظام Android معها على أنّها خدمة لتسهيل الاستخدام. يوضح هذا القسم الإعدادات المطلوبة والاختيارية لخدمات إمكانية الوصول.

بيان خدمة تسهيل الاستخدام

لكي يتم التعامل مع تطبيقك كخدمة لتسهيل الاستخدام، عليك تضمين عنصر service، بدلاً من العنصر activity، ضمن العنصر 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() وضبط خدمتك هناك، كما هو موضّح في المثال التالي:

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

}

الخيار الثاني هو إعداد الخدمة باستخدام ملف 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.

عند إعداد خدمة تسهيل الاستخدام، فكّر بعناية في الأحداث التي يمكن لخدمتك التعامل معها، واحرص على التسجيل فقط لتلك الأحداث. وبما أنّه يمكن للمستخدمين تفعيل أكثر من خدمة واحدة لتسهيل الاستخدام في وقت واحد، يجب ألا تستهلك خدمتك أحداثًا لا يمكنها التعامل معها. تذكر أن الخدمات الأخرى قد تتعامل مع هذه الأحداث لتحسين تجربة المستخدم.

مستوى صوت ميزة "تسهيل الاستخدام"

تتضمّن الأجهزة التي تعمل بالإصدار 8.0 من نظام التشغيل Android (المستوى 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.

اختصار زر أدوات تسهيل الاستخدام

في الأجهزة التي تعمل بالإصدار 8.0 من نظام التشغيل Android (المستوى 26 من واجهة برمجة التطبيقات) والإصدارات الأحدث، يمكن للمستخدمين تفعيل خدمة تسهيل الاستخدام المفضّلة لديهم وإيقافها من أي شاشة من خلال الضغط مع الاستمرار على مفتاحَي مستوى الصوت في الوقت نفسه. على الرغم من أنّ هذا الاختصار يتيح ميزة Talkback ويوقفها تلقائيًا، يمكن للمستخدمين ضبط الزر لتفعيل أو إيقاف أي خدمة مثبتة على أجهزتهم.

ولكي يتمكن المستخدمون من الوصول إلى خدمة إمكانية وصول معينة من اختصار إمكانية الوصول، يجب على الخدمة طلب الميزة في وقت التشغيل.

لمزيد من المعلومات، يمكنك مشاهدة فيديو جلسة الميزات الجديدة في إمكانية الوصول إلى Android من مؤتمر Google I/O لعام 2017، بدءًا من الساعة 13:25.

زر أدوات تسهيل الاستخدام

على الأجهزة التي تستخدم منطقة تنقّل معروضة على البرامج وتعمل بالإصدار 8.0 من نظام التشغيل Android (المستوى 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.

إيماءات بصمات الإصبع:

يمكن لخدمات تسهيل الاستخدام على الأجهزة التي تعمل بالإصدار 8.0 من نظام التشغيل Android (المستوى 26 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث الاستجابة لعمليات التمرير السريع للاتجاهات (للأعلى وللأسفل واليسار واليمين) من خلال أداة استشعار بصمة الإصبع في الجهاز. لإعداد خدمة لتلقي استدعاءات حول هذه التفاعلات، أكمل التسلسل التالي:

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

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.

تحويل النص إلى كلام بعدّة لغات

استطاعت خدمة تحويل النص إلى كلام (TTS) من Android التعرّف على العبارات ونطقها بلغات متعددة ضمن نص واحد، بدءًا من الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، لتفعيل إمكانية التبديل التلقائي للغة في خدمة لتسهيل الاستخدام، عليك إرفاق كل السلاسل في كائنات 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() الخاصة بالخدمة، ويمكنها الاستجابة من خلال التصرف نيابةً عن المستخدم.

الإيماءات المستمرة

الأجهزة التي تعمل بنظام التشغيل Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات) تدعم الإيماءات المستمرة أو الإيماءات الآلية التي تحتوي على أكثر من عنصر 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 في لوحة المفاتيح أو يضغط على الزر الأوسط في لوحة التحكّم.

من الممكن لعنصر في واجهة المستخدم أن يكون له تركيز على الإدخال بينما يركّز عنصر آخر على تسهيل الاستخدام. يتمثّل الغرض من التركيز على تسهيل الاستخدام في تزويد خدمات تسهيل الاستخدام بطريقة للتفاعل مع العناصر المرئية على الشاشة، بغض النظر عمّا إذا كان العنصر قابلاً للتركيز على البيانات من منظور النظام أم لا. للمساعدة في ضمان تفاعل خدمة تسهيل الاستخدام بشكل صحيح مع عناصر إدخال التطبيقات، يُرجى اتّباع الإرشادات الخاصة باختبار إمكانية الوصول إلى تطبيق لاختبار خدمتك أثناء استخدام تطبيق عادي.

يمكن لخدمة تسهيل الاستخدام تحديد عنصر واجهة المستخدم الذي يتضمّن تركيز إدخال أو تركيز على تسهيل الاستخدام، وذلك باستخدام الطريقة AccessibilityNodeInfo.findFocus(). يمكنك أيضًا البحث عن العناصر التي يمكن اختيارها مع التركيز على الإدخال باستخدام الطريقة focusSearch(). أخيرًا، يمكن لخدمة تسهيل الاستخدام تحديد تركيز تسهيل الاستخدام على الطريقة performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS).

جمع المعلومات

تتضمن خدمات تسهيل الاستخدام طرقًا قياسية لجمع وتمثيل الوحدات الرئيسية للمعلومات التي يوفرها المستخدم، مثل تفاصيل الحدث والنص والأرقام.

الحصول على تفاصيل تغيير النافذة

يتيح الإصدار 9 (المستوى 28 من واجهة برمجة التطبيقات) والإصدارات الأحدث للتطبيقات تتبُّع تحديثات النوافذ عندما يعيد أحد التطبيقات رسم نوافذ متعددة في الوقت نفسه. عند وقوع حدث TYPE_WINDOWS_CHANGED، استخدِم واجهة برمجة التطبيقات getWindowChanges() لتحديد كيفية تغيُّر النوافذ. أثناء إجراء تحديث متعدد النوافذ، تنتج كل نافذة مجموعة الأحداث الخاصة بها. تعرض الطريقة getSource() العرض الجذري للنافذة المرتبطة بكل حدث.

إذا كان أحد التطبيقات يحدّد عناوين جزء تسهيل الاستخدام لعناصر View الخاصة به، يمكن لخدمتك التعرّف على وقت تحديث واجهة المستخدم للتطبيق. عند وقوع حدث TYPE_WINDOW_STATE_CHANGED، استخدِم الأنواع التي تعرضها getContentChangeTypes() لتحديد كيفية تغيُّر النافذة. على سبيل المثال، يمكن لإطار العمل اكتشاف متى يحتوي جزء على عنوان جديد أو عندما يختفي جزء.

الحصول على تفاصيل الحدث

يوفّر Android معلومات لخدمات تسهيل الاستخدام حول تفاعل واجهة المستخدم من خلال كائنات AccessibilityEvent. في إصدارات Android السابقة، وفّرت المعلومات المتاحة في حدث تسهيل الاستخدام تفاصيل مهمة حول عناصر التحكّم في واجهة المستخدم التي اختارها المستخدمون، وتوفّر معلومات سياقية محدودة. وفي كثير من الحالات، قد تكون معلومات السياق المفقودة هذه مهمة لفهم معنى عنصر التحكم المحدد.

ومن الأمثلة على الواجهة التي يكون السياق فيها مهمًا، أي التقويم أو مخطط اليوم. إذا اختار المستخدم خانة زمنية من الاثنين إلى الجمعة في الساعة 4:00 مساءً في قائمة أيام الاثنين إلى الجمعة وأعلنت خدمة تسهيل الاستخدام "4 بعد الظهر"، ولكنها لم تعلن عن اسم يوم الأسبوع أو اليوم من الشهر أو اسم الشهر، ستكون الملاحظات الناتجة مربكة. في هذه الحالة، يُعد سياق عنصر التحكم في واجهة المستخدم أمرًا بالغ الأهمية للمستخدم الذي يريد تحديد موعد اجتماع.

منذ عام 2011، زاد نظام Android بشكل كبير من كمية المعلومات التي يمكن لخدمة تسهيل الاستخدام الحصول عليها حول تفاعل واجهة المستخدم من خلال إنشاء أحداث لإمكانية الوصول استنادًا إلى التسلسل الهرمي للعرض. التسلسل الهرمي لطريقة العرض هو مجموعة من مكونات واجهة المستخدم التي تحتوي على المكون (العناصر الرئيسية) وعناصر واجهة المستخدم التي قد يحتوي عليها هذا المكون (عناصره الفرعية). وبهذه الطريقة، يمكن لنظام Android توفير تفاصيل أكثر ثراءً حول أحداث إمكانية الوصول، ما يسمح لخدمات تسهيل الاستخدام بتقديم ملاحظات أكثر فائدة للمستخدمين.

تحصل خدمة تسهيل الاستخدام على معلومات عن حدث واجهة المستخدم من خلال AccessibilityEvent يتم تمريره بواسطة النظام إلى طريقة معاودة الاتصال onAccessibilityEvent() الخاصة بالخدمة. يوفر هذا الكائن تفاصيل عن الحدث، بما في ذلك نوع الكائن الذي تم اتخاذ إجراء بشأنه والنص الوصفي له والتفاصيل الأخرى.

  • AccessibilityEvent.getRecordCount() وgetRecord(int): تتيح لك هذه الطرق استرداد مجموعة كائنات AccessibilityRecord التي تساهم في AccessibilityEvent الذي قدّمه لك النظام. يوفر هذا المستوى من التفاصيل مزيدًا من السياق للحدث الذي يؤدي إلى تشغيل خدمة إمكانية الوصول.

  • AccessibilityRecord.getSource(): تعرض هذه الطريقة كائن AccessibilityNodeInfo. يتيح لك هذا الكائن طلب العرض الهرمي لتخطيط العرض (الأصل والفرعي) للمكوِّن الذي نشأ عن حدث إمكانية الوصول. تتيح هذه الميزة لخدمة تسهيل الاستخدام التحقيق في السياق الكامل لأحد الأحداث، بما في ذلك المحتوى وحالة أي وجهات نظر شاملة أو وجهات نظر فرعية.

يتيح نظام Android الأساسي لـ AccessibilityService الاستعلام عن التدرّج الهرمي للعرض، وجمع معلومات عن مكوّن واجهة المستخدم الذي ينشئ حدثًا بالإضافة إلى عنصره الرئيسي وعناصره الثانوية. لإجراء ذلك، اضبط السطر التالي في إعدادات XML:

android:canRetrieveWindowContent="true"

بعد ذلك، يمكنك الحصول على عنصر AccessibilityNodeInfo باستخدام getSource(). لا يعرض هذا الاستدعاء عنصرًا إلا إذا كانت النافذة التي نشأ منها الحدث لا تزال هي النافذة النشطة. وإذا لم يكن الأمر كذلك، فسيتم عرض قيمة فارغة، لذا يجب التصرف وفقًا لذلك.

في المثال التالي، تنفِّذ الرمز الإجراءات التالية عند تلقّي حدث:

  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 لتقديم ملاحظات حسية.

نص العملية

تشتمل الأجهزة التي تعمل بالإصدار 8.0 من نظام التشغيل Android (المستوى 26 من واجهة برمجة التطبيقات) والإصدارات الأحدث على العديد من ميزات معالجة النصوص التي تسهّل على خدمات تسهيل الاستخدام تحديد وحدات نصية معيّنة تظهر على الشاشة وتشغيلها.

التلميحات

يقدّم Android 9 (المستوى 28 من واجهة برمجة التطبيقات) العديد من الإمكانات التي تتيح لك الوصول إلى التلميحات في واجهة مستخدم التطبيق. يمكنك استخدام getTooltipText() لقراءة نص التلميح، واستخدام ACTION_SHOW_TOOLTIP و ACTION_HIDE_TOOLTIP لتوجيه إصدارات View إلى إظهار التلميحات أو إخفائها.

نص التلميح

بدءًا من عام 2017، اشتمل Android على العديد من الطرق للتفاعل مع نص تلميح كائن مستند إلى النص:

  • تشير الطريقتان isShowingHintText() وsetShowingHintText() إلى ما إذا كان المحتوى النصي الحالي للعقدة يمثّل نص تلميح العقدة ويضبطهما على التوالي.
  • توفّر getHintText() إمكانية الوصول إلى نص التلميح نفسه. حتى إذا لم يعرض الكائن نص تلميح، يتم استدعاء getHintText() بنجاح.

مواقع أحرف النص التي تظهر على الشاشة

في الأجهزة التي تعمل بالإصدار 8.0 من نظام التشغيل Android (المستوى 26 لواجهة برمجة التطبيقات) والإصدارات الأحدث، يمكن لخدمات تسهيل الاستخدام تحديد إحداثيات الشاشة لكل مربّع حدود شخصية مرئية داخل تطبيق TextView المصغّر. تعثر الخدمات على هذه الإحداثيات من خلال استدعاء refreshWithExtraData()، وتمرير EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY كوسيطة أولى، وكائن Bundle كوسيطة ثانية. أثناء تنفيذ الطريقة، يملأ النظام الوسيطة Bundle بمصفوفة قابلة للفصل من عناصر Rect. يمثل كل كائن Rect مربع الإحاطة بحرف معين.

القيم الموحّدة لنطاق من جانب واحد

تستخدم بعض كائنات AccessibilityNodeInfo مثيلاً من AccessibilityNodeInfo.RangeInfo للإشارة إلى أن عنصر واجهة المستخدم يمكن أن يأخذ نطاقًا من القيم. عند إنشاء نطاق باستخدام RangeInfo.obtain() أو عند استرداد القيم القصوى للنطاق باستخدام getMin() وgetMax()، يُرجى العِلم أنّ الأجهزة التي تعمل بالإصدار Android 8.0 (المستوى 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);
    ...
}

مصادر إضافية

لمزيد من المعلومات، يمكنك الاطّلاع على المراجع التالية:

الأدلّة

الدروس التطبيقية حول الترميز