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