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

Commit 92555b23 authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge "Add TileAdapterDelegate"

parents 7b0b4bf8 ac22e5bf
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -170,6 +170,9 @@
    <item type="id" name="accessibility_action_controls_move_before" />
    <item type="id" name="accessibility_action_controls_move_after" />

    <item type="id" name="accessibility_action_qs_move_to_position" />
    <item type="id" name="accessibility_action_qs_add_to_position" />

    <!-- Accessibility actions for PIP -->
    <item type="id" name="action_pip_resize" />
</resources>
+15 −12
Original line number Diff line number Diff line
@@ -2260,23 +2260,26 @@
    <!-- SysUI Tuner: Other section -->
    <string name="other">Other</string>

    <!-- Accessibility description of a QS tile while editing positions [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_tile_label">Position <xliff:g id="position" example="2">%1$d</xliff:g>, <xliff:g id="tile_name" example="Wi-Fi">%2$s</xliff:g>. Double tap to edit.</string>
    <!-- Accessibility description of action to remove QS tile on click. It will read as "Double-tap to remove tile" in screen readers [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_remove_tile_action">remove tile</string>

    <!-- Accessibility description of a QS tile while editing positions [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_add_tile_label"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g>. Double tap to add.</string>
    <!-- Accessibility action of action to add QS tile to end. It will read as "Double-tap to add tile to end" in screen readers [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_tile_add_action">add tile to end</string>

    <!-- Accessibility description of option to move QS tile [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_move_tile">Move <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g></string>
    <!-- Accessibility action for context menu to move QS tile [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_tile_start_move">Move tile</string>

    <!-- Accessibility description of option to remove QS tile [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_remove_tile">Remove <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g></string>
    <!-- Accessibility action for context menu to add QS tile [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_tile_start_add">Add tile</string>

    <!-- Accessibility action when QS tile is to be added [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_tile_add">Add <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
    <!-- Accessibility description when QS tile is to be moved, indicating the destination position [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_tile_move_to_position">Move to <xliff:g id="position" example="5">%1$d</xliff:g></string>

    <!-- Accessibility action when QS tile is to be moved [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_tile_move">Move <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
    <!-- Accessibility description when QS tile is to be added, indicating the destination position [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_tile_add_to_position">Add to position <xliff:g id="position" example="5">%1$d</xliff:g></string>

    <!-- Accessibility description indicating the currently selected tile's position. Only used for tiles that are currently in use [CHAR LIMIT=NONE] -->
    <string name="accessibility_qs_edit_position">Position <xliff:g id="position" example="5">%1$d</xliff:g></string>

    <!-- Accessibility label for window when QS editing is happening [CHAR LIMIT=NONE] -->
    <string name="accessibility_desc_quick_settings_edit">Quick settings editor.</string>
+133 −81
Original line number Diff line number Diff line
@@ -14,11 +14,8 @@

package com.android.systemui.qs.customize;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
@@ -28,10 +25,11 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup;
import androidx.recyclerview.widget.ItemTouchHelper;
@@ -49,7 +47,6 @@ import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSIconViewImpl;
import com.android.systemui.statusbar.phone.SystemUIDialog;

import java.util.ArrayList;
import java.util.List;
@@ -78,10 +75,10 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
    private final List<TileInfo> mTiles = new ArrayList<>();
    private final ItemTouchHelper mItemTouchHelper;
    private final ItemDecoration mDecoration;
    private final AccessibilityManager mAccessibilityManager;
    private final int mMinNumTiles;
    private int mEditIndex;
    private int mTileDividerIndex;
    private int mFocusIndex;
    private boolean mNeedsFocus;
    private List<String> mCurrentSpecs;
    private List<TileInfo> mOtherTiles;
@@ -90,17 +87,28 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
    private Holder mCurrentDrag;
    private int mAccessibilityAction = ACTION_NONE;
    private int mAccessibilityFromIndex;
    private CharSequence mAccessibilityFromLabel;
    private QSTileHost mHost;
    private final UiEventLogger mUiEventLogger;
    private final AccessibilityDelegateCompat mAccessibilityDelegate;
    private RecyclerView mRecyclerView;

    public TileAdapter(Context context, UiEventLogger uiEventLogger) {
        mContext = context;
        mUiEventLogger = uiEventLogger;
        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
        mItemTouchHelper = new ItemTouchHelper(mCallbacks);
        mDecoration = new TileItemDecoration(context);
        mMinNumTiles = context.getResources().getInteger(R.integer.quick_settings_min_num_tiles);
        mAccessibilityDelegate = new TileAdapterDelegate();
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
    }

    @Override
    public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
        mRecyclerView = null;
    }

    public void setHost(QSTileHost host) {
@@ -130,7 +138,6 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
            // Remove blank tile from last spot
            mTiles.remove(--mEditIndex);
            // Update the tile divider position
            mTileDividerIndex--;
            notifyDataSetChanged();
        }
        mAccessibilityAction = ACTION_NONE;
@@ -241,7 +248,6 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
    }

    private void setSelectableForHeaders(View view) {
        if (mAccessibilityManager.isTouchExplorationEnabled()) {
        final boolean selectable = mAccessibilityAction == ACTION_NONE;
        view.setFocusable(selectable);
        view.setImportantForAccessibility(selectable
@@ -249,7 +255,6 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
                : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
        view.setFocusableInTouchMode(selectable);
    }
    }

    @Override
    public void onBindViewHolder(final Holder holder, int position) {
@@ -285,12 +290,11 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
            holder.mTileView.setVisibility(View.VISIBLE);
            holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
            holder.mTileView.setContentDescription(mContext.getString(
                    R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel,
                    position));
                    R.string.accessibility_qs_edit_tile_add_to_position, position));
            holder.mTileView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    selectPosition(holder.getAdapterPosition(), v);
                    selectPosition(holder.getLayoutPosition());
                }
            });
            focusOnHolder(holder);
@@ -299,53 +303,48 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta

        TileInfo info = mTiles.get(position);

        if (position > mEditIndex) {
        final boolean selectable = 0 < position && position < mEditIndex;
        if (selectable && mAccessibilityAction == ACTION_ADD) {
            info.state.contentDescription = mContext.getString(
                    R.string.accessibility_qs_edit_add_tile_label, info.state.label);
        } else if (mAccessibilityAction == ACTION_ADD) {
                    R.string.accessibility_qs_edit_tile_add_to_position, position);
        } else if (selectable && mAccessibilityAction == ACTION_MOVE) {
            info.state.contentDescription = mContext.getString(
                    R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel, position);
        } else if (mAccessibilityAction == ACTION_MOVE) {
            info.state.contentDescription = mContext.getString(
                    R.string.accessibility_qs_edit_tile_move, mAccessibilityFromLabel, position);
                    R.string.accessibility_qs_edit_tile_move_to_position, position);
        } else {
            info.state.contentDescription = mContext.getString(
                    R.string.accessibility_qs_edit_tile_label, position, info.state.label);
            info.state.contentDescription = info.state.label;
        }
        info.state.expandedAccessibilityClassName = "";

        holder.mTileView.handleStateChanged(info.state);
        holder.mTileView.setShowAppLabel(position > mEditIndex && !info.isSystem);
        holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
        holder.mTileView.setClickable(true);
        holder.mTileView.setOnClickListener(null);
        holder.mTileView.setFocusable(true);
        holder.mTileView.setFocusableInTouchMode(true);

        if (mAccessibilityManager.isTouchExplorationEnabled()) {
            final boolean selectable = mAccessibilityAction == ACTION_NONE || position < mEditIndex;
        if (mAccessibilityAction != ACTION_NONE) {
            holder.mTileView.setClickable(selectable);
            holder.mTileView.setFocusable(selectable);
            holder.mTileView.setFocusableInTouchMode(selectable);
            holder.mTileView.setImportantForAccessibility(selectable
                    ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
                    : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
            holder.mTileView.setFocusableInTouchMode(selectable);
            if (selectable) {
                holder.mTileView.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        int position = holder.getAdapterPosition();
                        int position = holder.getLayoutPosition();
                        if (position == RecyclerView.NO_POSITION) return;
                        if (mAccessibilityAction != ACTION_NONE) {
                            selectPosition(position, v);
                        } else {
                            if (position < mEditIndex && canRemoveTiles()) {
                                showAccessibilityDialog(position, v);
                            } else if (position < mEditIndex && !canRemoveTiles()) {
                                startAccessibleMove(position);
                            } else {
                                startAccessibleAdd(position);
                            }
                            selectPosition(position);
                        }
                    }
                });
                if (position == mAccessibilityFromIndex) {
                    focusOnHolder(holder);
            }
        }
        if (position == mFocusIndex) {
            focusOnHolder(holder);
        }
    }

@@ -360,9 +359,13 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
                    holder.mTileView.removeOnLayoutChangeListener(this);
                    holder.mTileView.requestFocus();
                    if (mAccessibilityAction == ACTION_NONE) {
                        holder.mTileView.clearFocus();
                    }
                }
            });
            mNeedsFocus = false;
            mFocusIndex = RecyclerView.NO_POSITION;
        }
    }

@@ -370,72 +373,77 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
        return mCurrentSpecs.size() > mMinNumTiles;
    }

    private void selectPosition(int position, View v) {
    private void selectPosition(int position) {
        if (mAccessibilityAction == ACTION_ADD) {
            // Remove the placeholder.
            mTiles.remove(mEditIndex--);
            notifyItemRemoved(mEditIndex);
        }
        mAccessibilityAction = ACTION_NONE;
        move(mAccessibilityFromIndex, position, v);
        notifyDataSetChanged();
    }

    private void showAccessibilityDialog(final int position, final View v) {
        final TileInfo info = mTiles.get(position);
        CharSequence[] options = new CharSequence[] {
                mContext.getString(R.string.accessibility_qs_edit_move_tile, info.state.label),
                mContext.getString(R.string.accessibility_qs_edit_remove_tile, info.state.label),
        };
        AlertDialog dialog = new Builder(mContext)
                .setItems(options, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (which == 0) {
                            startAccessibleMove(position);
                        } else {
                            move(position, info.isSystem ? mEditIndex : mTileDividerIndex, v);
                            notifyItemChanged(mTileDividerIndex);
        move(mAccessibilityFromIndex, position, false);
        mFocusIndex = position;
        mNeedsFocus = true;
        notifyDataSetChanged();
    }
                    }
                }).setNegativeButton(android.R.string.cancel, null)
                .create();
        SystemUIDialog.setShowForAllUsers(dialog, true);
        SystemUIDialog.applyFlags(dialog);
        dialog.show();
    }

    private void startAccessibleAdd(int position) {
        mAccessibilityFromIndex = position;
        mAccessibilityFromLabel = mTiles.get(position).state.label;
        mAccessibilityAction = ACTION_ADD;
        // Add placeholder for last slot.
        mTiles.add(mEditIndex++, null);
        // Update the tile divider position
        mTileDividerIndex++;
        mFocusIndex = mEditIndex - 1;
        mNeedsFocus = true;
        if (mRecyclerView != null) {
            mRecyclerView.post(() -> mRecyclerView.smoothScrollToPosition(mFocusIndex));
        }
        notifyDataSetChanged();
    }

    private void startAccessibleMove(int position) {
        mAccessibilityFromIndex = position;
        mAccessibilityFromLabel = mTiles.get(position).state.label;
        mAccessibilityAction = ACTION_MOVE;
        mFocusIndex = position;
        mNeedsFocus = true;
        notifyDataSetChanged();
    }

    private boolean canRemoveFromPosition(int position) {
        return canRemoveTiles() && isCurrentTile(position);
    }

    private boolean isCurrentTile(int position) {
        return position < mEditIndex;
    }

    private boolean canAddFromPosition(int position) {
        return position > mEditIndex;
    }

    private void addFromPosition(int position) {
        if (!canAddFromPosition(position)) return;
        move(position, mEditIndex);
    }

    private void removeFromPosition(int position) {
        if (!canRemoveFromPosition(position)) return;
        TileInfo info = mTiles.get(position);
        move(position, info.isSystem ? mEditIndex : mTileDividerIndex);
    }

    public SpanSizeLookup getSizeLookup() {
        return mSizeLookup;
    }

    private boolean move(int from, int to, View v) {
    private boolean move(int from, int to) {
        return move(from, to, true);
    }

    private boolean move(int from, int to, boolean notify) {
        if (to == from) {
            return true;
        }
        CharSequence fromLabel = mTiles.get(from).state.label;
        move(from, to, mTiles);
        move(from, to, mTiles, notify);
        updateDividerLocations();
        if (to >= mEditIndex) {
            mUiEventLogger.log(QSEditEvent.QS_EDIT_REMOVE, 0, strip(mTiles.get(to)));
@@ -477,10 +485,12 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
        return spec;
    }

    private <T> void move(int from, int to, List<T> list) {
    private <T> void move(int from, int to, List<T> list, boolean notify) {
        list.add(to, list.remove(from));
        if (notify) {
            notifyItemMoved(from, to);
        }
    }

    public class Holder extends ViewHolder {
        private CustomizeTileView mTileView;
@@ -491,6 +501,8 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
                mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
                mTileView.setBackground(null);
                mTileView.getIcon().disableAnimation();
                mTileView.setTag(this);
                ViewCompat.setAccessibilityDelegate(mTileView, mAccessibilityDelegate);
            }
        }

@@ -527,6 +539,46 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
                    .setDuration(DRAG_LENGTH)
                    .alpha(.6f);
        }

        boolean canRemove() {
            return canRemoveFromPosition(getLayoutPosition());
        }

        boolean canAdd() {
            return canAddFromPosition(getLayoutPosition());
        }

        void toggleState() {
            if (canAdd()) {
                add();
            } else {
                remove();
            }
        }

        private void add() {
            addFromPosition(getLayoutPosition());
        }

        private void remove() {
            removeFromPosition(getLayoutPosition());
        }

        boolean isCurrentTile() {
            return TileAdapter.this.isCurrentTile(getLayoutPosition());
        }

        void startAccessibleAdd() {
            TileAdapter.this.startAccessibleAdd(getLayoutPosition());
        }

        void startAccessibleMove() {
            TileAdapter.this.startAccessibleMove(getLayoutPosition());
        }

        boolean canTakeAccessibleAction() {
            return mAccessibilityAction == ACTION_NONE;
        }
    }

    private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
@@ -648,7 +700,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
                    to == 0 || to == RecyclerView.NO_POSITION) {
                return false;
            }
            return move(from, to, target.itemView);
            return move(from, to);
        }

        @Override
+152 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.customize;

import android.os.Bundle;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;

import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;

import com.android.systemui.R;

import java.util.List;

/**
 * Accessibility delegate for {@link TileAdapter} views.
 *
 * This delegate will populate the accessibility info with the proper actions that can be taken for
 * the different tiles:
 * <ul>
 *   <li>Add to end if the tile is not a current tile (by double tap).</li>
 *   <li>Add to a given position (by context menu). This will let the user select a position.</li>
 *   <li>Remove, if the tile is a current tile (by double tap).</li>
 *   <li>Move to a given position (by context menu). This will let the user select a position.</li>
 * </ul>
 *
 * This only handles generating the associated actions. The logic for selecting positions is handled
 * by {@link TileAdapter}.
 *
 * In order for the delegate to work properly, the asociated {@link TileAdapter.Holder} should be
 * passed along with the view using {@link View#setTag}.
 */
class TileAdapterDelegate extends AccessibilityDelegateCompat {

    private static final int MOVE_TO_POSITION_ID = R.id.accessibility_action_qs_move_to_position;
    private static final int ADD_TO_POSITION_ID = R.id.accessibility_action_qs_add_to_position;

    private TileAdapter.Holder getHolder(View view) {
        return (TileAdapter.Holder) view.getTag();
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
        super.onInitializeAccessibilityNodeInfo(host, info);
        TileAdapter.Holder holder = getHolder(host);
        info.setCollectionItemInfo(null);
        info.setStateDescription("");
        if (holder == null || !holder.canTakeAccessibleAction()) {
            // If there's not a holder (not a regular Tile) or an action cannot be taken
            // because we are in the middle of an accessibility action, don't create a special node.
            return;
        }

        addClickAction(host, info, holder);
        maybeAddActionAddToPosition(host, info, holder);
        maybeAddActionMoveToPosition(host, info, holder);

        if (holder.isCurrentTile()) {
            info.setStateDescription(host.getContext().getString(
                    R.string.accessibility_qs_edit_position, holder.getLayoutPosition()));
        }
    }

    @Override
    public boolean performAccessibilityAction(View host, int action, Bundle args) {
        TileAdapter.Holder holder = getHolder(host);

        if (holder == null || !holder.canTakeAccessibleAction()) {
            // If there's not a holder (not a regular Tile) or an action cannot be taken
            // because we are in the middle of an accessibility action, perform the default action.
            return super.performAccessibilityAction(host, action, args);
        }
        if (action == AccessibilityNodeInfo.ACTION_CLICK) {
            holder.toggleState();
            return true;
        } else if (action == MOVE_TO_POSITION_ID) {
            holder.startAccessibleMove();
            return true;
        } else if (action == ADD_TO_POSITION_ID) {
            holder.startAccessibleAdd();
            return true;
        } else {
            return super.performAccessibilityAction(host, action, args);
        }
    }

    private void addClickAction(
            View host, AccessibilityNodeInfoCompat info, TileAdapter.Holder holder) {
        String clickActionString;
        if (holder.canAdd()) {
            clickActionString = host.getContext().getString(
                    R.string.accessibility_qs_edit_tile_add_action);
        } else if (holder.canRemove()) {
            clickActionString = host.getContext().getString(
                    R.string.accessibility_qs_edit_remove_tile_action);
        } else {
            // Remove the default click action if tile can't either be added or removed (for example
            // if there's the minimum number of tiles)
            List<AccessibilityNodeInfoCompat.AccessibilityActionCompat> listOfActions =
                    info.getActionList(); // This is a copy
            int numActions = listOfActions.size();
            for (int i = 0; i < numActions; i++) {
                if (listOfActions.get(i).getId() == AccessibilityNodeInfo.ACTION_CLICK) {
                    info.removeAction(listOfActions.get(i));
                }
            }
            return;
        }

        AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
                new AccessibilityNodeInfoCompat.AccessibilityActionCompat(
                        AccessibilityNodeInfo.ACTION_CLICK, clickActionString);
        info.addAction(action);
    }

    private void maybeAddActionMoveToPosition(
            View host, AccessibilityNodeInfoCompat info, TileAdapter.Holder holder) {
        if (holder.isCurrentTile()) {
            AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
                    new AccessibilityNodeInfoCompat.AccessibilityActionCompat(MOVE_TO_POSITION_ID,
                            host.getContext().getString(
                                    R.string.accessibility_qs_edit_tile_start_move));
            info.addAction(action);
        }
    }

    private void maybeAddActionAddToPosition(
            View host, AccessibilityNodeInfoCompat info, TileAdapter.Holder holder) {
        if (holder.canAdd()) {
            AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
                    new AccessibilityNodeInfoCompat.AccessibilityActionCompat(ADD_TO_POSITION_ID,
                            host.getContext().getString(
                                    R.string.accessibility_qs_edit_tile_start_add));
            info.addAction(action);
        }
    }
}
+265 −0

File added.

Preview size limit exceeded, changes collapsed.