diff options
| author | 2009-09-15 00:26:45 -0400 | |
|---|---|---|
| committer | 2009-09-15 00:26:45 -0400 | |
| commit | 678b4c20cb92ac2b86f13e52ea86d70301358680 (patch) | |
| tree | e65612797a92c39a749a0bf74e390214202be603 | |
| parent | 151921a62485f2141ad1316076c196ef00e1b421 (diff) | |
| parent | 8d37426c754e9822feaa8c6cc0b7c13e8523e217 (diff) | |
Merge change 25013 into eclair
* changes:
Various fixed for back key handling.
| -rw-r--r-- | core/java/android/app/Activity.java | 40 | ||||
| -rw-r--r-- | core/java/android/app/SearchDialog.java | 14 | ||||
| -rw-r--r-- | core/java/android/os/Build.java | 3 | ||||
| -rw-r--r-- | core/java/android/view/KeyEvent.java | 16 | ||||
| -rw-r--r-- | core/java/android/widget/AbsListView.java | 4 | ||||
| -rw-r--r-- | core/java/android/widget/AutoCompleteTextView.java | 25 | ||||
| -rw-r--r-- | core/java/android/widget/PopupWindow.java | 12 | ||||
| -rw-r--r-- | core/java/android/widget/ZoomButtonsController.java | 16 | ||||
| -rw-r--r-- | core/java/com/android/internal/view/menu/MenuDialogHelper.java | 33 |
9 files changed, 115 insertions, 48 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index be243a58599d..545db178658a 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -34,6 +34,7 @@ import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -1752,8 +1753,16 @@ public class Activity extends ContextThemeWrapper * * <p>If the focused view didn't want this event, this method is called. * - * <p>The default implementation sets up state to call - * {@link #onKeyLongPress}, and does other default key handling + * <p>The default implementation takes care of {@link KeyEvent#KEYCODE_BACK} + * by calling {@link #onBackPressed()}, though the behavior varies based + * on the application compatibility mode: for + * {@link android.os.Build.VERSION_CODES#ECLAIR} or later applications, + * it will set up the dispatch to call {@link #onKeyUp} where the action + * will be performed; for earlier applications, it will perform the + * action immediately in on-down, as those versions of the platform + * behaved. + * + * <p>Other additional default key handling may be performed * if configured with {@link #setDefaultKeyMode}. * * @return Return <code>true</code> to prevent this event from being propagated @@ -1764,7 +1773,12 @@ public class Activity extends ContextThemeWrapper */ public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { - event.startTracking(); + if (getApplicationInfo().targetSdkVersion + >= Build.VERSION_CODES.ECLAIR) { + event.startTracking(); + } else { + onBackPressed(); + } return true; } @@ -1841,10 +1855,13 @@ public class Activity extends ContextThemeWrapper * @see KeyEvent */ public boolean onKeyUp(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() - && !event.isCanceled()) { - onBackPressed(); - return true; + if (getApplicationInfo().targetSdkVersion + >= Build.VERSION_CODES.ECLAIR) { + if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() + && !event.isCanceled()) { + onBackPressed(); + return true; + } } return false; } @@ -2016,11 +2033,14 @@ public class Activity extends ContextThemeWrapper */ public boolean dispatchKeyEvent(KeyEvent event) { onUserInteraction(); - if (getWindow().superDispatchKeyEvent(event)) { + Window win = getWindow(); + if (win.superDispatchKeyEvent(event)) { return true; } - return event.dispatch(this, mDecor != null - ? mDecor.getKeyDispatcherState() : null, this); + View decor = mDecor; + if (decor == null) decor = win.getDecorView(); + return event.dispatch(this, decor != null + ? decor.getKeyDispatcherState() : null, this); } /** diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 62dc9b23d023..75a90c449d02 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -51,7 +51,6 @@ import android.util.Log; import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.KeyEvent; -import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -1684,7 +1683,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS public static class SearchAutoComplete extends AutoCompleteTextView { private int mThreshold; - private int mLastKeyDown; private SearchDialog mSearchDialog; public SearchAutoComplete(Context context) { @@ -1765,26 +1763,26 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS */ @Override public boolean onKeyPreIme(int keyCode, KeyEvent event) { - mLastKeyDown = keyCode; if (mSearchDialog.mSearchable == null) { return false; } if (keyCode == KeyEvent.KEYCODE_BACK) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - // We releae the back key, might we want to do + // We release the back key, might we want to do // something before the IME? if (mSearchDialog.backToPreviousComponent(false)) { + getKeyDispatcherState().startTracking(event, this); return true; } if (isInputMethodNotNeeded() || (isEmpty() && getDropDownChildCount() >= getAdapterCount())) { + getKeyDispatcherState().startTracking(event, this); return true; } - mLastKeyDown = 0; return false; // will dismiss soft keyboard if necessary } else if (event.getAction() == KeyEvent.ACTION_UP - && mLastKeyDown == keyCode && !event.isCanceled()) { + && event.isTracking() && !event.isCanceled()) { if (mSearchDialog.backToPreviousComponent(true)) { return true; } @@ -1815,8 +1813,10 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS protected boolean handleBackKey(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { - if (event.getAction() == KeyEvent.ACTION_DOWN) { + if (event.getAction() == KeyEvent.ACTION_DOWN + && event.getRepeatCount() == 0) { // Consume the event, to get an up at which point we execute. + event.startTracking(); return true; } if (event.getAction() == KeyEvent.ACTION_UP && event.isTracking() diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 6c2a27a7205e..b4778fee7788 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -143,6 +143,9 @@ public class Build { * Service.onStartCommand} function will return the new * {@link android.app.Service#START_STICKY} behavior instead of the * old compatibility {@link android.app.Service#START_STICKY_COMPATIBILITY}. + * <li> The {@link android.app.Activity} class will now execute back + * key presses on the key up instead of key down, to be able to detect + * canceled presses from virtual keys. * </ul> */ public static final int ECLAIR = CUR_DEVELOPMENT; diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index daa4b295a0f4..d4f978756f4d 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -18,6 +18,7 @@ package android.view; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; import android.util.SparseIntArray; import android.view.KeyCharacterMap; import android.view.KeyCharacterMap.KeyData; @@ -319,6 +320,9 @@ public class KeyEvent implements Parcelable { return KeyCharacterMap.getDeadChar(accent, c); } + static final boolean DEBUG = false; + static final String TAG = "KeyEvent"; + private int mMetaState; private int mAction; private int mKeyCode; @@ -1028,13 +1032,17 @@ public class KeyEvent implements Parcelable { switch (mAction) { case ACTION_DOWN: { mFlags &= ~FLAG_START_TRACKING; + if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state + + ": " + this); boolean res = receiver.onKeyDown(mKeyCode, this); if (state != null) { if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) { + if (DEBUG) Log.v(TAG, " Start tracking!"); state.startTracking(this, target); } else if (isLongPress() && state.isTracking(this)) { try { if (receiver.onKeyLongPress(mKeyCode, this)) { + if (DEBUG) Log.v(TAG, " Clear from long press!"); state.performedLongPress(this); res = true; } @@ -1045,6 +1053,8 @@ public class KeyEvent implements Parcelable { return res; } case ACTION_UP: + if (DEBUG) Log.v(TAG, "Key up to " + target + " in " + state + + ": " + this); if (state != null) { state.handleUpEvent(this); } @@ -1085,6 +1095,7 @@ public class KeyEvent implements Parcelable { * Reset back to initial state. */ public void reset() { + if (DEBUG) Log.v(TAG, "Reset: " + this); mDownKeyCode = 0; mDownTarget = null; mActiveLongPresses.clear(); @@ -1095,6 +1106,7 @@ public class KeyEvent implements Parcelable { */ public void reset(Object target) { if (mDownTarget == target) { + if (DEBUG) Log.v(TAG, "Reset in " + target + ": " + this); mDownKeyCode = 0; mDownTarget = null; } @@ -1115,6 +1127,7 @@ public class KeyEvent implements Parcelable { throw new IllegalArgumentException( "Can only start tracking on a down event"); } + if (DEBUG) Log.v(TAG, "Start trackingt in " + target + ": " + this); mDownKeyCode = event.getKeyCode(); mDownTarget = target; } @@ -1145,12 +1158,15 @@ public class KeyEvent implements Parcelable { */ public void handleUpEvent(KeyEvent event) { final int keyCode = event.getKeyCode(); + if (DEBUG) Log.v(TAG, "Handle key up " + event + ": " + this); int index = mActiveLongPresses.indexOfKey(keyCode); if (index >= 0) { + if (DEBUG) Log.v(TAG, " Index: " + index); event.mFlags |= FLAG_CANCELED | FLAG_CANCELED_LONG_PRESS; mActiveLongPresses.removeAt(index); } if (mDownKeyCode == keyCode) { + if (DEBUG) Log.v(TAG, " Tracking!"); event.mFlags |= FLAG_TRACKING; mDownKeyCode = 0; mDownTarget = null; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index bed2a7aa275e..b242b583ae9a 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2946,7 +2946,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te break; case KeyEvent.KEYCODE_BACK: if (mFiltered && mPopup != null && mPopup.isShowing()) { - if (event.getAction() == KeyEvent.ACTION_DOWN) { + if (event.getAction() == KeyEvent.ACTION_DOWN + && event.getRepeatCount() == 0) { + getKeyDispatcherState().startTracking(event, this); handled = true; } else if (event.getAction() == KeyEvent.ACTION_UP && event.isTracking() && !event.isCanceled()) { diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 7891d3cf177e..4566c4cfa1ae 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -132,8 +132,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe private AutoCompleteTextView.PassThroughClickListener mPassThroughClickListener; - private int mDownKeyCode; - public AutoCompleteTextView(Context context) { this(context, null); } @@ -605,19 +603,18 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe @Override public boolean onKeyPreIme(int keyCode, KeyEvent event) { - if (event.getAction() == KeyEvent.ACTION_DOWN - && event.getRepeatCount() == 0) { - mDownKeyCode = keyCode; - } - if (isPopupShowing()) { + if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing() + && !mDropDownAlwaysVisible) { // 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 (keyCode == KeyEvent.KEYCODE_BACK && !mDropDownAlwaysVisible) { - if (event.getAction() == KeyEvent.ACTION_UP - && mDownKeyCode == keyCode && !event.isCanceled()) { - dismissDropDown(); - return true; - } + if (event.getAction() == KeyEvent.ACTION_DOWN + && event.getRepeatCount() == 0) { + getKeyDispatcherState().startTracking(event, this); + return true; + } else if (event.getAction() == KeyEvent.ACTION_UP + && event.isTracking() && !event.isCanceled()) { + dismissDropDown(); + return true; } } return super.onKeyPreIme(keyCode, event); @@ -1026,7 +1023,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); - mDownKeyCode = 0; performValidation(); if (!hasWindowFocus && !mDropDownAlwaysVisible) { dismissDropDown(); @@ -1036,7 +1032,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(focused, direction, previouslyFocusedRect); - mDownKeyCode = 0; performValidation(); if (!focused && !mDropDownAlwaysVisible) { dismissDropDown(); diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 548dee95d0af..d86b67423a3e 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1323,8 +1323,16 @@ public class PopupWindow { @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - dismiss(); - return true; + if (event.getAction() == KeyEvent.ACTION_DOWN + && event.getRepeatCount() == 0) { + getKeyDispatcherState().startTracking(event, this); + return true; + } else if (event.getAction() == KeyEvent.ACTION_UP + && event.isTracking() && !event.isCanceled()) { + dismiss(); + return true; + } + return super.dispatchKeyEvent(event); } else { return super.dispatchKeyEvent(event); } diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java index a41e2e3dfd0d..760b8ffea8b5 100644 --- a/core/java/android/widget/ZoomButtonsController.java +++ b/core/java/android/widget/ZoomButtonsController.java @@ -476,7 +476,21 @@ public class ZoomButtonsController implements View.OnTouchListener { if (isInterestingKey(keyCode)) { if (keyCode == KeyEvent.KEYCODE_BACK) { - setVisible(false); + if (event.getAction() == KeyEvent.ACTION_DOWN + && event.getRepeatCount() == 0) { + if (mOwnerView != null) { + KeyEvent.DispatcherState ds = mOwnerView.getKeyDispatcherState(); + if (ds != null) { + ds.startTracking(event, this); + } + } + return true; + } else if (event.getAction() == KeyEvent.ACTION_UP + && event.isTracking() && !event.isCanceled()) { + setVisible(false); + return true; + } + } else { dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT); } diff --git a/core/java/com/android/internal/view/menu/MenuDialogHelper.java b/core/java/com/android/internal/view/menu/MenuDialogHelper.java index 88f7b2fe81b6..70f040a15b98 100644 --- a/core/java/com/android/internal/view/menu/MenuDialogHelper.java +++ b/core/java/com/android/internal/view/menu/MenuDialogHelper.java @@ -22,6 +22,7 @@ import android.content.DialogInterface; import android.os.IBinder; import android.view.KeyEvent; import android.view.View; +import android.view.Window; import android.view.WindowManager; import android.widget.ListAdapter; @@ -86,18 +87,26 @@ public class MenuDialogHelper implements DialogInterface.OnKeyListener, DialogIn } public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { - /* - * Close menu on key down (more responsive, and there's no way to cancel - * a key press so no point having it on key up. Note: This is also - * needed because when a top-level menu item that shows a submenu is - * invoked by chording, this onKey method will be called with the menu - * up event. - */ - if (event.getAction() == KeyEvent.ACTION_DOWN && (keyCode == KeyEvent.KEYCODE_MENU) - || (keyCode == KeyEvent.KEYCODE_BACK)) { - mMenu.close(true); - dialog.dismiss(); - return true; + if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_BACK) { + if (event.getAction() == KeyEvent.ACTION_DOWN + && event.getRepeatCount() == 0) { + Window win = mDialog.getWindow(); + if (win != null) { + View decor = win.getDecorView(); + if (decor != null) { + KeyEvent.DispatcherState ds = decor.getKeyDispatcherState(); + if (ds != null) { + ds.startTracking(event, this); + return true; + } + } + } + } else if (event.getAction() == KeyEvent.ACTION_UP + && event.isTracking() && !event.isCanceled()) { + mMenu.close(true); + dialog.dismiss(); + return true; + } } // Menu shortcut matching |