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/api/current.xml b/api/current.xml
index 9ae44e2..e76686f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -141896,6 +141896,17 @@
  visibility="public"
 >
 </field>
+<field name="VIRTUAL_KEY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="InflateException"
  extends="java.lang.RuntimeException"
@@ -142736,6 +142747,17 @@
  visibility="public"
 >
 </method>
+<method name="isCanceled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isModifierKey"
  return="boolean"
  abstract="false"
@@ -142851,6 +142873,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_CANCELED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_EDITOR_ACTION"
  type="int"
  transient="false"
@@ -142895,6 +142928,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_VIRTUAL_HARD_KEY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_WOKE_HERE"
  type="int"
  transient="false"
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index 841066c..f936f65 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -24,9 +24,18 @@
 
     private HapticFeedbackConstants() {}
 
+    /**
+     * The user has performed a long press on an object that is resulting
+     * in an action being performed.
+     */
     public static final int LONG_PRESS = 0;
     
     /**
+     * The user has pressed on a virtual on-screen key.
+     */
+    public static final int VIRTUAL_KEY = 1;
+    
+    /**
      * Flag for {@link View#performHapticFeedback(int, int)
      * View.performHapticFeedback(int, int)}: Ignore the setting in the
      * view for whether to perform haptic feedback, do it always.
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 6349288..f9b16fc 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -258,6 +258,25 @@
     public static final int FLAG_EDITOR_ACTION = 0x10;
     
     /**
+     * When associated with up key events, this indicates that the key press
+     * has been canceled.  Typically this is used with virtual touch screen
+     * keys, where the user can slide from the virtual key area on to the
+     * display: in that case, the application will receive a canceled up
+     * event and should not perform the action normally associated with the
+     * key.  Note that for this to work, the application can not perform an
+     * action for a key until it receives an up or the long press timeout has
+     * expired. 
+     */
+    public static final int FLAG_CANCELED = 0x20;
+    
+    /**
+     * This key event was generated by a virtual (on-screen) hard key area.
+     * Typically this is an area of the touchscreen, outside of the regular
+     * display, dedicated to "hardware" buttons.
+     */
+    public static final int FLAG_VIRTUAL_HARD_KEY = 0x40;
+    
+    /**
      * Returns the maximum keycode.
      */
     public static int getMaxKeyCode() {
@@ -694,6 +713,14 @@
     }
 
     /**
+     * For {@link #ACTION_UP} events, indicates that the event has been
+     * canceled as per {@link #FLAG_CANCELED}.
+     */
+    public final boolean isCanceled() {
+        return (mFlags&FLAG_CANCELED) != 0;
+    }
+    
+    /**
      * Retrieve the key code of the key event.  This is the physical key that
      * was pressed, <em>not</em> the Unicode character.
      * 
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 52f1a97..89b721d 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -288,9 +288,10 @@
         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 cacf7a2..884950f 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1665,7 +1665,9 @@
                     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 1371932..f4e9900 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -533,14 +533,15 @@
      * @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.
@@ -792,6 +793,13 @@
     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 3e98132..0ac5740 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -213,7 +213,7 @@
             
             // 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 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);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index e1804a7..78ca831 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -125,7 +125,8 @@
 import java.util.List;
 
 /** {@hide} */
-public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor {
+public class WindowManagerService extends IWindowManager.Stub
+        implements Watchdog.Monitor, KeyInputQueue.HapticFeedbackCallback {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_FOCUS = false;
@@ -4686,7 +4687,8 @@
                                     callingPid, callingUid)
                                     == PackageManager.PERMISSION_GRANTED) {
                         mPolicy.interceptKeyTi(null, keycode,
-                                nextKey.getMetaState(), down, repeatCount);
+                                nextKey.getMetaState(), down, repeatCount,
+                                nextKey.getFlags());
                     }
                     Log.w(TAG, "Event timeout during app switch: dropping "
                             + nextKey);
@@ -4709,7 +4711,8 @@
                                 callingPid, callingUid)
                                 == PackageManager.PERMISSION_GRANTED) {
                     if (mPolicy.interceptKeyTi(focus,
-                            keycode, nextKey.getMetaState(), down, repeatCount)) {
+                            keycode, nextKey.getMetaState(), down, repeatCount, 
+                            nextKey.getFlags())) {
                         return CONSUMED_EVENT_TOKEN;
                     }
                 }
@@ -5129,7 +5132,7 @@
         PowerManager.WakeLock mHoldingScreen;
 
         KeyQ() {
-            super(mContext);
+            super(mContext, WindowManagerService.this);
             PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
             mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                     "KEEP_SCREEN_ON_FLAG");
@@ -9202,6 +9205,10 @@
         synchronized (mKeyWaiter) { }
     }
 
+    public void virtualKeyFeedback(KeyEvent event) {
+        mPolicy.keyFeedbackFromInput(event);
+    }
+    
     /**
      * DimAnimator class that controls the dim animation. This holds the surface and
      * all state used for dim animation.