1. مقدمه
خدمات دسترسپذیری یکی از ویژگیهای چارچوب Android است که برای ارائه بازخورد ناوبری جایگزین به کاربر از طرف برنامههای نصب شده در دستگاههای Android طراحی شده است. یک سرویس دسترسپذیری میتواند از طرف برنامه با کاربر ارتباط برقرار کند، برای مثال با تبدیل متن به گفتار یا ارائه بازخورد لمسی هنگامی که کاربر در ناحیه مهمی از صفحه نمایش معلق است. این کد لبه به شما نشان می دهد که چگونه یک سرویس دسترسی بسیار ساده ایجاد کنید.
سرویس دسترسی چیست؟
سرویس دسترسپذیری به کاربران دارای معلولیت در استفاده از دستگاهها و برنامههای Android کمک میکند. این یک سرویس ممتاز طولانی مدت است که به کاربران کمک می کند اطلاعات را روی صفحه پردازش کنند و به آنها اجازه می دهد تا به طور معناداری با یک دستگاه تعامل داشته باشند.
نمونه هایی از خدمات دسترسی رایج
- دسترسی سوئیچ : به کاربران Android با محدودیت های حرکتی اجازه می دهد تا با استفاده از یک یا چند سوئیچ با دستگاه ها تعامل داشته باشند.
- دسترسی صوتی (بتا): به کاربران Android با محدودیتهای حرکتی اجازه میدهد دستگاهی را با دستورات گفتاری کنترل کنند.
- Talkback : صفحهخوانی که معمولاً توسط کاربران کم بینا یا نابینا استفاده میشود.
ساخت سرویس دسترسی
در حالی که Google خدماتی مانند Switch Access، Voice Access و Talkback را برای کاربران Android ارائه میکند، این سرویسها نمیتوانند به همه کاربران دارای معلولیت خدمات ارائه دهند. از آنجایی که بسیاری از کاربران دارای معلولیت نیازهای منحصر به فردی دارند، APIهای Android برای ایجاد سرویسهای دسترسپذیری باز هستند و توسعهدهندگان میتوانند سرویسهای دسترسپذیری را ایجاد کرده و آنها را از طریق فروشگاه Play توزیع کنند.
چیزی که خواهید ساخت
در این لبه کد، شما یک سرویس ساده ایجاد می کنید که با استفاده از API دسترسی، چند کار مفید را انجام می دهد. اگر میتوانید یک برنامه اندرویدی اولیه بنویسید، میتوانید سرویس مشابهی را توسعه دهید.
API دسترسی قدرتمند است: کد سرویسی که میسازید تنها در چهار فایل موجود است و از 200 خط کد استفاده میکند!
کاربر نهایی
شما یک سرویس برای یک کاربر فرضی با ویژگی های زیر می سازید:
- کاربر در رسیدن به دکمه های کناری دستگاه مشکل دارد.
- کاربر در پیمایش یا کشیدن انگشت با مشکل مواجه است.
جزئیات خدمات
سرویس شما یک نوار اقدام سراسری را روی صفحه می پوشاند. کاربر می تواند دکمه های این نوار را برای انجام اقدامات زیر لمس کند:
- دستگاه را بدون رسیدن به دکمه پاور واقعی کنار گوشی خاموش کنید.
- صدا را بدون لمس دکمه های ولوم کناری گوشی تنظیم کنید.
- اقدامات اسکرول را بدون پیمایش واقعی انجام دهید.
- بدون نیاز به استفاده از ژست کشیدن انگشت، تند کشیدن را انجام دهید.
آنچه شما نیاز دارید
این کد لبه فرض می کند که شما از موارد زیر استفاده خواهید کرد:
- کامپیوتری که اندروید استودیو را اجرا می کند.
- ترمینالی برای اجرای دستورات پوسته ساده.
- دستگاهی با Android 7.0 (Nougat) متصل به رایانهای که برای توسعه استفاده میکنید.
بیایید شروع کنیم!
2. راه اندازی
با استفاده از ترمینال، یک دایرکتوری ایجاد کنید که در آن کار می کنید. به این دایرکتوری تغییر دهید.
کد را دانلود کنید
می توانید مخزن حاوی کد این کد لبه را کلون کنید:
git clone https://github.com/android/codelab-android-accessibility.git
مخزن شامل چندین پروژه اندروید استودیو است. با استفاده از Android Studio، GlobalActionBarService را باز کنید.
Android Studio را با کلیک کردن روی نماد Studio راه اندازی کنید:
گزینه Import project (Eclipse ADT، Gradle و غیره) را انتخاب کنید:
به مکانی که منبع را شبیه سازی کرده اید بروید و GlobalActionBarService را انتخاب کنید.
سپس با استفاده از یک ترمینال، به دایرکتوری ریشه تغییر دهید.
3. درک کد شروع
پروژه ای را که باز کرده اید کاوش کنید.
اسکلت بدون استخوان برای سرویس دسترسی قبلاً برای شما ایجاد شده است. تمام کدهایی که در این لبه کد می نویسید به چهار فایل زیر محدود می شود:
- app/src/main/ AndroidManifest.xml
- app/src/main/res/layout/ action_bar.xml
- app/src/main/res/xml/ global_action_bar_service.xml
- app/src/main/java/com/example/android/globalactionbarservice/ GlobalActionBarService.java
در اینجا فهرستی از محتویات هر فایل آورده شده است.
AndroidManifest.xml
اطلاعات مربوط به سرویس دسترسی در مانیفست اعلام شده است:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.globalactionbarservice">
<application>
<service
android:name=".GlobalActionBarService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:exported="true">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/global_action_bar_service" />
</service>
</application>
</manifest>
سه مورد مورد نیاز زیر در AndroidManifest.xml اعلام شده است:
- مجوز اتصال به یک سرویس دسترسی:
<service
...
android:permission = "android.permission.BIND_ACCESSIBILITY_SERVICE">
...
</service>
- هدف AccessibilityService :
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
- مکان فایلی که حاوی فراداده سرویسی است که ایجاد می کنید:
<meta-data
...
android:resource="@xml/global_action_bar_service" />
</service>
global_action_bar_service.xml
این فایل حاوی متادیتای سرویس است.
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true" />
با استفاده از عنصر <accessibility-service> ، ابرداده های زیر تعریف شده اند:
- نوع بازخورد برای این سرویس (این لبه کد از feedbackGeneric استفاده می کند که پیش فرض خوبی است).
- پرچمهای دسترسی برای این سرویس (این آزمایشگاه کد از پرچمهای پیشفرض استفاده میکند).
- قابلیت های مورد نیاز برای سرویس:
- برای انجام کشیدن انگشت، android:canPerformGestures روی true تنظیم شده است.
- برای بازیابی محتوای پنجره، android:canRetrieveWindowContent روی true تنظیم شده است.
GlobalActionBarService.java
بیشتر کدهای سرویس دسترسی در GlobalActionBarService.java زندگی می کنند. در ابتدا، فایل حاوی حداقل کد مطلق برای یک سرویس دسترسی است:
- کلاسی که AccessibilityService را گسترش می دهد.
- چند روش نادیده گرفته شده مورد نیاز (در این کد لبه خالی مانده است).
public class GlobalActionBarService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
@Override
public void onInterrupt() {
}
}
در خلال برنامه کد به این فایل کد اضافه خواهید کرد.
action_bar.xml
این سرویس یک رابط کاربری با چهار دکمه را نشان میدهد و فایل طرحبندی action_bar.xml حاوی نشانهگذاری برای نمایش آن دکمهها است:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
این فایل در حال حاضر حاوی یک LinearLayout خالی است. شما نشانه گذاری برای دکمه ها در طول برنامه کد اضافه خواهید کرد.
راه اندازی برنامه
مطمئن شوید که یک دستگاه به رایانه شما متصل است. نماد سبز رنگ Play را فشار دهید از نوار منو به سمت بالای صفحه نمایش. این باید برنامه ای را که روی آن کار می کنید راه اندازی کند.
به Settings > Accessibility بروید. سرویس Global Action Bar بر روی دستگاه شما نصب شده است.
روی Global Action Bar Service کلیک کنید و آن را روشن کنید. شما باید گفتگوی مجوز زیر را ببینید:
سرویس دسترسپذیری برای مشاهده اقدامات کاربر، بازیابی محتوای پنجره و انجام ژستها از طرف کاربر مجوز درخواست میکند! هنگام استفاده از سرویس دسترسی شخص ثالث، مطمئن شوید که واقعا به منبع اعتماد دارید !
اجرای سرویس کار زیادی انجام نمی دهد، زیرا ما هنوز هیچ عملکردی اضافه نکرده ایم. بیایید این کار را شروع کنیم.
4. ایجاد دکمه ها
action_bar.xml را در res/layout باز کنید. علامت گذاری را در LinearLayout خالی فعلی اضافه کنید:
<LinearLayout ...>
<Button
android:id="@+id/power"
android:text="@string/power"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/volume_up"
android:text="@string/volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/scroll"
android:text="@string/scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/swipe"
android:text="@string/swipe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
با این کار دکمههایی ایجاد میشود که کاربر فشار میدهد تا اقدامات روی دستگاه را فعال کند.
GlobalActionBarService.java را باز کنید و یک متغیر برای ذخیره طرح بندی نوار اقدام اضافه کنید:
public class GlobalActionBarService extends AccessibilityService {
FrameLayout mLayout;
...
}
اکنون یک متد onServiceStarted() اضافه کنید:
public class GlobalActionBarService extends AccessibilityService {
FrameLayout mLayout;
@Override
protected void onServiceConnected() {
// Create an overlay and display the action bar
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.TOP;
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.action_bar, mLayout);
wm.addView(mLayout, lp);
}
}
کد طرح بندی را باد می کند و نوار عمل را به بالای صفحه اضافه می کند.
متد onServiceConnected() زمانی که سرویس متصل است اجرا می شود. در این زمان، سرویس دسترسپذیری تمام مجوزهایی را دارد که برای کارکرد نیاز دارد. مجوز کلیدی که در اینجا استفاده خواهید کرد، مجوز WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY است. این مجوز به شما امکان میدهد مستقیماً روی صفحه بالای محتوای موجود نقاشی کنید، بدون اینکه نیازی به عبور از یک جریان مجوزهای پیچیده داشته باشید.
چرخه عمر سرویس دسترسی
چرخه عمر یک سرویس دسترسی منحصراً توسط سیستم مدیریت می شود و از چرخه عمر سرویس تعیین شده پیروی می کند.
- یک سرویس دسترسپذیری زمانی شروع میشود که کاربر صراحتاً سرویس را در تنظیمات دستگاه روشن کند.
- پس از اتصال سیستم به یک سرویس، onServiceConnected() را فراخوانی می کند. این روش میتواند توسط سرویسهایی که میخواهند راهاندازی post binding را انجام دهند لغو شود.
- یک سرویس دسترسپذیری یا زمانی که کاربر آن را در تنظیمات دستگاه خاموش میکند یا زمانی که disableSelf() را فراخوانی میکند متوقف میشود.
اجرای سرویس
قبل از اینکه بتوانید سرویس را با استفاده از Android Studio راه اندازی کنید، باید مطمئن شوید که تنظیمات Run شما به درستی پیکربندی شده است.
پیکربندی Run خود را ویرایش کنید (از Run از منوی بالا استفاده کنید و به Edit Configurations بروید. سپس با استفاده از منوی بازشو، گزینه Launch را از "Default Activity" به "Nothing" تغییر دهید.
اکنون باید بتوانید این سرویس را با استفاده از Android Studio راه اندازی کنید.
نماد سبز رنگ Play را فشار دهید از نوار منو به سمت بالای صفحه نمایش. سپس، به تنظیمات > دسترسپذیری بروید و سرویس نوار اقدام جهانی را روشن کنید.
باید چهار دکمهای را که رابط کاربری سرویس را تشکیل میدهند، در بالای محتوای نمایش داده شده روی صفحه ببینید.
اکنون عملکردی را به چهار دکمه اضافه خواهید کرد تا کاربر بتواند آنها را برای انجام اقدامات مفید لمس کند.
5. پیکربندی دکمه پاور
متد ()configurePowerButton را به GlobalActionBarService.java اضافه کنید:
private void configurePowerButton() {
Button powerButton = (Button) mLayout.findViewById(R.id.power);
powerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
performGlobalAction(GLOBAL_ACTION_POWER_DIALOG);
}
});
}
برای دسترسی به منوی دکمه پاور، configurePowerButton() از متد performGlobalAction() استفاده می کند که توسط AccessibilityService ارائه شده است. کدی که به تازگی اضافه کردید ساده است: با کلیک کردن روی دکمه، یک onClickListener() فعال می شود. این عملکردGlobalAction (GLOBAL_ACTION_POWER_DIALOG) را فراخوانی می کند و گفتگوی پاور را به کاربر نمایش می دهد.
توجه داشته باشید که اقدامات جهانی به هیچ دیدگاهی مرتبط نیست. زدن دکمه بازگشت، دکمه Home، دکمه Recents نمونه های دیگری از اقدامات جهانی هستند.
اکنون ()configurePowerButton را به انتهای متد onServiceConnected() اضافه کنید:
@Override
protected void onServiceConnected() {
...
configurePowerButton();
}
نماد سبز رنگ Play را فشار دهید از نوار منو به سمت بالای صفحه نمایش. سپس، به تنظیمات > دسترسپذیری بروید و سرویس نوار اقدام جهانی را راهاندازی کنید.
دکمه پاور را فشار دهید تا گفتگوی پاور نمایش داده شود.
6. پیکربندی دکمه صدا
متد configureVolumeButton() را به GlobalActionBarService.java اضافه کنید:
private void configureVolumeButton() {
Button volumeUpButton = (Button) mLayout.findViewById(R.id.volume_up);
volumeUpButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
}
});
}
متد configureVolumeButton() یک onClickListener() اضافه می کند که وقتی کاربر دکمه صدا را فشار می دهد فعال می شود. در داخل این شنونده، configureVolumeButton() از AudioManager برای تنظیم میزان صدای جریان استفاده می کند.
توجه داشته باشید که هر کسی میتواند صدا را کنترل کند (برای انجام این کار لازم نیست یک سرویس دسترسی باشید).
حالا configureVolumeButton() را به انتهای متد onServiceConnected() اضافه کنید:
@Override
protected void onServiceConnected() {
...
configureVolumeButton();
}
نماد سبز رنگ Play را فشار دهید از نوار منو به سمت بالای صفحه نمایش. سپس، به تنظیمات > دسترسپذیری بروید و سرویس نوار اقدام جهانی را راهاندازی کنید.
دکمه ولوم را فشار دهید تا صدا را تغییر دهید.
کاربر فرضی که قادر به دستیابی به کنترلهای صدا در کنار دستگاه نیست، اکنون میتواند از سرویس Global Action Bar برای تغییر (افزایش) صدا استفاده کند.
7. پیکربندی دکمه اسکرول
این بخش شامل کدگذاری دو روش است. روش اول یک گره قابل پیمایش را پیدا می کند و روش دوم عمل اسکرول را از طرف کاربر انجام می دهد.
متد findScrollableNode را به GlobalActionBarService.java اضافه کنید:
private AccessibilityNodeInfo findScrollableNode(AccessibilityNodeInfo root) {
Deque<AccessibilityNodeInfo> deque = new ArrayDeque<>();
deque.add(root);
while (!deque.isEmpty()) {
AccessibilityNodeInfo node = deque.removeFirst();
if (node.getActionList().contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD)) {
return node;
}
for (int i = 0; i < node.getChildCount(); i++) {
deque.addLast(node.getChild(i));
}
}
return null;
}
یک سرویس دسترسپذیری به نماهای واقعی روی صفحه دسترسی ندارد. در عوض، بازتابی از آنچه روی صفحه است را به شکل درختی می بیند که از اشیاء AccessibilityNodeInfo تشکیل شده است. این اشیاء حاوی اطلاعاتی در مورد نمای نمایشی هستند (موقعیت نما، هر متن مرتبط با نما، ابرداده ای که برای دسترسی اضافه شده است، اقدامات پشتیبانی شده توسط نما، و غیره). متد findScrollableNode() یک پیمایش عرضی اول از این درخت را انجام می دهد که از گره ریشه شروع می شود. اگر یک گره قابل پیمایش پیدا کند (یعنی گرهای که از عملکرد AccessibilityNodeInfo.Accessibility.ACTION_SCROLL_FORWARD پشتیبانی میکند )
، آن را برمیگرداند، در غیر این صورت null را برمیگرداند.
اکنون متد ()configureScrollButton را به GlobalActionBarService.java اضافه کنید:
private void configureScrollButton() {
Button scrollButton = (Button) mLayout.findViewById(R.id.scroll);
scrollButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AccessibilityNodeInfo scrollable = findScrollableNode(getRootInActiveWindow());
if (scrollable != null) {
scrollable.performAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId());
}
}
});
}
این متد یک onClickListener() ایجاد می کند که با کلیک روی دکمه اسکرول فعال می شود. سعی می کند یک گره قابل پیمایش پیدا کند و در صورت موفقیت، عمل اسکرول را انجام می دهد.
اکنون configureScrollButton() را به onServiceConnected() اضافه کنید:
@Override
protected void onServiceConnected() {
...
configureScrollButton();
}
نماد سبز رنگ Play را فشار دهید از نوار منو به سمت بالای صفحه نمایش. سپس، به تنظیمات > دسترسپذیری بروید و سرویس نوار اقدام جهانی را راهاندازی کنید.
دکمه برگشت را فشار دهید تا به تنظیمات > دسترسپذیری بروید. موارد موجود در فعالیت تنظیمات دسترسپذیری قابل پیمایش هستند و با لمس دکمه اسکرول یک عمل پیمایش انجام میشود. کاربر فرضی ما که قادر به انجام آسان حرکات اسکرول نیست، اکنون می تواند از دکمه اسکرول برای پیمایش بر روی لیستی از موارد استفاده کند.
8. پیکربندی دکمه Swipe
متد configureSwipeButton() را به GlobalActionBarService.java اضافه کنید:
private void configureSwipeButton() {
Button swipeButton = (Button) mLayout.findViewById(R.id.swipe);
swipeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Path swipePath = new Path();
swipePath.moveTo(1000, 1000);
swipePath.lineTo(100, 1000);
GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
gestureBuilder.addStroke(new GestureDescription.StrokeDescription(swipePath, 0, 500));
dispatchGesture(gestureBuilder.build(), null, null);
}
});
}
متد configureSwipeButton() از یک API جدید استفاده می کند که در N اضافه شده است که حرکات را از طرف کاربر انجام می دهد. کد از یک شی GestureDescription برای تعیین مسیر حرکت حرکتی استفاده میکند (مقادیر کدگذاری شده در این لبه کد استفاده میشود)، و سپس با استفاده از متد AccessibilityService dispatchGesture() ژست کشیدن انگشت را از طرف کاربر ارسال میکند.
اکنون configureSwipeButton() را به onServiceConnected() اضافه کنید:
@Override
protected void onServiceConnected() {
...
configureSwipeButton();
}
نماد سبز رنگ Play را فشار دهید از نوار منو به سمت بالای صفحه نمایش. سپس، به تنظیمات > دسترسپذیری بروید و سرویس نوار اقدام جهانی را راهاندازی کنید.
ساده ترین راه برای آزمایش عملکرد کشیدن انگشت، باز کردن برنامه Maps نصب شده بر روی گوشی شما است. پس از بارگیری نقشه، با لمس دکمه Swipe صفحه را به سمت راست بکشید.
9. خلاصه
تبریک می گویم! شما یک سرویس دسترسی ساده و کاربردی ساخته اید.
شما می توانید این سرویس را به روش های مختلفی گسترش دهید. به عنوان مثال:
- نوار اکشن را متحرک کنید (در حال حاضر فقط بالای صفحه قرار دارد).
- به کاربر امکان افزایش و کاهش صدا را بدهید.
- به کاربر اجازه دهید هم به چپ و هم به راست بکشد.
- پشتیبانی از حرکات اضافی را اضافه کنید که نوار اقدام می تواند به آنها پاسخ دهد.
این کد لبه تنها زیرمجموعه کوچکی از عملکرد ارائه شده توسط APIهای دسترسی را پوشش می دهد. API موارد زیر را نیز پوشش می دهد (فهرست جزئی):
- پشتیبانی از چندین ویندوز
- پشتیبانی از AccessibilityEvent s. هنگامی که UI تغییر می کند، سرویس های دسترس پذیری در مورد آن تغییرات با استفاده از اشیاء AccessibilityEvent مطلع می شوند. سپس این سرویس می تواند به صورت مناسب به تغییرات UI پاسخ دهد.
- قابلیت کنترل بزرگنمایی
این لبه کد شما را با نوشتن یک سرویس دسترسپذیری شروع میکند. اگر کاربری را با مشکلات دسترسی خاص می شناسید که می خواهید به آنها رسیدگی کنید، اکنون می توانید یک سرویس برای کمک به آن کاربر بسازید.