Merge "Ensure a11y long click works on notif guts." into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
088de38a8c
@@ -52,7 +52,7 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
|
||||
private NotificationGuts mGutsContainer;
|
||||
|
||||
private OnClickListener mOnOk = v -> {
|
||||
closeControls(v);
|
||||
mGutsContainer.closeControls(v, false);
|
||||
};
|
||||
|
||||
public AppOpsInfo(Context context, AttributeSet attrs) {
|
||||
@@ -117,6 +117,7 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
|
||||
});
|
||||
TextView ok = findViewById(R.id.ok);
|
||||
ok.setOnClickListener(mOnOk);
|
||||
ok.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
|
||||
}
|
||||
|
||||
private String getPrompt() {
|
||||
@@ -160,19 +161,6 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
|
||||
}
|
||||
}
|
||||
|
||||
private void closeControls(View v) {
|
||||
mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
|
||||
int[] parentLoc = new int[2];
|
||||
int[] targetLoc = new int[2];
|
||||
mGutsContainer.getLocationOnScreen(parentLoc);
|
||||
v.getLocationOnScreen(targetLoc);
|
||||
final int centerX = v.getWidth() / 2;
|
||||
final int centerY = v.getHeight() / 2;
|
||||
final int x = targetLoc[0] - parentLoc[0] + centerX;
|
||||
final int y = targetLoc[1] - parentLoc[1] + centerY;
|
||||
mGutsContainer.closeControls(x, y, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGutsParent(NotificationGuts guts) {
|
||||
mGutsContainer = guts;
|
||||
@@ -200,6 +188,7 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
|
||||
|
||||
@Override
|
||||
public boolean handleCloseControls(boolean save, boolean force) {
|
||||
mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1122,9 +1122,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
}
|
||||
|
||||
public void setGutsView(MenuItem item) {
|
||||
if (mGuts != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
|
||||
((NotificationGuts.GutsContent) item.getGutsView()).setGutsParent(mGuts);
|
||||
mGuts.setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
|
||||
if (getGuts() != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
|
||||
getGuts().setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,13 +137,13 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
mSelectedAction = ACTION_HOME;
|
||||
mShortcutManager.requestPinShortcut(mShortcutInfo, null);
|
||||
mShadeController.animateCollapsePanels();
|
||||
closeControls(v, true);
|
||||
mGutsContainer.closeControls(v, true);
|
||||
};
|
||||
|
||||
private OnClickListener mOnSnoozeClick = v -> {
|
||||
mSelectedAction = ACTION_SNOOZE;
|
||||
mOnSnoozeClickListener.onClick(v, 1);
|
||||
closeControls(v, true);
|
||||
mGutsContainer.closeControls(v, true);
|
||||
};
|
||||
*/
|
||||
|
||||
@@ -164,7 +164,7 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
|
||||
private OnClickListener mOnDone = v -> {
|
||||
mPressedApply = true;
|
||||
closeControls(v, true);
|
||||
mGutsContainer.closeControls(v, true);
|
||||
};
|
||||
|
||||
public NotificationConversationInfo(Context context, AttributeSet attrs) {
|
||||
@@ -258,6 +258,7 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
|
||||
View done = findViewById(R.id.done);
|
||||
done.setOnClickListener(mOnDone);
|
||||
done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
|
||||
}
|
||||
|
||||
private void bindActions() {
|
||||
@@ -543,25 +544,6 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
controller.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the controls and commits the updated importance values (indirectly).
|
||||
*
|
||||
* <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
|
||||
* user does not have the ability to undo the action anymore.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void closeControls(View v, boolean save) {
|
||||
int[] parentLoc = new int[2];
|
||||
int[] targetLoc = new int[2];
|
||||
mGutsContainer.getLocationOnScreen(parentLoc);
|
||||
v.getLocationOnScreen(targetLoc);
|
||||
final int centerX = v.getWidth() / 2;
|
||||
final int centerY = v.getHeight() / 2;
|
||||
final int x = targetLoc[0] - parentLoc[0] + centerX;
|
||||
final int y = targetLoc[1] - parentLoc[1] + centerY;
|
||||
mGutsContainer.closeControls(x, y, save, false /* force */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGutsParent(NotificationGuts guts) {
|
||||
mGutsContainer = guts;
|
||||
|
||||
@@ -22,12 +22,14 @@ import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewAnimationUtils;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -59,6 +61,31 @@ public class NotificationGuts extends FrameLayout {
|
||||
|
||||
private GutsContent mGutsContent;
|
||||
|
||||
private View.AccessibilityDelegate mGutsContentAccessibilityDelegate =
|
||||
new View.AccessibilityDelegate() {
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(
|
||||
View host, AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performAccessibilityAction(View host, int action, Bundle args) {
|
||||
if (super.performAccessibilityAction(host, action, args)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case AccessibilityNodeInfo.ACTION_LONG_CLICK:
|
||||
closeControls(host, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
public interface GutsContent {
|
||||
|
||||
public void setGutsParent(NotificationGuts listener);
|
||||
@@ -110,6 +137,11 @@ public class NotificationGuts extends FrameLayout {
|
||||
* view on the lockscreen
|
||||
*/
|
||||
boolean needsFalsingProtection();
|
||||
|
||||
/**
|
||||
* Equivalent to {@link View#setAccessibilityDelegate(AccessibilityDelegate)}
|
||||
*/
|
||||
void setAccessibilityDelegate(AccessibilityDelegate gutsContentAccessibilityDelegate);
|
||||
}
|
||||
|
||||
public interface OnGutsClosedListener {
|
||||
@@ -146,6 +178,8 @@ public class NotificationGuts extends FrameLayout {
|
||||
}
|
||||
|
||||
public void setGutsContent(GutsContent content) {
|
||||
content.setGutsParent(this);
|
||||
content.setAccessibilityDelegate(mGutsContentAccessibilityDelegate);
|
||||
mGutsContent = content;
|
||||
removeAllViews();
|
||||
addView(mGutsContent.getContentView());
|
||||
@@ -235,6 +269,22 @@ public class NotificationGuts extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes any exposed guts/views.
|
||||
*/
|
||||
public void closeControls(View eventSource, boolean save) {
|
||||
int[] parentLoc = new int[2];
|
||||
int[] targetLoc = new int[2];
|
||||
getLocationOnScreen(parentLoc);
|
||||
eventSource.getLocationOnScreen(targetLoc);
|
||||
final int centerX = eventSource.getWidth() / 2;
|
||||
final int centerY = eventSource.getHeight() / 2;
|
||||
final int x = targetLoc[0] - parentLoc[0] + centerX;
|
||||
final int y = targetLoc[1] - parentLoc[1] + centerY;
|
||||
|
||||
closeControls(x, y, save, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes any exposed guts/views.
|
||||
*
|
||||
@@ -243,7 +293,7 @@ public class NotificationGuts extends FrameLayout {
|
||||
* @param save whether the state should be saved
|
||||
* @param force whether the guts should be force-closed regardless of state.
|
||||
*/
|
||||
public void closeControls(int x, int y, boolean save, boolean force) {
|
||||
private void closeControls(int x, int y, boolean save, boolean force) {
|
||||
// First try to dismiss any blocking helper.
|
||||
boolean wasBlockingHelperDismissed =
|
||||
Dependency.get(NotificationBlockingHelperManager.class)
|
||||
|
||||
@@ -141,7 +141,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
|
||||
// used by standard ui
|
||||
private OnClickListener mOnDismissSettings = v -> {
|
||||
mPressedApply = true;
|
||||
closeControls(v, true);
|
||||
mGutsContainer.closeControls(v, true);
|
||||
};
|
||||
|
||||
public NotificationInfo(Context context, AttributeSet attrs) {
|
||||
@@ -250,7 +250,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
|
||||
|
||||
View done = findViewById(R.id.done);
|
||||
done.setOnClickListener(mOnDismissSettings);
|
||||
|
||||
done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
|
||||
|
||||
View silent = findViewById(R.id.silence);
|
||||
View alert = findViewById(R.id.alert);
|
||||
@@ -330,7 +330,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
|
||||
mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
|
||||
mChannelEditorDialogController.setOnFinishListener(() -> {
|
||||
mPresentingChannelEditorDialog = false;
|
||||
closeControls(this, false);
|
||||
mGutsContainer.closeControls(this, false);
|
||||
});
|
||||
mChannelEditorDialogController.show();
|
||||
}
|
||||
@@ -528,25 +528,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the controls and commits the updated importance values (indirectly).
|
||||
*
|
||||
* <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
|
||||
* user does not have the ability to undo the action anymore.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void closeControls(View v, boolean save) {
|
||||
int[] parentLoc = new int[2];
|
||||
int[] targetLoc = new int[2];
|
||||
mGutsContainer.getLocationOnScreen(parentLoc);
|
||||
v.getLocationOnScreen(targetLoc);
|
||||
final int centerX = v.getWidth() / 2;
|
||||
final int centerY = v.getHeight() / 2;
|
||||
final int x = targetLoc[0] - parentLoc[0] + centerX;
|
||||
final int y = targetLoc[1] - parentLoc[1] + centerY;
|
||||
mGutsContainer.closeControls(x, y, save, false /* force */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGutsParent(NotificationGuts guts) {
|
||||
mGutsContainer = guts;
|
||||
|
||||
@@ -380,16 +380,8 @@ public class NotificationSnooze extends LinearLayout
|
||||
|
||||
private void undoSnooze(View v) {
|
||||
mSelectedOption = null;
|
||||
int[] parentLoc = new int[2];
|
||||
int[] targetLoc = new int[2];
|
||||
mGutsContainer.getLocationOnScreen(parentLoc);
|
||||
v.getLocationOnScreen(targetLoc);
|
||||
final int centerX = v.getWidth() / 2;
|
||||
final int centerY = v.getHeight() / 2;
|
||||
final int x = targetLoc[0] - parentLoc[0] + centerX;
|
||||
final int y = targetLoc[1] - parentLoc[1] + centerY;
|
||||
showSnoozeOptions(false);
|
||||
mGutsContainer.closeControls(x, y, false /* save */, false /* force */);
|
||||
mGutsContainer.closeControls(v, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -89,7 +89,7 @@ public class PartialConversationInfo extends LinearLayout implements
|
||||
|
||||
private OnClickListener mOnDone = v -> {
|
||||
mPressedApply = true;
|
||||
closeControls(v, true);
|
||||
mGutsContainer.closeControls(v, true);
|
||||
};
|
||||
|
||||
public PartialConversationInfo(Context context, AttributeSet attrs) {
|
||||
@@ -132,6 +132,7 @@ public class PartialConversationInfo extends LinearLayout implements
|
||||
|
||||
View done = findViewById(R.id.done);
|
||||
done.setOnClickListener(mOnDone);
|
||||
done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
|
||||
}
|
||||
|
||||
private void bindActions() {
|
||||
@@ -172,7 +173,7 @@ public class PartialConversationInfo extends LinearLayout implements
|
||||
mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
|
||||
mChannelEditorDialogController.setOnFinishListener(() -> {
|
||||
mPresentingChannelEditorDialog = false;
|
||||
closeControls(this, false);
|
||||
mGutsContainer.closeControls(this, false);
|
||||
});
|
||||
mChannelEditorDialogController.show();
|
||||
}
|
||||
@@ -317,25 +318,6 @@ public class PartialConversationInfo extends LinearLayout implements
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the controls and commits the updated importance values (indirectly).
|
||||
*
|
||||
* <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
|
||||
* user does not have the ability to undo the action anymore.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void closeControls(View v, boolean save) {
|
||||
int[] parentLoc = new int[2];
|
||||
int[] targetLoc = new int[2];
|
||||
mGutsContainer.getLocationOnScreen(parentLoc);
|
||||
v.getLocationOnScreen(targetLoc);
|
||||
final int centerX = v.getWidth() / 2;
|
||||
final int centerY = v.getHeight() / 2;
|
||||
final int x = targetLoc[0] - parentLoc[0] + centerX;
|
||||
final int y = targetLoc[1] - parentLoc[1] + centerY;
|
||||
mGutsContainer.closeControls(x, y, save, false /* force */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGutsParent(NotificationGuts guts) {
|
||||
mGutsContainer = guts;
|
||||
|
||||
@@ -144,7 +144,7 @@ public class AppOpsInfoTest extends SysuiTestCase {
|
||||
final View okButton = mAppOpsInfo.findViewById(R.id.ok);
|
||||
okButton.performClick();
|
||||
assertEquals(1, latch.getCount());
|
||||
verify(mGutsParent, times(1)).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
|
||||
verify(mGutsParent, times(1)).closeControls(eq(okButton), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -173,7 +173,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
doAnswer((Answer<Object>) invocation -> {
|
||||
mNotificationInfo.handleCloseControls(true, false);
|
||||
return null;
|
||||
}).when(mNotificationGuts).closeControls(anyInt(), anyInt(), eq(true), eq(false));
|
||||
}).when(mNotificationGuts).closeControls(any(View.class), eq(true));
|
||||
// Our view is never attached to a window so the View#post methods in NotificationInfo never
|
||||
// get called. Setting this will skip the post and do the action immediately.
|
||||
mNotificationInfo.mSkipPost = true;
|
||||
|
||||
Reference in New Issue
Block a user