Home | History | Annotate | Download | only in dirlist
      1 /*
      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 
     17 package com.android.documentsui.dirlist;
     18 
     19 import android.os.Bundle;
     20 import android.support.v4.view.AccessibilityDelegateCompat;
     21 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
     22 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
     23 import android.support.v7.widget.RecyclerView;
     24 import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
     25 import android.view.View;
     26 
     27 import java.util.function.Function;
     28 
     29 /**
     30  * Custom Accessibility Delegate for RecyclerViews to route click events on its child views to
     31  * 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
     37  * click callbacks.
     38  * <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.
     42  */
     43 public class AccessibilityEventRouter extends RecyclerViewAccessibilityDelegate {
     44 
     45     private final ItemDelegate mItemDelegate;
     46     private final Function<View, Boolean> mClickCallback;
     47 
     48     public AccessibilityEventRouter(
     49             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);
     58                 info.setSelected(host.isActivated());
     59             }
     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 }