Loading core/java/android/service/chooser/flags.aconfig +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 Loading core/java/com/android/internal/app/ChooserGridLayoutManager.java +128 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; /** Loading @@ -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); } } /** Loading @@ -49,6 +68,9 @@ public class ChooserGridLayoutManager extends GridLayoutManager { */ public ChooserGridLayoutManager(Context context, int spanCount) { super(context, spanCount); if (announceShortcutsAndSuggestedAppsLegacy()) { readGroupTitles(context); } } /** Loading @@ -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 Loading @@ -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); } } core/res/res/layout/chooser_row.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" Loading core/res/res/layout/chooser_row_direct_share.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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"> Loading core/res/res/values/strings.xml +10 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
core/java/android/service/chooser/flags.aconfig +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 Loading
core/java/com/android/internal/app/ChooserGridLayoutManager.java +128 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; /** Loading @@ -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); } } /** Loading @@ -49,6 +68,9 @@ public class ChooserGridLayoutManager extends GridLayoutManager { */ public ChooserGridLayoutManager(Context context, int spanCount) { super(context, spanCount); if (announceShortcutsAndSuggestedAppsLegacy()) { readGroupTitles(context); } } /** Loading @@ -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 Loading @@ -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); } }
core/res/res/layout/chooser_row.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" Loading
core/res/res/layout/chooser_row_direct_share.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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"> Loading
core/res/res/values/strings.xml +10 −0 Original line number Diff line number Diff line Loading @@ -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