1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
/*
* 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);
}
}
}
|