diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/app/Activity.java | 23 | ||||
-rw-r--r-- | core/java/android/app/Dialog.java | 23 | ||||
-rw-r--r-- | core/java/android/service/wallpaper/WallpaperService.java | 17 | ||||
-rw-r--r-- | core/java/android/view/MotionEvent.java | 60 | ||||
-rw-r--r-- | core/java/android/view/View.java | 124 | ||||
-rw-r--r-- | core/java/android/view/ViewGroup.java | 52 | ||||
-rw-r--r-- | core/java/android/view/ViewRoot.java | 52 | ||||
-rw-r--r-- | core/java/android/webkit/WebView.java | 28 | ||||
-rw-r--r-- | core/java/android/widget/AbsListView.java | 21 | ||||
-rw-r--r-- | core/java/android/widget/HorizontalScrollView.java | 35 | ||||
-rw-r--r-- | core/java/android/widget/ScrollView.java | 30 | ||||
-rw-r--r-- | core/java/com/android/internal/widget/PointerLocationView.java | 123 |
12 files changed, 476 insertions, 112 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 67e4806..9e72c1b 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2122,24 +2122,21 @@ public class Activity extends ContextThemeWrapper * Called when a generic motion event was not handled by any of the * views inside of the activity. * <p> - * Generic motion events are dispatched to the focused view to describe - * the motions of input devices such as joysticks. The + * Generic motion events describe joystick movements, mouse hovers, track pad + * touches, scroll wheel movements and other input events. The * {@link MotionEvent#getSource() source} of the motion event specifies * the class of input that was received. Implementations of this method * must examine the bits in the source before processing the event. * The following code example shows how this is done. + * </p><p> + * Generic motion events with source class + * {@link android.view.InputDevice#SOURCE_CLASS_POINTER} + * are delivered to the view under the pointer. All other generic motion events are + * delivered to the focused view. + * </p><p> + * See {@link View#onGenericMotionEvent(MotionEvent)} for an example of how to + * handle this event. * </p> - * <code> - * public boolean onGenericMotionEvent(MotionEvent event) { - * if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { - * float x = event.getX(); - * float y = event.getY(); - * // process the joystick motion - * return true; - * } - * return super.onGenericMotionEvent(event); - * } - * </code> * * @param event The generic motion event being processed. * diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index cc4fefc..087753b 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -627,24 +627,21 @@ public class Dialog implements DialogInterface, Window.Callback, * Called when a generic motion event was not handled by any of the * views inside of the dialog. * <p> - * Generic motion events are dispatched to the focused view to describe - * the motions of input devices such as joysticks. The + * Generic motion events describe joystick movements, mouse hovers, track pad + * touches, scroll wheel movements and other input events. The * {@link MotionEvent#getSource() source} of the motion event specifies * the class of input that was received. Implementations of this method * must examine the bits in the source before processing the event. * The following code example shows how this is done. + * </p><p> + * Generic motion events with source class + * {@link android.view.InputDevice#SOURCE_CLASS_POINTER} + * are delivered to the view under the pointer. All other generic motion events are + * delivered to the focused view. + * </p><p> + * See {@link View#onGenericMotionEvent(MotionEvent)} for an example of how to + * handle this event. * </p> - * <code> - * public boolean onGenericMotionEvent(MotionEvent event) { - * if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { - * float x = event.getX(); - * float y = event.getY(); - * // process the joystick motion - * return true; - * } - * return super.onGenericMotionEvent(event); - * } - * </code> * * @param event The generic motion event being processed. * diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index dd39714..20661d7 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -460,16 +460,17 @@ public abstract class WallpaperService extends Service { } private void dispatchPointer(MotionEvent event) { - synchronized (mLock) { - if (event.getAction() == MotionEvent.ACTION_MOVE) { - mPendingMove = event; - } else { - mPendingMove = null; + if (event.isTouchEvent()) { + synchronized (mLock) { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + mPendingMove = event; + } else { + mPendingMove = null; + } } + Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event); + mCaller.sendMessage(msg); } - - Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event); - mCaller.sendMessage(msg); } void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) { diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index cc37a28..a26dd04 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -40,6 +40,12 @@ import android.util.SparseArray; * by a motion event with {@link #ACTION_UP} or when gesture is canceled * with {@link #ACTION_CANCEL}. * </p><p> + * Some pointing devices such as mice may support vertical and/or horizontal scrolling. + * A scroll event is reported as a generic motion event with {@link #ACTION_SCROLL} that + * includes the relative scroll offset in the {@link #AXIS_VSCROLL} and + * {@link #AXIS_HSCROLL} axes. See {@link #getAxisValue(int)} for information + * about retrieving these additional axes. + * </p><p> * On trackball devices with source class {@link InputDevice#SOURCE_CLASS_TRACKBALL}, * the pointer coordinates specify relative movements as X/Y deltas. * A trackball gesture consists of a sequence of movements described by motion @@ -51,6 +57,8 @@ import android.util.SparseArray; * The joystick axis values are normalized to a range of -1.0 to 1.0 where 0.0 corresponds * to the center position. More information about the set of available axes and the * range of motion can be obtained using {@link InputDevice#getMotionRange}. + * Some common joystick axes are {@link #AXIS_X}, {@link #AXIS_Y}, + * {@link #AXIS_HAT_X}, {@link #AXIS_HAT_Y}, {@link #AXIS_Z} and {@link #AXIS_RZ}. * </p><p> * Motion events always report movements for all pointers at once. The number * of pointers only ever changes by one as individual pointers go up and down, @@ -163,10 +171,30 @@ public final class MotionEvent extends InputEvent implements Parcelable { * is not down (unlike {@link #ACTION_MOVE}). The motion contains the most * recent point, as well as any intermediate points since the last * hover move event. + * <p> + * This action is not a touch event so it is delivered to + * {@link View#onGenericMotionEvent(MotionEvent)} rather than + * {@link View#onTouchEvent(MotionEvent)}. + * </p> */ public static final int ACTION_HOVER_MOVE = 7; /** + * Constant for {@link #getAction}: The motion event contains relative + * vertical and/or horizontal scroll offsets. Use {@link #getAxisValue(int)} + * to retrieve the information from {@link #AXIS_VSCROLL} and {@link #AXIS_HSCROLL}. + * The pointer may or may not be down when this event is dispatched. + * This action is always delivered to the winder under the pointer, which + * may not be the window currently touched. + * <p> + * This action is not a touch event so it is delivered to + * {@link View#onGenericMotionEvent(MotionEvent)} rather than + * {@link View#onTouchEvent(MotionEvent)}. + * </p> + */ + public static final int ACTION_SCROLL = 8; + + /** * Bits in the action code that represent a pointer index, used with * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Shifting * down by {@link #ACTION_POINTER_INDEX_SHIFT} provides the actual pointer @@ -483,7 +511,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { * <p> * <ul> * <li>For a mouse, reports the relative movement of the vertical scroll wheel. - * The value is normalized to a range from -1.0 (up) to 1.0 (down). + * The value is normalized to a range from -1.0 (down) to 1.0 (up). * </ul> * </p><p> * This axis should be used to scroll views vertically. @@ -1237,6 +1265,32 @@ public final class MotionEvent extends InputEvent implements Parcelable { } /** + * Returns true if this motion event is a touch event. + * <p> + * Specifically excludes pointer events with action {@link #ACTION_HOVER_MOVE} + * or {@link #ACTION_SCROLL} because they are not actually touch events + * (the pointer is not down). + * </p> + * @return True if this motion event is a touch event. + * @hide + */ + public final boolean isTouchEvent() { + if ((getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + switch (getActionMasked()) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_OUTSIDE: + return true; + } + } + return false; + } + + /** * Gets the motion event flags. * * @see #FLAG_WINDOW_IS_OBSCURED @@ -2174,10 +2228,14 @@ public final class MotionEvent extends InputEvent implements Parcelable { return "ACTION_UP"; case ACTION_CANCEL: return "ACTION_CANCEL"; + case ACTION_OUTSIDE: + return "ACTION_OUTSIDE"; case ACTION_MOVE: return "ACTION_MOVE"; case ACTION_HOVER_MOVE: return "ACTION_HOVER_MOVE"; + case ACTION_SCROLL: + return "ACTION_SCROLL"; } int index = (action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT; switch (action & ACTION_MASK) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 78eb2e5..01bc2df 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -57,6 +57,7 @@ import android.util.Poolable; import android.util.PoolableManager; import android.util.Pools; import android.util.SparseArray; +import android.util.TypedValue; import android.view.ContextMenu.ContextMenuInfo; import android.view.View.MeasureSpec; import android.view.accessibility.AccessibilityEvent; @@ -2128,6 +2129,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility private OnTouchListener mOnTouchListener; + private OnGenericMotionListener mOnGenericMotionListener; + private OnDragListener mOnDragListener; private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; @@ -2257,6 +2260,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility public static final int DRAG_FLAG_GLOBAL = 1; /** + * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. + */ + private float mVerticalScrollFactor; + + /** * Position of the vertical scroll bar. */ private int mVerticalScrollbarPosition; @@ -3167,6 +3175,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Register a callback to be invoked when a generic motion event is sent to this view. + * @param l the generic motion listener to attach to this view + */ + public void setOnGenericMotionListener(OnGenericMotionListener l) { + mOnGenericMotionListener = l; + } + + /** * Register a drag event listener callback object for this View. The parameter is * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a * View, the system calls the @@ -4624,16 +4640,47 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** - * Pass a generic motion event down to the focused view. + * Dispatch a generic motion event. + * <p> + * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} + * are delivered to the view under the pointer. All other generic motion events are + * delivered to the focused view. + * </p> * * @param event The motion event to be dispatched. * @return True if the event was handled by the view, false otherwise. */ public boolean dispatchGenericMotionEvent(MotionEvent event) { + if (mOnGenericMotionListener != null && (mViewFlags & ENABLED_MASK) == ENABLED + && mOnGenericMotionListener.onGenericMotion(this, event)) { + return true; + } + return onGenericMotionEvent(event); } /** + * Dispatch a pointer event. + * <p> + * Dispatches touch related pointer events to {@link #onTouchEvent} and all + * other events to {@link #onGenericMotionEvent}. This separation of concerns + * reinforces the invariant that {@link #onTouchEvent} is really about touches + * and should not be expected to handle other pointing device features. + * </p> + * + * @param event The motion event to be dispatched. + * @return True if the event was handled by the view, false otherwise. + * @hide + */ + public final boolean dispatchPointerEvent(MotionEvent event) { + if (event.isTouchEvent()) { + return dispatchTouchEvent(event); + } else { + return dispatchGenericMotionEvent(event); + } + } + + /** * Called when the window containing this view gains or loses window focus. * ViewGroups should override to route to their children. * @@ -5142,20 +5189,34 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility /** * Implement this method to handle generic motion events. * <p> - * Generic motion events are dispatched to the focused view to describe - * the motions of input devices such as joysticks. The + * Generic motion events describe joystick movements, mouse hovers, track pad + * touches, scroll wheel movements and other input events. The * {@link MotionEvent#getSource() source} of the motion event specifies * the class of input that was received. Implementations of this method * must examine the bits in the source before processing the event. * The following code example shows how this is done. + * </p><p> + * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} + * are delivered to the view under the pointer. All other generic motion events are + * delivered to the focused view. * </p> * <code> * public boolean onGenericMotionEvent(MotionEvent event) { * if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { - * float x = event.getX(); - * float y = event.getY(); - * // process the joystick motion - * return true; + * if (event.getAction() == MotionEvent.ACTION_MOVE) { + * // process the joystick movement... + * return true; + * } + * } + * if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + * switch (event.getAction()) { + * case MotionEvent.ACTION_HOVER_MOVE: + * // process the mouse hover movement... + * return true; + * case MotionEvent.ACTION_SCROLL: + * // process the scroll wheel movement... + * return true; + * } * } * return super.onGenericMotionEvent(event); * } @@ -11653,6 +11714,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Gets a scale factor that determines the distance the view should scroll + * vertically in response to {@link MotionEvent#ACTION_SCROLL}. + * @return The vertical scroll scale factor. + * @hide + */ + protected float getVerticalScrollFactor() { + if (mVerticalScrollFactor == 0) { + TypedValue outValue = new TypedValue(); + if (!mContext.getTheme().resolveAttribute( + com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { + throw new IllegalStateException( + "Expected theme to define listPreferredItemHeight."); + } + mVerticalScrollFactor = outValue.getDimension( + mContext.getResources().getDisplayMetrics()); + } + return mVerticalScrollFactor; + } + + /** + * Gets a scale factor that determines the distance the view should scroll + * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. + * @return The horizontal scroll scale factor. + * @hide + */ + protected float getHorizontalScrollFactor() { + // TODO: Should use something else. + return getVerticalScrollFactor(); + } + + /** * A MeasureSpec encapsulates the layout requirements passed from parent to child. * Each MeasureSpec represents a requirement for either the width or the height. * A MeasureSpec is comprised of a size and a mode. There are three possible @@ -11860,6 +11952,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Interface definition for a callback to be invoked when a generic motion event is + * dispatched to this view. The callback will be invoked before the generic motion + * event is given to the view. + */ + public interface OnGenericMotionListener { + /** + * Called when a generic motion event is dispatched to a view. This allows listeners to + * get a chance to respond before the target view. + * + * @param v The view the generic motion event has been dispatched to. + * @param event The MotionEvent object containing full information about + * the event. + * @return True if the listener has consumed the event, false otherwise. + */ + boolean onGenericMotion(View v, MotionEvent event); + } + + /** * Interface definition for a callback to be invoked when a view has been clicked and held. */ public interface OnLongClickListener { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index a0d4263..5c06151 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1145,6 +1145,53 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ @Override public boolean dispatchGenericMotionEvent(MotionEvent event) { + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + // Send the event to the child under the pointer. + final int childrenCount = mChildrenCount; + if (childrenCount != 0) { + final View[] children = mChildren; + final float x = event.getX(); + final float y = event.getY(); + + for (int i = childrenCount - 1; i >= 0; i--) { + final View child = children[i]; + if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE + && child.getAnimation() == null) { + // Skip invisible child unless it is animating. + continue; + } + + if (!isTransformedTouchPointInView(x, y, child, null)) { + // Scroll point is out of child's bounds. + continue; + } + + final float offsetX = mScrollX - child.mLeft; + final float offsetY = mScrollY - child.mTop; + final boolean handled; + if (!child.hasIdentityMatrix()) { + MotionEvent transformedEvent = MotionEvent.obtain(event); + transformedEvent.offsetLocation(offsetX, offsetY); + transformedEvent.transform(child.getInverseMatrix()); + handled = child.dispatchGenericMotionEvent(transformedEvent); + transformedEvent.recycle(); + } else { + event.offsetLocation(offsetX, offsetY); + handled = child.dispatchGenericMotionEvent(event); + event.offsetLocation(-offsetX, -offsetY); + } + + if (handled) { + return true; + } + } + } + + // No child handled the event. Send it to this view group. + return super.dispatchGenericMotionEvent(event); + } + + // Send the event to the focused child or to this view group if it has focus. if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { return super.dispatchGenericMotionEvent(event); } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { @@ -1178,7 +1225,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Check for interception. final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN - || actionMasked == MotionEvent.ACTION_HOVER_MOVE || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { @@ -1188,6 +1234,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager intercepted = false; } } else { + // There are no touch targets and this action is not an initial down + // so this view group continues to intercept touches. intercepted = true; } @@ -1548,8 +1596,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int newAction; if (cancel) { newAction = MotionEvent.ACTION_CANCEL; - } else if (oldAction == MotionEvent.ACTION_HOVER_MOVE) { - newAction = MotionEvent.ACTION_HOVER_MOVE; } else { final int oldMaskedAction = oldAction & MotionEvent.ACTION_MASK; if (oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 39f99b8..c7b1955 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -2247,7 +2247,7 @@ public final class ViewRoot extends Handler implements ViewParent, private void deliverPointerEvent(MotionEvent event, boolean sendDone) { // If there is no view, then the event will not be handled. if (mView == null || !mAdded) { - finishPointerEvent(event, sendDone, false); + finishMotionEvent(event, sendDone, false); return; } @@ -2270,7 +2270,7 @@ public final class ViewRoot extends Handler implements ViewParent, event.offsetLocation(0, mCurScrollY); } if (MEASURE_LATENCY) { - lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano()); + lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano()); } // Remember the touch position for possible drag-initiation. @@ -2278,12 +2278,12 @@ public final class ViewRoot extends Handler implements ViewParent, mLastTouchPoint.y = event.getRawY(); // Dispatch touch to view hierarchy. - boolean handled = mView.dispatchTouchEvent(event); + boolean handled = mView.dispatchPointerEvent(event); if (MEASURE_LATENCY) { - lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano()); + lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano()); } if (handled) { - finishPointerEvent(event, sendDone, true); + finishMotionEvent(event, sendDone, true); return; } @@ -2325,23 +2325,27 @@ public final class ViewRoot extends Handler implements ViewParent, if (nearest != null) { event.offsetLocation(deltas[0], deltas[1]); event.setEdgeFlags(0); - if (mView.dispatchTouchEvent(event)) { - finishPointerEvent(event, sendDone, true); + if (mView.dispatchPointerEvent(event)) { + finishMotionEvent(event, sendDone, true); return; } } } // Pointer event was unhandled. - finishPointerEvent(event, sendDone, false); + finishMotionEvent(event, sendDone, false); } - private void finishPointerEvent(MotionEvent event, boolean sendDone, boolean handled) { + private void finishMotionEvent(MotionEvent event, boolean sendDone, boolean handled) { event.recycle(); if (sendDone) { finishInputEvent(handled); } - if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!"); + if (LOCAL_LOGV || WATCH_POINTER) { + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + Log.i(TAG, "Done dispatching!"); + } + } } private void deliverTrackballEvent(MotionEvent event, boolean sendDone) { @@ -2349,7 +2353,7 @@ public final class ViewRoot extends Handler implements ViewParent, // If there is no view, then the event will not be handled. if (mView == null || !mAdded) { - finishTrackballEvent(event, sendDone, false); + finishMotionEvent(event, sendDone, false); return; } @@ -2361,7 +2365,7 @@ public final class ViewRoot extends Handler implements ViewParent, // touch mode here. ensureTouchMode(false); - finishTrackballEvent(event, sendDone, true); + finishMotionEvent(event, sendDone, true); mLastTrackballTime = Integer.MIN_VALUE; return; } @@ -2471,14 +2475,7 @@ public final class ViewRoot extends Handler implements ViewParent, // Unfortunately we can't tell whether the application consumed the keys, so // we always consider the trackball event handled. - finishTrackballEvent(event, sendDone, true); - } - - private void finishTrackballEvent(MotionEvent event, boolean sendDone, boolean handled) { - event.recycle(); - if (sendDone) { - finishInputEvent(handled); - } + finishMotionEvent(event, sendDone, true); } private void deliverGenericMotionEvent(MotionEvent event, boolean sendDone) { @@ -2490,7 +2487,7 @@ public final class ViewRoot extends Handler implements ViewParent, if (isJoystick) { updateJoystickDirection(event, false); } - finishGenericMotionEvent(event, sendDone, false); + finishMotionEvent(event, sendDone, false); return; } @@ -2499,23 +2496,16 @@ public final class ViewRoot extends Handler implements ViewParent, if (isJoystick) { updateJoystickDirection(event, false); } - finishGenericMotionEvent(event, sendDone, true); + finishMotionEvent(event, sendDone, true); return; } if (isJoystick) { // Translate the joystick event into DPAD keys and try to deliver those. updateJoystickDirection(event, true); - finishGenericMotionEvent(event, sendDone, true); + finishMotionEvent(event, sendDone, true); } else { - finishGenericMotionEvent(event, sendDone, false); - } - } - - private void finishGenericMotionEvent(MotionEvent event, boolean sendDone, boolean handled) { - event.recycle(); - if (sendDone) { - finishInputEvent(handled); + finishMotionEvent(event, sendDone, false); } } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 06cb64e..98fc290 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -62,6 +62,7 @@ import android.util.EventLog; import android.util.Log; import android.view.Gravity; import android.view.HardwareCanvas; +import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -6147,6 +6148,33 @@ public class WebView extends AbsoluteLayout nativeHideCursor(); } + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + switch (event.getAction()) { + case MotionEvent.ACTION_SCROLL: { + final float vscroll; + final float hscroll; + if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) { + vscroll = 0; + hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL); + } else { + vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL); + hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL); + } + if (hscroll != 0 || vscroll != 0) { + final int vdelta = (int) (vscroll * getVerticalScrollFactor()); + final int hdelta = (int) (hscroll * getHorizontalScrollFactor()); + if (pinScrollBy(hdelta, vdelta, true, 0)) { + return true; + } + } + } + } + } + return super.onGenericMotionEvent(event); + } + private long mTrackballFirstTime = 0; private long mTrackballLastTime = 0; private float mTrackballRemainsX = 0.0f; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index eb53e56..c2c8d16 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -43,6 +43,7 @@ import android.view.ActionMode; import android.view.ContextMenu.ContextMenuInfo; import android.view.Gravity; import android.view.HapticFeedbackConstants; +import android.view.InputDevice; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; @@ -3261,6 +3262,26 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } @Override + public boolean onGenericMotionEvent(MotionEvent event) { + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + switch (event.getAction()) { + case MotionEvent.ACTION_SCROLL: { + if (mTouchMode == TOUCH_MODE_REST) { + final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL); + if (vscroll != 0) { + final int delta = (int) (vscroll * getVerticalScrollFactor()); + if (trackMotionScroll(delta, delta)) { + return true; + } + } + } + } + } + } + return super.onGenericMotionEvent(event); + } + + @Override public void draw(Canvas canvas) { super.draw(canvas); if (mEdgeGlowTop != null) { diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index e26e99b..3255f6f 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -26,6 +26,7 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.FocusFinder; +import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -634,6 +635,40 @@ public class HorizontalScrollView extends FrameLayout { } @Override + public boolean onGenericMotionEvent(MotionEvent event) { + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + switch (event.getAction()) { + case MotionEvent.ACTION_SCROLL: { + if (!mIsBeingDragged) { + final float hscroll; + if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) { + hscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL); + } else { + hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL); + } + if (hscroll != 0) { + final int delta = (int) (hscroll * getHorizontalScrollFactor()); + final int range = getScrollRange(); + int oldScrollX = mScrollX; + int newScrollX = oldScrollX + delta; + if (newScrollX < 0) { + newScrollX = 0; + } else if (newScrollX > range) { + newScrollX = range; + } + if (newScrollX != oldScrollX) { + super.scrollTo(newScrollX, mScrollY); + return true; + } + } + } + } + } + } + return super.onGenericMotionEvent(event); + } + + @Override protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { // Treat animating scrolls differently; see #computeScroll() for why. diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 9932320..7aca0db 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -27,6 +27,7 @@ import android.graphics.drawable.Drawable; import android.os.StrictMode; import android.util.AttributeSet; import android.view.FocusFinder; +import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -631,6 +632,35 @@ public class ScrollView extends FrameLayout { } @Override + public boolean onGenericMotionEvent(MotionEvent event) { + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + switch (event.getAction()) { + case MotionEvent.ACTION_SCROLL: { + if (!mIsBeingDragged) { + final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL); + if (vscroll != 0) { + final int delta = (int) (vscroll * getVerticalScrollFactor()); + final int range = getScrollRange(); + int oldScrollY = mScrollY; + int newScrollY = oldScrollY - delta; + if (newScrollY < 0) { + newScrollY = 0; + } else if (newScrollY > range) { + newScrollY = range; + } + if (newScrollY != oldScrollY) { + super.scrollTo(mScrollX, newScrollY); + return true; + } + } + } + } + } + } + return super.onGenericMotionEvent(event); + } + + @Override protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { // Treat animating scrolls differently; see #computeScroll() for why. diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index c72d0e8..5ac903d 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -318,10 +318,56 @@ public class PointerLocationView extends View { } } - private void logPointerCoords(MotionEvent.PointerCoords coords, int id) { + private void logPointerCoords(int action, int index, MotionEvent.PointerCoords coords, int id) { + final String prefix; + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: + prefix = "DOWN"; + break; + case MotionEvent.ACTION_UP: + prefix = "UP"; + break; + case MotionEvent.ACTION_MOVE: + prefix = "MOVE"; + break; + case MotionEvent.ACTION_CANCEL: + prefix = "CANCEL"; + break; + case MotionEvent.ACTION_OUTSIDE: + prefix = "OUTSIDE"; + break; + case MotionEvent.ACTION_POINTER_DOWN: + if (index == ((action & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT)) { + prefix = "DOWN"; + } else { + prefix = "MOVE"; + } + break; + case MotionEvent.ACTION_POINTER_UP: + if (index == ((action & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT)) { + prefix = "UP"; + } else { + prefix = "MOVE"; + } + break; + case MotionEvent.ACTION_HOVER_MOVE: + prefix = "HOVER MOVE"; + break; + case MotionEvent.ACTION_SCROLL: + prefix = "SCROLL"; + break; + default: + prefix = Integer.toString(action); + break; + } + Log.i(TAG, mText.clear() .append("Pointer ").append(id + 1) - .append(": (").append(coords.x, 3).append(", ").append(coords.y, 3) + .append(": ") + .append(prefix) + .append(" (").append(coords.x, 3).append(", ").append(coords.y, 3) .append(") Pressure=").append(coords.pressure, 3) .append(" Size=").append(coords.size, 3) .append(" TouchMajor=").append(coords.touchMajor, 3) @@ -335,7 +381,7 @@ public class PointerLocationView extends View { .toString()); } - public void addTouchEvent(MotionEvent event) { + public void addPointerEvent(MotionEvent event) { synchronized (mPointers) { int action = event.getAction(); @@ -363,10 +409,16 @@ public class PointerLocationView extends View { ps.mCurDown = false; } mCurDown = true; + mCurNumPointers = 0; mMaxNumPointers = 0; mVelocity.clear(); } - + + mCurNumPointers += 1; + if (mMaxNumPointers < mCurNumPointers) { + mMaxNumPointers = mCurNumPointers; + } + final int id = event.getPointerId(index); while (NP <= id) { PointerState ps = new PointerState(); @@ -375,49 +427,41 @@ public class PointerLocationView extends View { } if (mActivePointerId < 0 || - ! mPointers.get(mActivePointerId).mCurDown) { + !mPointers.get(mActivePointerId).mCurDown) { mActivePointerId = id; } final PointerState ps = mPointers.get(id); ps.mCurDown = true; - if (mPrintCoords) { - Log.i(TAG, mText.clear().append("Pointer ") - .append(id + 1).append(": DOWN").toString()); - } } - - final int NI = event.getPointerCount(); - final boolean hover = (action == MotionEvent.ACTION_HOVER_MOVE); - mCurDown = action != MotionEvent.ACTION_UP - && action != MotionEvent.ACTION_CANCEL - && !hover; - mCurNumPointers = mCurDown ? NI : 0; - if (mMaxNumPointers < mCurNumPointers) { - mMaxNumPointers = mCurNumPointers; - } + final int NI = event.getPointerCount(); mVelocity.addMovement(event); mVelocity.computeCurrentVelocity(1); - - for (int i=0; i<NI; i++) { - final int id = event.getPointerId(i); - final PointerState ps = hover ? null : mPointers.get(id); - final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords; - final int N = event.getHistorySize(); - for (int j=0; j<N; j++) { - event.getHistoricalPointerCoords(i, j, coords); + + final int N = event.getHistorySize(); + for (int historyPos = 0; historyPos < N; historyPos++) { + for (int i = 0; i < NI; i++) { + final int id = event.getPointerId(i); + final PointerState ps = mCurDown ? mPointers.get(id) : null; + final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords; + event.getHistoricalPointerCoords(i, historyPos, coords); if (mPrintCoords) { - logPointerCoords(coords, id); + logPointerCoords(action, i, coords, id); } if (ps != null) { - ps.addTrace(event.getHistoricalX(i, j), event.getHistoricalY(i, j)); + ps.addTrace(coords.x, coords.y); } } + } + for (int i = 0; i < NI; i++) { + final int id = event.getPointerId(i); + final PointerState ps = mCurDown ? mPointers.get(id) : null; + final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords; event.getPointerCoords(i, coords); if (mPrintCoords) { - logPointerCoords(coords, id); + logPointerCoords(action, i, coords, id); } if (ps != null) { ps.addTrace(coords.x, coords.y); @@ -425,7 +469,7 @@ public class PointerLocationView extends View { ps.mYVelocity = mVelocity.getYVelocity(id); } } - + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) { @@ -435,15 +479,13 @@ public class PointerLocationView extends View { final int id = event.getPointerId(index); final PointerState ps = mPointers.get(id); ps.mCurDown = false; - if (mPrintCoords) { - Log.i(TAG, mText.clear().append("Pointer ") - .append(id + 1).append(": UP").toString()); - } if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { mCurDown = false; + mCurNumPointers = 0; } else { + mCurNumPointers -= 1; if (mActivePointerId == id) { mActivePointerId = event.getPointerId(index == 0 ? 1 : 0); } @@ -462,11 +504,20 @@ public class PointerLocationView extends View { @Override public boolean onTouchEvent(MotionEvent event) { - addTouchEvent(event); + addPointerEvent(event); return true; } @Override + public boolean onGenericMotionEvent(MotionEvent event) { + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + addPointerEvent(event); + return true; + } + return super.onGenericMotionEvent(event); + } + + @Override public boolean onTrackballEvent(MotionEvent event) { Log.i(TAG, "Trackball: " + event); return super.onTrackballEvent(event); |