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

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

يوفّر 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.

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

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

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

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

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

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

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

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

بدءًا من الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، يمكن لخدمة تحويل النص إلى كلام (TTS) في Android التعرّف على العبارات ونطقها بلغات متعددة في نص واحد. لتفعيل إمكانية التبديل التلقائي للّغة في إحدى خدمات تسهيل الاستخدام، عليك دمج جميع السلاسل في كائنات LocaleSpan، كما هو موضّح في مقتطف الرمز التالي:

Kotlin

val localeWrappedTextView = findViewById<TextView>(R.id.my_french_greeting_text).apply {
    text = wrapTextInLocaleSpan("Bonjour!", Locale.FRANCE)
}

private fun wrapTextInLocaleSpan(originalText: CharSequence, loc: Locale): SpannableStringBuilder {
    return SpannableStringBuilder(originalText).apply {
        setSpan(LocaleSpan(loc), 0, originalText.length - 1, 0)
    }
}

Java

TextView localeWrappedTextView = findViewById(R.id.my_french_greeting_text);
localeWrappedTextView.setText(wrapTextInLocaleSpan("Bonjour!", Locale.FRANCE));

private SpannableStringBuilder wrapTextInLocaleSpan(
        CharSequence originalText, Locale loc) {
    SpannableStringBuilder myLocaleBuilder =
            new SpannableStringBuilder(originalText);
    myLocaleBuilder.setSpan(new LocaleSpan(loc), 0,
            originalText.length() - 1, 0);
    return myLocaleBuilder;
}

للمزيد من المعلومات، يُرجى مشاهدة فيديو جلسة ما الجديد في ميزات تسهيل الاستخدام في Android من مؤتمر Google I/O لعام 2017، ابتداءً من الساعة 10:59.

التصرف نيابةً عن المستخدمين

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

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

الاستماع إلى الإيماءات

يمكن لخدمات إمكانية الوصول الاستماع إلى إيماءات محددة والاستجابة بالتصرف نيابةً عن المستخدم. تتطلب هذه الميزة تفعيل خدمة إمكانية الوصول لميزة الاستكشاف باللمس. يمكن لخدمتك طلب هذا التفعيل من خلال ضبط العضو flags في مثيل AccessibilityServiceInfo الخاص بالخدمة على FLAG_REQUEST_TOUCH_EXPLORATION_MODE، كما هو موضّح في المثال التالي.

Kotlin

class MyAccessibilityService : AccessibilityService() {

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

Java

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

بعد طلب الخدمة تفعيل ميزة "الاستكشاف باللمس"، يجب على المستخدم تفعيل الميزة إذا لم تكن نشطة من قبل. عندما تكون هذه الميزة مفعّلة، تتلقّى خدمتك إشعارًا بإيماءات تسهيل الاستخدام من خلال طريقة معاودة الاتصال في onGesture() الخاصة بالخدمة، ويمكنها الاستجابة من خلال التصرف نيابةً عن المستخدم.

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

تتوافق الأجهزة التي تعمل بنظام التشغيل 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).

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

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

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

يسمح نظام التشغيل Android 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().

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

على الأجهزة التي تعمل بنظام التشغيل Android 8.0 (المستوى 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);
    ...
}

مراجع إضافية

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

الأدلّة

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