From ddca3ee3e86fbaa05c1528bd72afd955f0fb4ee6 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 23 Jul 2009 19:01:31 -0700 Subject: [PATCH] Add support for power keys, improve behavior of virtual keys. The platform now knows how to deal with a platform key, which at this point is "just like end call, but don't end a call." Also improve the handling of virtual keys, to allow for canceling when sliding off into the display and providing haptic feedback. Finally fixes a bug where the raw x and y in motion event were not always set which caused the status bar to not work. --- api/current.xml | 44 ++++++++++ .../android/view/HapticFeedbackConstants.java | 9 +++ core/java/android/view/KeyEvent.java | 27 +++++++ core/java/android/view/MotionEvent.java | 3 +- core/java/android/view/ViewRoot.java | 4 +- .../android/view/WindowManagerPolicy.java | 12 ++- .../java/com/android/server/InputDevice.java | 2 +- .../com/android/server/KeyInputQueue.java | 80 ++++++++++++++----- .../android/server/WindowManagerService.java | 15 +++- 9 files changed, 169 insertions(+), 27 deletions(-) diff --git a/api/current.xml b/api/current.xml index 9ae44e293928a..e76686f35fcbf 100644 --- a/api/current.xml +++ b/api/current.xml @@ -141896,6 +141896,17 @@ visibility="public" > + + + + + + + + not the Unicode character. diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 52f1a97c17f52..89b721d854357 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -288,9 +288,10 @@ public final class MotionEvent implements Parcelable { ev.mEventTimeNano = eventTimeNano; ev.mAction = action; ev.mMetaState = metaState; + ev.mRawX = inData[SAMPLE_X]; + ev.mRawY = inData[SAMPLE_Y]; ev.mXPrecision = xPrecision; ev.mYPrecision = yPrecision; - ev.mNumPointers = pointers; ev.mNumSamples = 1; diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index cacf7a2528c32..884950ffeacb2 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -1665,7 +1665,9 @@ public final class ViewRoot extends Handler implements ViewParent, if(Config.LOGV) { captureMotionLog("captureDispatchPointer", event); } - event.offsetLocation(0, mCurScrollY); + if (mCurScrollY != 0) { + event.offsetLocation(0, mCurScrollY); + } if (MEASURE_LATENCY) { lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano()); } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 13719323cb68b..f4e9900db8b8f 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -533,14 +533,15 @@ public interface WindowManagerPolicy { * @param win The window that currently has focus. This is where the key * event will normally go. * @param code Key code. - * @param metaKeys TODO + * @param metaKeys bit mask of meta keys that are held. * @param down Is this a key press (true) or release (false)? * @param repeatCount Number of times a key down has repeated. + * @param flags event's flags. * @return Returns true if the policy consumed the event and it should * not be further dispatched. */ public boolean interceptKeyTi(WindowState win, int code, - int metaKeys, boolean down, int repeatCount); + int metaKeys, boolean down, int repeatCount, int flags); /** * Called when layout of the windows is about to start. @@ -791,6 +792,13 @@ public interface WindowManagerPolicy { */ public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always); + /** + * A special function that is called from the very low-level input queue + * to provide feedback to the user. Currently only called for virtual + * keys. + */ + public void keyFeedbackFromInput(KeyEvent event); + /** * Called when we have stopped keeping the screen on because a window * requesting this is no longer visible. diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java index 3e98132cdb737..0ac5740cd0981 100644 --- a/services/java/com/android/server/InputDevice.java +++ b/services/java/com/android/server/InputDevice.java @@ -213,7 +213,7 @@ public class InputDevice { // We only consider the first pointer when computing the edge // flags, since they are global to the event. - if (action != MotionEvent.ACTION_DOWN) { + if (action == MotionEvent.ACTION_DOWN) { if (scaled[MotionEvent.SAMPLE_X] <= 0) { edgeFlags |= MotionEvent.EDGE_LEFT; } else if (scaled[MotionEvent.SAMPLE_X] >= dispW) { diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java index 17e9625409408..e0ee7ed6698ab 100644 --- a/services/java/com/android/server/KeyInputQueue.java +++ b/services/java/com/android/server/KeyInputQueue.java @@ -35,7 +35,6 @@ import android.view.WindowManagerPolicy; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; import java.io.BufferedReader; import java.io.File; @@ -55,6 +54,7 @@ public abstract class KeyInputQueue { final SparseArray mDevices = new SparseArray(); final ArrayList mVirtualKeys = new ArrayList(); + final HapticFeedbackCallback mHapticFeedbackCallback; int mGlobalMetaState = 0; boolean mHaveGlobalMetaState = false; @@ -107,6 +107,10 @@ public abstract class KeyInputQueue { int filterEvent(QueuedEvent ev); } + public interface HapticFeedbackCallback { + void virtualKeyFeedback(KeyEvent event); + } + static class QueuedEvent { InputDevice inputDevice; long whenNano; @@ -264,11 +268,13 @@ public abstract class KeyInputQueue { } } - KeyInputQueue(Context context) { + KeyInputQueue(Context context, HapticFeedbackCallback hapticFeedbackCallback) { if (MEASURE_LATENCY) { lt = new LatencyTimer(100, 1000); } + mHapticFeedbackCallback = hapticFeedbackCallback; + readVirtualKeys(); readExcludedDevices(); @@ -539,14 +545,40 @@ public abstract class KeyInputQueue { ms.mLastDown[0] = ms.mDown[0]; if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Generate key up for: " + vk.scancode); + KeyEvent event = newKeyEvent(di, + di.mKeyDownTime, curTime, false, + vk.lastKeycode, + 0, vk.scancode, + KeyEvent.FLAG_VIRTUAL_HARD_KEY); + mHapticFeedbackCallback.virtualKeyFeedback(event); addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, - newKeyEvent(di, di.mKeyDownTime, - curTime, false, - vk.lastKeycode, - 0, vk.scancode, 0)); + event); + } else if (isInsideDisplay(di)) { + // Whoops the pointer has moved into + // the display area! Cancel the + // virtual key and start a pointer + // motion. + mPressedVirtualKey = null; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, + "Cancel key up for: " + vk.scancode); + KeyEvent event = newKeyEvent(di, + di.mKeyDownTime, curTime, false, + vk.lastKeycode, + 0, vk.scancode, + KeyEvent.FLAG_CANCELED | + KeyEvent.FLAG_VIRTUAL_HARD_KEY); + mHapticFeedbackCallback.virtualKeyFeedback(event); + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_KEYBOARD, + event); + doMotion = true; + for (int i=InputDevice.MAX_POINTERS-1; i>=0; i--) { + ms.mLastDown[i] = false; + } } - } else if (ms.mDown[0] && !ms.mLastDown[0]) { + } + if (doMotion && ms.mDown[0] && !ms.mLastDown[0]) { vk = findSoftButton(di); if (vk != null) { doMotion = false; @@ -558,12 +590,15 @@ public abstract class KeyInputQueue { if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Generate key down for: " + vk.scancode + " (keycode=" + vk.lastKeycode + ")"); + KeyEvent event = newKeyEvent(di, + di.mKeyDownTime, curTime, true, + vk.lastKeycode, 0, + vk.scancode, + KeyEvent.FLAG_VIRTUAL_HARD_KEY); + mHapticFeedbackCallback.virtualKeyFeedback(event); addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, - newKeyEvent(di, di.mKeyDownTime, - curTime, true, - vk.lastKeycode, 0, - vk.scancode, 0)); + event); } } @@ -618,17 +653,12 @@ public abstract class KeyInputQueue { } }; - private VirtualKey findSoftButton(InputDevice dev) { - final int N = mVirtualKeys.size(); - if (N <= 0) { - return null; - } - + private boolean isInsideDisplay(InputDevice dev) { final InputDevice.AbsoluteInfo absx = dev.absX; final InputDevice.AbsoluteInfo absy = dev.absY; final InputDevice.MotionState absm = dev.mAbs; if (absx == null || absy == null || absm == null) { - return null; + return true; } if (absm.mCurData[MotionEvent.SAMPLE_X] >= absx.minValue @@ -639,9 +669,23 @@ public abstract class KeyInputQueue { + absm.mCurData[MotionEvent.SAMPLE_X] + "," + absm.mCurData[MotionEvent.SAMPLE_Y] + ") inside of display"); + return true; + } + + return false; + } + + private VirtualKey findSoftButton(InputDevice dev) { + final int N = mVirtualKeys.size(); + if (N <= 0) { return null; } + if (isInsideDisplay(dev)) { + return null; + } + + final InputDevice.MotionState absm = dev.mAbs; for (int i=0; i