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.
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 17e9625..e0ee7ed 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -35,7 +35,6 @@
 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 @@
 
     final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
     final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
+    final HapticFeedbackCallback mHapticFeedbackCallback;
     
     int mGlobalMetaState = 0;
     boolean mHaveGlobalMetaState = false;
@@ -107,6 +107,10 @@
         int filterEvent(QueuedEvent ev);
     }
     
+    public interface HapticFeedbackCallback {
+        void virtualKeyFeedback(KeyEvent event);
+    }
+    
     static class QueuedEvent {
         InputDevice inputDevice;
         long whenNano;
@@ -264,11 +268,13 @@
         }
     }
 
-    KeyInputQueue(Context context) {
+    KeyInputQueue(Context context, HapticFeedbackCallback  hapticFeedbackCallback) {
         if (MEASURE_LATENCY) {
             lt = new LatencyTimer(100, 1000);
         }
 
+        mHapticFeedbackCallback = hapticFeedbackCallback;
+        
         readVirtualKeys();
         readExcludedDevices();
         
@@ -539,14 +545,40 @@
                                             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 @@
                                             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 @@
         }
     };
 
-    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 @@
                     + 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<N; i++) {
             VirtualKey sb = mVirtualKeys.get(i);
             sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);