diff options
author | Jeff Brown <jeffbrown@google.com> | 2011-12-07 16:36:01 -0800 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2011-12-07 21:37:16 -0800 |
commit | 68b909d8acd92343fa0b1dff2f77fcd9d9991f9f (patch) | |
tree | 73df34f562dafe3807615c773530dedce3d83ae0 /policy | |
parent | eb3e4b98a45722d5d1ea73e45d86c119d678bb05 (diff) | |
download | frameworks_base-68b909d8acd92343fa0b1dff2f77fcd9d9991f9f.zip frameworks_base-68b909d8acd92343fa0b1dff2f77fcd9d9991f9f.tar.gz frameworks_base-68b909d8acd92343fa0b1dff2f77fcd9d9991f9f.tar.bz2 |
Fix system hotkey handling.
Fixed a problem where the key up for the ALT or META key was not
delivered to the task switcher dialog because it was deemed
to be inconsistent with the window's observed state. Consequently
the dialog would not be dismissed when the key was released.
Moved global hotkey handling for META+* shortcuts and ALT/META-TAB
into the window manager policy's interceptKeyBeforeDispatching
method. This change prevents applications from hijacking these
keys.
The original idea was that these shortcuts would be handled only
if the application did not handle them itself. That way certain
applications, such as remote desktop tools, could deliberately
override some of these less important system shortcuts.
Unfortunately, that does make the behavior inconsistent across
applications. What's more, bugs in the onKeyDown handler of
applications can cause the shortcuts to not work at all, for
no good reason.
Perhaps we can add an opt-in feature later to enable specific
applications to repurpose these keys when it makes sense.
Bug: 5720358
Change-Id: I22bf17606d12dbea6549c60d20763e6608576cf7
Diffstat (limited to 'policy')
3 files changed, 102 insertions, 78 deletions
diff --git a/policy/src/com/android/internal/policy/impl/IconUtilities.java b/policy/src/com/android/internal/policy/impl/IconUtilities.java index 4564f90..e997355 100644 --- a/policy/src/com/android/internal/policy/impl/IconUtilities.java +++ b/policy/src/com/android/internal/policy/impl/IconUtilities.java @@ -38,6 +38,8 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.util.DisplayMetrics; import android.util.Log; +import android.util.TypedValue; +import android.view.ContextThemeWrapper; import android.content.res.Resources; import android.content.Context; @@ -74,9 +76,13 @@ final class IconUtilities { mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2); mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL)); - mGlowColorPressedPaint.setColor(0xffffc300); + + TypedValue value = new TypedValue(); + mGlowColorPressedPaint.setColor(context.getTheme().resolveAttribute( + android.R.attr.colorPressedHighlight, value, true) ? value.data : 0xffffc300); mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); - mGlowColorFocusedPaint.setColor(0xffff8e00); + mGlowColorFocusedPaint.setColor(context.getTheme().resolveAttribute( + android.R.attr.colorFocusedHighlight, value, true) ? value.data : 0xffff8e00); mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); ColorMatrix cm = new ColorMatrix(); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 22f9880..f3ce6d0 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -298,9 +298,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { GlobalActions mGlobalActions; volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread boolean mPendingPowerKeyUpCanceled; - RecentApplicationsDialog mRecentAppsDialog; Handler mHandler; + static final int RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS = 0; + static final int RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW = 1; + static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 2; + + RecentApplicationsDialog mRecentAppsDialog; + int mRecentAppsDialogHeldModifiers; + private static final int LID_ABSENT = -1; private static final int LID_CLOSED = 0; private static final int LID_OPEN = 1; @@ -693,7 +699,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) { - showOrHideRecentAppsDialog(0, true /*dismissIfShown*/); + showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS); } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) { try { mStatusBarService.toggleRecentApps(); @@ -704,10 +710,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** - * Create (if necessary) and launch the recent apps dialog, or hide it if it is - * already shown. + * Create (if necessary) and show or dismiss the recent apps dialog according + * according to the requested behavior. */ - void showOrHideRecentAppsDialog(final int heldModifiers, final boolean dismissIfShown) { + void showOrHideRecentAppsDialog(final int behavior) { mHandler.post(new Runnable() { @Override public void run() { @@ -715,12 +721,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { mRecentAppsDialog = new RecentApplicationsDialog(mContext); } if (mRecentAppsDialog.isShowing()) { - if (dismissIfShown) { - mRecentAppsDialog.dismiss(); + switch (behavior) { + case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS: + mRecentAppsDialog.dismiss(); + break; + case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH: + mRecentAppsDialog.dismissAndSwitch(); + break; + case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW: + default: + break; } } else { - mRecentAppsDialog.setHeldModifiers(heldModifiers); - mRecentAppsDialog.show(); + switch (behavior) { + case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS: + mRecentAppsDialog.show(); + break; + case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW: + try { + mWindowManager.setInTouchMode(false); + } catch (RemoteException e) { + } + mRecentAppsDialog.show(); + break; + case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH: + default: + break; + } } } }); @@ -1598,7 +1625,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) { if (down && repeatCount == 0) { - showOrHideRecentAppsDialog(0, true /*dismissIfShown*/); + showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS); } return -1; } @@ -1634,6 +1661,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + // Invoke shortcuts using Meta. + if (down && repeatCount == 0 + && (metaState & KeyEvent.META_META_ON) != 0) { + final KeyCharacterMap kcm = event.getKeyCharacterMap(); + Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, + metaState & ~(KeyEvent.META_META_ON + | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON)); + if (shortcutIntent != null) { + shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(shortcutIntent); + } catch (ActivityNotFoundException ex) { + Slog.w(TAG, "Dropping shortcut key combination because " + + "the activity to which it is registered was not found: " + + "META+" + KeyEvent.keyCodeToString(keyCode), ex); + } + return -1; + } + } + // Handle application launch keys. if (down && repeatCount == 0) { String category = sApplicationLaunchKeyCategories.get(keyCode); @@ -1647,9 +1694,29 @@ public class PhoneWindowManager implements WindowManagerPolicy { + "the activity to which it is registered was not found: " + "keyCode=" + keyCode + ", category=" + category, ex); } + return -1; } } + // Display task switcher for ALT-TAB or Meta-TAB. + if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) { + if (mRecentAppsDialogHeldModifiers == 0) { + final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK; + if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON) + || KeyEvent.metaStateHasModifiers( + shiftlessModifiers, KeyEvent.META_META_ON)) { + mRecentAppsDialogHeldModifiers = shiftlessModifiers; + showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW); + return -1; + } + } + } else if (!down && mRecentAppsDialogHeldModifiers != 0 + && (metaState & mRecentAppsDialogHeldModifiers) == 0) { + mRecentAppsDialogHeldModifiers = 0; + showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH); + } + + // Let the application handle the key. return 0; } @@ -1671,39 +1738,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { final KeyCharacterMap kcm = event.getKeyCharacterMap(); final int keyCode = event.getKeyCode(); final int metaState = event.getMetaState(); - final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN - && event.getRepeatCount() == 0; - - if (initialDown) { - // Invoke shortcuts using Meta as a fallback. - if ((metaState & KeyEvent.META_META_ON) != 0) { - Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, - metaState & ~(KeyEvent.META_META_ON - | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON)); - if (shortcutIntent != null) { - shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - mContext.startActivity(shortcutIntent); - } catch (ActivityNotFoundException ex) { - Slog.w(TAG, "Dropping shortcut key combination because " - + "the activity to which it is registered was not found: " - + "META+" + KeyEvent.keyCodeToString(keyCode), ex); - } - return null; - } - } - - // Display task switcher for ALT-TAB or Meta-TAB. - if (keyCode == KeyEvent.KEYCODE_TAB) { - final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK; - if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON) - || KeyEvent.metaStateHasModifiers( - shiftlessModifiers, KeyEvent.META_META_ON)) { - showOrHideRecentAppsDialog(shiftlessModifiers, false /*dismissIfShown*/); - return null; - } - } - } // Check for fallback actions specified by the key character map. if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) { diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java index aa00fbd..b9903dd 100644 --- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -71,8 +71,6 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener } }; - private int mHeldModifiers; - public RecentApplicationsDialog(Context context) { super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications); @@ -124,17 +122,6 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener } } - /** - * Sets the modifier keys that are being held to keep the dialog open, or 0 if none. - * Used to make the recent apps dialog automatically dismiss itself when the modifiers - * all go up. - * @param heldModifiers The held key modifiers, such as {@link KeyEvent#META_ALT_ON}. - * Should exclude shift. - */ - public void setHeldModifiers(int heldModifiers) { - mHeldModifiers = heldModifiers; - } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_TAB) { @@ -174,30 +161,27 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener return super.onKeyDown(keyCode, event); } - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (mHeldModifiers != 0 && (event.getModifiers() & mHeldModifiers) == 0) { - final int numIcons = mIcons.length; - RecentTag tag = null; - for (int i = 0; i < numIcons; i++) { - if (mIcons[i].getVisibility() != View.VISIBLE) { + /** + * Dismiss the dialog and switch to the selected application. + */ + public void dismissAndSwitch() { + final int numIcons = mIcons.length; + RecentTag tag = null; + for (int i = 0; i < numIcons; i++) { + if (mIcons[i].getVisibility() != View.VISIBLE) { + break; + } + if (i == 0 || mIcons[i].hasFocus()) { + tag = (RecentTag) mIcons[i].getTag(); + if (mIcons[i].hasFocus()) { break; } - if (i == 0 || mIcons[i].hasFocus()) { - tag = (RecentTag) mIcons[i].getTag(); - if (mIcons[i].hasFocus()) { - break; - } - } - } - if (tag != null) { - switchTo(tag); } - dismiss(); - return true; } - - return super.onKeyUp(keyCode, event); + if (tag != null) { + switchTo(tag); + } + dismiss(); } /** |