Last big work on #1991910: Make swipes work with capacitive keys
This takes care of allowing us to cancel the back button. The
back button is a bear because it is strewn all over the place --
everywhere you can close something, there is some code looking
for the back button that now needs to deal with being canceled.
The main things changed are activity (of course), dialog,
input method, search dialog. There are some other misc places
in the framework (and some I missed here that I will get in a
second pass).
To facility all of this, the key dispatching APIs now provide
a lot more support for dealing with looking for cancelled keys,
and incidentally also provide an actual API for catching long
key presses. This also helped clean up the code in PhoneWindow
where it deals with all of the combinations of key pressed and
releases. (And also allows people to override
Activity.onKeyLongPress() to provide a different long press
action for a standard key like search.)
And while I was doing this, I reworked how we detect long
presses by having this be part of the key event delivered by
the window manager. This should greatly reduce (hopefully
outright eliminate) the problems with long presses being
mis-detected when an application is being slow.
Change-Id: Ia19066b8d588d573df3eee6d96e1c90fdc19f57d
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8c10091..be243a5 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1752,8 +1752,9 @@
*
* <p>If the focused view didn't want this event, this method is called.
*
- * <p>The default implementation handles KEYCODE_BACK to stop the activity
- * and go back, and other default key handling if configured with {@link #setDefaultKeyMode}.
+ * <p>The default implementation sets up state to call
+ * {@link #onKeyLongPress}, and does other default key handling
+ * if configured with {@link #setDefaultKeyMode}.
*
* @return Return <code>true</code> to prevent this event from being propagated
* further, or <code>false</code> to indicate that you have not handled
@@ -1762,16 +1763,19 @@
* @see android.view.KeyEvent
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
- finish();
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ event.startTracking();
return true;
}
if (mDefaultKeyMode == DEFAULT_KEYS_DISABLE) {
return false;
} else if (mDefaultKeyMode == DEFAULT_KEYS_SHORTCUT) {
- return getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL,
- keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE);
+ if (getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL,
+ keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE)) {
+ return true;
+ }
+ return false;
} else {
// Common code for DEFAULT_KEYS_DIALER & DEFAULT_KEYS_SEARCH_*
boolean clearSpannable = false;
@@ -1780,8 +1784,8 @@
clearSpannable = true;
handled = false;
} else {
- handled = TextKeyListener.getInstance().onKeyDown(null, mDefaultKeySsb,
- keyCode, event);
+ handled = TextKeyListener.getInstance().onKeyDown(
+ null, mDefaultKeySsb, keyCode, event);
if (handled && mDefaultKeySsb.length() > 0) {
// something useable has been typed - dispatch it now.
@@ -1813,11 +1817,23 @@
}
/**
+ * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+ * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
+ * the event).
+ */
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
* Called when a key was released and not handled by any of the views
* inside of the activity. So, for example, key presses while the cursor
* is inside a TextView will not trigger the event (unless it is a navigation
* to another object) because TextView handles its own key presses.
*
+ * <p>The default implementation handles KEYCODE_BACK to stop the activity
+ * and go back.
+ *
* @return Return <code>true</code> to prevent this event from being propagated
* further, or <code>false</code> to indicate that you have not handled
* this event and it should continue to be propagated.
@@ -1825,6 +1841,11 @@
* @see KeyEvent
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
+ && !event.isCanceled()) {
+ onBackPressed();
+ return true;
+ }
return false;
}
@@ -1838,6 +1859,15 @@
}
/**
+ * Called when the activity has detected the user's press of the back
+ * key. The default implementation simply finishes the current activity,
+ * but you can override this to do whatever you want.
+ */
+ public void onBackPressed() {
+ finish();
+ }
+
+ /**
* Called when a touch screen event was not handled by any of the views
* under it. This is most useful to process touch events that happen
* outside of your window bounds, where there is no view to receive it.
@@ -1909,9 +1939,10 @@
/**
* Called when the current {@link Window} of the activity gains or loses
* focus. This is the best indicator of whether this activity is visible
- * to the user.
+ * to the user. The default implementation clears the key tracking
+ * state, so should always be called.
*
- * <p>Note that this provides information what global focus state, which
+ * <p>Note that this provides information about global focus state, which
* is managed independently of activity lifecycles. As such, while focus
* changes will generally have some relation to lifecycle changes (an
* activity that is stopped will not generally get window focus), you
@@ -1988,7 +2019,8 @@
if (getWindow().superDispatchKeyEvent(event)) {
return true;
}
- return event.dispatch(this);
+ return event.dispatch(this, mDecor != null
+ ? mDecor.getKeyDispatcherState() : null, this);
}
/**