blob: 9a8b34271d6a354014165def3ec2726337461564 [file] [log] [blame]
Ben Line4ffd062017-01-19 15:10:49 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.documentsui.dirlist;
18
19import android.os.Bundle;
20import android.support.v4.view.AccessibilityDelegateCompat;
21import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
22import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
23import android.support.v7.widget.RecyclerView;
24import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
25import android.view.View;
26
27import java.util.function.Function;
28
29/**
30 * Custom Accessibility Delegate for RecyclerViews to route click events on its child views to
Ben Lina355d192017-03-03 14:11:57 -080031 * proper handlers, and to surface selection state to a11y events.
32 * <p>
33 * The majority of event handling isdone using TouchDetector instead of View.OnCLickListener, which
34 * most a11y services use to understand whether a particular view is clickable or not. Thus, we need
35 * to use a custom accessibility delegate to manually add ACTION_CLICK to clickable child views'
36 * accessibility node, and then correctly route these clicks done by a11y services to responsible
Ben Line4ffd062017-01-19 15:10:49 -080037 * click callbacks.
Ben Lina355d192017-03-03 14:11:57 -080038 * <p>
39 * DocumentsUI uses {@link View#setActivated(boolean)} instead of {@link View#setSelected(boolean)}
40 * for marking a view as selected. We will surface that selection state to a11y services in this
41 * class.
Ben Line4ffd062017-01-19 15:10:49 -080042 */
Ben Lina355d192017-03-03 14:11:57 -080043public class AccessibilityEventRouter extends RecyclerViewAccessibilityDelegate {
Ben Line4ffd062017-01-19 15:10:49 -080044
45 private final ItemDelegate mItemDelegate;
46 private final Function<View, Boolean> mClickCallback;
47
Ben Lina355d192017-03-03 14:11:57 -080048 public AccessibilityEventRouter(
Ben Line4ffd062017-01-19 15:10:49 -080049 RecyclerView recyclerView, Function<View, Boolean> clickCallback) {
50 super(recyclerView);
51 mClickCallback = clickCallback;
52 mItemDelegate = new ItemDelegate(this) {
53 @Override
54 public void onInitializeAccessibilityNodeInfo(View host,
55 AccessibilityNodeInfoCompat info) {
56 super.onInitializeAccessibilityNodeInfo(host, info);
57 info.addAction(AccessibilityActionCompat.ACTION_CLICK);
Ben Lina355d192017-03-03 14:11:57 -080058 info.setSelected(host.isActivated());
Ben Line4ffd062017-01-19 15:10:49 -080059 }
60
61 @Override
62 public boolean performAccessibilityAction(View host, int action, Bundle args) {
63 // We are only handling click events; route all other to default implementation
64 if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
65 return mClickCallback.apply(host);
66 }
67 return super.performAccessibilityAction(host, action, args);
68 }
69 };
70 }
71
72 @Override
73 public AccessibilityDelegateCompat getItemDelegate() {
74 return mItemDelegate;
75 }
76}