Mark actions unimportant for accessibility when obscured by RemoteInputView.

To prevent animation jank, we don't actually hide or remove the action
buttons (like "reply") on a notification while they're obscured by the
remote input view (like while the user is typing their reply).

Visually, this is fine, but Voice Access still sees those buttons as
important. If the user speaks the action (like "reply"), Voice Access
will activate the buttons, but nothing visible will happen. If the user
has numbers shown, Voice Access will number the buttons, but the numbers
will appear to point at the remote input view instead.

To avoid this, we mark the NotificationActionListLayout as unimportant
for accessibility while the remote input view is visible, and return it
to "auto" important when the remote input view isn't visible.

Bug: 230297786
Test: atest NotificationContentViewTest
Change-Id: I50fdda3adabd0039ed84b3781c0d275fc176ef89
This commit is contained in:
Julia Tuttle
2022-10-04 16:54:07 -04:00
parent f12d6c2894
commit 152fc131c5
2 changed files with 76 additions and 0 deletions

View File

@@ -1986,6 +1986,25 @@ public class NotificationContentView extends FrameLayout implements Notification
public void setRemoteInputVisible(boolean remoteInputVisible) {
mRemoteInputVisible = remoteInputVisible;
setClipChildren(!remoteInputVisible);
setActionsImportanceForAccessibility(
remoteInputVisible ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
}
private void setActionsImportanceForAccessibility(int mode) {
if (mExpandedChild != null) {
setActionsImportanceForAccessibility(mode, mExpandedChild);
}
if (mHeadsUpChild != null) {
setActionsImportanceForAccessibility(mode, mHeadsUpChild);
}
}
private void setActionsImportanceForAccessibility(int mode, View child) {
View actionsCandidate = child.findViewById(com.android.internal.R.id.actions);
if (actionsCandidate != null) {
actionsCandidate.setImportantForAccessibility(mode);
}
}
@Override

View File

@@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
import com.android.internal.widget.NotificationActionListLayout;
import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
@@ -142,4 +143,60 @@ public class NotificationContentViewTest extends SysuiTestCase {
verify(mockExpandedEB, times(1)).requestAccessibilityFocus();
verify(mockHeadsUpEB, times(0)).requestAccessibilityFocus();
}
@Test
@UiThreadTest
public void testRemoteInputVisibleSetsActionsUnimportantHideDescendantsForAccessibility() {
View mockContracted = mock(NotificationHeaderView.class);
View mockExpandedActions = mock(NotificationActionListLayout.class);
View mockExpanded = mock(NotificationHeaderView.class);
when(mockExpanded.findViewById(com.android.internal.R.id.actions)).thenReturn(
mockExpandedActions);
View mockHeadsUpActions = mock(NotificationActionListLayout.class);
View mockHeadsUp = mock(NotificationHeaderView.class);
when(mockHeadsUp.findViewById(com.android.internal.R.id.actions)).thenReturn(
mockHeadsUpActions);
mView.setContractedChild(mockContracted);
mView.setExpandedChild(mockExpanded);
mView.setHeadsUpChild(mockHeadsUp);
mView.setRemoteInputVisible(true);
verify(mockContracted, times(0)).findViewById(0);
verify(mockExpandedActions, times(1)).setImportantForAccessibility(
View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
verify(mockHeadsUpActions, times(1)).setImportantForAccessibility(
View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
@Test
@UiThreadTest
public void testRemoteInputInvisibleSetsActionsAutoImportantForAccessibility() {
View mockContracted = mock(NotificationHeaderView.class);
View mockExpandedActions = mock(NotificationActionListLayout.class);
View mockExpanded = mock(NotificationHeaderView.class);
when(mockExpanded.findViewById(com.android.internal.R.id.actions)).thenReturn(
mockExpandedActions);
View mockHeadsUpActions = mock(NotificationActionListLayout.class);
View mockHeadsUp = mock(NotificationHeaderView.class);
when(mockHeadsUp.findViewById(com.android.internal.R.id.actions)).thenReturn(
mockHeadsUpActions);
mView.setContractedChild(mockContracted);
mView.setExpandedChild(mockExpanded);
mView.setHeadsUpChild(mockHeadsUp);
mView.setRemoteInputVisible(false);
verify(mockContracted, times(0)).findViewById(0);
verify(mockExpandedActions, times(1)).setImportantForAccessibility(
View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
verify(mockHeadsUpActions, times(1)).setImportantForAccessibility(
View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
}
}