ধারণা এবং জেটপ্যাক কম্পোজ বাস্তবায়ন
অ্যাক্সেসিবিলিটি সার্ভিস হলো এমন একটি অ্যাপ যা প্রতিবন্ধী ব্যবহারকারীদের বা যারা সাময়িকভাবে কোনো ডিভাইসের সাথে পুরোপুরিভাবে ইন্টারঅ্যাক্ট করতে অক্ষম, তাদের সহায়তা করার জন্য ইউজার ইন্টারফেসকে উন্নত করে। উদাহরণস্বরূপ, যেসব ব্যবহারকারী গাড়ি চালাচ্ছেন, ছোট বাচ্চার যত্ন নিচ্ছেন, বা খুব কোলাহলপূর্ণ কোনো পার্টিতে আছেন, তাদের অতিরিক্ত বা বিকল্প ইন্টারফেস ফিডব্যাকের প্রয়োজন হতে পারে।
অ্যান্ড্রয়েড টকব্যাক (TalkBack) সহ বিভিন্ন স্ট্যান্ডার্ড অ্যাক্সেসিবিলিটি সার্ভিস প্রদান করে এবং ডেভেলপাররা তাদের নিজস্ব সার্ভিস তৈরি ও বিতরণ করতে পারেন। এই ডকুমেন্টটিতে একটি অ্যাক্সেসিবিলিটি সার্ভিস তৈরির প্রাথমিক বিষয়গুলো ব্যাখ্যা করা হয়েছে।
একটি অ্যাক্সেসিবিলিটি সার্ভিস একটি সাধারণ অ্যাপের সাথে যুক্ত করা যেতে পারে অথবা একটি স্বতন্ত্র অ্যান্ড্রয়েড প্রজেক্ট হিসেবেও তৈরি করা যেতে পারে। উভয় ক্ষেত্রেই সার্ভিসটি তৈরি করার ধাপগুলো একই।
আপনার প্রবেশগম্যতা পরিষেবা তৈরি করুন
আপনার প্রোজেক্টের মধ্যে, 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 ক্লাসটি সরিয়ে ফেলতে পারেন।
প্রকাশ্য ঘোষণা এবং অনুমতি
অ্যান্ড্রয়েড সিস্টেম দ্বারা অ্যাক্সেসিবিলিটি পরিষেবা হিসাবে বিবেচিত হওয়ার জন্য, যে অ্যাপগুলি অ্যাক্সেসিবিলিটি পরিষেবা প্রদান করে সেগুলিকে তাদের অ্যাপ ম্যানিফেস্টে নির্দিষ্ট ঘোষণা অন্তর্ভুক্ত করতে হবে। এই বিভাগে অ্যাক্সেসিবিলিটি পরিষেবার জন্য প্রয়োজনীয় এবং ঐচ্ছিক সেটিংস ব্যাখ্যা করা হয়েছে।
প্রবেশগম্যতা পরিষেবা ঘোষণা
আপনার অ্যাপটিকে একটি অ্যাক্সেসিবিলিটি সার্ভিস হিসেবে গণ্য করার জন্য, আপনার ম্যানিফেস্টের 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 অ্যাট্রিবিউটগুলো ব্যবহার করা যেতে পারে, সে সম্পর্কে আরও তথ্যের জন্য নিম্নলিখিত রেফারেন্স ডকুমেন্টেশন দেখুন:
-
android:description -
android:packageNames -
android:accessibilityEventTypes -
android:accessibilityFlags -
android:accessibilityFeedbackType -
android:notificationTimeout -
android:canRetrieveWindowContent -
android:settingsActivity
রানটাইমে কোন কোন কনফিগারেশন সেটিংস ডায়নামিকভাবে সেট করা যায় সে সম্পর্কে আরও তথ্যের জন্য, AccessibilityServiceInfo রেফারেন্স ডকুমেন্টেশন দেখুন।
আপনার অ্যাক্সেসিবিলিটি পরিষেবা কনফিগার করুন
আপনার অ্যাক্সেসিবিলিটি সার্ভিসের কনফিগারেশন ভেরিয়েবল সেট করার সময় নিম্নলিখিত বিষয়গুলো বিবেচনা করুন, যা সিস্টেমকে বলে দেবে কখন এবং কীভাবে এটি চালাতে হবে:
- আপনি এটি কোন ধরনের ইভেন্টে সাড়া দেবে বলে চান?
- পরিষেবাটি কি সমস্ত অ্যাপের জন্য সক্রিয় থাকা প্রয়োজন, নাকি শুধুমাত্র নির্দিষ্ট প্যাকেজ নামগুলোর জন্য?
- এটি কী কী ভিন্ন ধরনের ফিডব্যাক ব্যবহার করে?
এই ভেরিয়েবলগুলো সেট করার জন্য আপনার কাছে দুটি বিকল্প আছে। ব্যাকওয়ার্ড কম্প্যাটিবল বিকল্পটি হলো কোডের মাধ্যমে setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo) ব্যবহার করে এগুলো সেট করা। এটি করার জন্য, onServiceConnected() মেথডটি ওভাররাইড করুন এবং সেখানে আপনার সার্ভিসটি কনফিগার করুন, যেমনটি নিচের উদাহরণে দেখানো হয়েছে:
কোটলিন
override fun onServiceConnected() { info.apply { // Set the type of events that this service wants to listen to. Others // aren't passed to this service. eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED or AccessibilityEvent.TYPE_VIEW_FOCUSED // If you only want this service to work with specific apps, set their // package names here. Otherwise, when the service is activated, it // listens to events from all apps. packageNames = arrayOf("com.example.android.myFirstApp", "com.example.android.mySecondApp") // Set the type of feedback your service provides. feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN // Default services are invoked only if no package-specific services are // present for the type of AccessibilityEvent generated. This service is // app-specific, so the flag isn't necessary. For a general-purpose // service, consider setting the DEFAULT flag. // flags = AccessibilityServiceInfo.DEFAULT; notificationTimeout = 100 } this.serviceInfo = info }
জাভা
@Override public void onServiceConnected() { // Set the type of events that this service wants to listen to. Others // aren't passed to this service. info.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED; // If you only want this service to work with specific apps, set their // package names here. Otherwise, when the service is activated, it listens // to events from all apps. info.packageNames = new String[] {"com.example.android.myFirstApp", "com.example.android.mySecondApp"}; // Set the type of feedback your service provides. info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN; // Default services are invoked only if no package-specific services are // present for the type of AccessibilityEvent generated. This service is // app-specific, so the flag isn't necessary. For a general-purpose service, // consider setting the DEFAULT flag. // info.flags = AccessibilityServiceInfo.DEFAULT; info.notificationTimeout = 100; this.setServiceInfo(info); }
দ্বিতীয় বিকল্পটি হলো একটি XML ফাইল ব্যবহার করে সার্ভিসটি কনফিগার করা। কিছু নির্দিষ্ট কনফিগারেশন অপশন, যেমন canRetrieveWindowContent , শুধুমাত্র তখনই পাওয়া যায় যদি আপনি XML ব্যবহার করে আপনার সার্ভিসটি কনফিগার করেন। আগের উদাহরণের কনফিগারেশন অপশনগুলো XML ব্যবহার করে সংজ্ঞায়িত করা হলে দেখতে এইরকম হয়:
<accessibility-service android:accessibilityEventTypes="typeViewClicked|typeViewFocused" android:packageNames="com.example.android.myFirstApp, com.example.android.mySecondApp" android:accessibilityFeedbackType="feedbackSpoken" android:notificationTimeout="100" android:settingsActivity="com.example.android.apis.accessibility.TestBackActivity" android:canRetrieveWindowContent="true" />
আপনি যদি XML ব্যবহার করেন, তাহলে আপনার সার্ভিস ডিক্লারেশনে একটি <meta-data> ট্যাগ যোগ করে XML ফাইলটিকে নির্দেশ করুন। যদি আপনি আপনার XML ফাইলটি res/xml/serviceconfig.xml এ সংরক্ষণ করেন, তাহলে নতুন ট্যাগটি দেখতে এইরকম হবে:
<service android:name=".MyAccessibilityService"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/serviceconfig" /> </service>
প্রবেশগম্যতা পরিষেবা পদ্ধতি
একটি অ্যাক্সেসিবিলিটি সার্ভিসকে অবশ্যই AccessibilityService ক্লাসটি এক্সটেন্ড করতে হবে এবং সেই ক্লাসের নিম্নলিখিত মেথডগুলো ওভাররাইড করতে হবে। এই মেথডগুলো সেই ক্রমানুসারে উপস্থাপন করা হয়েছে যে ক্রমে অ্যান্ড্রয়েড সিস্টেম এগুলোকে কল করে: সার্ভিসটি শুরু হওয়ার সময় ( onServiceConnected() ), এটি চলার সময় ( onAccessibilityEvent() , onInterrupt() ), এবং এটি বন্ধ হয়ে যাওয়ার সময় ( onUnbind() )।
onServiceConnected(): (ঐচ্ছিক) সিস্টেম আপনার অ্যাক্সেসিবিলিটি সার্ভিসের সাথে সংযোগ স্থাপন করার সময় এই মেথডটি কল করে। আপনার সার্ভিসের জন্য এককালীন সেটআপ ধাপগুলো সম্পন্ন করতে এই মেথডটি ব্যবহার করুন, যার মধ্যে রয়েছে ইউজার ফিডব্যাক সিস্টেম সার্ভিস, যেমন অডিও ম্যানেজার বা ডিভাইস ভাইব্রেটরের সাথে সংযোগ স্থাপন করা। আপনি যদি রানটাইমে আপনার সার্ভিসের কনফিগারেশন সেট করতে বা এককালীন কোনো পরিবর্তন করতে চান, তবেsetServiceInfo()কল করার জন্য এটি একটি সুবিধাজনক স্থান।onAccessibilityEvent(): (আবশ্যক) যখন সিস্টেম আপনার অ্যাক্সেসিবিলিটি সার্ভিস দ্বারা নির্দিষ্ট করা ইভেন্ট ফিল্টারিং প্যারামিটারের সাথে মেলে এমন কোনোAccessibilityEventশনাক্ত করে, তখন এটি এই মেথডটিকে কলব্যাক করে। যেমন, যখন ব্যবহারকারী কোনো অ্যাপে একটি বোতামে ট্যাপ করেন বা কোনো ইউজার ইন্টারফেস কন্ট্রোলে ফোকাস করেন, যে অ্যাপটির জন্য আপনার অ্যাক্সেসিবিলিটি সার্ভিস ফিডব্যাক প্রদান করছে। সিস্টেম যখন এই মেথডটিকে কল করে, তখন এটি সংশ্লিষ্টAccessibilityEventপাস করে, যা সার্ভিসটি তখন ব্যাখ্যা করতে এবং ব্যবহারকারীকে ফিডব্যাক দেওয়ার জন্য ব্যবহার করতে পারে। আপনার সার্ভিসের লাইফসাইকেলে এই মেথডটি বহুবার কল করা যেতে পারে।onInterrupt(): (আবশ্যক) যখন সিস্টেম আপনার সার্ভিসের দেওয়া ফিডব্যাকে বাধা দিতে চায়, তখন এই মেথডটি কল করা হয়। এটি সাধারণত ব্যবহারকারীর কোনো কাজের প্রতিক্রিয়ায় করা হয়, যেমন—ফোকাসকে অন্য কোনো কন্ট্রোলে সরানো। আপনার সার্ভিসের জীবনচক্রে এই মেথডটি বহুবার কল করা হতে পারে।onUnbind(): (ঐচ্ছিক) সিস্টেম যখন অ্যাক্সেসিবিলিটি সার্ভিসটি বন্ধ করতে যায়, তখন এই মেথডটি কল করে। যেকোনো এককালীন শাটডাউন প্রক্রিয়া সম্পন্ন করতে এই মেথডটি ব্যবহার করুন, যার মধ্যে রয়েছে অডিও ম্যানেজার বা ডিভাইস ভাইব্রেটরের মতো ইউজার ফিডব্যাক সিস্টেম সার্ভিসগুলোকে ডি-অ্যালোকেট করা।
এই কলব্যাক মেথডগুলো আপনার অ্যাক্সেসিবিলিটি সার্ভিসের জন্য মৌলিক কাঠামো প্রদান করে। আপনি নির্ধারণ করতে পারেন যে অ্যান্ড্রয়েড সিস্টেম থেকে AccessibilityEvent অবজেক্ট আকারে প্রাপ্ত ডেটা কীভাবে প্রসেস করবেন এবং ব্যবহারকারীকে ফিডব্যাক দেবেন। একটি অ্যাক্সেসিবিলিটি ইভেন্ট থেকে তথ্য পাওয়ার বিষয়ে আরও জানতে, "ইভেন্টের বিবরণ পান" দেখুন।
প্রবেশগম্যতা ইভেন্টগুলির জন্য নিবন্ধন করুন
অ্যাক্সেসিবিলিটি সার্ভিস কনফিগারেশন প্যারামিটারগুলোর অন্যতম গুরুত্বপূর্ণ কাজ হলো, আপনার সার্ভিসটি কোন ধরনের অ্যাক্সেসিবিলিটি ইভেন্ট পরিচালনা করতে পারবে তা নির্দিষ্ট করে দেওয়া। এই তথ্য নির্দিষ্ট করার ফলে অ্যাক্সেসিবিলিটি সার্ভিসগুলো একে অপরের সাথে সহযোগিতা করতে পারে এবং আপনাকে নির্দিষ্ট অ্যাপ থেকে শুধুমাত্র নির্দিষ্ট ধরনের ইভেন্ট পরিচালনা করার সুবিধা দেয়। ইভেন্ট ফিল্টারিং-এ নিম্নলিখিত মানদণ্ডগুলো অন্তর্ভুক্ত থাকতে পারে:
প্যাকেজ নাম: সেইসব অ্যাপের প্যাকেজ নাম উল্লেখ করুন, যাদের অ্যাক্সেসিবিলিটি ইভেন্টগুলো আপনি আপনার সার্ভিস দ্বারা পরিচালনা করাতে চান। এই প্যারামিটারটি বাদ দেওয়া হলে, আপনার অ্যাক্সেসিবিলিটি সার্ভিসটি যেকোনো অ্যাপের অ্যাক্সেসিবিলিটি ইভেন্ট পরিচালনা করার জন্য উপলব্ধ বলে গণ্য হবে। আপনি এই প্যারামিটারটি অ্যাক্সেসিবিলিটি সার্ভিস কনফিগারেশন ফাইলে
android:packageNamesঅ্যাট্রিবিউটের মাধ্যমে কমা দ্বারা পৃথক করা একটি তালিকা হিসেবে অথবাAccessibilityServiceInfo.packageNamesমেম্বারটি ব্যবহার করে সেট করতে পারেন।ইভেন্টের প্রকারভেদ: আপনার সার্ভিস কোন ধরনের অ্যাক্সেসিবিলিটি ইভেন্টগুলো পরিচালনা করবে তা নির্দিষ্ট করুন। আপনি এই প্যারামিটারটি অ্যাক্সেসিবিলিটি সার্ভিস কনফিগারেশন ফাইলে
android:accessibilityEventTypesঅ্যাট্রিবিউটের মাধ্যমে|অক্ষর দ্বারা পৃথক করা একটি তালিকা হিসাবে সেট করতে পারেন—উদাহরণস্বরূপ,accessibilityEventTypes="typeViewClicked|typeViewFocused"। অথবা আপনিAccessibilityServiceInfo.eventTypesমেম্বার ব্যবহার করেও এটি সেট করতে পারেন।
আপনার অ্যাক্সেসিবিলিটি পরিষেবা সেট আপ করার সময়, আপনার পরিষেবা কোন ইভেন্টগুলি পরিচালনা করতে পারে তা সাবধানে বিবেচনা করুন এবং শুধুমাত্র সেই ইভেন্টগুলির জন্যই নিবন্ধন করুন। যেহেতু ব্যবহারকারীরা একই সময়ে একাধিক অ্যাক্সেসিবিলিটি পরিষেবা সক্রিয় করতে পারেন, তাই আপনার পরিষেবা এমন কোনো ইভেন্ট গ্রহণ করবে না যা এটি পরিচালনা করতে পারে না। মনে রাখবেন যে ব্যবহারকারীর অভিজ্ঞতা উন্নত করার জন্য অন্যান্য পরিষেবা সেই ইভেন্টগুলি পরিচালনা করতে পারে।
প্রবেশযোগ্যতার পরিমাণ
অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) এবং এর পরবর্তী সংস্করণে চালিত ডিভাইসগুলোতে 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); } } }
আরও তথ্যের জন্য, গুগল আই/ও ২০১৭-এর 'অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটিতে নতুন কী আছে' সেশন ভিডিওটি ৬:৩৫ থেকে দেখুন।
অ্যাক্সেসিবিলিটি শর্টকাট
অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) এবং এর চেয়ে উন্নত সংস্করণে চালিত ডিভাইসগুলোতে, ব্যবহারকারীরা যেকোনো স্ক্রিন থেকে একই সাথে দুটি ভলিউম কী চেপে ধরে তাদের পছন্দের অ্যাক্সেসিবিলিটি সার্ভিসটি চালু বা বন্ধ করতে পারেন। যদিও এই শর্টকাটটি ডিফল্টভাবে টকব্যাক চালু ও বন্ধ করে, ব্যবহারকারীরা তাদের ডিভাইসে ইনস্টল করা যেকোনো সার্ভিস চালু ও বন্ধ করার জন্য বাটনটি কনফিগার করতে পারেন।
ব্যবহারকারীদের অ্যাক্সেসিবিলিটি শর্টকাট থেকে কোনো নির্দিষ্ট অ্যাক্সেসিবিলিটি পরিষেবা অ্যাক্সেস করার জন্য, পরিষেবাটিকে রানটাইমে ফিচারটির জন্য অনুরোধ করতে হবে।
আরও তথ্যের জন্য, গুগল আই/ও ২০১৭-এর 'অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটিতে নতুন কী আছে' সেশন ভিডিওটি ১৩:২৫ থেকে দেখুন।
অ্যাক্সেসিবিলিটি বোতাম
সফটওয়্যার-রেন্ডারড নেভিগেশন এরিয়া ব্যবহারকারী এবং অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) বা তার উচ্চতর সংস্করণে চালিত ডিভাইসগুলিতে, নেভিগেশন বারের ডানদিকে একটি অ্যাক্সেসিবিলিটি বাটন থাকে। ব্যবহারকারীরা এই বাটনটি চাপলে, স্ক্রিনে বর্তমানে প্রদর্শিত বিষয়বস্তুর উপর নির্ভর করে, তারা বেশ কয়েকটি সক্রিয় অ্যাক্সেসিবিলিটি ফিচার এবং সার্ভিসের মধ্যে যেকোনো একটি চালু করতে পারেন।
ব্যবহারকারীদের অ্যাক্সেসিবিলিটি বাটন ব্যবহার করে কোনো নির্দিষ্ট অ্যাক্সেসিবিলিটি সার্ভিস চালু করার সুযোগ দিতে হলে, সার্ভিসটিকে একটি 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); } }
আরও তথ্যের জন্য, গুগল আই/ও ২০১৭-এর 'অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটিতে নতুন কী আছে' সেশন ভিডিওটি ১৬:২৮ থেকে দেখুন।
আঙুলের ছাপের অঙ্গভঙ্গি
অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) এবং এর চেয়ে উন্নত সংস্করণে চালিত ডিভাইসগুলোর অ্যাক্সেসিবিলিটি সার্ভিসগুলো ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সরের উপর দিয়ে করা দিকনির্দেশক সোয়াইপ (উপরে, নিচে, বামে এবং ডানে)-এ সাড়া দিতে পারে। এই ইন্টারঅ্যাকশনগুলো সম্পর্কে কলব্যাক গ্রহণ করার জন্য কোনো সার্ভিস কনফিগার করতে, নিম্নলিখিত ধাপগুলো অনুসরণ করুন:
-
USE_BIOMETRICপারমিশন এবংCAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURESক্যাপাবিলিটি ঘোষণা করুন। -
android:accessibilityFlagsঅ্যাট্রিবিউটের মধ্যেFLAG_REQUEST_FINGERPRINT_GESTURESফ্ল্যাগটি সেট করুন। - কলব্যাকের জন্য নিবন্ধন করতে
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); } } }
আরও তথ্যের জন্য, গুগল আই/ও ২০১৭-এর 'অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটিতে নতুন কী আছে' সেশন ভিডিওটি ৯:০৩ থেকে দেখুন।
বহুভাষিক টেক্সট টু স্পিচ
অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) থেকে শুরু করে, অ্যান্ড্রয়েডের টেক্সট-টু-স্পিচ (টিটিএস) পরিষেবা একটি একক টেক্সট ব্লকের মধ্যে একাধিক ভাষার বাক্যাংশ শনাক্ত করতে এবং তা বলতে পারে। একটি অ্যাক্সেসিবিলিটি পরিষেবাতে এই স্বয়ংক্রিয় ভাষা-পরিবর্তন ক্ষমতা সক্রিয় করতে, নিম্নলিখিত কোড স্নিপেটে দেখানো অনুযায়ী সমস্ত স্ট্রিংকে 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; }
আরও তথ্যের জন্য, গুগল আই/ও ২০১৭-এর 'অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটিতে নতুন কী আছে' সেশন ভিডিওটি ১০:৫৯ থেকে দেখুন।
ব্যবহারকারীদের পক্ষে কাজ করুন
২০১১ সাল থেকে, অ্যাক্সেসিবিলিটি সার্ভিসগুলো ব্যবহারকারীদের হয়ে কাজ করতে পারে, যার মধ্যে ইনপুট ফোকাস পরিবর্তন করা এবং ইউজার ইন্টারফেসের উপাদানগুলো নির্বাচন (সক্রিয়) করা অন্তর্ভুক্ত। ২০১২ সালে, এই কাজের পরিধি আরও প্রসারিত হয়ে তালিকা স্ক্রল করা এবং টেক্সট ফিল্ডের সাথে ইন্টারঅ্যাক্ট করার মতো বিষয়গুলোও অন্তর্ভুক্ত করে। অ্যাক্সেসিবিলিটি সার্ভিসগুলো সার্বিক কাজও করতে পারে, যেমন হোম স্ক্রিনে যাওয়া, ব্যাক বাটন চাপা এবং নোটিফিকেশন স্ক্রিন ও সাম্প্রতিক অ্যাপের তালিকা খোলা। ২০১২ সাল থেকে অ্যান্ড্রয়েডে ‘অ্যাক্সেসিবিলিটি ফোকাস’ অন্তর্ভুক্ত করা হয়েছে, যা একটি অ্যাক্সেসিবিলিটি সার্ভিসের মাধ্যমে সমস্ত দৃশ্যমান উপাদানকে নির্বাচনযোগ্য করে তোলে।
এই সক্ষমতাগুলো অ্যাক্সেসিবিলিটি পরিষেবাগুলোর ডেভেলপারদের জেসচার নেভিগেশনের মতো বিকল্প নেভিগেশন মোড তৈরি করতে এবং প্রতিবন্ধী ব্যবহারকারীদের তাদের অ্যান্ড্রয়েড-চালিত ডিভাইসগুলোর ওপর উন্নততর নিয়ন্ত্রণ প্রদান করতে সাহায্য করে।
অঙ্গভঙ্গি শুনুন
অ্যাক্সেসিবিলিটি সার্ভিসগুলো নির্দিষ্ট অঙ্গভঙ্গি শনাক্ত করতে পারে এবং ব্যবহারকারীর পক্ষ থেকে কাজ করে সাড়া দিতে পারে। এই ফিচারটির জন্য আপনার অ্যাক্সেসিবিলিটি সার্ভিসকে ‘এক্সপ্লোর বাই টাচ’ ফিচারটি সক্রিয় করার অনুরোধ করতে হবে। আপনার সার্ভিসটি তার 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() কলব্যাক পদ্ধতির মাধ্যমে অ্যাক্সেসিবিলিটি জেসচারের বিজ্ঞপ্তি পায় এবং ব্যবহারকারীর পক্ষ থেকে কাজ করে সাড়া দিতে পারে।
অব্যাহত অঙ্গভঙ্গি
অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) এবং এর চেয়ে উচ্চতর সংস্করণে চালিত ডিভাইসগুলো কন্টিনিউড জেসচার , অথবা একাধিক 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); }
আরও তথ্যের জন্য, গুগল আই/ও ২০১৭-এর 'অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটিতে নতুন কী আছে' সেশন ভিডিওটি ১৫:৪৭ থেকে দেখুন।
অ্যাক্সেসিবিলিটি অ্যাকশন ব্যবহার করুন
অ্যাক্সেসিবিলিটি সার্ভিসগুলো ব্যবহারকারীদের হয়ে অ্যাপের সাথে মিথস্ক্রিয়া সহজ করতে এবং তাদের আরও বেশি উৎপাদনশীল করে তুলতে পারে। অ্যাক্সেসিবিলিটি সার্ভিসের এই কাজ করার ক্ষমতা ২০১১ সালে যুক্ত করা হয়েছিল এবং ২০১২ সালে এটিকে উল্লেখযোগ্যভাবে সম্প্রসারিত করা হয়।
ব্যবহারকারীদের পক্ষ থেকে কাজ করার জন্য, আপনার অ্যাক্সেসিবিলিটি সার্ভিসকে অবশ্যই অ্যাপ থেকে ইভেন্ট গ্রহণ করার জন্য রেজিস্টার করতে হবে এবং সার্ভিস কনফিগারেশন ফাইলে 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() মেথডটি ব্যবহার করুন।
ফোকাস প্রকার ব্যবহার করুন
২০১২ সালে, অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটি ফোকাস নামে একটি ইউজার ইন্টারফেস ফোকাস চালু করে। অ্যাক্সেসিবিলিটি সার্ভিসগুলো এই ফোকাস ব্যবহার করে যেকোনো দৃশ্যমান ইউজার ইন্টারফেস এলিমেন্ট নির্বাচন করতে এবং সেটির উপর কাজ করতে পারে। এই ফোকাস টাইপটি ইনপুট ফোকাস থেকে ভিন্ন, যা নির্ধারণ করে যে যখন কোনো ব্যবহারকারী অক্ষর টাইপ করে, কিবোর্ডে এন্টার চাপে, বা ডি-প্যাডের মাঝের বোতামটি চাপে, তখন স্ক্রিনের কোন ইউজার ইন্টারফেস এলিমেন্টটি ইনপুট গ্রহণ করবে।
ইউজার ইন্টারফেসের একটি এলিমেন্টে ইনপুট ফোকাস থাকার পাশাপাশি অন্য একটি এলিমেন্টে অ্যাক্সেসিবিলিটি ফোকাস থাকাও সম্ভব। অ্যাক্সেসিবিলিটি ফোকাসের উদ্দেশ্য হলো, সিস্টেমের দৃষ্টিকোণ থেকে এলিমেন্টটি ইনপুট-ফোকাসযোগ্য কি না, তা নির্বিশেষে, স্ক্রিনের দৃশ্যমান এলিমেন্টগুলোর সাথে ইন্টারঅ্যাক্ট করার জন্য অ্যাক্সেসিবিলিটি সার্ভিসগুলোকে একটি পদ্ধতি প্রদান করা। আপনার অ্যাক্সেসিবিলিটি সার্ভিসটি অ্যাপের ইনপুট এলিমেন্টগুলোর সাথে সঠিকভাবে ইন্টারঅ্যাক্ট করছে কি না, তা নিশ্চিত করতে, একটি সাধারণ অ্যাপ ব্যবহার করার সময় আপনার সার্ভিসটি পরীক্ষা করার জন্য অ্যাপের অ্যাক্সেসিবিলিটি পরীক্ষার নির্দেশিকাগুলো অনুসরণ করুন।
একটি অ্যাক্সেসিবিলিটি সার্ভিস AccessibilityNodeInfo.findFocus() মেথড ব্যবহার করে নির্ধারণ করতে পারে যে কোন ইউজার ইন্টারফেস এলিমেন্টে ইনপুট ফোকাস বা অ্যাক্সেসিবিলিটি ফোকাস আছে। এছাড়াও, আপনি focusSearch() মেথড ব্যবহার করে ইনপুট ফোকাসের মাধ্যমে নির্বাচনযোগ্য এলিমেন্টগুলো অনুসন্ধান করতে পারেন। সবশেষে, আপনার অ্যাক্সেসিবিলিটি সার্ভিস performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS) মেথড ব্যবহার করে অ্যাক্সেসিবিলিটি ফোকাস সেট করতে পারে।
তথ্য সংগ্রহ করুন
অ্যাক্সেসিবিলিটি পরিষেবাগুলোর ব্যবহারকারীর দেওয়া তথ্যের মূল একক, যেমন ইভেন্টের বিবরণ, লেখা এবং সংখ্যা সংগ্রহ ও উপস্থাপনের জন্য প্রমিত পদ্ধতি রয়েছে।
জানালা পরিবর্তনের বিবরণ জানুন
অ্যান্ড্রয়েড ৯ (এপিআই লেভেল ২৮) এবং এর পরবর্তী সংস্করণগুলো অ্যাপকে একই সাথে একাধিক উইন্ডো রিড্র করার সময় উইন্ডো আপডেটের হিসাব রাখতে দেয়। যখন একটি TYPE_WINDOWS_CHANGED ইভেন্ট ঘটে, তখন উইন্ডোগুলো কীভাবে পরিবর্তিত হচ্ছে তা নির্ধারণ করতে getWindowChanges() এপিআই ব্যবহার করুন। একাধিক উইন্ডো আপডেটের সময়, প্রতিটি উইন্ডো তার নিজস্ব ইভেন্ট তৈরি করে। getSource() মেথডটি প্রতিটি ইভেন্টের সাথে সম্পর্কিত উইন্ডোর রুট ভিউ রিটার্ন করে।
যদি কোনো অ্যাপ তার View অবজেক্টগুলোর জন্য অ্যাক্সেসিবিলিটি পেন টাইটেল নির্ধারণ করে, তাহলে আপনার সার্ভিসটি অ্যাপটির UI কখন আপডেট হয় তা শনাক্ত করতে পারে। যখন একটি TYPE_WINDOW_STATE_CHANGED ইভেন্ট ঘটে, তখন উইন্ডোটি কীভাবে পরিবর্তিত হবে তা নির্ধারণ করতে getContentChangeTypes() দ্বারা রিটার্ন করা টাইপগুলো ব্যবহার করুন। উদাহরণস্বরূপ, ফ্রেমওয়ার্কটি শনাক্ত করতে পারে কখন একটি পেনের নতুন টাইটেল এসেছে বা কখন একটি পেন অদৃশ্য হয়ে গেছে।
ইভেন্টের বিবরণ জানুন
অ্যান্ড্রয়েড AccessibilityEvent অবজেক্টের মাধ্যমে ইউজার ইন্টারফেস ইন্টারঅ্যাকশন সম্পর্কে অ্যাক্সেসিবিলিটি সার্ভিসগুলোকে তথ্য সরবরাহ করে। অ্যান্ড্রয়েডের পূর্ববর্তী সংস্করণগুলোতে, একটি অ্যাক্সেসিবিলিটি ইভেন্টে প্রাপ্ত তথ্য ব্যবহারকারীদের দ্বারা নির্বাচিত ইউজার ইন্টারফেস কন্ট্রোল সম্পর্কে গুরুত্বপূর্ণ বিবরণ দিলেও, প্রাসঙ্গিক তথ্য সীমিত ছিল। অনেক ক্ষেত্রে, নির্বাচিত কন্ট্রোলটির অর্থ বোঝার জন্য এই অনুপস্থিত প্রাসঙ্গিক তথ্য অত্যন্ত গুরুত্বপূর্ণ হতে পারত।
এমন একটি ইন্টারফেসের উদাহরণ যেখানে প্রাসঙ্গিকতা অত্যন্ত গুরুত্বপূর্ণ, তা হলো একটি ক্যালেন্ডার বা দিনপঞ্জি। যদি ব্যবহারকারী সোমবার থেকে শুক্রবারের দিনের তালিকা থেকে বিকেল ৪টার একটি সময় নির্বাচন করেন এবং অ্যাক্সেসিবিলিটি পরিষেবাটি শুধু "বিকেল ৪টা" ঘোষণা করে, কিন্তু সপ্তাহের দিনের নাম, মাসের দিন বা মাসের নাম ঘোষণা না করে, তাহলে এর ফলে প্রাপ্ত প্রতিক্রিয়াটি বিভ্রান্তিকর হয়। এক্ষেত্রে, যে ব্যবহারকারী একটি মিটিংয়ের সময় নির্ধারণ করতে চান, তার জন্য একটি ইউজার ইন্টারফেস কন্ট্রোলের প্রাসঙ্গিকতা অত্যন্ত গুরুত্বপূর্ণ।
২০১১ সাল থেকে, অ্যান্ড্রয়েড ভিউ হায়ারার্কির উপর ভিত্তি করে অ্যাক্সেসিবিলিটি ইভেন্ট তৈরি করার মাধ্যমে ইউজার ইন্টারফেস ইন্টারঅ্যাকশন সম্পর্কে একটি অ্যাক্সেসিবিলিটি সার্ভিস যে পরিমাণ তথ্য পেতে পারে, তা উল্লেখযোগ্যভাবে বাড়িয়ে দিয়েছে। একটি ভিউ হায়ারার্কি হলো ইউজার ইন্টারফেস কম্পোনেন্টগুলোর একটি সেট, যার মধ্যে কম্পোনেন্টটি (এর প্যারেন্ট) এবং সেই কম্পোনেন্টের অন্তর্ভুক্ত হতে পারে এমন ইউজার ইন্টারফেস এলিমেন্টগুলো (এর চাইল্ড) থাকে। এইভাবে, অ্যান্ড্রয়েড অ্যাক্সেসিবিলিটি ইভেন্টগুলো সম্পর্কে আরও বিস্তারিত তথ্য প্রদান করতে পারে, যা অ্যাক্সেসিবিলিটি সার্ভিসগুলোকে ব্যবহারকারীদের আরও কার্যকর ফিডব্যাক দিতে সাহায্য করে।
একটি অ্যাক্সেসিবিলিটি সার্ভিস তার onAccessibilityEvent() কলব্যাক মেথডে সিস্টেম দ্বারা প্রেরিত একটি AccessibilityEvent এর মাধ্যমে কোনো ইউজার ইন্টারফেস ইভেন্ট সম্পর্কে তথ্য পায়। এই অবজেক্টটি ইভেন্টটি সম্পর্কে বিস্তারিত তথ্য প্রদান করে, যার মধ্যে রয়েছে যে অবজেক্টের উপর কাজ করা হচ্ছে তার ধরন, এর বর্ণনামূলক টেক্সট এবং অন্যান্য বিবরণ।
AccessibilityEvent.getRecordCount()এবংgetRecord(int): এই মেথডগুলো আপনাকেAccessibilityRecordঅবজেক্টগুলোর সেট পুনরুদ্ধার করতে দেয়, যেগুলো সিস্টেম থেকে পাঠানোAccessibilityEventএ অবদান রাখে। এই ধরনের বিস্তারিত তথ্য আপনার অ্যাক্সেসিবিলিটি সার্ভিসকে ট্রিগার করা ইভেন্টটির জন্য আরও বেশি প্রেক্ষাপট প্রদান করে।AccessibilityRecord.getSource(): এই মেথডটি একটিAccessibilityNodeInfoঅবজেক্ট রিটার্ন করে। এই অবজেক্টটি আপনাকে সেই কম্পোনেন্টের ভিউ লেআউট হায়ারার্কি (প্যারেন্ট এবং চাইল্ড) অনুরোধ করার সুযোগ দেয়, যেখান থেকে অ্যাক্সেসিবিলিটি ইভেন্টটি উদ্ভূত হয়েছে। এই ফিচারটি একটি অ্যাক্সেসিবিলিটি সার্ভিসকে কোনো ইভেন্টের সম্পূর্ণ প্রেক্ষাপট খতিয়ে দেখার সুযোগ দেয়, যার মধ্যে যেকোনো এনক্লোজিং ভিউ বা চাইল্ড ভিউ-এর কন্টেন্ট এবং স্টেটও অন্তর্ভুক্ত থাকে।
অ্যান্ড্রয়েড প্ল্যাটফর্ম একটি AccessibilityService ভিউ হায়ারার্কি কোয়েরি করার ক্ষমতা প্রদান করে, যার মাধ্যমে ইভেন্ট তৈরি করা UI কম্পোনেন্ট এবং তার প্যারেন্ট ও চাইল্ড সম্পর্কে তথ্য সংগ্রহ করা যায়। এটি করার জন্য, আপনার XML কনফিগারেশনে নিম্নলিখিত লাইনটি সেট করুন:
android:canRetrieveWindowContent="true"
সেটি হয়ে গেলে, getSource() ব্যবহার করে একটি AccessibilityNodeInfo অবজেক্ট নিন। এই কলটি কেবল তখনই একটি অবজেক্ট রিটার্ন করে, যদি যে উইন্ডো থেকে ইভেন্টটি এসেছে সেটি তখনও সক্রিয় থাকে। অন্যথায়, এটি null রিটার্ন করে, তাই সেই অনুযায়ী কাজ করুন।
নিম্নলিখিত উদাহরণে, কোনো ইভেন্ট প্রাপ্ত হলে কোডটি নিম্নলিখিত কাজগুলো করে:
- যেখান থেকে ইভেন্টটির উৎপত্তি হয়, সেই ভিউটির প্যারেন্টকে তাৎক্ষণিকভাবে ধরে ফেলে।
- সেই ভিউতে, চাইল্ড ভিউ হিসেবে একটি লেবেল এবং একটি চেকবক্স খোঁজা হয়।
- যদি এটি সেগুলোকে খুঁজে পায়, তবে ব্যবহারকারীকে জানানোর জন্য একটি স্ট্রিং তৈরি করে, যেখানে লেবেল এবং সেটি চেক করা হয়েছিল কিনা তা উল্লেখ থাকে।
ভিউ হায়ারার্কি ট্র্যাভার্স করার সময় যদি কোনো পর্যায়ে নাল ভ্যালু রিটার্ন করা হয়, তাহলে মেথডটি নীরবে কাজ করা বন্ধ করে দেয়।
কোটলিন
// 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 ব্যবহার করে এটি ব্যবহারকারীর সাথে কীভাবে ইন্টারঅ্যাক্ট করবে তা কনফিগার করার চেষ্টা করুন।
প্রক্রিয়া পাঠ্য
অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) এবং এর চেয়ে উন্নত সংস্করণে চালিত ডিভাইসগুলোতে বেশ কিছু টেক্সট-প্রসেসিং ফিচার রয়েছে, যা অ্যাক্সেসিবিলিটি সার্ভিসগুলোর জন্য স্ক্রিনে প্রদর্শিত নির্দিষ্ট টেক্সট ইউনিট শনাক্ত করা এবং সেগুলোর ওপর কাজ করা সহজ করে তোলে।
টুলটিপ
অ্যান্ড্রয়েড ৯ (এপিআই লেভেল ২৮) এমন কিছু বৈশিষ্ট্য চালু করেছে যা আপনাকে একটি অ্যাপের ইউআই-তে থাকা টুলটিপগুলো অ্যাক্সেস করার সুযোগ দেয়। একটি টুলটিপের টেক্সট পড়ার জন্য getTooltipText() ব্যবহার করুন, এবং View এর ইনস্ট্যান্সগুলোকে তাদের টুলটিপ দেখানো বা লুকানোর নির্দেশ দিতে ACTION_SHOW_TOOLTIP ও ACTION_HIDE_TOOLTIP ব্যবহার করুন।
ইঙ্গিত পাঠ্য
২০১৭ সাল থেকে, অ্যান্ড্রয়েডে টেক্সট-ভিত্তিক অবজেক্টের হিন্ট টেক্সটের সাথে ইন্টারঅ্যাক্ট করার জন্য বেশ কয়েকটি পদ্ধতি অন্তর্ভুক্ত করা হয়েছে:
-
isShowingHintText()এবংsetShowingHintText()মেথডগুলো যথাক্রমে নির্দেশ করে এবং নির্ধারণ করে যে, নোডটির বর্তমান টেক্সট কন্টেন্টটি নোডটির হিন্ট টেক্সট কিনা। -
getHintText()সরাসরি হিন্ট টেক্সট অ্যাক্সেস করার সুযোগ দেয়। কোনো অবজেক্টে হিন্ট টেক্সট প্রদর্শিত না হলেও,getHintText()কল করা সফল হয়।
পর্দায় থাকা টেক্সট অক্ষরগুলির অবস্থান
অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) এবং তার পরবর্তী সংস্করণে চালিত ডিভাইসগুলিতে, অ্যাক্সেসিবিলিটি সার্ভিসগুলো একটি TextView উইজেটের মধ্যে থাকা প্রতিটি দৃশ্যমান অক্ষরের বাউন্ডিং বক্সের স্ক্রিন কোঅর্ডিনেট নির্ধারণ করতে পারে। সার্ভিসগুলো refreshWithExtraData() মেথড কল করার মাধ্যমে এই কোঅর্ডিনেটগুলো খুঁজে বের করে, যেখানে প্রথম আর্গুমেন্ট হিসেবে EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY এবং দ্বিতীয় আর্গুমেন্ট হিসেবে একটি Bundle অবজেক্ট পাস করা হয়। মেথডটি কার্যকর হওয়ার সময়, সিস্টেম Bundle আর্গুমেন্টটিকে Rect অবজেক্টের একটি পার্সেলযোগ্য অ্যারে দিয়ে পূরণ করে। প্রতিটি Rect অবজেক্ট একটি নির্দিষ্ট অক্ষরের বাউন্ডিং বক্সকে প্রতিনিধিত্ব করে।
প্রমিত একতরফা পরিসরের মান
কিছু AccessibilityNodeInfo অবজেক্ট একটি UI এলিমেন্টের বিভিন্ন মান থাকতে পারে তা বোঝাতে AccessibilityNodeInfo.RangeInfo এর একটি ইনস্ট্যান্স ব্যবহার করে। 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); ... }
অতিরিক্ত সম্পদ
আরও জানতে, নিম্নলিখিত উৎসগুলো দেখুন: