Merge "Add missing copyright headers to a couple of files" into honeycomb-mr1
diff --git a/api/current.xml b/api/current.xml
index 2517c23..5e8a077 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -28850,7 +28850,7 @@
deprecated="not deprecated"
visibility="public"
>
-<method name="completedDownload"
+<method name="addCompletedDownload"
return="long"
abstract="false"
native="false"
@@ -218115,6 +218115,28 @@
visibility="public"
>
</field>
+<field name="AXIS_BRAKE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="23"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GAS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="22"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="AXIS_GENERIC_1"
type="int"
transient="false"
@@ -218368,6 +218390,17 @@
visibility="public"
>
</field>
+<field name="AXIS_RUDDER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="20"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="AXIS_RX"
type="int"
transient="false"
@@ -218412,6 +218445,17 @@
visibility="public"
>
</field>
+<field name="AXIS_THROTTLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="19"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="AXIS_TOOL_MAJOR"
type="int"
transient="false"
@@ -218467,6 +218511,17 @@
visibility="public"
>
</field>
+<field name="AXIS_WHEEL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="21"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="AXIS_X"
type="int"
transient="false"
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index d04fa57..b88e5cf 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -376,8 +376,8 @@
/**
* This download shows in the notifications after completion ONLY.
* It is usuable only with
- * {@link DownloadManager#completedDownload(String, String, boolean, String,
- * String, long, boolean)}.
+ * {@link DownloadManager#addCompletedDownload(String, String,
+ * boolean, String, String, long, boolean)}.
*/
public static final int VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION = 3;
@@ -1111,7 +1111,7 @@
* @return an ID for the download entry added to the downloads app, unique across the system
* This ID is used to make future calls related to this download.
*/
- public long completedDownload(String title, String description,
+ public long addCompletedDownload(String title, String description,
boolean isMediaScannerScannable, String mimeType, String path, long length,
boolean showNotification) {
// make sure the input args are non-null/non-zero
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 262eb81..aeff31f 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -40,13 +40,6 @@
hostView = new WeakReference<View>(view);
}
- public void invalidateView() {
- View v = hostView.get();
- if (v != null) {
- v.invalidate();
- }
- }
-
@Override
HardwareCanvas start() {
if (mStarted) {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 076f712..3c39149 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -675,6 +675,87 @@
public static final int AXIS_RTRIGGER = 18;
/**
+ * Constant used to identify the Throttle axis of a motion event.
+ * <p>
+ * <ul>
+ * <li>For a joystick, reports the absolute position of the throttle control.
+ * The value is normalized to a range from 0.0 (fully open) to 1.0 (fully closed).
+ * </ul>
+ * </p>
+ *
+ * @see #getAxisValue(int, int)
+ * @see #getHistoricalAxisValue(int, int, int)
+ * @see MotionEvent.PointerCoords#getAxisValue(int)
+ * @see InputDevice#getMotionRange
+ */
+ public static final int AXIS_THROTTLE = 19;
+
+ /**
+ * Constant used to identify the Rudder axis of a motion event.
+ * <p>
+ * <ul>
+ * <li>For a joystick, reports the absolute position of the rudder control.
+ * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
+ * </ul>
+ * </p>
+ *
+ * @see #getAxisValue(int, int)
+ * @see #getHistoricalAxisValue(int, int, int)
+ * @see MotionEvent.PointerCoords#getAxisValue(int)
+ * @see InputDevice#getMotionRange
+ */
+ public static final int AXIS_RUDDER = 20;
+
+ /**
+ * Constant used to identify the Wheel axis of a motion event.
+ * <p>
+ * <ul>
+ * <li>For a joystick, reports the absolute position of the steering wheel control.
+ * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
+ * </ul>
+ * </p>
+ *
+ * @see #getAxisValue(int, int)
+ * @see #getHistoricalAxisValue(int, int, int)
+ * @see MotionEvent.PointerCoords#getAxisValue(int)
+ * @see InputDevice#getMotionRange
+ */
+ public static final int AXIS_WHEEL = 21;
+
+ /**
+ * Constant used to identify the Gas axis of a motion event.
+ * <p>
+ * <ul>
+ * <li>For a joystick, reports the absolute position of the gas (accelerator) control.
+ * The value is normalized to a range from 0.0 (no acceleration)
+ * to 1.0 (maximum acceleration).
+ * </ul>
+ * </p>
+ *
+ * @see #getAxisValue(int, int)
+ * @see #getHistoricalAxisValue(int, int, int)
+ * @see MotionEvent.PointerCoords#getAxisValue(int)
+ * @see InputDevice#getMotionRange
+ */
+ public static final int AXIS_GAS = 22;
+
+ /**
+ * Constant used to identify the Brake axis of a motion event.
+ * <p>
+ * <ul>
+ * <li>For a joystick, reports the absolute position of the brake control.
+ * The value is normalized to a range from 0.0 (no braking) to 1.0 (maximum braking).
+ * </ul>
+ * </p>
+ *
+ * @see #getAxisValue(int, int)
+ * @see #getHistoricalAxisValue(int, int, int)
+ * @see MotionEvent.PointerCoords#getAxisValue(int)
+ * @see InputDevice#getMotionRange
+ */
+ public static final int AXIS_BRAKE = 23;
+
+ /**
* Constant used to identify the Generic 1 axis of a motion event.
* The interpretation of a generic axis is device-specific.
*
@@ -877,6 +958,11 @@
names.append(AXIS_HAT_Y, "AXIS_HAT_Y");
names.append(AXIS_LTRIGGER, "AXIS_LTRIGGER");
names.append(AXIS_RTRIGGER, "AXIS_RTRIGGER");
+ names.append(AXIS_THROTTLE, "AXIS_THROTTLE");
+ names.append(AXIS_RUDDER, "AXIS_RUDDER");
+ names.append(AXIS_WHEEL, "AXIS_WHEEL");
+ names.append(AXIS_GAS, "AXIS_GAS");
+ names.append(AXIS_BRAKE, "AXIS_BRAKE");
names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1");
names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2");
names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 32c9e27..fa24d30 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8563,8 +8563,6 @@
canvas.onPreDraw(mLocalDirtyRect);
mLocalDirtyRect.setEmpty();
- final int restoreCount = canvas.save();
-
computeScroll();
canvas.translate(-mScrollX, -mScrollY);
@@ -8578,7 +8576,6 @@
draw(canvas);
}
- canvas.restoreToCount(restoreCount);
} finally {
canvas.onPostDraw();
mHardwareLayer.end(currentCanvas);
@@ -8728,8 +8725,6 @@
// The dirty rect should always be null for a display list
canvas.onPreDraw(null);
- final int restoreCount = canvas.save();
-
computeScroll();
canvas.translate(-mScrollX, -mScrollY);
mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
@@ -8742,7 +8737,6 @@
draw(canvas);
}
- canvas.restoreToCount(restoreCount);
} finally {
canvas.onPostDraw();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 2d3157e9d..f0a3a0f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -847,6 +847,9 @@
private Rect mScrollingLayerBounds = new Rect();
private boolean mSentAutoScrollMessage = false;
+ // used for serializing asynchronously handled touch events.
+ private final TouchEventQueue mTouchEventQueue = new TouchEventQueue();
+
// Used to notify listeners of a new picture.
private PictureListener mPictureListener;
/**
@@ -4112,7 +4115,7 @@
}
if (animateZoom) {
mZoomManager.animateZoom(canvas);
- } else {
+ } else if (!canvas.isHardwareAccelerated()) {
canvas.scale(mZoomManager.getScale(), mZoomManager.getScale());
}
@@ -5081,6 +5084,8 @@
}
addAccessibilityApisToJavaScript();
+
+ mTouchEventQueue.reset();
}
@Override
@@ -5432,34 +5437,17 @@
+ " numPointers=" + ev.getPointerCount());
}
- int action = ev.getActionMasked();
- if (ev.getPointerCount() > 1) { // Multi-touch
- mIsHandlingMultiTouch = true;
-
- // If WebKit already showed no interests in this sequence of events,
- // WebView handles them directly.
- if (mPreventDefault == PREVENT_DEFAULT_NO) {
- handleMultiTouchInWebView(ev);
- } else {
- passMultiTouchToWebKit(ev);
- }
- return true;
+ // If WebKit wasn't interested in this multitouch gesture, enqueue
+ // the event for handling directly rather than making the round trip
+ // to WebKit and back.
+ if (ev.getPointerCount() > 1 && mPreventDefault != PREVENT_DEFAULT_NO) {
+ passMultiTouchToWebKit(ev, mTouchEventQueue.nextTouchSequence());
} else {
- final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
- if (detector != null) {
- // ScaleGestureDetector needs a consistent event stream to operate properly.
- // It won't take any action with fewer than two pointers, but it needs to
- // update internal bookkeeping state.
- detector.onTouchEvent(ev);
- }
+ mTouchEventQueue.enqueueTouchEvent(ev);
}
- // Skip ACTION_MOVE for single touch if it's still handling multi-touch.
- if (mIsHandlingMultiTouch && action == MotionEvent.ACTION_MOVE) {
- return false;
- }
-
- return handleTouchEventCommon(ev, action, Math.round(ev.getX()), Math.round(ev.getY()));
+ // Since all events are handled asynchronously, we always want the gesture stream.
+ return true;
}
/*
@@ -5579,6 +5567,7 @@
ted.mReprocess = mDeferTouchProcess;
ted.mNativeLayer = nativeScrollableLayer(
contentX, contentY, ted.mNativeLayerRect, null);
+ ted.mDontEnqueueResult = true;
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
if (mDeferTouchProcess) {
// still needs to set them for compute deltaX/Y
@@ -5625,6 +5614,7 @@
ted.mReprocess = mDeferTouchProcess;
ted.mNativeLayer = mScrollingLayer;
ted.mNativeLayerRect.set(mScrollingLayerRect);
+ ted.mDontEnqueueResult = true;
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mLastSentTouchTime = eventTime;
if (mDeferTouchProcess) {
@@ -5806,6 +5796,7 @@
ted.mReprocess = mDeferTouchProcess;
ted.mNativeLayer = mScrollingLayer;
ted.mNativeLayerRect.set(mScrollingLayerRect);
+ ted.mDontEnqueueResult = true;
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
}
mLastTouchUpTime = eventTime;
@@ -5828,6 +5819,7 @@
ted.mNativeLayer = nativeScrollableLayer(
contentX, contentY,
ted.mNativeLayerRect, null);
+ ted.mDontEnqueueResult = true;
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES){
mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
@@ -5952,7 +5944,7 @@
return true;
}
- private void passMultiTouchToWebKit(MotionEvent ev) {
+ private void passMultiTouchToWebKit(MotionEvent ev, long sequence) {
TouchEventData ted = new TouchEventData();
ted.mAction = ev.getActionMasked();
final int count = ev.getPointerCount();
@@ -5967,6 +5959,7 @@
ted.mMetaState = ev.getMetaState();
ted.mReprocess = true;
ted.mMotionEvent = MotionEvent.obtain(ev);
+ ted.mSequence = sequence;
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
cancelLongPress();
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
@@ -6016,7 +6009,7 @@
if (action == MotionEvent.ACTION_POINTER_DOWN) {
cancelTouch();
action = MotionEvent.ACTION_DOWN;
- } else if (action == MotionEvent.ACTION_POINTER_UP) {
+ } else if (action == MotionEvent.ACTION_POINTER_UP && ev.getPointerCount() == 2) {
// set mLastTouchX/Y to the remaining point
mLastTouchX = Math.round(x);
mLastTouchY = Math.round(y);
@@ -6044,6 +6037,7 @@
ted.mAction = MotionEvent.ACTION_CANCEL;
ted.mNativeLayer = nativeScrollableLayer(
x, y, ted.mNativeLayerRect, null);
+ ted.mDontEnqueueResult = true;
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mPreventDefault = PREVENT_DEFAULT_IGNORE;
}
@@ -7121,6 +7115,297 @@
return mWebViewCore;
}
+ /**
+ * Used only by TouchEventQueue to store pending touch events.
+ */
+ private static class QueuedTouch {
+ long mSequence;
+ MotionEvent mEvent; // Optional
+ TouchEventData mTed; // Optional
+
+ QueuedTouch mNext;
+
+ public QueuedTouch set(TouchEventData ted) {
+ mSequence = ted.mSequence;
+ mTed = ted;
+ mEvent = null;
+ mNext = null;
+ return this;
+ }
+
+ public QueuedTouch set(MotionEvent ev, long sequence) {
+ mEvent = MotionEvent.obtain(ev);
+ mSequence = sequence;
+ mTed = null;
+ mNext = null;
+ return this;
+ }
+
+ public QueuedTouch add(QueuedTouch other) {
+ if (other.mSequence < mSequence) {
+ other.mNext = this;
+ return other;
+ }
+
+ QueuedTouch insertAt = this;
+ while (insertAt.mNext != null && insertAt.mNext.mSequence < other.mSequence) {
+ insertAt = insertAt.mNext;
+ }
+ other.mNext = insertAt.mNext;
+ insertAt.mNext = other;
+ return this;
+ }
+ }
+
+ /**
+ * WebView handles touch events asynchronously since some events must be passed to WebKit
+ * for potentially slower processing. TouchEventQueue serializes touch events regardless
+ * of which path they take to ensure that no events are ever processed out of order
+ * by WebView.
+ */
+ private class TouchEventQueue {
+ private long mNextTouchSequence = Long.MIN_VALUE + 1;
+ private long mLastHandledTouchSequence = Long.MIN_VALUE;
+ private QueuedTouch mTouchEventQueue;
+ private QueuedTouch mQueuedTouchRecycleBin;
+ private int mQueuedTouchRecycleCount;
+ private static final int MAX_RECYCLED_QUEUED_TOUCH = 15;
+
+ private QueuedTouch obtainQueuedTouch() {
+ if (mQueuedTouchRecycleBin != null) {
+ QueuedTouch result = mQueuedTouchRecycleBin;
+ mQueuedTouchRecycleBin = result.mNext;
+ mQueuedTouchRecycleCount--;
+ return result;
+ }
+ return new QueuedTouch();
+ }
+
+ private void recycleQueuedTouch(QueuedTouch qd) {
+ if (mQueuedTouchRecycleCount < MAX_RECYCLED_QUEUED_TOUCH) {
+ qd.mNext = mQueuedTouchRecycleBin;
+ mQueuedTouchRecycleBin = qd;
+ mQueuedTouchRecycleCount++;
+ }
+ }
+
+ /**
+ * Reset the touch event queue. This will dump any pending events
+ * and reset the sequence numbering.
+ */
+ public void reset() {
+ mNextTouchSequence = Long.MIN_VALUE + 1;
+ mLastHandledTouchSequence = Long.MIN_VALUE;
+ while (mTouchEventQueue != null) {
+ QueuedTouch recycleMe = mTouchEventQueue;
+ mTouchEventQueue = mTouchEventQueue.mNext;
+ recycleQueuedTouch(recycleMe);
+ }
+ }
+
+ /**
+ * Return the next valid sequence number for tagging incoming touch events.
+ * @return The next touch event sequence number
+ */
+ public long nextTouchSequence() {
+ return mNextTouchSequence++;
+ }
+
+ /**
+ * Enqueue a touch event in the form of TouchEventData.
+ * The sequence number will be read from the mSequence field of the argument.
+ *
+ * If the touch event's sequence number is the next in line to be processed, it will
+ * be handled before this method returns. Any subsequent events that have already
+ * been queued will also be processed in their proper order.
+ *
+ * @param ted Touch data to be processed in order.
+ */
+ public void enqueueTouchEvent(TouchEventData ted) {
+ if (mLastHandledTouchSequence + 1 == ted.mSequence) {
+ handleQueuedTouchEventData(ted);
+
+ mLastHandledTouchSequence++;
+
+ // Do we have any more? Run them if so.
+ QueuedTouch qd = mTouchEventQueue;
+ while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) {
+ handleQueuedTouch(qd);
+ QueuedTouch recycleMe = qd;
+ qd = qd.mNext;
+ recycleQueuedTouch(recycleMe);
+ mLastHandledTouchSequence++;
+ }
+ mTouchEventQueue = qd;
+ } else {
+ QueuedTouch qd = obtainQueuedTouch().set(ted);
+ mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
+ }
+ }
+
+ /**
+ * Enqueue a touch event in the form of a MotionEvent from the framework.
+ *
+ * If the touch event's sequence number is the next in line to be processed, it will
+ * be handled before this method returns. Any subsequent events that have already
+ * been queued will also be processed in their proper order.
+ *
+ * @param ev MotionEvent to be processed in order
+ */
+ public void enqueueTouchEvent(MotionEvent ev) {
+ final long sequence = nextTouchSequence();
+ if (mLastHandledTouchSequence + 1 == sequence) {
+ handleQueuedMotionEvent(ev);
+
+ mLastHandledTouchSequence++;
+
+ // Do we have any more? Run them if so.
+ QueuedTouch qd = mTouchEventQueue;
+ while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) {
+ handleQueuedTouch(qd);
+ QueuedTouch recycleMe = qd;
+ qd = qd.mNext;
+ recycleQueuedTouch(recycleMe);
+ mLastHandledTouchSequence++;
+ }
+ mTouchEventQueue = qd;
+ } else {
+ QueuedTouch qd = obtainQueuedTouch().set(ev, sequence);
+ mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
+ }
+ }
+
+ private void handleQueuedTouch(QueuedTouch qt) {
+ if (qt.mTed != null) {
+ handleQueuedTouchEventData(qt.mTed);
+ } else {
+ handleQueuedMotionEvent(qt.mEvent);
+ qt.mEvent.recycle();
+ }
+ }
+
+ private void handleQueuedMotionEvent(MotionEvent ev) {
+ int action = ev.getActionMasked();
+ if (ev.getPointerCount() > 1) { // Multi-touch
+ mIsHandlingMultiTouch = true;
+
+ handleMultiTouchInWebView(ev);
+ } else {
+ final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
+ if (detector != null) {
+ // ScaleGestureDetector needs a consistent event stream to operate properly.
+ // It won't take any action with fewer than two pointers, but it needs to
+ // update internal bookkeeping state.
+ detector.onTouchEvent(ev);
+ }
+
+ handleTouchEventCommon(ev, action, Math.round(ev.getX()), Math.round(ev.getY()));
+ }
+ }
+
+ private void handleQueuedTouchEventData(TouchEventData ted) {
+ if (!ted.mReprocess) {
+ if (ted.mAction == MotionEvent.ACTION_DOWN
+ && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) {
+ // if prevent default is called from WebCore, UI
+ // will not handle the rest of the touch events any
+ // more.
+ mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES
+ : PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN;
+ } else if (ted.mAction == MotionEvent.ACTION_MOVE
+ && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
+ // the return for the first ACTION_MOVE will decide
+ // whether UI will handle touch or not. Currently no
+ // support for alternating prevent default
+ mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES
+ : PREVENT_DEFAULT_NO;
+ }
+ if (mPreventDefault == PREVENT_DEFAULT_YES) {
+ mTouchHighlightRegion.setEmpty();
+ }
+ } else {
+ if (ted.mPoints.length > 1) { // multi-touch
+ if (ted.mAction == MotionEvent.ACTION_POINTER_UP &&
+ ted.mMotionEvent.getPointerCount() == 2) {
+ mIsHandlingMultiTouch = false;
+ }
+ if (!ted.mNativeResult) {
+ mPreventDefault = PREVENT_DEFAULT_NO;
+ handleMultiTouchInWebView(ted.mMotionEvent);
+ } else {
+ mPreventDefault = PREVENT_DEFAULT_YES;
+ }
+ return;
+ }
+
+ // prevent default is not called in WebCore, so the
+ // message needs to be reprocessed in UI
+ if (!ted.mNativeResult) {
+ // Following is for single touch.
+ switch (ted.mAction) {
+ case MotionEvent.ACTION_DOWN:
+ mLastDeferTouchX = contentToViewX(ted.mPoints[0].x)
+ - mScrollX;
+ mLastDeferTouchY = contentToViewY(ted.mPoints[0].y)
+ - mScrollY;
+ mDeferTouchMode = TOUCH_INIT_MODE;
+ break;
+ case MotionEvent.ACTION_MOVE: {
+ // no snapping in defer process
+ int x = contentToViewX(ted.mPoints[0].x) - mScrollX;
+ int y = contentToViewY(ted.mPoints[0].y) - mScrollY;
+ if (mDeferTouchMode != TOUCH_DRAG_MODE) {
+ mDeferTouchMode = TOUCH_DRAG_MODE;
+ mLastDeferTouchX = x;
+ mLastDeferTouchY = y;
+ startScrollingLayer(x, y);
+ startDrag();
+ }
+ int deltaX = pinLocX((int) (mScrollX
+ + mLastDeferTouchX - x))
+ - mScrollX;
+ int deltaY = pinLocY((int) (mScrollY
+ + mLastDeferTouchY - y))
+ - mScrollY;
+ doDrag(deltaX, deltaY);
+ if (deltaX != 0) mLastDeferTouchX = x;
+ if (deltaY != 0) mLastDeferTouchY = y;
+ break;
+ }
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ if (mDeferTouchMode == TOUCH_DRAG_MODE) {
+ // no fling in defer process
+ mScroller.springBack(mScrollX, mScrollY, 0,
+ computeMaxScrollX(), 0,
+ computeMaxScrollY());
+ invalidate();
+ WebViewCore.resumePriority();
+ WebViewCore.resumeUpdatePicture(mWebViewCore);
+ }
+ mDeferTouchMode = TOUCH_DONE_MODE;
+ break;
+ case WebViewCore.ACTION_DOUBLETAP:
+ // doDoubleTap() needs mLastTouchX/Y as anchor
+ mLastTouchX = contentToViewX(ted.mPoints[0].x) - mScrollX;
+ mLastTouchY = contentToViewY(ted.mPoints[0].y) - mScrollY;
+ mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
+ mDeferTouchMode = TOUCH_DONE_MODE;
+ break;
+ case WebViewCore.ACTION_LONGPRESS:
+ HitTestResult hitTest = getHitTestResult();
+ if (hitTest != null && hitTest.mType
+ != HitTestResult.UNKNOWN_TYPE) {
+ performLongClick();
+ }
+ mDeferTouchMode = TOUCH_DONE_MODE;
+ break;
+ }
+ }
+ }
+ }
+ }
+
//-------------------------------------------------------------------------
// Methods can be called from a separate thread, like WebViewCore
// If it needs to call the View system, it has to send message.
@@ -7236,6 +7521,7 @@
ted.mNativeLayer = nativeScrollableLayer(
ted.mPoints[0].x, ted.mPoints[0].y,
ted.mNativeLayerRect, null);
+ ted.mDontEnqueueResult = true;
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES) {
mTouchMode = TOUCH_DONE_MODE;
@@ -7450,105 +7736,9 @@
if (inFullScreenMode()) {
break;
}
- if (msg.obj == null) {
- if (msg.arg1 == MotionEvent.ACTION_DOWN
- && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) {
- // if prevent default is called from WebCore, UI
- // will not handle the rest of the touch events any
- // more.
- mPreventDefault = msg.arg2 == 1 ? PREVENT_DEFAULT_YES
- : PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN;
- } else if (msg.arg1 == MotionEvent.ACTION_MOVE
- && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
- // the return for the first ACTION_MOVE will decide
- // whether UI will handle touch or not. Currently no
- // support for alternating prevent default
- mPreventDefault = msg.arg2 == 1 ? PREVENT_DEFAULT_YES
- : PREVENT_DEFAULT_NO;
- }
- if (mPreventDefault == PREVENT_DEFAULT_YES) {
- mTouchHighlightRegion.setEmpty();
- }
- } else {
- TouchEventData ted = (TouchEventData) msg.obj;
-
- if (ted.mPoints.length > 1) { // multi-touch
- if (ted.mAction == MotionEvent.ACTION_POINTER_UP) {
- mIsHandlingMultiTouch = false;
- }
- if (msg.arg2 == 0) {
- mPreventDefault = PREVENT_DEFAULT_NO;
- handleMultiTouchInWebView(ted.mMotionEvent);
- } else {
- mPreventDefault = PREVENT_DEFAULT_YES;
- }
- break;
- }
-
- // prevent default is not called in WebCore, so the
- // message needs to be reprocessed in UI
- if (msg.arg2 == 0) {
- // Following is for single touch.
- switch (ted.mAction) {
- case MotionEvent.ACTION_DOWN:
- mLastDeferTouchX = contentToViewX(ted.mPoints[0].x)
- - mScrollX;
- mLastDeferTouchY = contentToViewY(ted.mPoints[0].y)
- - mScrollY;
- mDeferTouchMode = TOUCH_INIT_MODE;
- break;
- case MotionEvent.ACTION_MOVE: {
- // no snapping in defer process
- int x = contentToViewX(ted.mPoints[0].x) - mScrollX;
- int y = contentToViewY(ted.mPoints[0].y) - mScrollY;
- if (mDeferTouchMode != TOUCH_DRAG_MODE) {
- mDeferTouchMode = TOUCH_DRAG_MODE;
- mLastDeferTouchX = x;
- mLastDeferTouchY = y;
- startScrollingLayer(x, y);
- startDrag();
- }
- int deltaX = pinLocX((int) (mScrollX
- + mLastDeferTouchX - x))
- - mScrollX;
- int deltaY = pinLocY((int) (mScrollY
- + mLastDeferTouchY - y))
- - mScrollY;
- doDrag(deltaX, deltaY);
- if (deltaX != 0) mLastDeferTouchX = x;
- if (deltaY != 0) mLastDeferTouchY = y;
- break;
- }
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- if (mDeferTouchMode == TOUCH_DRAG_MODE) {
- // no fling in defer process
- mScroller.springBack(mScrollX, mScrollY, 0,
- computeMaxScrollX(), 0,
- computeMaxScrollY());
- invalidate();
- WebViewCore.resumePriority();
- WebViewCore.resumeUpdatePicture(mWebViewCore);
- }
- mDeferTouchMode = TOUCH_DONE_MODE;
- break;
- case WebViewCore.ACTION_DOUBLETAP:
- // doDoubleTap() needs mLastTouchX/Y as anchor
- mLastTouchX = contentToViewX(ted.mPoints[0].x) - mScrollX;
- mLastTouchY = contentToViewY(ted.mPoints[0].y) - mScrollY;
- mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
- mDeferTouchMode = TOUCH_DONE_MODE;
- break;
- case WebViewCore.ACTION_LONGPRESS:
- HitTestResult hitTest = getHitTestResult();
- if (hitTest != null && hitTest.mType
- != HitTestResult.UNKNOWN_TYPE) {
- performLongClick();
- }
- mDeferTouchMode = TOUCH_DONE_MODE;
- break;
- }
- }
+ TouchEventData ted = (TouchEventData) msg.obj;
+ if (!ted.mDontEnqueueResult) {
+ mTouchEventQueue.enqueueTouchEvent(ted);
}
break;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index c18c9e4..f367b93 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -825,6 +825,9 @@
MotionEvent mMotionEvent;
int mNativeLayer;
Rect mNativeLayerRect = new Rect();
+ long mSequence;
+ boolean mNativeResult;
+ boolean mDontEnqueueResult;
}
static class GeolocationPermissionsData {
@@ -1332,13 +1335,14 @@
nativeScrollLayer(ted.mNativeLayer,
ted.mNativeLayerRect);
}
+ ted.mNativeResult = nativeHandleTouchEvent(ted.mAction, ted.mIds,
+ xArray, yArray, count, ted.mMetaState);
Message.obtain(
mWebView.mPrivateHandler,
WebView.PREVENT_TOUCH_ID,
ted.mAction,
- nativeHandleTouchEvent(ted.mAction, ted.mIds,
- xArray, yArray, count, ted.mMetaState) ? 1 : 0,
- ted.mReprocess ? ted : null).sendToTarget();
+ ted.mNativeResult ? 1 : 0,
+ ted).sendToTarget();
break;
}
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 2d2165b..1c0a2bb 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -889,7 +889,7 @@
boolean isConnected = mServiceConnection.isConnected();
boolean hasNewItems = false;
- if (!isConnected) {
+ if (!isInCache && !isConnected) {
// Requesting bind service will trigger a super.notifyDataSetChanged(), which will
// in turn trigger another request to getView()
requestBindService();
diff --git a/core/res/res/drawable-hdpi/btn_default_disabled_holo.9.png b/core/res/res/drawable-hdpi/btn_default_disabled_holo.9.png
new file mode 100644
index 0000000..6840962
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_disabled_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_focused_holo.9.png b/core/res/res/drawable-hdpi/btn_default_focused_holo.9.png
new file mode 100644
index 0000000..b3196c3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_normal_holo.9.png b/core/res/res/drawable-hdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..c44ae7a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
new file mode 100644
index 0000000..e240a2d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_disabled_holo.9.png b/core/res/res/drawable-mdpi/btn_default_disabled_holo.9.png
new file mode 100644
index 0000000..9a24b9c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_default_disabled_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_focused_holo.9.png b/core/res/res/drawable-mdpi/btn_default_focused_holo.9.png
new file mode 100644
index 0000000..93d9741
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_default_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_normal_holo.9.png b/core/res/res/drawable-mdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..f462d98
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
new file mode 100644
index 0000000..30373a6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 066aae9..af0074b 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -828,7 +828,7 @@
<string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
<string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi yanıt vermiyor."</string>
<string name="force_close" msgid="3653416315450806396">"Kapanmaya zorla"</string>
- <string name="report" msgid="4060218260984795706">"Rapor"</string>
+ <string name="report" msgid="4060218260984795706">"Bildir"</string>
<string name="wait" msgid="7147118217226317732">"Bekle"</string>
<string name="launch_warning_title" msgid="8323761616052121936">"Uygulama yönlendirildi"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> ÅŸimdi çalışıyor."</string>
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 6d925d6..1428b63 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -409,6 +409,10 @@
axis 0x03 RX
axis 0x04 RY
axis 0x05 RZ
+axis 0x06 THROTTLE
+axis 0x07 RUDDER
+axis 0x08 WHEEL
+axis 0x09 GAS
+axis 0x0a BRAKE
axis 0x10 HAT_X
axis 0x11 HAT_Y
-
\ No newline at end of file
diff --git a/data/keyboards/Vendor_045e_Product_028e.kl b/data/keyboards/Vendor_045e_Product_028e.kl
new file mode 100644
index 0000000..99f046a
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_028e.kl
@@ -0,0 +1,46 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# XBox 360 USB Controller
+#
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 314 BUTTON_SELECT
+key 315 BUTTON_START
+key 316 BUTTON_MODE
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_046d_Product_c294.kl b/data/keyboards/Vendor_046d_Product_c294.kl
new file mode 100644
index 0000000..5492f49
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c294.kl
@@ -0,0 +1,53 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Logitech G25 Racing Wheel (in Compatibility Mode)
+#
+
+# 4 way buttons above hat
+key 0x121 BUTTON_A
+key 0x123 BUTTON_B
+key 0x120 BUTTON_X
+key 0x122 BUTTON_Y
+
+# Row of buttons under hat
+key 0x12b BUTTON_1
+key 0x128 BUTTON_2
+key 0x129 BUTTON_3
+key 0x12a BUTTON_4
+
+# Gear shift positions
+# 0x12a top-left gear (aliased as BUTTON_4)
+# 0x12b bottom-left gear (aliased as BUTTON_1)
+
+# Buttons on wheel
+key 0x127 BUTTON_L1
+key 0x126 BUTTON_R1
+
+# Toggles under wheel
+key 0x125 BUTTON_L2
+key 0x124 BUTTON_R2
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Steering Wheel
+axis 0x00 WHEEL
+
+# Accelerator / Brake
+# 00..7e : accelerator
+# 80..ff : brake
+axis 0x01 split 0x7f GAS BRAKE
diff --git a/data/keyboards/Vendor_046d_Product_c299.kl b/data/keyboards/Vendor_046d_Product_c299.kl
new file mode 100644
index 0000000..d42963d
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c299.kl
@@ -0,0 +1,62 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Logitech G25 Racing Wheel (in Native Mode)
+#
+
+# 4 way buttons above hat
+key 0x121 BUTTON_A
+key 0x123 BUTTON_B
+key 0x120 BUTTON_X
+key 0x122 BUTTON_Y
+
+# Row of buttons under hat
+key 0x12b BUTTON_1
+key 0x128 BUTTON_2
+key 0x129 BUTTON_3
+key 0x12a BUTTON_4
+
+# Gear shift positions
+key 0x12c BUTTON_5
+key 0x12d BUTTON_6
+key 0x12e BUTTON_7
+key 0x12f BUTTON_8
+key 0x2d0 BUTTON_9
+key 0x2d1 BUTTON_10
+key 0x2d2 BUTTON_11
+
+# Buttons on wheel
+key 0x127 BUTTON_L1
+key 0x126 BUTTON_R1
+
+# Toggles under wheel
+key 0x125 BUTTON_L2
+key 0x124 BUTTON_R2
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Steering Wheel
+axis 0x00 WHEEL
+
+# Clutch
+axis 0x01 invert GENERIC_1
+
+# Accelerator
+axis 0x02 invert GAS
+
+# Brake
+axis 0x05 invert BRAKE
diff --git a/data/keyboards/common.mk b/data/keyboards/common.mk
index 5b367b9..335298c 100644
--- a/data/keyboards/common.mk
+++ b/data/keyboards/common.mk
@@ -19,7 +19,10 @@
Generic.kl \
AVRCP.kl \
qwerty.kl \
+ Vendor_045e_Product_028e.kl \
Vendor_046d_Product_c216.kl \
+ Vendor_046d_Product_c294.kl \
+ Vendor_046d_Product_c299.kl \
Vendor_046d_Product_c532.kl \
Vendor_054c_Product_0268.kl \
Vendor_05ac_Product_0239.kl \
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index c541456..782ffdb 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -735,6 +735,7 @@
* This method expects uri in the following format
* content://media/<table_name>/<row_index> (or)
* file://sdcard/test.mp4
+ * http://test.com/test.mp4
*
* Here <table_name> shall be "video" or "audio" or "images"
* <row_index> the index of the content in given table
@@ -746,6 +747,10 @@
if (null == scheme || scheme.equals("") ||
scheme.equals(ContentResolver.SCHEME_FILE)) {
path = uri.getPath();
+
+ } else if (scheme.equals("http")) {
+ path = uri.toString();
+
} else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
String[] projection = new String[] {MediaStore.MediaColumns.DATA};
Cursor cursor = null;
diff --git a/include/ui/KeyLayoutMap.h b/include/ui/KeyLayoutMap.h
index 904c8f3..d82d0c8 100644
--- a/include/ui/KeyLayoutMap.h
+++ b/include/ui/KeyLayoutMap.h
@@ -24,6 +24,36 @@
namespace android {
+struct AxisInfo {
+ enum Mode {
+ // Axis value is reported directly.
+ MODE_NORMAL = 0,
+ // Axis value should be inverted before reporting.
+ MODE_INVERT = 1,
+ // Axis value should be split into two axes
+ MODE_SPLIT = 2,
+ };
+
+ // Axis mode.
+ Mode mode;
+
+ // Axis id.
+ // When split, this is the axis used for values smaller than the split position.
+ int32_t axis;
+
+ // When split, this is the axis used for values after higher than the split position.
+ int32_t highAxis;
+
+ // The split value, or 0 if not split.
+ int32_t splitValue;
+
+ // The flat value, or -1 if none.
+ int32_t flatOverride;
+
+ AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) {
+ }
+};
+
/**
* Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes.
*/
@@ -36,7 +66,7 @@
status_t mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const;
status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
- status_t mapAxis(int32_t scanCode, int32_t* axis) const;
+ status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
private:
struct Key {
@@ -45,7 +75,7 @@
};
KeyedVector<int32_t, Key> mKeys;
- KeyedVector<int32_t, int32_t> mAxes;
+ KeyedVector<int32_t, AxisInfo> mAxes;
KeyLayoutMap();
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index bdfbf7c..b912e9b 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -270,6 +270,11 @@
{ "HAT_Y", 16 },
{ "LTRIGGER", 17 },
{ "RTRIGGER", 18 },
+ { "THROTTLE", 19 },
+ { "RUDDER", 20 },
+ { "WHEEL", 21 },
+ { "GAS", 22 },
+ { "BRAKE", 23 },
{ "GENERIC_1", 32 },
{ "GENERIC_2", 33 },
{ "GENERIC_3", 34 },
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp
index 2ed0e66..8626a03 100644
--- a/libs/ui/KeyLayoutMap.cpp
+++ b/libs/ui/KeyLayoutMap.cpp
@@ -113,20 +113,23 @@
return NO_ERROR;
}
-status_t KeyLayoutMap::mapAxis(int32_t scanCode, int32_t* axis) const {
+status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
ssize_t index = mAxes.indexOfKey(scanCode);
if (index < 0) {
#if DEBUG_MAPPING
LOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
#endif
- *axis = -1;
return NAME_NOT_FOUND;
}
- *axis = mAxes.valueAt(index);
+ *outAxisInfo = mAxes.valueAt(index);
#if DEBUG_MAPPING
- LOGD("mapAxis: scanCode=%d ~ Result axis=%d.", scanCode, *axis);
+ LOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
+ "splitValue=%d, flatOverride=%d.",
+ scanCode,
+ outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
+ outAxisInfo->splitValue, outAxisInfo->flatOverride);
#endif
return NO_ERROR;
}
@@ -249,19 +252,89 @@
return BAD_VALUE;
}
+ AxisInfo axisInfo;
+
mTokenizer->skipDelimiters(WHITESPACE);
- String8 axisToken = mTokenizer->nextToken(WHITESPACE);
- int32_t axis = getAxisByLabel(axisToken.string());
- if (axis < 0) {
- LOGE("%s: Expected axis label, got '%s'.", mTokenizer->getLocation().string(),
- axisToken.string());
- return BAD_VALUE;
+ String8 token = mTokenizer->nextToken(WHITESPACE);
+ if (token == "invert") {
+ axisInfo.mode = AxisInfo::MODE_INVERT;
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ String8 axisToken = mTokenizer->nextToken(WHITESPACE);
+ axisInfo.axis = getAxisByLabel(axisToken.string());
+ if (axisInfo.axis < 0) {
+ LOGE("%s: Expected inverted axis label, got '%s'.",
+ mTokenizer->getLocation().string(), axisToken.string());
+ return BAD_VALUE;
+ }
+ } else if (token == "split") {
+ axisInfo.mode = AxisInfo::MODE_SPLIT;
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ String8 splitToken = mTokenizer->nextToken(WHITESPACE);
+ axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
+ if (*end) {
+ LOGE("%s: Expected split value, got '%s'.",
+ mTokenizer->getLocation().string(), splitToken.string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
+ axisInfo.axis = getAxisByLabel(lowAxisToken.string());
+ if (axisInfo.axis < 0) {
+ LOGE("%s: Expected low axis label, got '%s'.",
+ mTokenizer->getLocation().string(), lowAxisToken.string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
+ axisInfo.highAxis = getAxisByLabel(highAxisToken.string());
+ if (axisInfo.highAxis < 0) {
+ LOGE("%s: Expected high axis label, got '%s'.",
+ mTokenizer->getLocation().string(), highAxisToken.string());
+ return BAD_VALUE;
+ }
+ } else {
+ axisInfo.axis = getAxisByLabel(token.string());
+ if (axisInfo.axis < 0) {
+ LOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
+ mTokenizer->getLocation().string(), token.string());
+ return BAD_VALUE;
+ }
+ }
+
+ for (;;) {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ if (mTokenizer->isEol()) {
+ break;
+ }
+ String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
+ if (keywordToken == "flat") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ String8 flatToken = mTokenizer->nextToken(WHITESPACE);
+ axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
+ if (*end) {
+ LOGE("%s: Expected flat value, got '%s'.",
+ mTokenizer->getLocation().string(), flatToken.string());
+ return BAD_VALUE;
+ }
+ } else {
+ LOGE("%s: Expected keyword 'flat', got '%s'.",
+ mTokenizer->getLocation().string(), keywordToken.string());
+ return BAD_VALUE;
+ }
}
#if DEBUG_PARSER
- LOGD("Parsed axis: scanCode=%d, axis=%d.", scanCode, axis);
+ LOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
+ "splitValue=%d, flatOverride=%d.",
+ scanCode,
+ axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
+ axisInfo.splitValue, axisInfo.flatOverride);
#endif
- mMap->mAxes.add(scanCode, axis);
+ mMap->mAxes.add(scanCode, axisInfo);
return NO_ERROR;
}
diff --git a/media/java/android/mtp/MtpClient.java b/media/java/android/mtp/MtpClient.java
index c4ee19e..40e2f9b 100644
--- a/media/java/android/mtp/MtpClient.java
+++ b/media/java/android/mtp/MtpClient.java
@@ -29,6 +29,7 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
/**
@@ -43,7 +44,10 @@
private final Context mContext;
private final UsbManager mUsbManager;
private final ArrayList<Listener> mListeners = new ArrayList<Listener>();
- private final ArrayList<MtpDevice> mDeviceList = new ArrayList<MtpDevice>();
+ // mDevices contains all MtpDevices that have been seen by our client,
+ // so we can inform when the device has been detached.
+ // mDevices is also used for synchronization in this class.
+ private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>();
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override
@@ -51,21 +55,21 @@
UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
String deviceName = usbDevice.getDeviceName();
- synchronized (mDeviceList) {
- MtpDevice mtpDevice = getDeviceLocked(deviceName);
+ synchronized (mDevices) {
+ MtpDevice mtpDevice = mDevices.get(deviceName);
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
if (mtpDevice == null) {
- mtpDevice = openDevice(usbDevice);
+ mtpDevice = openDeviceLocked(usbDevice);
}
if (mtpDevice != null) {
- mDeviceList.add(mtpDevice);
+ mDevices.put(deviceName, mtpDevice);
for (Listener listener : mListeners) {
listener.deviceAdded(mtpDevice);
}
}
} else if (mtpDevice != null) {
- mDeviceList.remove(mtpDevice);
+ mDevices.remove(deviceName);
for (Listener listener : mListeners) {
listener.deviceRemoved(mtpDevice);
}
@@ -127,16 +131,6 @@
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
context.registerReceiver(mUsbReceiver, filter);
-
- for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
- MtpDevice mtpDevice = getDeviceLocked(usbDevice.getDeviceName());
- if (mtpDevice == null) {
- mtpDevice = openDevice(usbDevice);
- }
- if (mtpDevice != null) {
- mDeviceList.add(mtpDevice);
- }
- }
}
/**
@@ -146,7 +140,7 @@
* @param device the device to open
* @return an MtpDevice for the device.
*/
- private MtpDevice openDevice(UsbDevice usbDevice) {
+ private MtpDevice openDeviceLocked(UsbDevice usbDevice) {
if (isCamera(usbDevice)) {
MtpDevice mtpDevice = new MtpDevice(usbDevice);
if (mtpDevice.open(mUsbManager)) {
@@ -170,7 +164,7 @@
* @param listener the listener to register
*/
public void addListener(Listener listener) {
- synchronized (mDeviceList) {
+ synchronized (mDevices) {
if (!mListeners.contains(listener)) {
mListeners.add(listener);
}
@@ -183,7 +177,7 @@
* @param listener the listener to unregister
*/
public void removeListener(Listener listener) {
- synchronized (mDeviceList) {
+ synchronized (mDevices) {
mListeners.remove(listener);
}
}
@@ -196,8 +190,8 @@
* @return the MtpDevice, or null if it does not exist
*/
public MtpDevice getDevice(String deviceName) {
- synchronized (mDeviceList) {
- return getDeviceLocked(deviceName);
+ synchronized (mDevices) {
+ return mDevices.get(deviceName);
}
}
@@ -209,28 +203,32 @@
* @return the MtpDevice, or null if it does not exist
*/
public MtpDevice getDevice(int id) {
- synchronized (mDeviceList) {
- return getDeviceLocked(UsbDevice.getDeviceName(id));
+ synchronized (mDevices) {
+ return mDevices.get(UsbDevice.getDeviceName(id));
}
}
- private MtpDevice getDeviceLocked(String deviceName) {
- for (MtpDevice device : mDeviceList) {
- if (device.getDeviceName().equals(deviceName)) {
- return device;
- }
- }
- return null;
- }
-
/**
* Retrieves a list of all currently connected {@link android.mtp.MtpDevice}.
*
* @return the list of MtpDevices
*/
public List<MtpDevice> getDeviceList() {
- synchronized (mDeviceList) {
- return new ArrayList<MtpDevice>(mDeviceList);
+ synchronized (mDevices) {
+ // Query the USB manager since devices might have attached
+ // before we added our listener.
+ for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
+ String deviceName = usbDevice.getDeviceName();
+ MtpDevice mtpDevice = mDevices.get(deviceName);
+ if (mtpDevice == null) {
+ mtpDevice = openDeviceLocked(usbDevice);
+ }
+ if (mtpDevice != null) {
+ mDevices.put(deviceName, mtpDevice);
+ }
+ }
+
+ return new ArrayList<MtpDevice>(mDevices.values());
}
}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index f19e8be..86be54a 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -359,6 +359,11 @@
AMOTION_EVENT_AXIS_HAT_Y = 16,
AMOTION_EVENT_AXIS_LTRIGGER = 17,
AMOTION_EVENT_AXIS_RTRIGGER = 18,
+ AMOTION_EVENT_AXIS_THROTTLE = 19,
+ AMOTION_EVENT_AXIS_RUDDER = 20,
+ AMOTION_EVENT_AXIS_WHEEL = 21,
+ AMOTION_EVENT_AXIS_GAS = 22,
+ AMOTION_EVENT_AXIS_BRAKE = 23,
AMOTION_EVENT_AXIS_GENERIC_1 = 32,
AMOTION_EVENT_AXIS_GENERIC_2 = 33,
AMOTION_EVENT_AXIS_GENERIC_3 = 34,
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml
index 1afb2e3..543f4ed 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml
@@ -22,7 +22,6 @@
android:layout_height="0dp"
android:orientation="vertical"
android:background="@drawable/notify_panel_clock_bg"
- android:clickable="true"
>
<LinearLayout
android:id="@+id/icons"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
index 744f667..8b68240 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
@@ -18,11 +18,15 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.MotionEvent;
import android.widget.RelativeLayout;
import com.android.systemui.R;
public class NotificationPeekPanel extends RelativeLayout implements StatusBarPanel {
+ TabletStatusBar mBar;
+
public NotificationPeekPanel(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -39,5 +43,16 @@
return x >= l && x < r && y >= t && y < b;
}
+ public void setBar(TabletStatusBar bar) {
+ mBar = bar;
+ }
+
+ // We don't really want to intercept the touch event, but we *do* want to reset the fade timer
+ // in case the user is interacting with some custom controls or something.
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ mBar.resetNotificationPeekFadeTimer();
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 4557105..58c4d5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -217,6 +217,8 @@
// Notification preview window
mNotificationPeekWindow = (NotificationPeekPanel) View.inflate(context,
R.layout.status_bar_notification_peek, null);
+ mNotificationPeekWindow.setBar(this);
+
mNotificationPeekRow = (ViewGroup) mNotificationPeekWindow.findViewById(R.id.content);
mNotificationPeekWindow.setVisibility(View.GONE);
mNotificationPeekWindow.setOnTouchListener(
@@ -1211,10 +1213,20 @@
}
}
- private class NotificationIconTouchListener implements View.OnTouchListener {
- final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms
- final static int NOTIFICATION_PEEK_FADE_DELAY = 5000; // ms
+ final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms
+ final static int NOTIFICATION_PEEK_FADE_DELAY = 3000; // ms
+ public void resetNotificationPeekFadeTimer() {
+ if (DEBUG) {
+ Slog.d(TAG, "setting peek fade timer for " + NOTIFICATION_PEEK_FADE_DELAY
+ + "ms from now");
+ }
+ mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK);
+ mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK,
+ NOTIFICATION_PEEK_FADE_DELAY);
+ }
+
+ private class NotificationIconTouchListener implements View.OnTouchListener {
VelocityTracker mVT;
int mPeekIndex;
float mInitialTouchX, mInitialTouchY;
@@ -1303,8 +1315,7 @@
}
if (peeking) {
- mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK,
- NOTIFICATION_PEEK_FADE_DELAY);
+ resetNotificationPeekFadeTimer();
}
mVT.recycle();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index ec89db3..64857ed 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2187,7 +2187,7 @@
super.onDetachedFromWindow();
final Callback cb = getCallback();
- if (cb != null && !isDestroyed() && mFeatureId < 0) {
+ if (cb != null && mFeatureId < 0) {
cb.onDetachedFromWindow();
}
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 2fe5980..e37a6b1 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -352,14 +352,13 @@
return NAME_NOT_FOUND;
}
-status_t EventHub::mapAxis(int32_t deviceId, int scancode,
- int32_t* outAxis) const
+status_t EventHub::mapAxis(int32_t deviceId, int scancode, AxisInfo* outAxisInfo) const
{
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device && device->keyMap.haveKeyLayout()) {
- status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxis);
+ status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxisInfo);
if (err == NO_ERROR) {
return NO_ERROR;
}
@@ -369,14 +368,13 @@
device = getDeviceLocked(mBuiltInKeyboardId);
if (device && device->keyMap.haveKeyLayout()) {
- status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxis);
+ status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxisInfo);
if (err == NO_ERROR) {
return NO_ERROR;
}
}
}
- *outAxis = -1;
return NAME_NOT_FOUND;
}
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 445c04b..ab42a1f 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -176,7 +176,7 @@
int32_t* outKeycode, uint32_t* outFlags) const = 0;
virtual status_t mapAxis(int32_t deviceId, int scancode,
- int32_t* outAxis) const = 0;
+ AxisInfo* outAxisInfo) const = 0;
// exclude a particular device from opening
// this can be used to ignore input devices for sensors
@@ -235,7 +235,7 @@
int32_t* outKeycode, uint32_t* outFlags) const;
virtual status_t mapAxis(int32_t deviceId, int scancode,
- int32_t* outAxis) const;
+ AxisInfo* outAxisInfo) const;
virtual void addExcludedDevice(const char* deviceName);
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index b92c3b5..00c3eb7 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -3854,7 +3854,10 @@
for (size_t i = 0; i < mAxes.size(); i++) {
const Axis& axis = mAxes.valueAt(i);
- info->addMotionRange(axis.axis, axis.min, axis.max, axis.flat, axis.fuzz);
+ info->addMotionRange(axis.axisInfo.axis, axis.min, axis.max, axis.flat, axis.fuzz);
+ if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
+ info->addMotionRange(axis.axisInfo.highAxis, axis.min, axis.max, axis.flat, axis.fuzz);
+ }
}
}
@@ -3865,18 +3868,29 @@
size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) {
const Axis& axis = mAxes.valueAt(i);
- const char* label = getAxisLabel(axis.axis);
- char name[32];
+ const char* label = getAxisLabel(axis.axisInfo.axis);
if (label) {
- strncpy(name, label, sizeof(name));
- name[sizeof(name) - 1] = '\0';
+ dump.appendFormat(INDENT4 "%s", label);
} else {
- snprintf(name, sizeof(name), "%d", axis.axis);
+ dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis);
}
- dump.appendFormat(INDENT4 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, "
- "scale=%0.3f, offset=%0.3f\n",
- name, axis.min, axis.max, axis.flat, axis.fuzz,
- axis.scale, axis.offset);
+ if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
+ label = getAxisLabel(axis.axisInfo.highAxis);
+ if (label) {
+ dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue);
+ } else {
+ dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis,
+ axis.axisInfo.splitValue);
+ }
+ } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) {
+ dump.append(" (invert)");
+ }
+
+ dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f\n",
+ axis.min, axis.max, axis.flat, axis.fuzz);
+ dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, "
+ "highScale=%0.5f, highOffset=%0.5f\n",
+ axis.scale, axis.offset, axis.highScale, axis.highOffset);
dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, rawFlat=%d, rawFuzz=%d\n",
mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz);
@@ -3891,25 +3905,38 @@
RawAbsoluteAxisInfo rawAxisInfo;
getEventHub()->getAbsoluteAxisInfo(getDeviceId(), abs, &rawAxisInfo);
if (rawAxisInfo.valid) {
- int32_t axisId;
- bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisId);
+ // Map axis.
+ AxisInfo axisInfo;
+ bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo);
if (!explicitlyMapped) {
// Axis is not explicitly mapped, will choose a generic axis later.
- axisId = -1;
+ axisInfo.mode = AxisInfo::MODE_NORMAL;
+ axisInfo.axis = -1;
}
+ // Apply flat override.
+ int32_t rawFlat = axisInfo.flatOverride < 0
+ ? rawAxisInfo.flat : axisInfo.flatOverride;
+
+ // Calculate scaling factors and limits.
Axis axis;
- if (isCenteredAxis(axisId)) {
+ if (axisInfo.mode == AxisInfo::MODE_SPLIT) {
+ float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue);
+ float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
+ axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
+ scale, 0.0f, highScale, 0.0f,
+ 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
+ } else if (isCenteredAxis(axisInfo.axis)) {
float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
- axis.initialize(rawAxisInfo, axisId, explicitlyMapped,
- scale, offset, -1.0f, 1.0f,
- rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale);
+ axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
+ scale, offset, scale, offset,
+ -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
} else {
float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
- axis.initialize(rawAxisInfo, axisId, explicitlyMapped,
- scale, 0.0f, 0.0f, 1.0f,
- rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale);
+ axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
+ scale, 0.0f, scale, 0.0f,
+ 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
}
// To eliminate noise while the joystick is at rest, filter out small variations
@@ -3934,14 +3961,14 @@
size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) {
Axis& axis = mAxes.editValueAt(i);
- if (axis.axis < 0) {
+ if (axis.axisInfo.axis < 0) {
while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16
&& haveAxis(nextGenericAxisId)) {
nextGenericAxisId += 1;
}
if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) {
- axis.axis = nextGenericAxisId;
+ axis.axisInfo.axis = nextGenericAxisId;
nextGenericAxisId += 1;
} else {
LOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids "
@@ -3954,10 +3981,13 @@
}
}
-bool JoystickInputMapper::haveAxis(int32_t axis) {
+bool JoystickInputMapper::haveAxis(int32_t axisId) {
size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) {
- if (mAxes.valueAt(i).axis == axis) {
+ const Axis& axis = mAxes.valueAt(i);
+ if (axis.axisInfo.axis == axisId
+ || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT
+ && axis.axisInfo.highAxis == axisId)) {
return true;
}
}
@@ -3987,6 +4017,8 @@
case AMOTION_EVENT_AXIS_HAT_X:
case AMOTION_EVENT_AXIS_HAT_Y:
case AMOTION_EVENT_AXIS_ORIENTATION:
+ case AMOTION_EVENT_AXIS_RUDDER:
+ case AMOTION_EVENT_AXIS_WHEEL:
return true;
default:
return false;
@@ -4000,7 +4032,7 @@
size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) {
Axis& axis = mAxes.editValueAt(i);
- axis.newValue = 0;
+ axis.resetValue();
}
sync(when, true /*force*/);
@@ -4014,10 +4046,34 @@
ssize_t index = mAxes.indexOfKey(rawEvent->scanCode);
if (index >= 0) {
Axis& axis = mAxes.editValueAt(index);
- float newValue = rawEvent->value * axis.scale + axis.offset;
- if (newValue != axis.newValue) {
- axis.newValue = newValue;
+ float newValue, highNewValue;
+ switch (axis.axisInfo.mode) {
+ case AxisInfo::MODE_INVERT:
+ newValue = (axis.rawAxisInfo.maxValue - rawEvent->value)
+ * axis.scale + axis.offset;
+ highNewValue = 0.0f;
+ break;
+ case AxisInfo::MODE_SPLIT:
+ if (rawEvent->value < axis.axisInfo.splitValue) {
+ newValue = (axis.axisInfo.splitValue - rawEvent->value)
+ * axis.scale + axis.offset;
+ highNewValue = 0.0f;
+ } else if (rawEvent->value > axis.axisInfo.splitValue) {
+ newValue = 0.0f;
+ highNewValue = (rawEvent->value - axis.axisInfo.splitValue)
+ * axis.highScale + axis.highOffset;
+ } else {
+ newValue = 0.0f;
+ highNewValue = 0.0f;
+ }
+ break;
+ default:
+ newValue = rawEvent->value * axis.scale + axis.offset;
+ highNewValue = 0.0f;
+ break;
}
+ axis.newValue = newValue;
+ axis.highNewValue = highNewValue;
}
break;
}
@@ -4033,7 +4089,7 @@
}
void JoystickInputMapper::sync(nsecs_t when, bool force) {
- if (!force && !haveAxesChangedSignificantly()) {
+ if (!filterAxes(force)) {
return;
}
@@ -4044,9 +4100,11 @@
size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) {
- Axis& axis = mAxes.editValueAt(i);
- pointerCoords.setAxisValue(axis.axis, axis.newValue);
- axis.oldValue = axis.newValue;
+ const Axis& axis = mAxes.valueAt(i);
+ pointerCoords.setAxisValue(axis.axisInfo.axis, axis.currentValue);
+ if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
+ pointerCoords.setAxisValue(axis.axisInfo.highAxis, axis.highCurrentValue);
+ }
}
// Moving a joystick axis should not wake the devide because joysticks can
@@ -4061,12 +4119,49 @@
1, &pointerId, &pointerCoords, 0, 0, 0);
}
-bool JoystickInputMapper::haveAxesChangedSignificantly() {
+bool JoystickInputMapper::filterAxes(bool force) {
+ bool atLeastOneSignificantChange = force;
size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) {
- const Axis& axis = mAxes.valueAt(i);
- if (axis.newValue != axis.oldValue
- && fabs(axis.newValue - axis.oldValue) > axis.filter) {
+ Axis& axis = mAxes.editValueAt(i);
+ if (force || hasValueChangedSignificantly(axis.filter,
+ axis.newValue, axis.currentValue, axis.min, axis.max)) {
+ axis.currentValue = axis.newValue;
+ atLeastOneSignificantChange = true;
+ }
+ if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
+ if (force || hasValueChangedSignificantly(axis.filter,
+ axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) {
+ axis.highCurrentValue = axis.highNewValue;
+ atLeastOneSignificantChange = true;
+ }
+ }
+ }
+ return atLeastOneSignificantChange;
+}
+
+bool JoystickInputMapper::hasValueChangedSignificantly(
+ float filter, float newValue, float currentValue, float min, float max) {
+ if (newValue != currentValue) {
+ // Filter out small changes in value unless the value is converging on the axis
+ // bounds or center point. This is intended to reduce the amount of information
+ // sent to applications by particularly noisy joysticks (such as PS3).
+ if (fabs(newValue - currentValue) > filter
+ || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min)
+ || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max)
+ || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange(
+ float filter, float newValue, float currentValue, float thresholdValue) {
+ float newDistance = fabs(newValue - thresholdValue);
+ if (newDistance < filter) {
+ float oldDistance = fabs(currentValue - thresholdValue);
+ if (newDistance < oldDistance) {
return true;
}
}
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 655f0f0..e2cf08e7 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -1011,38 +1011,50 @@
private:
struct Axis {
RawAbsoluteAxisInfo rawAxisInfo;
+ AxisInfo axisInfo;
- int32_t axis; // axis id
bool explicitlyMapped; // true if the axis was explicitly assigned an axis id
float scale; // scale factor from raw to normalized values
float offset; // offset to add after scaling for normalization
+ float highScale; // scale factor from raw to normalized values of high split
+ float highOffset; // offset to add after scaling for normalization of high split
float min; // normalized inclusive minimum
float max; // normalized inclusive maximum
float flat; // normalized flat region size
float fuzz; // normalized error tolerance
- float oldValue; // previous value
- float newValue; // most recent value
-
float filter; // filter out small variations of this size
+ float currentValue; // current value
+ float newValue; // most recent value
+ float highCurrentValue; // current value of high split
+ float highNewValue; // most recent value of high split
- void initialize(const RawAbsoluteAxisInfo& rawAxisInfo,
- int32_t axis, bool explicitlyMapped, float scale, float offset,
+ void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo,
+ bool explicitlyMapped, float scale, float offset,
+ float highScale, float highOffset,
float min, float max, float flat, float fuzz) {
this->rawAxisInfo = rawAxisInfo;
- this->axis = axis;
+ this->axisInfo = axisInfo;
this->explicitlyMapped = explicitlyMapped;
this->scale = scale;
this->offset = offset;
+ this->highScale = highScale;
+ this->highOffset = highOffset;
this->min = min;
this->max = max;
this->flat = flat;
this->fuzz = fuzz;
this->filter = 0;
- this->oldValue = 0;
+ resetValue();
+ }
+
+ void resetValue() {
+ this->currentValue = 0;
this->newValue = 0;
+ this->highCurrentValue = 0;
+ this->highNewValue = 0;
}
};
@@ -1051,9 +1063,14 @@
void sync(nsecs_t when, bool force);
- bool haveAxis(int32_t axis);
+ bool haveAxis(int32_t axisId);
void pruneAxes(bool ignoreExplicitlyMappedAxes);
- bool haveAxesChangedSignificantly();
+ bool filterAxes(bool force);
+
+ static bool hasValueChangedSignificantly(float filter,
+ float newValue, float currentValue, float min, float max);
+ static bool hasMovedNearerToValueWithinFilteredRange(float filter,
+ float newValue, float currentValue, float thresholdValue);
static bool isCenteredAxis(int32_t axis);
};
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 8404b3a..d77cb2f 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -592,7 +592,7 @@
}
virtual status_t mapAxis(int32_t deviceId, int scancode,
- int32_t* outAxis) const {
+ AxisInfo* outAxisInfo) const {
return NAME_NOT_FOUND;
}