আপনার নিজস্ব অ্যাক্সেসিবিলিটি পরিষেবা তৈরি করুন

একটি অ্যাক্সেসিবিলিটি পরিষেবা হল এমন একটি অ্যাপ যা অক্ষম ব্যবহারকারীদের সাহায্য করার জন্য ব্যবহারকারীর ইন্টারফেসকে উন্নত করে বা যারা সাময়িকভাবে কোনও ডিভাইসের সাথে সম্পূর্ণভাবে ইন্টারঅ্যাক্ট করতে পারে না। উদাহরণস্বরূপ, যে ব্যবহারকারীরা গাড়ি চালাচ্ছেন, একটি ছোট বাচ্চার যত্ন নিচ্ছেন বা খুব জোরে পার্টিতে যোগ দিচ্ছেন তাদের অতিরিক্ত বা বিকল্প ইন্টারফেস প্রতিক্রিয়ার প্রয়োজন হতে পারে।

Android টকব্যাক সহ স্ট্যান্ডার্ড অ্যাক্সেসিবিলিটি পরিষেবা সরবরাহ করে এবং বিকাশকারীরা তাদের নিজস্ব পরিষেবাগুলি তৈরি এবং বিতরণ করতে পারে৷ এই নথিটি একটি অ্যাক্সেসিবিলিটি পরিষেবা তৈরির মূল বিষয়গুলি ব্যাখ্যা করে৷

একটি অ্যাক্সেসিবিলিটি পরিষেবা একটি সাধারণ অ্যাপের সাথে বান্ডিল করা যেতে পারে বা একটি স্বতন্ত্র Android প্রকল্প হিসাবে তৈরি করা যেতে পারে। পরিষেবা তৈরির পদক্ষেপ উভয় পরিস্থিতিতে একই।

আপনার অ্যাক্সেসিবিলিটি পরিষেবা তৈরি করুন

আপনার প্রকল্পের মধ্যে, একটি ক্লাস তৈরি করুন যা AccessibilityService প্রসারিত করে:

কোটলিন

package com.example.android.apis.accessibility

import android.accessibilityservice.AccessibilityService
import android.view.accessibility.AccessibilityEvent

class MyAccessibilityService : AccessibilityService() {
...
    override fun onInterrupt() {}

    override fun onAccessibilityEvent(event: AccessibilityEvent?) {}
...
}

জাভা

package com.example.android.apis.accessibility;

import android.accessibilityservice.AccessibilityService;
import android.view.accessibility.AccessibilityEvent;

public class MyAccessibilityService extends AccessibilityService {
...
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
    }

    @Override
    public void onInterrupt() {
    }

...
}

আপনি যদি এই Service জন্য একটি নতুন প্রকল্প তৈরি করেন এবং এটির সাথে কোনও অ্যাপ যুক্ত করার পরিকল্পনা না করেন তবে আপনি আপনার উত্স থেকে স্টার্টার Activity ক্লাসটি সরাতে পারেন৷

ম্যানিফেস্ট ঘোষণা এবং অনুমতি

যে অ্যাপগুলি অ্যাক্সেসিবিলিটি পরিষেবাগুলি প্রদান করে তাদের অবশ্যই তাদের অ্যাপ ম্যানিফেস্টে নির্দিষ্ট ঘোষণাগুলি অন্তর্ভুক্ত করতে হবে যাতে Android সিস্টেম দ্বারা একটি অ্যাক্সেসিবিলিটি পরিষেবা হিসাবে বিবেচিত হয়৷ এই বিভাগটি অ্যাক্সেসিবিলিটি পরিষেবাগুলির জন্য প্রয়োজনীয় এবং ঐচ্ছিক সেটিংস ব্যাখ্যা করে৷

অ্যাক্সেসিবিলিটি পরিষেবা ঘোষণা

আপনার অ্যাপটিকে একটি অ্যাক্সেসিবিলিটি পরিষেবা হিসাবে বিবেচনা করার জন্য, আপনার ম্যানিফেস্টের application উপাদানের মধ্যে — activity উপাদানের পরিবর্তে — একটি service উপাদান অন্তর্ভুক্ত করুন৷ উপরন্তু, service উপাদানের মধ্যে, একটি অ্যাক্সেসিবিলিটি পরিষেবা অভিপ্রায় ফিল্টার অন্তর্ভুক্ত করুন৷ ম্যানিফেস্টকে অবশ্যই BIND_ACCESSIBILITY_SERVICE অনুমতি যোগ করে পরিষেবাটিকে সুরক্ষিত করতে হবে তা নিশ্চিত করতে যে শুধুমাত্র সিস্টেম এটির সাথে আবদ্ধ হতে পারে৷ এখানে একটি উদাহরণ:

  <application>
    <service android:name=".MyAccessibilityService"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
        android:label="@string/accessibility_service_label">
      <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
      </intent-filter>
    </service>
  </application>

অ্যাক্সেসিবিলিটি পরিষেবা কনফিগারেশন

অ্যাক্সেসিবিলিটি পরিষেবাগুলিকে অবশ্যই একটি কনফিগারেশন প্রদান করতে হবে যা পরিষেবাটি পরিচালনা করে এমন অ্যাক্সেসিবিলিটি ইভেন্টগুলির প্রকার এবং পরিষেবা সম্পর্কে অতিরিক্ত তথ্য নির্দিষ্ট করে৷ অ্যাক্সেসিবিলিটি সার্ভিসের কনফিগারেশন AccessibilityServiceInfo ক্লাসে থাকে। আপনার পরিষেবা এই ক্লাসের একটি উদাহরণ ব্যবহার করে একটি কনফিগারেশন তৈরি এবং সেট করতে পারে এবং রানটাইমে setServiceInfo() পারে। যাইহোক, এই পদ্ধতি ব্যবহার করে সমস্ত কনফিগারেশন বিকল্প উপলব্ধ নয়।

আপনি আপনার ম্যানিফেস্টে একটি কনফিগারেশন ফাইলের রেফারেন্স সহ একটি <meta-data> উপাদান অন্তর্ভুক্ত করতে পারেন, যা আপনাকে আপনার অ্যাক্সেসিবিলিটি পরিষেবার জন্য বিকল্পগুলির সম্পূর্ণ পরিসর সেট করতে দেয়, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

<service android:name=".MyAccessibilityService">
  ...
  <meta-data
    android:name="android.accessibilityservice"
    android:resource="@xml/accessibility_service_config" />
</service>

এই <meta-data> উপাদানটি একটি XML ফাইলকে বোঝায় যা আপনি আপনার অ্যাপের রিসোর্স ডিরেক্টরিতে তৈরি করেন: <project_dir>/res/xml/accessibility_service_config.xml> । নিম্নলিখিত কোড পরিষেবা কনফিগারেশন ফাইলের বিষয়বস্তুর একটি উদাহরণ দেখায়:

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
    android:packageNames="com.example.android.apis"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFlags="flagDefault"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity"
/>

অ্যাক্সেসিবিলিটি সার্ভিস কনফিগারেশন ফাইলে ব্যবহার করা যেতে পারে এমন XML অ্যাট্রিবিউট সম্পর্কে আরও তথ্যের জন্য, নিম্নলিখিত রেফারেন্স ডকুমেন্টেশন দেখুন:

রানটাইমে কোন কনফিগারেশন সেটিংস গতিশীলভাবে সেট করা যায় সে সম্পর্কে আরও তথ্যের জন্য, AccessibilityServiceInfo রেফারেন্স ডকুমেন্টেশন দেখুন।

আপনার অ্যাক্সেসিবিলিটি পরিষেবা কনফিগার করুন

আপনার অ্যাক্সেসিবিলিটি পরিষেবার জন্য কনফিগারেশন ভেরিয়েবল সেট করার সময় কীভাবে এবং কখন চালানো হবে তা সিস্টেমকে জানাতে নিম্নলিখিতগুলি বিবেচনা করুন:

  • কোন ধরনের ইভেন্টে আপনি এটি সাড়া দিতে চান?
  • পরিষেবাটি কি সমস্ত অ্যাপের জন্য সক্রিয় হতে হবে, নাকি শুধুমাত্র নির্দিষ্ট প্যাকেজ নাম?
  • কি বিভিন্ন ধরনের প্রতিক্রিয়া এটি ব্যবহার করে?

এই ভেরিয়েবল সেট করার জন্য আপনার কাছে দুটি বিকল্প আছে। পশ্চাদগামী সামঞ্জস্যপূর্ণ বিকল্প হল setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo) ব্যবহার করে কোডে সেগুলি সেট করার জন্য, onServiceConnected() পদ্ধতিটি ওভাররাইড করুন এবং সেখানে আপনার পরিষেবা কনফিগার করুন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

কোটলিন

override fun onServiceConnected() {
    info.apply {
        // Set the type of events that this service wants to listen to. Others
        // aren't passed to this service.
        eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED or AccessibilityEvent.TYPE_VIEW_FOCUSED

        // If you only want this service to work with specific apps, set their
        // package names here. Otherwise, when the service is activated, it
        // listens to events from all apps.
        packageNames = arrayOf("com.example.android.myFirstApp", "com.example.android.mySecondApp")

        // Set the type of feedback your service provides.
        feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN

        // Default services are invoked only if no package-specific services are
        // present for the type of AccessibilityEvent generated. This service is
        // app-specific, so the flag isn't necessary. For a general-purpose
        // service, consider setting the DEFAULT flag.

        // flags = AccessibilityServiceInfo.DEFAULT;

        notificationTimeout = 100
    }

    this.serviceInfo = info

}

জাভা

@Override
public void onServiceConnected() {
    // Set the type of events that this service wants to listen to. Others
    // aren't passed to this service.
    info.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED |
            AccessibilityEvent.TYPE_VIEW_FOCUSED;

    // If you only want this service to work with specific apps, set their
    // package names here. Otherwise, when the service is activated, it listens
    // to events from all apps.
    info.packageNames = new String[]
            {"com.example.android.myFirstApp", "com.example.android.mySecondApp"};

    // Set the type of feedback your service provides.
    info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN;

    // Default services are invoked only if no package-specific services are
    // present for the type of AccessibilityEvent generated. This service is
    // app-specific, so the flag isn't necessary. For a general-purpose service,
    // consider setting the DEFAULT flag.

    // info.flags = AccessibilityServiceInfo.DEFAULT;

    info.notificationTimeout = 100;

    this.setServiceInfo(info);

}

দ্বিতীয় বিকল্পটি হল একটি XML ফাইল ব্যবহার করে পরিষেবাটি কনফিগার করা। কিছু কনফিগারেশন বিকল্প, যেমন canRetrieveWindowContent , শুধুমাত্র তখনই পাওয়া যায় যদি আপনি XML ব্যবহার করে আপনার পরিষেবা কনফিগার করেন। পূর্ববর্তী উদাহরণ থেকে কনফিগারেশন বিকল্পগুলি XML ব্যবহার করে সংজ্ঞায়িত করার সময় এইরকম দেখায়:

<accessibility-service
     android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
     android:packageNames="com.example.android.myFirstApp, com.example.android.mySecondApp"
     android:accessibilityFeedbackType="feedbackSpoken"
     android:notificationTimeout="100"
     android:settingsActivity="com.example.android.apis.accessibility.TestBackActivity"
     android:canRetrieveWindowContent="true"
/>

আপনি যদি XML ব্যবহার করেন, তাহলে XML ফাইলের দিকে নির্দেশ করে আপনার পরিষেবা ঘোষণায় একটি <meta-data> ট্যাগ যোগ করে আপনার ম্যানিফেস্টে এটি উল্লেখ করুন। আপনি যদি আপনার 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 ক্লাসকে প্রসারিত করবে এবং সেই ক্লাস থেকে নিম্নলিখিত পদ্ধতিগুলিকে ওভাররাইড করবে৷ এই পদ্ধতিগুলিকে অ্যান্ড্রয়েড সিস্টেম যে ক্রমে তাদের কল করে সেই ক্রমে উপস্থাপন করা হয়: যখন পরিষেবাটি শুরু হয় ( onServiceConnected() ), এটি চলাকালীন ( onAccessibilityEvent() , onInterrupt() ), কখন এটি বন্ধ হয় ( onUnbind() )।

  • onServiceConnected() : (ঐচ্ছিক) সিস্টেমটি এই পদ্ধতিটিকে কল করে যখন এটি আপনার অ্যাক্সেসিবিলিটি পরিষেবার সাথে সংযোগ করে। অডিও ম্যানেজার বা ডিভাইস ভাইব্রেটরের মতো ব্যবহারকারীর প্রতিক্রিয়া সিস্টেম পরিষেবাগুলির সাথে সংযোগ সহ আপনার পরিষেবার জন্য এককালীন সেটআপ পদক্ষেপগুলি করতে এই পদ্ধতিটি ব্যবহার করুন৷ আপনি যদি রানটাইমে আপনার পরিষেবার কনফিগারেশন সেট করতে চান বা এক-কালীন সামঞ্জস্য করতে চান, তাহলে setServiceInfo() কল করার জন্য এটি একটি সুবিধাজনক অবস্থান।

  • onAccessibilityEvent() : (প্রয়োজনীয়) সিস্টেমটি এই পদ্ধতিটিকে কল ব্যাক করে যখন এটি একটি AccessibilityEvent সনাক্ত করে যা আপনার অ্যাক্সেসিবিলিটি পরিষেবা দ্বারা নির্দিষ্ট করা ইভেন্ট ফিল্টারিং প্যারামিটারগুলির সাথে মেলে, যেমন যখন ব্যবহারকারী একটি বোতামে ট্যাপ করে বা একটি অ্যাপে ব্যবহারকারী ইন্টারফেস নিয়ন্ত্রণে ফোকাস করে আপনার অ্যাক্সেসযোগ্যতা পরিষেবা জন্য প্রতিক্রিয়া প্রদান করা হয়. যখন সিস্টেম এই পদ্ধতিটিকে কল করে, তখন এটি সংশ্লিষ্ট AccessibilityEvent পাস করে, যা পরিষেবাটি তখন ব্যাখ্যা করতে পারে এবং ব্যবহারকারীকে প্রতিক্রিয়া প্রদান করতে ব্যবহার করতে পারে। আপনার পরিষেবার জীবনচক্রে এই পদ্ধতিটি বহুবার বলা যেতে পারে।

  • onInterrupt() : (প্রয়োজনীয়) সিস্টেমটি এই পদ্ধতিটিকে কল করে যখন সিস্টেমটি আপনার পরিষেবা প্রদান করা প্রতিক্রিয়াকে বাধা দিতে চায়, সাধারণত ব্যবহারকারীর ক্রিয়াকলাপের প্রতিক্রিয়া হিসাবে যেমন ফোকাসকে অন্য নিয়ন্ত্রণে স্থানান্তর করা হয়। আপনার পরিষেবার জীবনচক্রে এই পদ্ধতিটি বহুবার বলা যেতে পারে।

  • onUnbind() : (ঐচ্ছিক) সিস্টেম এই পদ্ধতিটিকে কল করে যখন সিস্টেম অ্যাক্সেসিবিলিটি পরিষেবা বন্ধ করতে চলেছে। অডিও ম্যানেজার বা ডিভাইস ভাইব্রেটরের মতো ব্যবহারকারীর প্রতিক্রিয়া সিস্টেম পরিষেবাগুলি ডি-অ্যালোকেটিং সহ যে কোনও এক-কালীন শাটডাউন পদ্ধতি করতে এই পদ্ধতিটি ব্যবহার করুন।

এই কলব্যাক পদ্ধতিগুলি আপনার অ্যাক্সেসিবিলিটি পরিষেবার জন্য মৌলিক কাঠামো প্রদান করে৷ AccessibilityEvent অবজেক্টের আকারে অ্যান্ড্রয়েড সিস্টেম দ্বারা প্রদত্ত ডেটা কীভাবে প্রক্রিয়া করা যায় এবং ব্যবহারকারীকে প্রতিক্রিয়া প্রদান করা যায় তা আপনি সিদ্ধান্ত নিতে পারেন। একটি অ্যাক্সেসিবিলিটি ইভেন্ট থেকে তথ্য পাওয়ার বিষয়ে আরও তথ্যের জন্য, ইভেন্টের বিবরণ পান দেখুন।

অ্যাক্সেসিবিলিটি ইভেন্টের জন্য নিবন্ধন করুন

অ্যাক্সেসিবিলিটি পরিষেবা কনফিগারেশন প্যারামিটারগুলির সবচেয়ে গুরুত্বপূর্ণ ফাংশনগুলির মধ্যে একটি হল আপনার পরিষেবাটি কী ধরনের অ্যাক্সেসিবিলিটি ইভেন্টগুলি পরিচালনা করতে পারে তা আপনাকে নির্দিষ্ট করতে দেওয়া৷ এই তথ্যটি নির্দিষ্ট করার ফলে অ্যাক্সেসিবিলিটি পরিষেবাগুলি একে অপরের সাথে সহযোগিতা করতে দেয় এবং আপনাকে নির্দিষ্ট অ্যাপগুলি থেকে শুধুমাত্র নির্দিষ্ট ইভেন্টের ধরনগুলি পরিচালনা করার নমনীয়তা দেয়৷ ইভেন্ট ফিল্টারিং নিম্নলিখিত মানদণ্ড অন্তর্ভুক্ত করতে পারে:

  • প্যাকেজের নাম: অ্যাপগুলির প্যাকেজের নাম উল্লেখ করুন যেগুলির অ্যাক্সেসিবিলিটি ইভেন্টগুলি আপনি আপনার পরিষেবা পরিচালনা করতে চান৷ যদি এই প্যারামিটারটি বাদ দেওয়া হয়, আপনার অ্যাক্সেসিবিলিটি পরিষেবা যে কোনও অ্যাপের জন্য পরিষেবা অ্যাক্সেসিবিলিটি ইভেন্টগুলিতে উপলব্ধ বলে বিবেচিত হয়৷ আপনি android:packageNames অ্যাট্রিবিউট সহ অ্যাক্সেসিবিলিটি পরিষেবা কনফিগারেশন ফাইলগুলিতে একটি কমা-বিভাজিত তালিকা হিসাবে এই প্যারামিটার সেট করতে পারেন বা AccessibilityServiceInfo.packageNames সদস্য ব্যবহার করতে পারেন।

  • ইভেন্টের ধরন: আপনি আপনার পরিষেবা পরিচালনা করতে চান এমন অ্যাক্সেসিবিলিটি ইভেন্টগুলির প্রকারগুলি নির্দিষ্ট করুন৷ আপনি android:accessibilityEventTypes অ্যাট্রিবিউট সহ অ্যাক্সেসিবিলিটি পরিষেবা কনফিগারেশন ফাইলগুলিতে এই প্যারামিটারটি সেট করতে পারেন | অক্ষর—উদাহরণস্বরূপ, accessibilityEventTypes="typeViewClicked|typeViewFocused" । অথবা আপনি AccessibilityServiceInfo.eventTypes সদস্য ব্যবহার করে এটি সেট করতে পারেন।

আপনার অ্যাক্সেসিবিলিটি পরিষেবা সেট আপ করার সময়, আপনার পরিষেবা কোন ইভেন্টগুলি পরিচালনা করতে পারে তা সাবধানে বিবেচনা করুন এবং শুধুমাত্র সেই ইভেন্টগুলির জন্য নিবন্ধন করুন৷ যেহেতু ব্যবহারকারীরা একবারে একাধিক অ্যাক্সেসিবিলিটি পরিষেবা সক্রিয় করতে পারে, তাই আপনার পরিষেবা অবশ্যই এমন ইভেন্টগুলিকে গ্রাস করবে না যা এটি পরিচালনা করতে পারে না৷ মনে রাখবেন যে ব্যবহারকারীর অভিজ্ঞতা উন্নত করতে অন্যান্য পরিষেবাগুলি সেই ইভেন্টগুলি পরিচালনা করতে পারে৷

অ্যাক্সেসিবিলিটি ভলিউম

Android 8.0 (API স্তর 26) এবং উচ্চতর চলমান ডিভাইসগুলিতে STREAM_ACCESSIBILITY ভলিউম বিভাগ অন্তর্ভুক্ত রয়েছে, যা আপনাকে ডিভাইসের অন্যান্য শব্দ থেকে স্বাধীনভাবে আপনার অ্যাক্সেসিবিলিটি পরিষেবার অডিও আউটপুটের ভলিউম নিয়ন্ত্রণ করতে দেয়৷

অ্যাক্সেসিবিলিটি পরিষেবাগুলি FLAG_ENABLE_ACCESSIBILITY_VOLUME বিকল্প সেট করে এই স্ট্রীম প্রকারটি ব্যবহার করতে পারে৷ তারপর আপনি AudioManager ডিভাইসের ইনস্ট্যান্সে adjustStreamVolume() পদ্ধতিতে কল করে ডিভাইসের অ্যাক্সেসিবিলিটি অডিও ভলিউম পরিবর্তন করতে পারেন।

নিম্নলিখিত কোড স্নিপেট দেখায় কিভাবে একটি অ্যাক্সেসিবিলিটি পরিষেবা STREAM_ACCESSIBILITY ভলিউম বিভাগ ব্যবহার করতে পারে:

কোটলিন

import android.media.AudioManager.*

class MyAccessibilityService : AccessibilityService() {

    private val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager

    override fun onAccessibilityEvent(accessibilityEvent: AccessibilityEvent) {
        if (accessibilityEvent.source.text == "Increase volume") {
            audioManager.adjustStreamVolume(AudioManager.STREAM_ACCESSIBILITY, ADJUST_RAISE, 0)
        }
    }
}

জাভা

import static android.media.AudioManager.*;

public class MyAccessibilityService extends AccessibilityService {
    private AudioManager audioManager =
            (AudioManager) getSystemService(AUDIO_SERVICE);

    @Override
    public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
        AccessibilityNodeInfo interactedNodeInfo =
                accessibilityEvent.getSource();
        if (interactedNodeInfo.getText().equals("Increase volume")) {
            audioManager.adjustStreamVolume(AudioManager.STREAM_ACCESSIBILITY,
                ADJUST_RAISE, 0);
        }
    }
}

আরও তথ্যের জন্য, Google I/O 2017 থেকে Android অ্যাক্সেসিবিলিটি সেশন ভিডিওতে নতুন কী দেখুন, 6:35 এ শুরু হচ্ছে৷

অ্যাক্সেসিবিলিটি শর্টকাট

Android 8.0 (API স্তর 26) এবং উচ্চতর চলমান ডিভাইসগুলিতে, ব্যবহারকারীরা একই সময়ে উভয় ভলিউম কী টিপে এবং ধরে রেখে যেকোনো স্ক্রীন থেকে তাদের পছন্দের অ্যাক্সেসিবিলিটি পরিষেবা সক্ষম এবং অক্ষম করতে পারেন৷ যদিও এই শর্টকাটটি ডিফল্টরূপে Talkback সক্ষম এবং অক্ষম করে, ব্যবহারকারীরা তাদের ডিভাইসে ইনস্টল করা যেকোনো পরিষেবা সক্ষম এবং অক্ষম করতে বোতামটি কনফিগার করতে পারেন।

ব্যবহারকারীদের অ্যাক্সেসিবিলিটি শর্টকাট থেকে একটি নির্দিষ্ট অ্যাক্সেসিবিলিটি পরিষেবা অ্যাক্সেস করার জন্য, পরিষেবাটিকে রানটাইমে বৈশিষ্ট্যটির জন্য অনুরোধ করতে হবে।

আরও তথ্যের জন্য, Google I/O 2017-এর Android অ্যাক্সেসিবিলিটি সেশন ভিডিওতে নতুন কী আছে দেখুন, 13:25 এ শুরু হচ্ছে।

অ্যাক্সেসিবিলিটি বোতাম

একটি সফ্টওয়্যার-রেন্ডার করা নেভিগেশন এলাকা ব্যবহার করে এবং Android 8.0 (API লেভেল 26) বা উচ্চতর চলমান ডিভাইসগুলিতে, নেভিগেশন বারের ডানদিকে একটি অ্যাক্সেসিবিলিটি বোতাম রয়েছে৷ যখন ব্যবহারকারীরা এই বোতামটি চাপেন, তারা বর্তমানে স্ক্রিনে প্রদর্শিত বিষয়বস্তুর উপর নির্ভর করে বেশ কয়েকটি সক্রিয় অ্যাক্সেসিবিলিটি বৈশিষ্ট্য এবং পরিষেবাগুলির মধ্যে একটিকে আহ্বান করতে পারে৷

ব্যবহারকারীদের অ্যাক্সেসিবিলিটি বোতাম ব্যবহার করে একটি প্রদত্ত অ্যাক্সেসিবিলিটি পরিষেবা চালু করতে দিতে, পরিষেবাটিকে AccessibilityServiceInfo অবজেক্টের android:accessibilityFlags অ্যাট্রিবিউটে FLAG_REQUEST_ACCESSIBILITY_BUTTON পতাকা যোগ করতে হবে। পরিষেবাটি তারপর registerAccessibilityButtonCallback() ব্যবহার করে কলব্যাক নিবন্ধন করতে পারে।

নিম্নলিখিত কোড স্নিপেটটি প্রদর্শন করে যে আপনি কীভাবে অ্যাক্সেসিবিলিটি পরিষেবা কনফিগার করতে পারেন ব্যবহারকারীর অ্যাক্সেসিবিলিটি বোতাম টিপে প্রতিক্রিয়া জানাতে:

কোটলিন

private var mAccessibilityButtonController: AccessibilityButtonController? = null
private var accessibilityButtonCallback:
        AccessibilityButtonController.AccessibilityButtonCallback? = null
private var mIsAccessibilityButtonAvailable: Boolean = false

override fun onServiceConnected() {
    mAccessibilityButtonController = accessibilityButtonController
    mIsAccessibilityButtonAvailable =
            mAccessibilityButtonController?.isAccessibilityButtonAvailable ?: false

    if (!mIsAccessibilityButtonAvailable) return

    serviceInfo = serviceInfo.apply {
        flags = flags or AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON
    }

    accessibilityButtonCallback =
        object : AccessibilityButtonController.AccessibilityButtonCallback() {
            override fun onClicked(controller: AccessibilityButtonController) {
                Log.d("MY_APP_TAG", "Accessibility button pressed!")

                // Add custom logic for a service to react to the
                // accessibility button being pressed.
            }

            override fun onAvailabilityChanged(
                    controller: AccessibilityButtonController,
                    available: Boolean
            ) {
                if (controller == mAccessibilityButtonController) {
                    mIsAccessibilityButtonAvailable = available
                }
            }
    }

    accessibilityButtonCallback?.also {
        mAccessibilityButtonController?.registerAccessibilityButtonCallback(it, null)
    }
}

জাভা

private AccessibilityButtonController accessibilityButtonController;
private AccessibilityButtonController
        .AccessibilityButtonCallback accessibilityButtonCallback;
private boolean mIsAccessibilityButtonAvailable;

@Override
protected void onServiceConnected() {
    accessibilityButtonController = getAccessibilityButtonController();
    mIsAccessibilityButtonAvailable =
            accessibilityButtonController.isAccessibilityButtonAvailable();

    if (!mIsAccessibilityButtonAvailable) {
        return;
    }

    AccessibilityServiceInfo serviceInfo = getServiceInfo();
    serviceInfo.flags
            |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
    setServiceInfo(serviceInfo);

    accessibilityButtonCallback =
        new AccessibilityButtonController.AccessibilityButtonCallback() {
            @Override
            public void onClicked(AccessibilityButtonController controller) {
                Log.d("MY_APP_TAG", "Accessibility button pressed!");

                // Add custom logic for a service to react to the
                // accessibility button being pressed.
            }

            @Override
            public void onAvailabilityChanged(
              AccessibilityButtonController controller, boolean available) {
                if (controller.equals(accessibilityButtonController)) {
                    mIsAccessibilityButtonAvailable = available;
                }
            }
        };

    if (accessibilityButtonCallback != null) {
        accessibilityButtonController.registerAccessibilityButtonCallback(
                accessibilityButtonCallback, null);
    }
}

আরও তথ্যের জন্য, Google I/O 2017 থেকে Android অ্যাক্সেসিবিলিটি সেশন ভিডিওতে নতুন কী আছে দেখুন, 16:28 এ শুরু হচ্ছে।

আঙুলের ছাপের অঙ্গভঙ্গি

Android 8.0 (API স্তর 26) বা উচ্চতর চলমান ডিভাইসগুলিতে অ্যাক্সেসিবিলিটি পরিষেবাগুলি একটি ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সর বরাবর দিকনির্দেশক সোয়াইপ (উপর, নীচে, বাম এবং ডানে) প্রতিক্রিয়া জানাতে পারে। এই মিথস্ক্রিয়া সম্পর্কে কলব্যাক গ্রহণ করার জন্য একটি পরিষেবা কনফিগার করতে, নিম্নলিখিত ক্রমটি সম্পূর্ণ করুন:

  1. USE_BIOMETRIC অনুমতি এবং CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES ক্ষমতা ঘোষণা করুন৷
  2. android:accessibilityFlags অ্যাট্রিবিউটের মধ্যে FLAG_REQUEST_FINGERPRINT_GESTURES পতাকা সেট করুন।
  3. registerFingerprintGestureCallback() ব্যবহার করে কলব্যাকের জন্য নিবন্ধন করুন।

মনে রাখবেন যে সমস্ত ডিভাইসে ফিঙ্গারপ্রিন্ট সেন্সর অন্তর্ভুক্ত নয়। একটি ডিভাইস সেন্সর সমর্থন করে কিনা তা সনাক্ত করতে, isHardwareDetected() পদ্ধতি ব্যবহার করুন। এমনকি একটি ফিঙ্গারপ্রিন্ট সেন্সর অন্তর্ভুক্ত এমন একটি ডিভাইসেও, আপনার পরিষেবা যখন প্রমাণীকরণের উদ্দেশ্যে ব্যবহার করা হয় তখন সেন্সরটি ব্যবহার করতে পারে না। সেন্সরটি কখন উপলব্ধ তা সনাক্ত করতে, isGestureDetectionAvailable() পদ্ধতিতে কল করুন এবং onGestureDetectionAvailabilityChanged() কলব্যাকটি প্রয়োগ করুন৷

নিম্নলিখিত কোড স্নিপেট একটি ভার্চুয়াল গেম বোর্ডের চারপাশে নেভিগেট করতে আঙ্গুলের ছাপের অঙ্গভঙ্গি ব্যবহার করার একটি উদাহরণ দেখায়:

// AndroidManifest.xml
<manifest ... >
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
    ...
    <application>
        <service android:name="com.example.MyFingerprintGestureService" ... >
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/myfingerprintgestureservice" />
        </service>
    </application>
</manifest>
// myfingerprintgestureservice.xml
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:accessibilityFlags=" ... |flagRequestFingerprintGestures"
    android:canRequestFingerprintGestures="true"
    ... />

কোটলিন

// MyFingerprintGestureService.kt
import android.accessibilityservice.FingerprintGestureController.*

class MyFingerprintGestureService : AccessibilityService() {

    private var gestureController: FingerprintGestureController? = null
    private var fingerprintGestureCallback:
            FingerprintGestureController.FingerprintGestureCallback? = null
    private var mIsGestureDetectionAvailable: Boolean = false

    override fun onCreate() {
        gestureController = fingerprintGestureController
        mIsGestureDetectionAvailable = gestureController?.isGestureDetectionAvailable ?: false
    }

    override fun onServiceConnected() {
        if (mFingerprintGestureCallback != null || !mIsGestureDetectionAvailable) return

        fingerprintGestureCallback =
                object : FingerprintGestureController.FingerprintGestureCallback() {
                    override fun onGestureDetected(gesture: Int) {
                        when (gesture) {
                            FINGERPRINT_GESTURE_SWIPE_DOWN -> moveGameCursorDown()
                            FINGERPRINT_GESTURE_SWIPE_LEFT -> moveGameCursorLeft()
                            FINGERPRINT_GESTURE_SWIPE_RIGHT -> moveGameCursorRight()
                            FINGERPRINT_GESTURE_SWIPE_UP -> moveGameCursorUp()
                            else -> Log.e(MY_APP_TAG, "Error: Unknown gesture type detected!")
                        }
                    }

                    override fun onGestureDetectionAvailabilityChanged(available: Boolean) {
                        mIsGestureDetectionAvailable = available
                    }
                }

        fingerprintGestureCallback?.also {
            gestureController?.registerFingerprintGestureCallback(it, null)
        }
    }
}

জাভা

// MyFingerprintGestureService.java
import static android.accessibilityservice.FingerprintGestureController.*;

public class MyFingerprintGestureService extends AccessibilityService {
    private FingerprintGestureController gestureController;
    private FingerprintGestureController
            .FingerprintGestureCallback fingerprintGestureCallback;
    private boolean mIsGestureDetectionAvailable;

    @Override
    public void onCreate() {
        gestureController = getFingerprintGestureController();
        mIsGestureDetectionAvailable =
                gestureController.isGestureDetectionAvailable();
    }

    @Override
    protected void onServiceConnected() {
        if (fingerprintGestureCallback != null
                || !mIsGestureDetectionAvailable) {
            return;
        }

        fingerprintGestureCallback =
               new FingerprintGestureController.FingerprintGestureCallback() {
            @Override
            public void onGestureDetected(int gesture) {
                switch (gesture) {
                    case FINGERPRINT_GESTURE_SWIPE_DOWN:
                        moveGameCursorDown();
                        break;
                    case FINGERPRINT_GESTURE_SWIPE_LEFT:
                        moveGameCursorLeft();
                        break;
                    case FINGERPRINT_GESTURE_SWIPE_RIGHT:
                        moveGameCursorRight();
                        break;
                    case FINGERPRINT_GESTURE_SWIPE_UP:
                        moveGameCursorUp();
                        break;
                    default:
                        Log.e(MY_APP_TAG,
                                  "Error: Unknown gesture type detected!");
                        break;
                }
            }

            @Override
            public void onGestureDetectionAvailabilityChanged(boolean available) {
                mIsGestureDetectionAvailable = available;
            }
        };

        if (fingerprintGestureCallback != null) {
            gestureController.registerFingerprintGestureCallback(
                    fingerprintGestureCallback, null);
        }
    }
}

আরও তথ্যের জন্য, Google I/O 2017-এর Android অ্যাক্সেসিবিলিটি সেশন ভিডিওতে নতুন কী আছে দেখুন, 9:03 এ শুরু হচ্ছে।

বহুভাষিক পাঠ্য থেকে বক্তৃতা

অ্যান্ড্রয়েড 8.0 (এপিআই লেভেল 26) থেকে শুরু করে, অ্যান্ড্রয়েডের টেক্সট-টু-স্পিচ (টিটিএস) পরিষেবা পাঠ্যের একক ব্লকের মধ্যে একাধিক ভাষায় বাক্যাংশ সনাক্ত করতে এবং বলতে পারে। একটি অ্যাক্সেসিবিলিটি পরিষেবাতে এই স্বয়ংক্রিয় ভাষা-স্যুইচিং সক্ষমতা সক্ষম করতে, নিম্নলিখিত কোড স্নিপেটে দেখানো হিসাবে LocaleSpan অবজেক্টে সমস্ত স্ট্রিং মুড়ে দিন:

কোটলিন

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

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

জাভা

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

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

আরও তথ্যের জন্য, Google I/O 2017-এর Android অ্যাক্সেসিবিলিটি সেশন ভিডিওতে নতুন কী আছে দেখুন, 10:59 এ শুরু হচ্ছে।

ব্যবহারকারীদের পক্ষে কাজ করুন

2011 থেকে শুরু করে, অ্যাক্সেসিবিলিটি পরিষেবাগুলি ব্যবহারকারীদের পক্ষে কাজ করতে পারে, যার মধ্যে ইনপুট ফোকাস পরিবর্তন করা এবং ব্যবহারকারী ইন্টারফেস উপাদান নির্বাচন (সক্রিয় করা) অন্তর্ভুক্ত রয়েছে। 2012 সালে, স্ক্রলিং তালিকা এবং পাঠ্য ক্ষেত্রের সাথে ইন্টারঅ্যাকটিং অন্তর্ভুক্ত করার জন্য কর্মের পরিসর প্রসারিত হয়েছে। অ্যাক্সেসিবিলিটি পরিষেবাগুলিও বিশ্বব্যাপী পদক্ষেপ নিতে পারে, যেমন হোম স্ক্রিনে নেভিগেট করা, ব্যাক বোতাম টিপুন এবং বিজ্ঞপ্তি স্ক্রীন এবং সাম্প্রতিক অ্যাপের তালিকা খোলা। 2012 সাল থেকে, অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটি ফোকাস অন্তর্ভুক্ত করে, যা একটি অ্যাক্সেসিবিলিটি পরিষেবা দ্বারা সমস্ত দৃশ্যমান উপাদান নির্বাচনযোগ্য করে তোলে৷

এই ক্ষমতাগুলি অ্যাক্সেসিবিলিটি পরিষেবাগুলির বিকাশকারীদের বিকল্প নেভিগেশন মোড তৈরি করতে দেয়, যেমন অঙ্গভঙ্গি নেভিগেশন, এবং অক্ষম ব্যবহারকারীদের তাদের Android-চালিত ডিভাইসগুলির উপর উন্নত নিয়ন্ত্রণ দেয়৷

অঙ্গভঙ্গি জন্য শুনুন

অ্যাক্সেসিবিলিটি পরিষেবাগুলি নির্দিষ্ট অঙ্গভঙ্গি শুনতে এবং ব্যবহারকারীর পক্ষে কাজ করে প্রতিক্রিয়া জানাতে পারে৷ এই বৈশিষ্ট্যটির জন্য প্রয়োজন যে আপনার অ্যাক্সেসিবিলিটি পরিষেবার অনুরোধ টাচ দ্বারা অন্বেষণ বৈশিষ্ট্য সক্রিয়করণ। আপনার পরিষেবা এই অ্যাক্টিভেশনের অনুরোধ করতে পারে পরিষেবার AccessibilityServiceInfo ইনস্ট্যান্সের flags সদস্যকে FLAG_REQUEST_TOUCH_EXPLORATION_MODE এ সেট করে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে৷

কোটলিন

class MyAccessibilityService : AccessibilityService() {

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

জাভা

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

আপনার পরিষেবা স্পর্শ দ্বারা এক্সপ্লোর সক্রিয়করণের অনুরোধ করার পরে, ব্যবহারকারীকে অবশ্যই বৈশিষ্ট্যটি চালু করতে দিতে হবে, যদি এটি ইতিমধ্যে সক্রিয় না থাকে। যখন এই বৈশিষ্ট্যটি সক্রিয় থাকে, তখন আপনার পরিষেবা আপনার পরিষেবার onGesture() কলব্যাক পদ্ধতির মাধ্যমে অ্যাক্সেসিবিলিটি অঙ্গভঙ্গির বিজ্ঞপ্তি পায় এবং ব্যবহারকারীর পক্ষে কাজ করে প্রতিক্রিয়া জানাতে পারে৷

অবিরত অঙ্গভঙ্গি

Android 8.0 (API স্তর 26) চালিত ডিভাইসগুলি অবিরত অঙ্গভঙ্গি সমর্থন করে, বা একাধিক Path অবজেক্ট ধারণকারী প্রোগ্রাম্যাটিক অঙ্গভঙ্গি।

স্ট্রোকের একটি ক্রম নির্দিষ্ট করার সময়, আপনি নিম্নলিখিত কোড স্নিপেটে দেখানো হিসাবে GestureDescription.StrokeDescription কনস্ট্রাক্টরে চূড়ান্ত যুক্তি willContinue ব্যবহার করে নির্দিষ্ট করতে পারেন যে তারা একই প্রোগ্রামেটিক অঙ্গভঙ্গির অন্তর্গত:

কোটলিন

// Simulates an L-shaped drag path: 200 pixels right, then 200 pixels down.
private fun doRightThenDownDrag() {
    val dragRightPath = Path().apply {
        moveTo(200f, 200f)
        lineTo(400f, 200f)
    }
    val dragRightDuration = 500L // 0.5 second

    // The starting point of the second path must match
    // the ending point of the first path.
    val dragDownPath = Path().apply {
        moveTo(400f, 200f)
        lineTo(400f, 400f)
    }
    val dragDownDuration = 500L
    val rightThenDownDrag = GestureDescription.StrokeDescription(
            dragRightPath,
            0L,
            dragRightDuration,
            true
    ).apply {
        continueStroke(dragDownPath, dragRightDuration, dragDownDuration, false)
    }
}

জাভা

// Simulates an L-shaped drag path: 200 pixels right, then 200 pixels down.
private void doRightThenDownDrag() {
    Path dragRightPath = new Path();
    dragRightPath.moveTo(200, 200);
    dragRightPath.lineTo(400, 200);
    long dragRightDuration = 500L; // 0.5 second

    // The starting point of the second path must match
    // the ending point of the first path.
    Path dragDownPath = new Path();
    dragDownPath.moveTo(400, 200);
    dragDownPath.lineTo(400, 400);
    long dragDownDuration = 500L;
    GestureDescription.StrokeDescription rightThenDownDrag =
            new GestureDescription.StrokeDescription(dragRightPath, 0L,
            dragRightDuration, true);
    rightThenDownDrag.continueStroke(dragDownPath, dragRightDuration,
            dragDownDuration, false);
}

আরও তথ্যের জন্য, Google I/O 2017 থেকে Android অ্যাক্সেসিবিলিটি সেশন ভিডিওতে নতুন কী আছে দেখুন, 15:47 এ শুরু হচ্ছে।

অ্যাক্সেসিবিলিটি অ্যাকশন ব্যবহার করুন

অ্যাক্সেসিবিলিটি পরিষেবাগুলি ব্যবহারকারীদের পক্ষে অ্যাপ্লিকেশানগুলির সাথে মিথস্ক্রিয়া সহজ করতে এবং আরও উত্পাদনশীল হতে কাজ করতে পারে৷ কার্য সম্পাদনের জন্য অ্যাক্সেসিবিলিটি পরিষেবাগুলির ক্ষমতা 2011 সালে যোগ করা হয়েছিল এবং 2012 সালে উল্লেখযোগ্যভাবে প্রসারিত হয়েছিল।

ব্যবহারকারীদের পক্ষে কাজ করার জন্য, আপনার অ্যাক্সেসিবিলিটি পরিষেবাকে অবশ্যই অ্যাপ থেকে ইভেন্টগুলি পেতে নিবন্ধন করতে হবে এবং পরিষেবা কনফিগারেশন ফাইলে android:canRetrieveWindowContent true করে অ্যাপের বিষয়বস্তু দেখার অনুমতির অনুরোধ করতে হবে। যখন আপনার পরিষেবা দ্বারা ইভেন্টগুলি পাওয়া যায়, তখন এটি getSource() ব্যবহার করে ইভেন্ট থেকে AccessibilityNodeInfo অবজেক্টটি পুনরুদ্ধার করতে পারে। AccessibilityNodeInfo অবজেক্টের সাহায্যে, আপনার পরিষেবা তারপরে কি পদক্ষেপ নিতে হবে তা নির্ধারণ করতে ভিউ হায়ারার্কি অন্বেষণ করতে পারে এবং তারপর ব্যবহারকারীর জন্য performAction() ব্যবহার করে কাজ করতে পারে।

কোটলিন

class MyAccessibilityService : AccessibilityService() {

    override fun onAccessibilityEvent(event: AccessibilityEvent) {
        // Get the source node of the event.
        event.source?.apply {

            // Use the event and node information to determine what action to
            // take.

            // Act on behalf of the user.
            performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)

            // Recycle the nodeInfo object.
            recycle()
        }
    }
    ...
}

জাভা

public class MyAccessibilityService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        // Get the source node of the event.
        AccessibilityNodeInfo nodeInfo = event.getSource();

        // Use the event and node information to determine what action to take.

        // Act on behalf of the user.
        nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);

        // Recycle the nodeInfo object.
        nodeInfo.recycle();
    }
    ...
}

performAction() পদ্ধতি আপনার পরিষেবাকে একটি অ্যাপের মধ্যে পদক্ষেপ নিতে দেয়। আপনার পরিষেবার যদি কোনও গ্লোবাল অ্যাকশন সঞ্চালনের প্রয়োজন হয়, যেমন হোম স্ক্রিনে নেভিগেট করা, ব্যাক বোতামে ট্যাপ করা, অথবা বিজ্ঞপ্তির স্ক্রীন বা সাম্প্রতিক অ্যাপের তালিকা খোলা, তাহলে performGlobalAction() পদ্ধতি ব্যবহার করুন।

ফোকাস প্রকার ব্যবহার করুন

2012 সালে, অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটি ফোকাস নামে একটি ইউজার ইন্টারফেস ফোকাস চালু করেছিল। অ্যাক্সেসিবিলিটি পরিষেবাগুলি কোনও দৃশ্যমান ব্যবহারকারী ইন্টারফেস উপাদান নির্বাচন করতে এবং এটিতে কাজ করতে এই ফোকাসটি ব্যবহার করতে পারে। এই ফোকাস টাইপ ইনপুট ফোকাস থেকে আলাদা, যা নির্ধারণ করে যে কোন ব্যবহারকারী অক্ষর টাইপ করলে, কীবোর্ডে এন্টার চাপলে বা ডি-প্যাডের কেন্দ্র বোতামে চাপ দিলে অন-স্ক্রীন ব্যবহারকারী ইন্টারফেস উপাদান কী ইনপুট গ্রহণ করে।

একটি ইউজার ইন্টারফেসের একটি উপাদানের পক্ষে ইনপুট ফোকাস থাকা সম্ভব যেখানে অন্য একটি উপাদানের অ্যাক্সেসিবিলিটি ফোকাস রয়েছে। অ্যাক্সেসিবিলিটি ফোকাসের উদ্দেশ্য হল একটি স্ক্রিনে দৃশ্যমান উপাদানগুলির সাথে ইন্টারঅ্যাক্ট করার একটি পদ্ধতি সহ অ্যাক্সেসিবিলিটি পরিষেবা প্রদান করা, উপাদানটি সিস্টেমের দৃষ্টিকোণ থেকে ইনপুট-ফোকাসযোগ্য কিনা তা নির্বিশেষে। আপনার অ্যাক্সেসিবিলিটি পরিষেবাটি অ্যাপের ইনপুট উপাদানগুলির সাথে সঠিকভাবে ইন্টারঅ্যাক্ট করে তা নিশ্চিত করতে সাহায্য করার জন্য, একটি সাধারণ অ্যাপ ব্যবহার করার সময় আপনার পরিষেবা পরীক্ষা করার জন্য একটি অ্যাপের অ্যাক্সেসিবিলিটি পরীক্ষা করার জন্য নির্দেশিকা অনুসরণ করুন।

একটি অ্যাক্সেসিবিলিটি পরিষেবা AccessibilityNodeInfo.findFocus() পদ্ধতি ব্যবহার করে কোন ইউজার ইন্টারফেসের উপাদান ইনপুট ফোকাস বা অ্যাক্সেসিবিলিটি ফোকাস আছে তা নির্ধারণ করতে পারে। এছাড়াও আপনি focusSearch() পদ্ধতি ব্যবহার করে ইনপুট ফোকাসের সাথে নির্বাচন করা যেতে পারে এমন উপাদানগুলি অনুসন্ধান করতে পারেন। অবশেষে, আপনার অ্যাক্সেসিবিলিটি পরিষেবা performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS) পদ্ধতি ব্যবহার করে অ্যাক্সেসিবিলিটি ফোকাস সেট করতে পারে।

তথ্য সংগ্রহ

অ্যাক্সেসিবিলিটি পরিষেবাগুলিতে ব্যবহারকারী-প্রদত্ত তথ্য যেমন ইভেন্টের বিশদ বিবরণ, পাঠ্য এবং সংখ্যার মূল একক সংগ্রহ এবং প্রতিনিধিত্ব করার মানক পদ্ধতি রয়েছে।

উইন্ডো পরিবর্তনের বিবরণ পান

অ্যান্ড্রয়েড 9 (এপিআই লেভেল 28) এবং উচ্চতর অ্যাপগুলিকে উইন্ডো আপডেটের ট্র্যাক রাখতে দেয় যখন একটি অ্যাপ একই সাথে একাধিক উইন্ডো পুনরায় আঁকে। যখন একটি TYPE_WINDOWS_CHANGED ইভেন্ট ঘটে, উইন্ডোজ কিভাবে পরিবর্তন হয় তা নির্ধারণ করতে getWindowChanges() API ব্যবহার করুন। একটি মাল্টি-উইন্ডো আপডেটের সময়, প্রতিটি উইন্ডো তার নিজস্ব ইভেন্টের সেট তৈরি করে। getSource() পদ্ধতি প্রতিটি ইভেন্টের সাথে যুক্ত উইন্ডোর রুট ভিউ প্রদান করে।

যদি কোনো অ্যাপ তার View অবজেক্টের জন্য অ্যাক্সেসিবিলিটি প্যান শিরোনাম সংজ্ঞায়িত করে, তাহলে অ্যাপের UI আপডেট হলে আপনার পরিষেবা চিনতে পারে। যখন একটি TYPE_WINDOW_STATE_CHANGED ইভেন্ট ঘটে, তখন উইন্ডো কীভাবে পরিবর্তিত হয় তা নির্ধারণ করতে getContentChangeTypes() দ্বারা প্রত্যাবর্তিত প্রকারগুলি ব্যবহার করুন৷ উদাহরণস্বরূপ, ফ্রেমওয়ার্ক সনাক্ত করতে পারে যখন একটি প্যানে একটি নতুন শিরোনাম আছে বা কখন একটি ফলক অদৃশ্য হয়ে যায়।

ইভেন্ট বিবরণ পান

অ্যানড্রয়েড AccessibilityEvent অবজেক্টের মাধ্যমে ব্যবহারকারীর ইন্টারফেস মিথস্ক্রিয়া সম্পর্কে অ্যাক্সেসিবিলিটি পরিষেবাগুলিতে তথ্য সরবরাহ করে। পূর্ববর্তী অ্যান্ড্রয়েড সংস্করণগুলিতে, একটি অ্যাক্সেসিবিলিটি ইভেন্টে উপলব্ধ তথ্য, ব্যবহারকারীদের দ্বারা নির্বাচিত ইউজার ইন্টারফেস নিয়ন্ত্রণ সম্পর্কে উল্লেখযোগ্য বিবরণ প্রদান করার সময়, সীমিত প্রাসঙ্গিক তথ্য সরবরাহ করে। অনেক ক্ষেত্রে, এই অনুপস্থিত প্রসঙ্গ তথ্য নির্বাচিত নিয়ন্ত্রণের অর্থ বোঝার জন্য গুরুত্বপূর্ণ হতে পারে।

একটি ইন্টারফেসের উদাহরণ যেখানে প্রসঙ্গ সমালোচনামূলক হয় একটি ক্যালেন্ডার বা দিন পরিকল্পনাকারী। ব্যবহারকারী যদি সোমবার থেকে শুক্রবার দিনের তালিকায় একটি 4:00 PM সময় স্লট নির্বাচন করে এবং অ্যাক্সেসিবিলিটি পরিষেবা "4 PM" ঘোষণা করে, কিন্তু সপ্তাহের দিনের নাম, মাসের দিন বা মাসের নাম ঘোষণা না করে, ফলস্বরূপ প্রতিক্রিয়া বিভ্রান্তিকর। এই ক্ষেত্রে, একটি ব্যবহারকারী ইন্টারফেস নিয়ন্ত্রণের প্রেক্ষাপট একটি ব্যবহারকারীর জন্য গুরুত্বপূর্ণ যে একটি মিটিং শিডিউল করতে চায়।

2011 সাল থেকে, ভিউ হায়ারার্কির উপর ভিত্তি করে অ্যাক্সেসিবিলিটি ইভেন্টগুলি রচনা করে একটি অ্যাক্সেসিবিলিটি পরিষেবা ব্যবহারকারী ইন্টারফেস মিথস্ক্রিয়া সম্পর্কে যে পরিমাণ তথ্য পেতে পারে তা Android উল্লেখযোগ্যভাবে প্রসারিত করে৷ একটি ভিউ হায়ারার্কি হল ইউজার ইন্টারফেস কম্পোনেন্টের সেট যাতে কম্পোনেন্ট থাকে (এর বাবা-মা) এবং ইউজার ইন্টারফেস এলিমেন্ট যা সেই কম্পোনেন্ট (এর বাচ্চাদের) দ্বারা থাকতে পারে। এইভাবে, অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটি ইভেন্টগুলি সম্পর্কে আরও সমৃদ্ধ বিশদ প্রদান করতে পারে, অ্যাক্সেসিবিলিটি পরিষেবাগুলি ব্যবহারকারীদের আরও দরকারী প্রতিক্রিয়া প্রদান করতে দেয়৷

একটি অ্যাক্সেসিবিলিটি পরিষেবা সিস্টেম দ্বারা পরিষেবার onAccessibilityEvent() কলব্যাক পদ্ধতিতে পাস করা একটি অ্যাক্সেসিবিলিটি AccessibilityEvent মাধ্যমে একটি ব্যবহারকারী ইন্টারফেস ইভেন্ট সম্পর্কে তথ্য পায়। এই অবজেক্টটি ইভেন্ট সম্পর্কে বিশদ বিবরণ প্রদান করে, যার মধ্যে কোন বস্তুর উপর কাজ করা হচ্ছে, এর বর্ণনামূলক পাঠ্য এবং অন্যান্য বিশদ বিবরণ রয়েছে।

  • AccessibilityEvent.getRecordCount() এবং getRecord(int) : এই পদ্ধতিগুলি আপনাকে AccessibilityRecord অবজেক্টের সেট পুনরুদ্ধার করতে দেয় যা সিস্টেমের দ্বারা আপনার কাছে দেওয়া AccessibilityEvent অবদান রাখে। এই স্তরের বিশদটি সেই ইভেন্টের জন্য আরও প্রসঙ্গ সরবরাহ করে যা আপনার অ্যাক্সেসিবিলিটি পরিষেবাকে ট্রিগার করে৷

  • AccessibilityRecord.getSource() : এই পদ্ধতিটি একটি AccessibilityNodeInfo অবজেক্ট প্রদান করে। এই অবজেক্টটি আপনাকে অ্যাক্সেসিবিলিটি ইভেন্টের উদ্ভবকারী উপাদানটির ভিউ লেআউট শ্রেণিবিন্যাস (পিতামাতা এবং শিশু) অনুরোধ করতে দেয়। এই বৈশিষ্ট্যটি একটি অ্যাক্সেসিবিলিটি পরিষেবাকে একটি ইভেন্টের সম্পূর্ণ প্রেক্ষাপটের তদন্ত করতে দেয়, যেকোন এনক্লোজিং ভিউ বা চাইল্ড ভিউয়ের বিষয়বস্তু এবং অবস্থা সহ।

অ্যান্ড্রয়েড প্ল্যাটফর্মটি একটি AccessibilityService জন্য ভিউ হায়ারার্কি অনুসন্ধান করার ক্ষমতা প্রদান করে, UI উপাদান সম্পর্কে তথ্য সংগ্রহ করে যা একটি ইভেন্টের পাশাপাশি এর পিতামাতা এবং শিশুদের জন্য তৈরি করে। এটি করার জন্য, আপনার XML কনফিগারেশনে নিম্নলিখিত লাইনটি সেট করুন:

android:canRetrieveWindowContent="true"

এটি সম্পন্ন করার পরে, getSource() ব্যবহার করে একটি AccessibilityNodeInfo অবজেক্ট পান। এই কলটি শুধুমাত্র একটি অবজেক্ট রিটার্ন করে যদি ইভেন্টটি যে উইন্ডো থেকে উদ্ভূত হয় সেটি এখনও সক্রিয় উইন্ডো থাকে। যদি না হয়, এটি নাল ফেরত দেয়, তাই সেই অনুযায়ী আচরণ করুন।

নিম্নলিখিত উদাহরণে, একটি ইভেন্ট প্রাপ্ত হলে কোডটি নিম্নলিখিতগুলি করে:

  1. অবিলম্বে দৃশ্যের অভিভাবককে আঁকড়ে ধরে যেখানে ঘটনাটির উৎপত্তি হয়৷
  2. সেই দৃশ্যে, চাইল্ড ভিউ হিসাবে একটি লেবেল এবং একটি চেকবক্স খোঁজে।
  3. যদি এটি তাদের খুঁজে পায়, ব্যবহারকারীকে রিপোর্ট করার জন্য একটি স্ট্রিং তৈরি করে, লেবেলটি নির্দেশ করে এবং এটি পরীক্ষা করা হয়েছে কিনা।

ভিউ হায়ারার্কি অতিক্রম করার সময় যদি কোনো সময়ে একটি শূন্য মান ফেরত দেওয়া হয়, তবে পদ্ধতিটি শান্তভাবে ছেড়ে দেয়।

কোটলিন

// Alternative onAccessibilityEvent that uses AccessibilityNodeInfo.

override fun onAccessibilityEvent(event: AccessibilityEvent) {

    val source: AccessibilityNodeInfo = event.source ?: return

    // Grab the parent of the view that fires the event.
    val rowNode: AccessibilityNodeInfo = getListItemNodeInfo(source) ?: return

    // Using this parent, get references to both child nodes, the label, and the
    // checkbox.
    val taskLabel: CharSequence = rowNode.getChild(0)?.text ?: run {
        rowNode.recycle()
        return
    }

    val isComplete: Boolean = rowNode.getChild(1)?.isChecked ?: run {
        rowNode.recycle()
        return
    }

    // Determine what the task is and whether it's complete based on the text
    // inside the label, and the state of the checkbox.
    if (rowNode.childCount < 2 || !rowNode.getChild(1).isCheckable) {
        rowNode.recycle()
        return
    }

    val completeStr: String = if (isComplete) {
        getString(R.string.checked)
    } else {
        getString(R.string.not_checked)
    }
    val reportStr = "$taskLabel$completeStr"
    speakToUser(reportStr)
}

জাভা

// Alternative onAccessibilityEvent that uses AccessibilityNodeInfo.

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {

    AccessibilityNodeInfo source = event.getSource();
    if (source == null) {
        return;
    }

    // Grab the parent of the view that fires the event.
    AccessibilityNodeInfo rowNode = getListItemNodeInfo(source);
    if (rowNode == null) {
        return;
    }

    // Using this parent, get references to both child nodes, the label, and the
    // checkbox.
    AccessibilityNodeInfo labelNode = rowNode.getChild(0);
    if (labelNode == null) {
        rowNode.recycle();
        return;
    }

    AccessibilityNodeInfo completeNode = rowNode.getChild(1);
    if (completeNode == null) {
        rowNode.recycle();
        return;
    }

    // Determine what the task is and whether it's complete based on the text
    // inside the label, and the state of the checkbox.
    if (rowNode.getChildCount() < 2 || !rowNode.getChild(1).isCheckable()) {
        rowNode.recycle();
        return;
    }

    CharSequence taskLabel = labelNode.getText();
    final boolean isComplete = completeNode.isChecked();
    String completeStr = null;

    if (isComplete) {
        completeStr = getString(R.string.checked);
    } else {
        completeStr = getString(R.string.not_checked);
    }
    String reportStr = taskLabel + completeStr;
    speakToUser(reportStr);
}

এখন আপনার কাছে একটি সম্পূর্ণ, কার্যকরী অ্যাক্সেসিবিলিটি পরিষেবা রয়েছে৷ অ্যান্ড্রয়েডের টেক্সট-টু-স্পিচ ইঞ্জিন যোগ করে বা হ্যাপটিক প্রতিক্রিয়া প্রদানের জন্য একটি Vibrator ব্যবহার করে ব্যবহারকারীর সাথে এটি কীভাবে ইন্টারঅ্যাক্ট করে তা কনফিগার করার চেষ্টা করুন।

প্রসেস টেক্সট

Android 8.0 (API স্তর 26) এবং উচ্চতর চলমান ডিভাইসগুলিতে বেশ কিছু পাঠ্য-প্রক্রিয়াকরণ বৈশিষ্ট্য রয়েছে যা অ্যাক্সেসিবিলিটি পরিষেবাগুলিকে স্ক্রিনে প্রদর্শিত পাঠ্যের নির্দিষ্ট ইউনিটগুলি সনাক্ত করা এবং পরিচালনা করা সহজ করে তোলে।

টুলটিপস

অ্যান্ড্রয়েড 9 (এপিআই স্তর 28) বেশ কয়েকটি ক্ষমতার পরিচয় দেয় যা আপনাকে একটি অ্যাপের UI-তে টুলটিপগুলিতে অ্যাক্সেস দেয়। একটি টুলটিপের পাঠ্য পড়তে getTooltipText() ব্যবহার করুন, এবং তাদের টুলটিপগুলি দেখানো বা লুকানোর জন্য View দৃষ্টান্ত নির্দেশ করতে ACTION_SHOW_TOOLTIP এবং ACTION_HIDE_TOOLTIP ব্যবহার করুন৷

ইঙ্গিত পাঠ্য

2017 থেকে শুরু করে, অ্যান্ড্রয়েড একটি পাঠ্য-ভিত্তিক বস্তুর ইঙ্গিত পাঠ্যের সাথে ইন্টারঅ্যাক্ট করার জন্য বিভিন্ন পদ্ধতি অন্তর্ভুক্ত করে:

  • isShowingHintText() এবং setShowingHintText() পদ্ধতিগুলি যথাক্রমে নির্দেশ করে এবং সেট করে, নোডের বর্তমান পাঠ্য বিষয়বস্তু নোডের ইঙ্গিত পাঠ্যকে প্রতিনিধিত্ব করে কিনা।
  • getHintText() নিজেই ইঙ্গিত পাঠ্য অ্যাক্সেস প্রদান করে। এমনকি যদি একটি বস্তু ইঙ্গিত পাঠ্য প্রদর্শন না করে, getHintText() কল করা সফল হয়।

অন-স্ক্রীন পাঠ্য অক্ষরের অবস্থান

Android 8.0 (API স্তর 26) এবং উচ্চতর চলমান ডিভাইসগুলিতে, অ্যাক্সেসিবিলিটি পরিষেবাগুলি একটি TextView উইজেটের মধ্যে প্রতিটি দৃশ্যমান অক্ষরের বাউন্ডিং বাক্সের জন্য স্ক্রীন স্থানাঙ্ক নির্ধারণ করতে পারে। পরিষেবাগুলি refreshWithExtraData() কল করে, প্রথম আর্গুমেন্ট হিসাবে EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY এবং দ্বিতীয় আর্গুমেন্ট হিসাবে একটি Bundle অবজেক্ট পাস করে এই স্থানাঙ্কগুলি খুঁজে পায়৷ পদ্ধতিটি কার্যকর করার সাথে সাথে, সিস্টেমটি Bundle আর্গুমেন্টকে Rect অবজেক্টের একটি পার্সেলেবল অ্যারে দিয়ে তৈরি করে। প্রতিটি Rect বস্তু একটি নির্দিষ্ট অক্ষরের আবদ্ধ বাক্স প্রতিনিধিত্ব করে।

প্রমিত একতরফা পরিসীমা মান

কিছু AccessibilityNodeInfo অবজেক্টগুলি AccessibilityNodeInfo.RangeInfo এর একটি উদাহরণ ব্যবহার করে নির্দেশ করে যে একটি UI উপাদান বিভিন্ন মান গ্রহণ করতে পারে। RangeInfo.obtain() ব্যবহার করে একটি পরিসর তৈরি করার সময়, অথবা getMin() এবং getMax() ব্যবহার করে পরিসরের চরম মানগুলি পুনরুদ্ধার করার সময়, মনে রাখবেন যে Android 8.0 (API স্তর 26) এবং উচ্চতর ডিভাইসগুলি একতরফা রেঞ্জের প্রতিনিধিত্ব করে একটি প্রমিত পদ্ধতি:

  • ন্যূনতম কোন ব্যাপ্তির জন্য, Float.NEGATIVE_INFINITY ন্যূনতম মান উপস্থাপন করে৷
  • সর্বোচ্চ না থাকা ব্যাপ্তির জন্য, Float.POSITIVE_INFINITY সর্বাধিক মান উপস্থাপন করে৷

অ্যাক্সেসিবিলিটি ইভেন্টগুলিতে সাড়া দিন

এখন যেহেতু আপনার পরিষেবাটি ইভেন্টগুলি চালানো এবং শোনার জন্য সেট আপ করা হয়েছে, কোড লিখুন যাতে এটি একটি AccessibilityEvent এলে কী করতে হবে তা জানে৷ onAccessibilityEvent(AccessibilityEvent) পদ্ধতি ওভাররাইড করে শুরু করুন। সেই পদ্ধতিতে, ইভেন্টের ধরন নির্ধারণ করতে getEventType() ব্যবহার করুন এবং ইভেন্টটি ফায়ার করে এমন দৃশ্যের সাথে যুক্ত যেকোন লেবেল পাঠ্য বের করতে getContentDescription() ব্যবহার করুন:

কোটলিন

override fun onAccessibilityEvent(event: AccessibilityEvent) {
    var eventText: String = when (event.eventType) {
        AccessibilityEvent.TYPE_VIEW_CLICKED -> "Clicked: "
        AccessibilityEvent.TYPE_VIEW_FOCUSED -> "Focused: "
        else -> ""
    }

    eventText += event.contentDescription

    // Do something nifty with this text, like speak the composed string back to
    // the user.
    speakToUser(eventText)
    ...
}

জাভা

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    final int eventType = event.getEventType();
    String eventText = null;
    switch(eventType) {
        case AccessibilityEvent.TYPE_VIEW_CLICKED:
            eventText = "Clicked: ";
            break;
        case AccessibilityEvent.TYPE_VIEW_FOCUSED:
            eventText = "Focused: ";
            break;
    }

    eventText = eventText + event.getContentDescription();

    // Do something nifty with this text, like speak the composed string back to
    // the user.
    speakToUser(eventText);
    ...
}

অতিরিক্ত সম্পদ

আরও জানতে, নিম্নলিখিত সংস্থানগুলি দেখুন:

গাইড

কোডল্যাব