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

Commit 1829a77c authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Present target grid as hierarchical for a11y purposes." into main

parents 792a97e0 952a2df6
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
package: "android.service.chooser"
container: "system"

flag {
  name: "announce_shortcuts_and_suggested_apps_legacy"
  namespace: "intentresolver"
  description: "Enable talkback announcement for the app shortcuts and the suggested apps target groups in the legacy sharesheet codebase."
  bug: "380211084"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "chooser_album_text"
  is_exported: true
+128 −0
Original line number Diff line number Diff line
@@ -16,9 +16,20 @@

package com.android.internal.app;

import static android.service.chooser.Flags.announceShortcutsAndSuggestedAppsLegacy;

import android.annotation.Nullable;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
import android.widget.GridView;
import android.widget.TextView;

import com.android.internal.R;
import com.android.internal.app.ChooserActivity.ChooserGridAdapter;
import com.android.internal.widget.GridLayoutManager;
import com.android.internal.widget.RecyclerView;

@@ -28,6 +39,11 @@ import com.android.internal.widget.RecyclerView;
 */
public class ChooserGridLayoutManager extends GridLayoutManager {

    private CharSequence mShortcutGroupTitle = "";
    private CharSequence mSuggestedAppsGroupTitle = "";
    private CharSequence mAllAppListGroupTitle = "";
    @Nullable
    private RecyclerView mRecyclerView;
    private boolean mVerticalScrollEnabled = true;

    /**
@@ -39,6 +55,9 @@ public class ChooserGridLayoutManager extends GridLayoutManager {
    public ChooserGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        if (announceShortcutsAndSuggestedAppsLegacy()) {
            readGroupTitles(context);
        }
    }

    /**
@@ -49,6 +68,9 @@ public class ChooserGridLayoutManager extends GridLayoutManager {
     */
    public ChooserGridLayoutManager(Context context, int spanCount) {
        super(context, spanCount);
        if (announceShortcutsAndSuggestedAppsLegacy()) {
            readGroupTitles(context);
        }
    }

    /**
@@ -61,6 +83,27 @@ public class ChooserGridLayoutManager extends GridLayoutManager {
    public ChooserGridLayoutManager(Context context, int spanCount, int orientation,
            boolean reverseLayout) {
        super(context, spanCount, orientation, reverseLayout);
        if (announceShortcutsAndSuggestedAppsLegacy()) {
            readGroupTitles(context);
        }
    }

    private void readGroupTitles(Context context) {
        mShortcutGroupTitle = context.getString(R.string.shortcut_group_a11y_title);
        mSuggestedAppsGroupTitle = context.getString(R.string.suggested_apps_group_a11y_title);
        mAllAppListGroupTitle = context.getString(R.string.all_apps_group_a11y_title);
    }

    @Override
    public void onAttachedToWindow(RecyclerView view) {
        super.onAttachedToWindow(view);
        mRecyclerView = view;
    }

    @Override
    public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
        super.onDetachedFromWindow(view, recycler);
        mRecyclerView = null;
    }

    @Override
@@ -78,4 +121,89 @@ public class ChooserGridLayoutManager extends GridLayoutManager {
    public boolean canScrollVertically() {
        return mVerticalScrollEnabled && super.canScrollVertically();
    }

    @Override
    public void onInitializeAccessibilityNodeInfoForItem(
            RecyclerView.Recycler recycler,
            RecyclerView.State state,
            View host,
            AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfoForItem(recycler, state, host, info);
        if (announceShortcutsAndSuggestedAppsLegacy() && host instanceof ViewGroup) {
            if (host.getId() == R.id.shortcuts_container) {
                info.setClassName(GridView.class.getName());
                info.setContainerTitle(mShortcutGroupTitle);
                info.setCollectionInfo(createShortcutsA11yCollectionInfo((ViewGroup) host));
            } else if (host.getId() == R.id.chooser_row) {
                RecyclerView.Adapter adapter =
                        mRecyclerView == null ? null : mRecyclerView.getAdapter();
                ChooserListAdapter gridAdapter = adapter instanceof ChooserGridAdapter
                        ? ((ChooserGridAdapter) adapter).getListAdapter()
                        : null;
                info.setClassName(GridView.class.getName());
                info.setCollectionInfo(createSuggestedAppsA11yCollectionInfo((ViewGroup) host));
                if (gridAdapter == null || gridAdapter.getAlphaTargetCount() > 0) {
                    info.setContainerTitle(mSuggestedAppsGroupTitle);
                } else {
                    // if all applications fit into one row, they will be put into the suggested
                    // applications group.
                    info.setContainerTitle(mAllAppListGroupTitle);
                }
            }
        }
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(RecyclerView.Recycler recycler,
            RecyclerView.State state, AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfo(recycler, state, info);
        if (announceShortcutsAndSuggestedAppsLegacy()) {
            info.setContainerTitle(mAllAppListGroupTitle);
        }
    }

    @Override
    public boolean isLayoutHierarchical(RecyclerView.Recycler recycler, RecyclerView.State state) {
        return announceShortcutsAndSuggestedAppsLegacy()
                || super.isLayoutHierarchical(recycler, state);
    }

    private CollectionInfo createShortcutsA11yCollectionInfo(ViewGroup container) {
        int rowCount = 0;
        int columnCount = 0;
        for (int i = 0; i < container.getChildCount(); i++) {
            View row = container.getChildAt(i);
            int rowColumnCount = 0;
            if (row instanceof ViewGroup rowGroup && row.getVisibility() == View.VISIBLE) {
                for (int j = 0; j < rowGroup.getChildCount(); j++) {
                    View v = rowGroup.getChildAt(j);
                    if (v != null && v.getVisibility() == View.VISIBLE) {
                        rowColumnCount++;
                        if (v instanceof TextView) {
                            // A special case of the no-targets message that also contains an
                            // off-screen item (which looks like a bug).
                            rowColumnCount = 1;
                            break;
                        }
                    }
                }
            }
            if (rowColumnCount > 0) {
                rowCount++;
                columnCount = Math.max(columnCount, rowColumnCount);
            }
        }
        return CollectionInfo.obtain(rowCount, columnCount, false);
    }

    private CollectionInfo createSuggestedAppsA11yCollectionInfo(ViewGroup container) {
        int columnCount = 0;
        for (int i = 0; i < container.getChildCount(); i++) {
            View v = container.getChildAt(i);
            if (v.getVisibility() == View.VISIBLE) {
                columnCount++;
            }
        }
        return CollectionInfo.obtain(1, columnCount, false);
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/chooser_row"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="100dp"
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/shortcuts_container"
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="200dp">
+10 −0
Original line number Diff line number Diff line
@@ -5744,6 +5744,16 @@
    <string name="unpin_specific_target">Unpin <xliff:g id="label" example="Tweet">%1$s</xliff:g></string>
    <!-- View application info for a target. -->
    <string name="app_info">App info</string>
    <!-- Accessibility announcement for the shortcut group (https://developer.android.com/training/sharing/direct-share-targets)
     in the list of targets. [CHAR LIMIT=NONE]-->
    <string name="shortcut_group_a11y_title">Direct share targets</string>
    <!-- Accessibility announcement for the suggested application group in the list of targets.
    [CHAR LIMIT=NONE] -->
    <string name="suggested_apps_group_a11y_title">App suggestions</string>
    <!-- Accessibility announcement for the all-applications group in the list of targets.
    [CHAR LIMIT=NONE] -->
    <string name="all_apps_group_a11y_title">App list</string>
    <!-- The representation of a time duration when negative. An example is -1:14. This can be used with a countdown timer for example.-->
    <string name="negative_duration">\u2212<xliff:g id="time" example="1:14">%1$s</xliff:g></string>
Loading