blob: 1e426adac0b8f5ded791828ed7ed117be423ffad [file] [log] [blame]
/*
* 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);
}
}
}