1. Giới thiệu
Dịch vụ hỗ trợ tiếp cận là một tính năng của khung Android được thiết kế để cung cấp cho người dùng thông tin phản hồi thay thế về cách điều hướng thay mặt cho các ứng dụng được cài đặt trên thiết bị Android. Dịch vụ hỗ trợ tiếp cận có thể thay mặt ứng dụng giao tiếp với người dùng, chẳng hạn như bằng cách chuyển đổi văn bản sang lời nói hoặc đưa ra phản hồi xúc giác khi người dùng di chuột lên một vùng quan trọng trên màn hình. Lớp học lập trình này cho bạn biết cách tạo một dịch vụ hỗ trợ tiếp cận rất đơn giản.
Dịch vụ hỗ trợ tiếp cận là gì?
Dịch vụ hỗ trợ tiếp cận hỗ trợ người dùng bị khuyết tật sử dụng thiết bị và ứng dụng Android. Đây là một dịch vụ đặc quyền lâu dài, giúp người dùng xử lý thông tin trên màn hình và tương tác có ý nghĩa với thiết bị.
Ví dụ về các dịch vụ hỗ trợ tiếp cận phổ biến
- Tiếp cận bằng công tắc: cho phép người dùng Android bị hạn chế về khả năng vận động tương tác với các thiết bị bằng một hoặc nhiều công tắc.
- Điều khiển bằng giọng nói (beta): cho phép người dùng Android bị hạn chế về khả năng vận động điều khiển thiết bị bằng lệnh thoại.
- Talkback: một trình đọc màn hình thường được người dùng khiếm thị hoặc khiếm thị sử dụng.
Xây dựng dịch vụ hỗ trợ tiếp cận
Mặc dù Google cung cấp các dịch vụ như Tiếp cận bằng công tắc, Điều khiển bằng giọng nói và TalkBack cho người dùng Android, nhưng các dịch vụ này không thể phục vụ tất cả người dùng bị khuyết tật. Vì nhiều người dùng khuyết tật có nhu cầu riêng, nên các API của Android để tạo dịch vụ hỗ trợ tiếp cận luôn có sẵn để nhà phát triển có thể thoải mái tạo dịch vụ hỗ trợ tiếp cận cũng như phân phối các dịch vụ đó thông qua Cửa hàng Play.
Sản phẩm bạn sẽ tạo ra
Trong lớp học lập trình này, bạn sẽ phát triển một dịch vụ đơn giản có thể thực hiện một số việc hữu ích thông qua API hỗ trợ tiếp cận. Nếu viết được một ứng dụng Android cơ bản, bạn có thể phát triển một dịch vụ tương tự.
API hỗ trợ tiếp cận rất mạnh mẽ: mã cho dịch vụ mà bạn sẽ xây dựng chỉ chứa trong 4 tệp và sử dụng khoảng 200 dòng mã!
Người dùng cuối
Bạn sẽ tạo một dịch vụ cho một người dùng giả định với các đặc điểm sau:
- Người dùng gặp khó khăn khi nhấn vào các nút bên trên thiết bị.
- Người dùng gặp khó khăn khi cuộn hoặc vuốt.
Thông tin chi tiết về dịch vụ
Dịch vụ của bạn sẽ phủ một thanh thao tác chung lên màn hình. Người dùng có thể chạm vào các nút trên thanh này để thực hiện các thao tác sau:
- Tắt nguồn thiết bị mà không chạm vào nút nguồn thực tế ở cạnh bên của điện thoại.
- Điều chỉnh âm lượng mà không cần nhấn vào các nút âm lượng ở cạnh bên của điện thoại.
- Thực hiện các thao tác cuộn mà không thực sự cuộn.
- Thực hiện thao tác vuốt mà không cần phải dùng cử chỉ vuốt.
Bạn cần có
Lớp học lập trình này giả định bạn sẽ sử dụng:
- Một máy tính chạy Android Studio.
- Một thiết bị đầu cuối để thực thi các lệnh shell đơn giản.
- Một thiết bị chạy Android 7.0 (Nougat) được kết nối với máy tính mà bạn sẽ dùng để phát triển.
Hãy bắt đầu!
2. Thiết lập
Sử dụng cửa sổ dòng lệnh để tạo một thư mục mà bạn sẽ làm việc. Hãy chuyển sang thư mục này.
Tải mã nguồn xuống
Bạn có thể sao chép kho lưu trữ chứa mã nguồn cho lớp học lập trình này:
git clone https://github.com/android/codelab-android-accessibility.git
Kho lưu trữ này chứa một số dự án Android Studio. Sử dụng Android Studio, mở GlobalActionBarService.
Chạy Android Studio bằng cách nhấp vào biểu tượng Studio:
Chọn tuỳ chọn Nhập dự án (Eclipse ADT, Gradle, v.v.):
Chuyển đến vị trí mà bạn đã sao chép nguồn rồi chọn GlobalActionBarService.
Sau đó, sử dụng một thiết bị đầu cuối, thay đổi vào thư mục gốc.
3. Tìm hiểu về đoạn mã khởi đầu
Khám phá dự án mà bạn đã mở.
Chúng tôi đã tạo sẵn bộ khung cho dịch vụ hỗ trợ tiếp cận cho bạn. Tất cả mã bạn sẽ viết trong lớp học lập trình này chỉ giới hạn ở 4 tệp sau:
- 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
Dưới đây là hướng dẫn từng bước về nội dung của từng tệp.
AndroidManifest.xml
Thông tin về dịch vụ hỗ trợ tiếp cận được khai báo trong tệp kê khai:
<?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>
Bạn đã khai báo 3 mục bắt buộc sau trong tệp AndroidManifest.xml:
- Quyền liên kết với một dịch vụ hỗ trợ tiếp cận:
<service
...
android:permission = "android.permission.BIND_ACCESSIBILITY_SERVICE">
...
</service>
- Ý định AccessibilityService:
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
- Vị trí của tệp chứa siêu dữ liệu cho dịch vụ bạn đang tạo:
<meta-data
...
android:resource="@xml/global_action_bar_service" />
</service>
global_action_bar_service.xml
Tệp này chứa siêu dữ liệu của dịch vụ.
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true" />
Sử dụng phần tử <accessibility-service>, siêu dữ liệu sau đã được xác định:
- Loại phản hồi dành cho dịch vụ này (lớp học lập trình này sử dụng feedbackGeneric, đây là một lựa chọn mặc định tốt).
- Cờ hỗ trợ tiếp cận cho dịch vụ (lớp học lập trình này sử dụng cờ mặc định).
- Các khả năng cần thiết cho dịch vụ:
- Để thực hiện thao tác vuốt, android:canPerformGestures được đặt thành android:canPerformGestures.
- Để truy xuất nội dung trong cửa sổ, android:canRetrieveWindowContent được đặt thành true.
GlobalActionBarService.java
Hầu hết mã của dịch vụ hỗ trợ tiếp cận đều nằm trong GlobalActionBarService.java. Ban đầu, tệp này chứa mã tối thiểu hoàn toàn cho một dịch vụ hỗ trợ tiếp cận:
- Một lớp mở rộng AccessibilityService.
- Một số phương thức bị ghi đè bắt buộc (để trống trong lớp học lập trình này).
public class GlobalActionBarService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
@Override
public void onInterrupt() {
}
}
Bạn sẽ thêm mã vào tệp này trong lớp học lập trình này.
action_bar.xml
Dịch vụ này hiển thị một giao diện người dùng có 4 nút và tệp bố cục action_bar.xml chứa mã đánh dấu để hiển thị các nút đó:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
Tệp này hiện có chứa một LinearLayout trống. Bạn sẽ thêm mã đánh dấu cho các nút trong lớp học lập trình này.
Khởi chạy ứng dụng
Hãy đảm bảo rằng thiết bị đã kết nối với máy tính của bạn. Nhấn vào biểu tượng Phát màu xanh lục trên thanh trình đơn ở phía đầu màn hình. Thao tác này sẽ khởi chạy ứng dụng mà bạn đang xử lý.
Chuyển đến Cài đặt > Hỗ trợ tiếp cận. Dịch vụ thanh thao tác chung đã được cài đặt trên thiết bị của bạn.
Nhấp vào Global Action Bar Service (Dịch vụ thanh thao tác chung) rồi bật dịch vụ này. Bạn sẽ thấy hộp thoại cấp quyền sau đây:
Dịch vụ hỗ trợ tiếp cận yêu cầu quyền quan sát hành động của người dùng, truy xuất nội dung trong cửa sổ và thực hiện các cử chỉ thay mặt cho người dùng! Khi sử dụng dịch vụ hỗ trợ tiếp cận của bên thứ ba, hãy đảm bảo bạn thực sự tin tưởng nguồn đó!
Việc chạy dịch vụ không có nhiều tác dụng, vì chúng tôi chưa thêm bất kỳ chức năng nào. Hãy bắt đầu thực hiện việc đó.
4. Tạo các nút
Mở tệp action_bar.xml trong res/layout. Thêm mã đánh dấu bên trong LinearLayout hiện đang trống:
<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>
Thao tác này sẽ tạo ra các nút mà người dùng sẽ nhấn để kích hoạt thao tác trên thiết bị.
Mở GlobalActionBarService.java rồi thêm một biến để lưu trữ bố cục cho thanh thao tác:
public class GlobalActionBarService extends AccessibilityService {
FrameLayout mLayout;
...
}
Bây giờ, hãy thêm một phương thức 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);
}
}
Mã này sẽ tăng cường bố cục và thêm thanh thao tác về phía đầu màn hình.
Phương thức onServiceConnected() sẽ chạy khi dịch vụ được kết nối. Tại thời điểm này, dịch vụ hỗ trợ tiếp cận có tất cả các quyền cần thiết để hoạt động. Quyền khoá bạn sẽ sử dụng ở đây là quyền WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY. Quyền này cho phép bạn vẽ trực tiếp trên màn hình phía trên nội dung hiện có mà không cần trải qua một quy trình cấp quyền phức tạp.
Vòng đời của Dịch vụ hỗ trợ tiếp cận
Vòng đời của một dịch vụ hỗ trợ tiếp cận do hệ thống chỉ quản lý và tuân theo vòng đời dịch vụ đã thiết lập.
- Dịch vụ hỗ trợ tiếp cận sẽ bắt đầu khi người dùng bật dịch vụ đó một cách rõ ràng trong phần cài đặt của thiết bị.
- Sau khi liên kết với một dịch vụ, hệ thống sẽ gọi onServiceConnected(). Các dịch vụ muốn thực hiện việc thiết lập liên kết bài đăng có thể ghi đè phương thức này.
- Dịch vụ hỗ trợ tiếp cận sẽ dừng khi người dùng tắt dịch vụ đó trong phần cài đặt thiết bị hoặc khi dịch vụ này gọi disableSelf().
Chạy dịch vụ
Trước khi có thể chạy dịch vụ này bằng Android Studio, bạn cần đảm bảo rằng chế độ cài đặt Run (Chạy) của mình được định cấu hình chính xác.
Chỉnh sửa cấu hình Run (Chạy) của bạn (sử dụng Run (Chạy) trong trình đơn trên cùng) rồi chuyển đến Edit Configurations (Chỉnh sửa cấu hình). Sau đó, sử dụng trình đơn thả xuống, thay đổi Tuỳ chọn khởi chạy từ "Hoạt động mặc định" thành "Không có gì".
Giờ đây, bạn đã có thể chạy dịch vụ này bằng Android Studio.
Nhấn vào biểu tượng Phát màu xanh lục trên thanh trình đơn ở phía đầu màn hình. Sau đó, hãy truy cập phần Cài đặt > Hỗ trợ tiếp cận và bật Dịch vụ thanh thao tác chung.
Bạn sẽ thấy 4 nút tạo thành giao diện người dùng của dịch vụ phủ lên trên nội dung xuất hiện trên màn hình.
Bây giờ, bạn sẽ thêm chức năng vào 4 nút này để người dùng có thể chạm vào các nút này và thực hiện các thao tác hữu ích.
5. Định cấu hình nút Nguồn
Thêm phương thức configurePowerButton() vào configurePowerButton():
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);
}
});
}
Để truy cập vào trình đơn của nút nguồn, configurePowerButton() sử dụng phương thức performGlobalAction() do AccessibilityService cung cấp. Mã bạn vừa thêm rất đơn giản: việc nhấp vào nút này sẽ kích hoạt một onClickListener(). Thao tác này sẽ gọi performGlobalAction(GLOBAL_ACTION_POWER_DIALOG) và hiển thị hộp thoại nguồn cho người dùng.
Xin lưu ý rằng các thao tác chung không gắn liền với bất kỳ chế độ xem nào. Nhấn nút Quay lại, nút Màn hình chính, nút Gần đây là các ví dụ khác về thao tác chung.
Bây giờ, hãy thêm configurePowerButton() vào cuối phương thức onServiceConnected():
@Override
protected void onServiceConnected() {
...
configurePowerButton();
}
Nhấn vào biểu tượng Phát màu xanh lục trên thanh trình đơn ở phía đầu màn hình. Sau đó, hãy truy cập phần Cài đặt > Hỗ trợ tiếp cận và khởi động Dịch vụ thanh thao tác chung.
Nhấn nút Nguồn để hiển thị hộp thoại nguồn.
6. Định cấu hình nút âm lượng
Thêm phương thức configureVolumeButton() vào configureVolumeButton():
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);
}
});
}
Phương thức configureVolumeButton() sẽ thêm một onClickListener() được kích hoạt khi người dùng nhấn nút âm lượng. Bên trong trình nghe này, configureVolumeButton() sử dụng AudioManager để điều chỉnh âm lượng của luồng.
Xin lưu ý rằng bất kỳ ai cũng có thể điều khiển âm lượng (bạn không cần phải là dịch vụ hỗ trợ tiếp cận để thực hiện việc này).
Bây giờ, hãy thêm configureVolumeButton() vào cuối phương thức onServiceConnected():
@Override
protected void onServiceConnected() {
...
configureVolumeButton();
}
Nhấn vào biểu tượng Phát màu xanh lục trên thanh trình đơn ở phía đầu màn hình. Sau đó, hãy truy cập vào phần Cài đặt > Hỗ trợ tiếp cận và khởi động Dịch vụ thanh thao tác chung.
Nhấn vào nút Âm lượng để thay đổi âm lượng.
Người dùng giả định không thể chạm tới các nút điều khiển âm lượng ở cạnh thiết bị hiện có thể sử dụng Dịch vụ thanh thao tác trên toàn cầu để thay đổi (tăng) âm lượng.
7. Định cấu hình nút cuộn
Phần này liên quan đến việc lập trình 2 phương pháp. Phương thức đầu tiên tìm một nút có thể cuộn, còn phương thức thứ hai thực hiện thao tác cuộn thay mặt người dùng.
Thêm phương thức findScrollableNode vào findScrollableNode:
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;
}
Dịch vụ hỗ trợ tiếp cận không có quyền truy cập vào các chế độ xem thực tế trên màn hình. Thay vào đó, ứng dụng này phản ánh nội dung trên màn hình dưới dạng cây tạo thành từ các đối tượng AccessibilityNodeInfo. Các đối tượng này chứa thông tin về chế độ xem mà chúng đại diện (vị trí của chế độ xem, mọi văn bản liên kết với chế độ xem, siêu dữ liệu đã được thêm vào cho tính năng hỗ trợ tiếp cận, các thao tác mà chế độ xem hỗ trợ, v.v.). Phương thức findScrollableNode() thực hiện một lần truyền tải theo chiều rộng trước tiên của cây này, bắt đầu từ nút gốc. Nếu tìm thấy một nút có thể cuộn (tức là một nút hỗ trợ thao tác AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD)
), thì nút này sẽ trả về giá trị rỗng, nếu không thì sẽ trả về giá trị rỗng.
Bây giờ, hãy thêm phương thức configureScrollButton() vào configureScrollButton():
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());
}
}
});
}
Phương thức này sẽ tạo một onClickListener() sẽ kích hoạt khi người dùng nhấp vào nút cuộn. Nó sẽ cố gắng tìm một nút có thể cuộn và nếu thành công, sẽ thực hiện thao tác cuộn.
Bây giờ, hãy thêm configureScrollButton() vào configureScrollButton():
@Override
protected void onServiceConnected() {
...
configureScrollButton();
}
Nhấn vào biểu tượng Phát màu xanh lục trên thanh trình đơn ở phía đầu màn hình. Sau đó, hãy truy cập vào phần Cài đặt > Hỗ trợ tiếp cận và khởi động Dịch vụ thanh thao tác chung.
Nhấn nút quay lại để chuyển đến phần Cài đặt > Hỗ trợ tiếp cận. Các mục trong hoạt động cài đặt hỗ trợ tiếp cận có thể cuộn được và thao tác chạm vào nút Cuộn sẽ thực hiện một thao tác cuộn. Người dùng giả định của chúng ta không thể dễ dàng thực hiện các thao tác cuộn nay có thể sử dụng nút Cuộn để cuộn qua danh sách các mục.
8. Định cấu hình nút vuốt
Thêm phương thức configureSwipeButton() vào configureSwipeButton():
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);
}
});
}
Phương thức configureSwipeButton() sử dụng một API mới đã được thêm vào trong N. API này thực hiện các cử chỉ thay mặt cho người dùng. Mã này sử dụng đối tượng GestureDescription để chỉ định đường dẫn thực hiện cử chỉ (sử dụng các giá trị mã hóa cứng trong lớp học lập trình này), sau đó gửi cử chỉ vuốt thay mặt cho người dùng bằng phương thức AccessibilityService dispatchGesture().
Bây giờ, hãy thêm configureSwipeButton() vào configureSwipeButton():
@Override
protected void onServiceConnected() {
...
configureSwipeButton();
}
Nhấn vào biểu tượng Phát màu xanh lục trên thanh trình đơn ở phía đầu màn hình. Sau đó, hãy truy cập vào phần Cài đặt > Hỗ trợ tiếp cận và khởi động Dịch vụ thanh thao tác chung.
Cách dễ nhất để kiểm tra chức năng vuốt là mở ứng dụng Maps được cài đặt trên điện thoại của bạn. Sau khi bản đồ tải xong, chạm vào nút Vuốt sẽ vuốt màn hình sang phải.
9. Tóm tắt
Xin chúc mừng! Bạn đã xây dựng một dịch vụ hỗ trợ tiếp cận có đầy đủ chức năng và đơn giản.
Bạn có thể mở rộng dịch vụ này theo nhiều cách. Ví dụ:
- Làm cho thanh thao tác có thể di chuyển được (hiện thanh này chỉ nằm ở trên cùng của màn hình).
- Cho phép người dùng tăng và giảm âm lượng.
- Cho phép người dùng vuốt cả trái và phải.
- Thêm tính năng hỗ trợ cho các cử chỉ khác mà thanh thao tác có thể phản hồi.
Lớp học lập trình này chỉ đề cập đến một nhóm nhỏ chức năng do API hỗ trợ tiếp cận cung cấp. API này cũng bao gồm (danh sách một phần):
- Hỗ trợ nhiều cửa sổ.
- Hỗ trợ cho AccessibilityEvent. Khi giao diện người dùng thay đổi, các dịch vụ hỗ trợ tiếp cận sẽ được thông báo về những thay đổi đó thông qua đối tượng AccessibilityEvent. Sau đó, dịch vụ này có thể phản hồi khi phù hợp với những thay đổi trên giao diện người dùng.
- Có thể điều khiển độ phóng to.
Lớp học lập trình này sẽ giúp bạn bắt đầu viết một dịch vụ hỗ trợ tiếp cận. Nếu biết người dùng có các vấn đề cụ thể về hỗ trợ tiếp cận và bạn muốn giải quyết vấn đề đó, thì giờ đây, bạn có thể xây dựng một dịch vụ để trợ giúp người dùng đó.