From 2d32eb61db0bd7de6bce09dd1549271d5479f8dc Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Tue, 6 Jul 2021 16:10:01 +0900 Subject: [PATCH] Clear popups on KEYCODE_ESCAPE as well as KEYCODE_BACK On desktop devices, users expect that the Escape key will clear various popup windows in the same way as the Back button will on mobile devices. This adds support for Escape to places the Back button currently clears ListPopupWindow, AutoCompleteTextView, PopupWindow, and ScrollView. Bug: 174164194 Test: Open popups of each type on a device with a physical keyboard and press escape. Change-Id: I32e65ce4317db7de043c8a050d87126b0f38acce --- core/java/android/widget/AbsListView.java | 57 ++++++++++--------- .../android/widget/AutoCompleteTextView.java | 4 +- core/java/android/widget/ListPopupWindow.java | 3 +- core/java/android/widget/PopupWindow.java | 3 +- core/java/android/widget/ScrollView.java | 3 +- 5 files changed, 37 insertions(+), 33 deletions(-) diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 721260e8cafe6..87f4a15ded15f 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -5938,36 +5938,37 @@ public abstract class AbsListView extends AdapterView implements Te boolean handled = false; boolean okToSend = true; switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_RIGHT: - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_ENTER: - case KeyEvent.KEYCODE_NUMPAD_ENTER: - okToSend = false; - break; - case KeyEvent.KEYCODE_BACK: - if (mFiltered && mPopup != null && mPopup.isShowing()) { - if (event.getAction() == KeyEvent.ACTION_DOWN - && event.getRepeatCount() == 0) { - KeyEvent.DispatcherState state = getKeyDispatcherState(); - if (state != null) { - state.startTracking(event, this); + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: + case KeyEvent.KEYCODE_DPAD_CENTER: + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_NUMPAD_ENTER: + okToSend = false; + break; + case KeyEvent.KEYCODE_BACK: + case KeyEvent.KEYCODE_ESCAPE: + if (mFiltered && mPopup != null && mPopup.isShowing()) { + if (event.getAction() == KeyEvent.ACTION_DOWN + && event.getRepeatCount() == 0) { + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.startTracking(event, this); + } + handled = true; + } else if (event.getAction() == KeyEvent.ACTION_UP + && event.isTracking() && !event.isCanceled()) { + handled = true; + mTextFilter.setText(""); } - handled = true; - } else if (event.getAction() == KeyEvent.ACTION_UP - && event.isTracking() && !event.isCanceled()) { - handled = true; - mTextFilter.setText(""); } - } - okToSend = false; - break; - case KeyEvent.KEYCODE_SPACE: - // Only send spaces once we are filtered - okToSend = mFiltered; - break; + okToSend = false; + break; + case KeyEvent.KEYCODE_SPACE: + // Only send spaces once we are filtered + okToSend = mFiltered; + break; } if (okToSend) { diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index ce29eea9fd0cd..cfae95dc414f3 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -788,8 +788,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe @Override public boolean onKeyPreIme(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing() - && !mPopup.isDropDownAlwaysVisible()) { + if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) + && isPopupShowing() && !mPopup.isDropDownAlwaysVisible()) { // special case for the back key, we do not even try to send it // to the drop down list but instead, consume it immediately if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index 6232480f86203..7766f1a0b350d 100755 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -1071,7 +1071,8 @@ public class ListPopupWindow implements ShowableListMenu { * @see #setModal(boolean) */ public boolean onKeyPreIme(int keyCode, @NonNull KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK && isShowing()) { + if ((keyCode == KeyEvent.KEYCODE_BACK + || keyCode == KeyEvent.KEYCODE_ESCAPE) && isShowing()) { // special case for the back key, we do not even try to send it // to the drop down list but instead, consume it immediately final View anchorView = mDropDownAnchorView; diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index e7e148abb95a0..decd9a547edb6 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -2521,7 +2521,8 @@ public class PopupWindow { @Override public boolean dispatchKeyEvent(KeyEvent event) { - if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { + if (event.getKeyCode() == KeyEvent.KEYCODE_BACK + || event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { if (getKeyDispatcherState() == null) { return super.dispatchKeyEvent(event); } diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 693b13bbf224e..3ad7b46d503a5 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -509,7 +509,8 @@ public class ScrollView extends FrameLayout { mTempRect.setEmpty(); if (!canScroll()) { - if (isFocused() && event.getKeyCode() != KeyEvent.KEYCODE_BACK) { + if (isFocused() && event.getKeyCode() != KeyEvent.KEYCODE_BACK + && event.getKeyCode() != KeyEvent.KEYCODE_ESCAPE) { View currentFocused = findFocus(); if (currentFocused == this) currentFocused = null; View nextFocused = FocusFinder.getInstance().findNextFocus(this,