المفاهيم والتنفيذ في Jetpack Compose
خدمة مخصّصة لتسهيل الاستخدام هي تطبيق يحسّن واجهة المستخدم لمساعدة المستخدمين ذوي الاحتياجات الخاصة أو الذين قد لا يتمكنون مؤقتًا من التفاعل بشكل كامل مع الجهاز. على سبيل المثال، قد يحتاج المستخدمون الذين يقودون السيارة أو يعتنون بطفل صغير أو يحضرون حفلة صاخبة جدًا إلى ملاحظات إضافية أو بديلة بشأن واجهة المستخدم.
يوفّر 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، أدرِج intent filter لخدمة مخصّصة لتسهيل الاستخدام. يجب أن يحمي البيان أيضًا الخدمة
من خلال إضافة الإذن 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 التي يمكن استخدامها في ملف إعداد خدمة مخصّصة لتسهيل الاستخدام، يُرجى الاطّلاع على مستندات المرجع التالية:
android:descriptionandroid:packageNamesandroid:accessibilityEventTypesandroid:accessibilityFlagsandroid:accessibilityFeedbackTypeandroid:notificationTimeoutandroid:canRetrieveWindowContentandroid:settingsActivity
لمزيد من المعلومات حول إعدادات الضبط التي يمكن ضبطها بشكل ديناميكي في وقت التشغيل، يُرجى الاطّلاع على مستندات 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()) إلى وقت إيقافها (onUnbind())، مرورًا بوقت تشغيلها (onAccessibilityEvent() وonInterrupt()).
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.
زر أدوات تسهيل الاستخدام
في الأجهزة التي تستخدم مساحة تنقّل معروضة بواسطة برنامج وتعمل بالإصدار 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.
إيماءات بصمات الإصبع
يمكن لخدمات تسهيل الاستخدام على الأجهزة التي تعمل بالإصدار 8.0 من نظام التشغيل Android (المستوى 26 من واجهة برمجة التطبيقات) والإصدارات الأحدث الاستجابة للتمريرات السريعة الاتجاهية (للأعلى وللأسفل ولليسار ولليمين) على أداة استشعار بصمة الإصبع في الجهاز. لإعداد خدمة لتلقّي عمليات ردّ بشأن هذه التفاعلات، أكمِل التسلسل التالي:
- أدرِج إذن
USE_BIOMETRICوإمكانيةCAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES. - اضبط العلامة
FLAG_REQUEST_FINGERPRINT_GESTURESضمن السمةandroid:accessibilityFlags. - سجِّل عمليات إعادة الاستدعاء باستخدام
registerFingerprintGestureCallback()).
يُرجى العِلم أنّ بعض الأجهزة لا تتضمّن مستشعرات بصمات الإصبع. لتحديد ما إذا كان الجهاز يتوافق مع أداة الاستشعار، استخدِم طريقة isHardwareDetected(). حتى على جهاز يتضمّن أداة استشعار بصمة الإصبع، لا يمكن لخدمتك استخدام أداة الاستشعار عندما تكون قيد الاستخدام لأغراض المصادقة. لتحديد وقت توفّر المستشعر، استدعِ طريقة isGestureDetectionAvailable() ونفِّذ عملية رد الاتصال onGestureDetectionAvailabilityChanged().
يوضّح مقتطف الرمز التالي مثالاً على استخدام إيماءات بصمات الأصابع للتنقّل في لوحة ألعاب افتراضية:
// AndroidManifest.xml <manifest ... > <uses-permission android:name="android.permission.USE_FINGERPRINT" /> ... <application> <service android:name="com.example.MyFingerprintGestureService" ... > <meta-data android:name="android.accessibilityservice" android:resource="@xml/myfingerprintgestureservice" /> </service> </application> </manifest>
// myfingerprintgestureservice.xml <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" ... android:accessibilityFlags=" ... |flagRequestFingerprintGestures" android:canRequestFingerprintGestures="true" ... />
Kotlin
// MyFingerprintGestureService.kt import android.accessibilityservice.FingerprintGestureController.* class MyFingerprintGestureService : AccessibilityService() { private var gestureController: FingerprintGestureController? = null private var fingerprintGestureCallback: FingerprintGestureController.FingerprintGestureCallback? = null private var mIsGestureDetectionAvailable: Boolean = false override fun onCreate() { gestureController = fingerprintGestureController mIsGestureDetectionAvailable = gestureController?.isGestureDetectionAvailable ?: false } override fun onServiceConnected() { if (mFingerprintGestureCallback != null || !mIsGestureDetectionAvailable) return fingerprintGestureCallback = object : FingerprintGestureController.FingerprintGestureCallback() { override fun onGestureDetected(gesture: Int) { when (gesture) { FINGERPRINT_GESTURE_SWIPE_DOWN -> moveGameCursorDown() FINGERPRINT_GESTURE_SWIPE_LEFT -> moveGameCursorLeft() FINGERPRINT_GESTURE_SWIPE_RIGHT -> moveGameCursorRight() FINGERPRINT_GESTURE_SWIPE_UP -> moveGameCursorUp() else -> Log.e(MY_APP_TAG, "Error: Unknown gesture type detected!") } } override fun onGestureDetectionAvailabilityChanged(available: Boolean) { mIsGestureDetectionAvailable = available } } fingerprintGestureCallback?.also { gestureController?.registerFingerprintGestureCallback(it, null) } } }
Java
// MyFingerprintGestureService.java import static android.accessibilityservice.FingerprintGestureController.*; public class MyFingerprintGestureService extends AccessibilityService { private FingerprintGestureController gestureController; private FingerprintGestureController .FingerprintGestureCallback fingerprintGestureCallback; private boolean mIsGestureDetectionAvailable; @Override public void onCreate() { gestureController = getFingerprintGestureController(); mIsGestureDetectionAvailable = gestureController.isGestureDetectionAvailable(); } @Override protected void onServiceConnected() { if (fingerprintGestureCallback != null || !mIsGestureDetectionAvailable) { return; } fingerprintGestureCallback = new FingerprintGestureController.FingerprintGestureCallback() { @Override public void onGestureDetected(int gesture) { switch (gesture) { case FINGERPRINT_GESTURE_SWIPE_DOWN: moveGameCursorDown(); break; case FINGERPRINT_GESTURE_SWIPE_LEFT: moveGameCursorLeft(); break; case FINGERPRINT_GESTURE_SWIPE_RIGHT: moveGameCursorRight(); break; case FINGERPRINT_GESTURE_SWIPE_UP: moveGameCursorUp(); break; default: Log.e(MY_APP_TAG, "Error: Unknown gesture type detected!"); break; } } @Override public void onGestureDetectionAvailabilityChanged(boolean available) { mIsGestureDetectionAvailable = available; } }; if (fingerprintGestureCallback != null) { gestureController.registerFingerprintGestureCallback( fingerprintGestureCallback, null); } } }
لمزيد من المعلومات، يمكنك مشاهدة فيديو جلسة الميزات الجديدة في تسهيل استخدام Android من مؤتمر Google I/O 2017، بدءًا من الدقيقة 9:03.
تحويل النص إلى كلام بلغات متعددة
بدءًا من الإصدار 8.0 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 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، تم توسيع نطاق الإجراءات ليشمل التنقّل في القوائم والتفاعل مع الحقول النصية. يمكن لخدمات تسهيل الاستخدام أيضًا تنفيذ إجراءات عامة، مثل الانتقال إلى الشاشة الرئيسية والضغط على زر الرجوع وفتح شاشة الإشعارات وقائمة التطبيقات المستخدمة مؤخرًا. يتضمّن Android منذ عام 2012 وضع التركيز على إمكانية الوصول، ما يتيح لخدمة مخصّصة لتسهيل الاستخدام اختيار جميع العناصر المرئية.
تتيح هذه الإمكانات لمطوّري خدمات تسهيل الاستخدام إنشاء أوضاع تنقّل بديلة، مثل التنقّل بالإيماءات، وتمنح المستخدمين ذوي الاحتياجات الخاصة تحكّمًا أفضل في أجهزتهم التي تعمل بنظام التشغيل 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() الخاصة بالخدمة، ويمكنها الاستجابة من خلال اتّخاذ إجراء نيابةً عن المستخدم.
الإيماءات المتواصلة
تتيح الأجهزة التي تعمل بالإصدار 8.0 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 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().
لا تعرض هذه الدالة عنصرًا إلا إذا كانت النافذة التي نشأ فيها الحدث هي النافذة النشطة. وفي حال عدم توفّرها، تعرض الدالة قيمة فارغة، لذا يجب التعامل مع هذه الحالة بشكل مناسب.
في المثال التالي، تنفّذ التعليمة البرمجية ما يلي عند تلقّي حدث:
- يتم الحصول على العنصر الرئيسي للعرض الذي نشأ منه الحدث على الفور.
- في طريقة العرض هذه، ابحث عن تصنيف ومربّع اختيار كطرق عرض فرعية.
- وإذا عثر عليها، ينشئ سلسلة لإبلاغ المستخدم، مع الإشارة إلى التصنيف وما إذا تم التحقّق منه.
إذا تم إرجاع قيمة فارغة في أي وقت أثناء التنقّل في هيكلية طرق العرض، تتوقف الطريقة بدون إشعار.
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()، تذكَّر أنّ الأجهزة التي تعمل بالإصدار 8.0 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 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); ... }
مراجع إضافية
لمزيد من المعلومات، يُرجى الاطّلاع على المراجع التالية: