Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03401d30 authored by Tony Huang's avatar Tony Huang
Browse files

Add support on Switch Access long click on dirlist

Current AccessibilityDelegate does not support Access Switch long
click, add new long click callback to support it.

Fix: 130273135
Test: manual use Swich Access to test
Test: atest DocumentsUIGoogleTests
Change-Id: Icf5184ae4fe100ac8bbf8cf020e3cc14fa85ed46
parent a2141c1d
Loading
Loading
Loading
Loading
+4 −3
Original line number Original line Diff line number Diff line
@@ -17,8 +17,6 @@
package com.android.documentsui;
package com.android.documentsui;


import android.content.Context;
import android.content.Context;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.KeyEvent;
@@ -28,6 +26,9 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView;


import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.android.documentsui.NavigationViewManager.Breadcrumb;
import com.android.documentsui.NavigationViewManager.Breadcrumb;
import com.android.documentsui.NavigationViewManager.Environment;
import com.android.documentsui.NavigationViewManager.Environment;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.DocumentInfo;
@@ -77,7 +78,7 @@ public final class HorizontalBreadcrumb extends RecyclerView
        // for more details on how we are routing these a11y events.
        // for more details on how we are routing these a11y events.
        setAccessibilityDelegateCompat(
        setAccessibilityDelegateCompat(
                new AccessibilityEventRouter(this,
                new AccessibilityEventRouter(this,
                        (View child) -> onAccessibilityClick(child)));
                        (View child) -> onAccessibilityClick(child), null));


        setLayoutManager(mLayoutManager);
        setLayoutManager(mLayoutManager);
        addOnItemTouchListener(new ClickListener(getContext(), this::onSingleTapUp));
        addOnItemTouchListener(new ClickListener(getContext(), this::onSingleTapUp));
+18 −4
Original line number Original line Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.documentsui.dirlist;
import android.os.Bundle;
import android.os.Bundle;
import android.view.View;
import android.view.View;


import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
@@ -45,11 +47,14 @@ public class AccessibilityEventRouter extends RecyclerViewAccessibilityDelegate


    private final ItemDelegate mItemDelegate;
    private final ItemDelegate mItemDelegate;
    private final Function<View, Boolean> mClickCallback;
    private final Function<View, Boolean> mClickCallback;
    private final Function<View, Boolean> mLongClickCallback;


    public AccessibilityEventRouter(
    public AccessibilityEventRouter(
            RecyclerView recyclerView, Function<View, Boolean> clickCallback) {
            RecyclerView recyclerView, @NonNull Function<View, Boolean> clickCallback,
            @Nullable Function<View, Boolean> longClickCallback) {
        super(recyclerView);
        super(recyclerView);
        mClickCallback = clickCallback;
        mClickCallback = clickCallback;
        mLongClickCallback = longClickCallback;
        mItemDelegate = new ItemDelegate(this) {
        mItemDelegate = new ItemDelegate(this) {
            @Override
            @Override
            public void onInitializeAccessibilityNodeInfo(View host,
            public void onInitializeAccessibilityNodeInfo(View host,
@@ -60,11 +65,10 @@ public class AccessibilityEventRouter extends RecyclerViewAccessibilityDelegate
                // is null, it can't be clicked
                // is null, it can't be clicked
                if (holder instanceof DocumentHolder) {
                if (holder instanceof DocumentHolder) {
                    if (((DocumentHolder)holder).getItemDetails() != null) {
                    if (((DocumentHolder)holder).getItemDetails() != null) {
                        info.addAction(AccessibilityActionCompat.ACTION_CLICK);
                        addAction(info);
                        info.addAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK);
                    }
                    }
                } else {
                } else {
                    info.addAction(AccessibilityActionCompat.ACTION_CLICK);
                    addAction(info);
                }
                }
                info.setSelected(host.isActivated());
                info.setSelected(host.isActivated());
            }
            }
@@ -74,6 +78,9 @@ public class AccessibilityEventRouter extends RecyclerViewAccessibilityDelegate
                // We are only handling click events; route all other to default implementation
                // We are only handling click events; route all other to default implementation
                if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
                if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
                    return mClickCallback.apply(host);
                    return mClickCallback.apply(host);
                } else if (action == AccessibilityNodeInfoCompat.ACTION_LONG_CLICK
                        && mLongClickCallback != null) {
                    return mLongClickCallback.apply(host);
                }
                }
                return super.performAccessibilityAction(host, action, args);
                return super.performAccessibilityAction(host, action, args);
            }
            }
@@ -84,4 +91,11 @@ public class AccessibilityEventRouter extends RecyclerViewAccessibilityDelegate
    public AccessibilityDelegateCompat getItemDelegate() {
    public AccessibilityDelegateCompat getItemDelegate() {
        return mItemDelegate;
        return mItemDelegate;
    }
    }

    private void addAction(AccessibilityNodeInfoCompat info) {
        info.addAction(AccessibilityActionCompat.ACTION_CLICK);
        if (mLongClickCallback != null) {
            info.addAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK);
        }
    }
}
}
 No newline at end of file
+17 −7
Original line number Original line Diff line number Diff line
@@ -325,7 +325,8 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On


        mRecView.setAccessibilityDelegateCompat(
        mRecView.setAccessibilityDelegateCompat(
                new AccessibilityEventRouter(mRecView,
                new AccessibilityEventRouter(mRecView,
                        (View child) -> onAccessibilityClick(child)));
                        (View child) -> onAccessibilityClick(child),
                        (View child) -> onAccessibilityLongClick(child)));
        mSelectionMetadata = new SelectionMetadata(mModel::getItem);
        mSelectionMetadata = new SelectionMetadata(mModel::getItem);
        mDetailsLookup = new DocsItemDetailsLookup(mRecView);
        mDetailsLookup = new DocsItemDetailsLookup(mRecView);


@@ -765,12 +766,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On


    private boolean onAccessibilityClick(View child) {
    private boolean onAccessibilityClick(View child) {
        if (mSelectionMgr.hasSelection()) {
        if (mSelectionMgr.hasSelection()) {
            final String id = getModelId(child);
            selectItem(child);
            if (mSelectionMgr.isSelected(id)) {
                mSelectionMgr.deselect(id);
            } else {
                mSelectionMgr.select(id);
            }
        } else {
        } else {
            DocumentHolder holder = getDocumentHolder(child);
            DocumentHolder holder = getDocumentHolder(child);
            mActions.openItem(holder.getItemDetails(), ActionHandler.VIEW_TYPE_PREVIEW,
            mActions.openItem(holder.getItemDetails(), ActionHandler.VIEW_TYPE_PREVIEW,
@@ -779,6 +775,20 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
        return true;
        return true;
    }
    }


    private boolean onAccessibilityLongClick(View child) {
        selectItem(child);
        return true;
    }

    private void selectItem(View child) {
        final String id = getModelId(child);
        if (mSelectionMgr.isSelected(id)) {
            mSelectionMgr.deselect(id);
        } else {
            mSelectionMgr.select(id);
        }
    }

    private void cancelThumbnailTask(View view) {
    private void cancelThumbnailTask(View view) {
        final ImageView iconThumb = (ImageView) view.findViewById(R.id.icon_thumb);
        final ImageView iconThumb = (ImageView) view.findViewById(R.id.icon_thumb);
        if (iconThumb != null) {
        if (iconThumb != null) {
+21 −7
Original line number Original line Diff line number Diff line
@@ -16,15 +16,15 @@


package com.android.documentsui.dirlist;
package com.android.documentsui.dirlist;


import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.recyclerview.widget.RecyclerView;

import android.database.Cursor;
import android.database.Cursor;
import android.test.AndroidTestCase;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.View;
import android.view.View;
import android.widget.Space;
import android.widget.Space;


import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.recyclerview.widget.RecyclerView;

import com.android.documentsui.testing.TestRecyclerView;
import com.android.documentsui.testing.TestRecyclerView;
import com.android.documentsui.testing.Views;
import com.android.documentsui.testing.Views;


@@ -38,13 +38,17 @@ public class AccessibilityTest extends AndroidTestCase {


    private TestRecyclerView mView;
    private TestRecyclerView mView;
    private AccessibilityEventRouter mAccessibilityDelegate;
    private AccessibilityEventRouter mAccessibilityDelegate;
    private boolean mCallbackCalled = false;
    private boolean mClickCallbackCalled = false;
    private boolean mLongClickCallbackCalled = false;


    @Override
    @Override
    public void setUp() throws Exception {
    public void setUp() throws Exception {
        mView = TestRecyclerView.create(ITEMS);
        mView = TestRecyclerView.create(ITEMS);
        mAccessibilityDelegate = new AccessibilityEventRouter(mView, (View v) -> {
        mAccessibilityDelegate = new AccessibilityEventRouter(mView, (View v) -> {
            mCallbackCalled = true;
            mClickCallbackCalled = true;
            return true;
        }, (View v) -> {
            mLongClickCallbackCalled = true;
            return true;
            return true;
        });
        });
        mView.setAccessibilityDelegateCompat(mAccessibilityDelegate);
        mView.setAccessibilityDelegateCompat(mAccessibilityDelegate);
@@ -79,7 +83,17 @@ public class AccessibilityTest extends AndroidTestCase {
        View item = Views.createTestView(true);
        View item = Views.createTestView(true);
        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
        mAccessibilityDelegate.getItemDelegate().onInitializeAccessibilityNodeInfo(item, info);
        mAccessibilityDelegate.getItemDelegate().onInitializeAccessibilityNodeInfo(item, info);
        mAccessibilityDelegate.getItemDelegate().performAccessibilityAction(item, AccessibilityNodeInfoCompat.ACTION_CLICK, null);
        mAccessibilityDelegate.getItemDelegate()
        assertTrue(mCallbackCalled);
            .performAccessibilityAction(item, AccessibilityNodeInfoCompat.ACTION_CLICK, null);
        assertTrue(mClickCallbackCalled);
    }

    public void test_routesAccessibilityLongClicks() throws Exception {
        View item = Views.createTestView(true);
        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
        mAccessibilityDelegate.getItemDelegate().onInitializeAccessibilityNodeInfo(item, info);
        mAccessibilityDelegate.getItemDelegate()
            .performAccessibilityAction(item, AccessibilityNodeInfoCompat.ACTION_LONG_CLICK, null);
        assertTrue(mLongClickCallbackCalled);
    }
    }
}
}