/* * 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: * * * 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 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); } } }