diff options
-rw-r--r-- | api/current.xml | 11 | ||||
-rw-r--r-- | core/java/android/view/ScaleGestureDetector.java | 254 | ||||
-rw-r--r-- | core/java/android/webkit/WebView.java | 27 | ||||
-rw-r--r-- | core/java/android/widget/DatePicker.java | 11 | ||||
-rw-r--r-- | core/java/android/widget/NumberPicker.java | 5 | ||||
-rw-r--r-- | graphics/java/android/graphics/SurfaceTexture.java | 8 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java | 122 |
7 files changed, 342 insertions, 96 deletions
diff --git a/api/current.xml b/api/current.xml index 37318ff..bf388b1 100644 --- a/api/current.xml +++ b/api/current.xml @@ -249696,6 +249696,17 @@ <parameter name="defStyle" type="int"> </parameter> </constructor> +<method name="getCalendarView" + return="android.widget.CalendarView" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getCalendarViewShown" return="boolean" abstract="false" diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 17b5dd7..218ee4f 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -154,6 +154,11 @@ public class ScaleGestureDetector { private float mBottomSlopEdge; private boolean mSloppyGesture; + // Pointer IDs currently responsible for the two fingers controlling the gesture + private int mActiveId0; + private int mActiveId1; + private boolean mActive0MostRecent; + public ScaleGestureDetector(Context context, OnScaleGestureListener listener) { ViewConfiguration config = ViewConfiguration.get(context); mContext = context; @@ -162,11 +167,21 @@ public class ScaleGestureDetector { } public boolean onTouchEvent(MotionEvent event) { - final int action = event.getAction(); + final int action = event.getActionMasked(); boolean handled = true; if (!mGestureInProgress) { - switch (action & MotionEvent.ACTION_MASK) { + switch (action) { + case MotionEvent.ACTION_DOWN: { + mActiveId0 = event.getPointerId(0); + mActive0MostRecent = true; + } + break; + + case MotionEvent.ACTION_UP: + reset(); + break; + case MotionEvent.ACTION_POINTER_DOWN: { // We have a new multi-finger gesture @@ -175,12 +190,15 @@ public class ScaleGestureDetector { mRightSlopEdge = metrics.widthPixels - mEdgeSlop; mBottomSlopEdge = metrics.heightPixels - mEdgeSlop; - // Be paranoid in case we missed an event - reset(); - + if (mPrevEvent != null) mPrevEvent.recycle(); mPrevEvent = MotionEvent.obtain(event); mTimeDelta = 0; + int index1 = event.getActionIndex(); + int index0 = event.findPointerIndex(mActiveId0); + mActiveId1 = event.getPointerId(index1); + mActive0MostRecent = false; + setContext(event); // Check if we have a sloppy gesture. If so, delay @@ -190,10 +208,10 @@ public class ScaleGestureDetector { final float edgeSlop = mEdgeSlop; final float rightSlop = mRightSlopEdge; final float bottomSlop = mBottomSlopEdge; - final float x0 = event.getRawX(); - final float y0 = event.getRawY(); - final float x1 = getRawX(event, 1); - final float y1 = getRawY(event, 1); + float x0 = getRawX(event, index0); + float y0 = getRawY(event, index0); + float x1 = getRawX(event, index1); + float y1 = getRawY(event, index1); boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlop || y0 > bottomSlop; @@ -205,14 +223,15 @@ public class ScaleGestureDetector { mFocusY = -1; mSloppyGesture = true; } else if (p0sloppy) { - mFocusX = event.getX(1); - mFocusY = event.getY(1); + mFocusX = event.getX(index1); + mFocusY = event.getY(index1); mSloppyGesture = true; } else if (p1sloppy) { - mFocusX = event.getX(0); - mFocusY = event.getY(0); + mFocusX = event.getX(index0); + mFocusY = event.getY(index0); mSloppyGesture = true; } else { + mSloppyGesture = false; mGestureInProgress = mListener.onScaleBegin(this); } } @@ -224,25 +243,51 @@ public class ScaleGestureDetector { final float edgeSlop = mEdgeSlop; final float rightSlop = mRightSlopEdge; final float bottomSlop = mBottomSlopEdge; - final float x0 = event.getRawX(); - final float y0 = event.getRawY(); - final float x1 = getRawX(event, 1); - final float y1 = getRawY(event, 1); + int index0 = event.findPointerIndex(mActiveId0); + int index1 = event.findPointerIndex(mActiveId1); + float x0 = getRawX(event, index0); + float y0 = getRawY(event, index0); + float x1 = getRawX(event, index1); + float y1 = getRawY(event, index1); boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop - || x0 > rightSlop || y0 > bottomSlop; + || x0 > rightSlop || y0 > bottomSlop; boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop - || x1 > rightSlop || y1 > bottomSlop; + || x1 > rightSlop || y1 > bottomSlop; + + if (p0sloppy) { + // Do we have a different pointer that isn't sloppy? + int index = findNewActiveIndex(event, mActiveId1, index0); + if (index >= 0) { + index0 = index; + mActiveId0 = event.getPointerId(index); + x0 = getRawX(event, index); + y0 = getRawY(event, index); + p0sloppy = false; + } + } + + if (p1sloppy) { + // Do we have a different pointer that isn't sloppy? + int index = findNewActiveIndex(event, mActiveId0, index1); + if (index >= 0) { + index1 = index; + mActiveId1 = event.getPointerId(index); + x1 = getRawX(event, index); + y1 = getRawY(event, index); + p1sloppy = false; + } + } if(p0sloppy && p1sloppy) { mFocusX = -1; mFocusY = -1; } else if (p0sloppy) { - mFocusX = event.getX(1); - mFocusY = event.getY(1); + mFocusX = event.getX(index1); + mFocusY = event.getY(index1); } else if (p1sloppy) { - mFocusX = event.getX(0); - mFocusY = event.getY(0); + mFocusX = event.getX(index0); + mFocusY = event.getY(index0); } else { mSloppyGesture = false; mGestureInProgress = mListener.onScaleBegin(this); @@ -252,43 +297,109 @@ public class ScaleGestureDetector { case MotionEvent.ACTION_POINTER_UP: if (mSloppyGesture) { - // Set focus point to the remaining finger - int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0; - mFocusX = event.getX(id); - mFocusY = event.getY(id); + final int pointerCount = event.getPointerCount(); + final int actionIndex = event.getActionIndex(); + final int actionId = event.getPointerId(actionIndex); + + if (pointerCount > 2) { + if (actionId == mActiveId0) { + final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex); + if (newIndex >= 0) mActiveId0 = event.getPointerId(newIndex); + } else if (actionId == mActiveId1) { + final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex); + if (newIndex >= 0) mActiveId1 = event.getPointerId(newIndex); + } + } else { + // Set focus point to the remaining finger + final int index = event.findPointerIndex(actionId == mActiveId0 ? + mActiveId1 : mActiveId0); + mActiveId0 = event.getPointerId(index); + mActive0MostRecent = true; + mActiveId1 = -1; + mFocusX = event.getX(index); + mFocusY = event.getY(index); + } } break; } } else { // Transform gesture in progress - attempt to handle it - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_POINTER_UP: - // Gesture ended + switch (action) { + case MotionEvent.ACTION_POINTER_DOWN: { + // End the old gesture and begin a new one with the most recent two fingers. + mListener.onScaleEnd(this); + final int oldActive0 = mActiveId0; + final int oldActive1 = mActiveId1; + reset(); + + mPrevEvent = MotionEvent.obtain(event); + mActiveId0 = mActive0MostRecent ? oldActive0 : oldActive1; + mActiveId1 = event.getPointerId(event.getActionIndex()); + mActive0MostRecent = false; + setContext(event); - // Set focus point to the remaining finger - int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0; - mFocusX = event.getX(id); - mFocusY = event.getY(id); + mGestureInProgress = mListener.onScaleBegin(this); + } + break; - if (!mSloppyGesture) { - mListener.onScaleEnd(this); + case MotionEvent.ACTION_POINTER_UP: { + final int pointerCount = event.getPointerCount(); + final int actionIndex = event.getActionIndex(); + final int actionId = event.getPointerId(actionIndex); + + boolean gestureEnded = false; + if (pointerCount > 2) { + if (actionId == mActiveId0) { + final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex); + if (newIndex >= 0) { + mActiveId0 = event.getPointerId(newIndex); + } else { + gestureEnded = true; + } + } else if (actionId == mActiveId1) { + final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex); + if (newIndex >= 0) { + mActiveId1 = event.getPointerId(newIndex); + } else { + gestureEnded = true; + } + } + mPrevEvent.recycle(); + mPrevEvent = MotionEvent.obtain(event); + setContext(event); + } else { + gestureEnded = true; } - reset(); - break; + if (gestureEnded) { + // Gesture ended + setContext(event); + + // Set focus point to the remaining finger + final int activeId = actionId == mActiveId0 ? mActiveId1 : mActiveId0; + final int index = event.findPointerIndex(activeId); + mFocusX = event.getX(index); + mFocusY = event.getY(index); - case MotionEvent.ACTION_CANCEL: - if (!mSloppyGesture) { mListener.onScaleEnd(this); + reset(); + mActiveId0 = activeId; + mActive0MostRecent = true; } + } + break; + case MotionEvent.ACTION_CANCEL: + mListener.onScaleEnd(this); reset(); break; - case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_UP: + reset(); + break; + + case MotionEvent.ACTION_MOVE: { setContext(event); // Only accept the event if our relative pressure is within @@ -302,16 +413,43 @@ public class ScaleGestureDetector { mPrevEvent = MotionEvent.obtain(event); } } - break; + } + break; } } return handled; } + private int findNewActiveIndex(MotionEvent ev, int otherActiveId, int oldIndex) { + final int pointerCount = ev.getPointerCount(); + + // It's ok if this isn't found and returns -1, it simply won't match. + final int otherActiveIndex = ev.findPointerIndex(otherActiveId); + int newActiveIndex = -1; + + // Pick a new id and update tracking state. Only pick pointers not on the slop edges. + for (int i = 0; i < pointerCount; i++) { + if (i != oldIndex && i != otherActiveIndex) { + final float edgeSlop = mEdgeSlop; + final float rightSlop = mRightSlopEdge; + final float bottomSlop = mBottomSlopEdge; + float x = getRawX(ev, i); + float y = getRawY(ev, i); + if (x >= edgeSlop && y >= edgeSlop && x <= rightSlop && y <= bottomSlop) { + newActiveIndex = i; + break; + } + } + } + + return newActiveIndex; + } + /** * MotionEvent has no getRawX(int) method; simulate it pending future API approval. */ private static float getRawX(MotionEvent event, int pointerIndex) { + if (pointerIndex == 0) return event.getRawX(); float offset = event.getRawX() - event.getX(); return event.getX(pointerIndex) + offset; } @@ -320,6 +458,7 @@ public class ScaleGestureDetector { * MotionEvent has no getRawY(int) method; simulate it pending future API approval. */ private static float getRawY(MotionEvent event, int pointerIndex) { + if (pointerIndex == 0) return event.getRawY(); float offset = event.getRawY() - event.getY(); return event.getY(pointerIndex) + offset; } @@ -336,14 +475,19 @@ public class ScaleGestureDetector { final MotionEvent prev = mPrevEvent; - final float px0 = prev.getX(0); - final float py0 = prev.getY(0); - final float px1 = prev.getX(1); - final float py1 = prev.getY(1); - final float cx0 = curr.getX(0); - final float cy0 = curr.getY(0); - final float cx1 = curr.getX(1); - final float cy1 = curr.getY(1); + final int prevIndex0 = prev.findPointerIndex(mActiveId0); + final int prevIndex1 = prev.findPointerIndex(mActiveId1); + final int currIndex0 = curr.findPointerIndex(mActiveId0); + final int currIndex1 = curr.findPointerIndex(mActiveId1); + + final float px0 = prev.getX(prevIndex0); + final float py0 = prev.getY(prevIndex0); + final float px1 = prev.getX(prevIndex1); + final float py1 = prev.getY(prevIndex1); + final float cx0 = curr.getX(currIndex0); + final float cy0 = curr.getY(currIndex0); + final float cx1 = curr.getX(currIndex1); + final float cy1 = curr.getY(currIndex1); final float pvx = px1 - px0; final float pvy = py1 - py0; @@ -357,8 +501,8 @@ public class ScaleGestureDetector { mFocusX = cx0 + cvx * 0.5f; mFocusY = cy0 + cvy * 0.5f; mTimeDelta = curr.getEventTime() - prev.getEventTime(); - mCurrPressure = curr.getPressure(0) + curr.getPressure(1); - mPrevPressure = prev.getPressure(0) + prev.getPressure(1); + mCurrPressure = curr.getPressure(currIndex0) + curr.getPressure(currIndex1); + mPrevPressure = prev.getPressure(prevIndex0) + prev.getPressure(prevIndex1); } private void reset() { @@ -372,6 +516,8 @@ public class ScaleGestureDetector { } mSloppyGesture = false; mGestureInProgress = false; + mActiveId0 = -1; + mActiveId1 = -1; } /** diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index f8ece6b..06cb64e 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -5414,12 +5414,20 @@ public class WebView extends AbsoluteLayout // If WebKit already showed no interests in this sequence of events, // WebView handles them directly. - if (mPreventDefault == PREVENT_DEFAULT_NO && action == MotionEvent.ACTION_MOVE) { + if (mPreventDefault == PREVENT_DEFAULT_NO) { handleMultiTouchInWebView(ev); } else { passMultiTouchToWebKit(ev); } return true; + } 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); + } } // Skip ACTION_MOVE for single touch if it's still handling multi-touch. @@ -5959,23 +5967,6 @@ public class WebView extends AbsoluteLayout float x = ev.getX(); float y = ev.getY(); - if (!detector.isInProgress() && - ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) { - // Insert a fake pointer down event in order to start - // the zoom scale detector. - MotionEvent temp = MotionEvent.obtain(ev); - // Clear the original event and set it to - // ACTION_POINTER_DOWN. - try { - temp.setAction(temp.getAction() & - ~MotionEvent.ACTION_MASK | - MotionEvent.ACTION_POINTER_DOWN); - detector.onTouchEvent(temp); - } finally { - temp.recycle(); - } - } - detector.onTouchEvent(ev); if (detector.isInProgress()) { diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index cd3862f..df32c51 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -366,12 +366,23 @@ public class DatePicker extends FrameLayout { * Gets whether the {@link CalendarView} is shown. * * @return True if the calendar view is shown. + * @see #getCalendarView() */ public boolean getCalendarViewShown() { return mCalendarView.isShown(); } /** + * Gets the {@link CalendarView}. + * + * @return The calendar view. + * @see #getCalendarViewShown() + */ + public CalendarView getCalendarView () { + return mCalendarView; + } + + /** * Sets whether the {@link CalendarView} is shown. * * @param shown True if the calendar view is to be shown. diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index 8e660ff..7a59178 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -608,6 +608,7 @@ public class NumberPicker extends LinearLayout { case MotionEvent.ACTION_DOWN: mLastMotionEventY = mLastDownEventY = event.getY(); removeAllCallbacks(); + hideInputControls(); mBeginEditOnUpEvent = false; mAdjustScrollerOnUpEvent = true; if (mDrawSelectorWheel) { @@ -620,7 +621,6 @@ public class NumberPicker extends LinearLayout { } mBeginEditOnUpEvent = scrollersFinished; mAdjustScrollerOnUpEvent = true; - hideInputControls(); return true; } if (isEventInViewHitRect(event, mInputText) @@ -630,7 +630,6 @@ public class NumberPicker extends LinearLayout { && isEventInViewHitRect(event, mDecrementButton))) { mAdjustScrollerOnUpEvent = false; setDrawSelectorWheel(true); - hideInputControls(); return true; } break; @@ -641,7 +640,6 @@ public class NumberPicker extends LinearLayout { mBeginEditOnUpEvent = false; onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); setDrawSelectorWheel(true); - hideInputControls(); return true; } break; @@ -1265,7 +1263,6 @@ public class NumberPicker extends LinearLayout { } } - postAdjustScrollerCommand(flingScroller.getDuration()); invalidate(); } diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java index ab75b81..2d23fe9 100644 --- a/graphics/java/android/graphics/SurfaceTexture.java +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -45,13 +45,7 @@ import android.os.Message; * be done by transforming (1, 1, 0, 1). * * <p>The texture object uses the GL_TEXTURE_EXTERNAL_OES texture target, which is defined by the - * {@link http://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image_external.txt - * GL_OES_EGL_image_external} OpenGL ES extension. This limits how the texture may be used. Each - * time the texture is bound it must be bound to the GL_TEXTURE_EXTERNAL_OES target rather than the - * GL_TEXTURE_2D target. Additionally, any OpenGL ES 2.0 shader that samples from the texture must - * declare its use of this extension using, for example, an "#extension GL_OES_EGL_image_external : - * require" directive. Such shaders must also access the texture using the samplerExternalOES GLSL - * sampler type. + * OES_EGL_image_external OpenGL ES extension. This limits how the texture may be used. * * <p>SurfaceTexture objects may be created on any thread. {@link #updateTexImage} may only be * called on the thread with the OpenGL ES context that contains the texture object. The 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 fac2fcd..233d601 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -349,7 +349,7 @@ public class TabletStatusBar extends StatusBar implements // the button to open the notification area mNotificationTrigger = sb.findViewById(R.id.notificationTrigger); - mNotificationTrigger.setOnClickListener(mOnClickListener); + mNotificationTrigger.setOnTouchListener(new NotificationTriggerTouchListener()); // the more notifications icon mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons); @@ -881,6 +881,9 @@ public class TabletStatusBar extends StatusBar implements } public void animateExpand() { + mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK); + mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK); + mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK); mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL); mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL); } @@ -892,6 +895,8 @@ public class TabletStatusBar extends StatusBar implements mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL); mHandler.removeMessages(MSG_CLOSE_INPUT_METHODS_PANEL); mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL); + mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK); + mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK); } // called by StatusBar @@ -1126,10 +1131,74 @@ public class TabletStatusBar extends StatusBar implements return entry.notification; } + private class NotificationTriggerTouchListener implements View.OnTouchListener { + VelocityTracker mVT; + float mInitialTouchX, mInitialTouchY; + int mTouchSlop; + + public NotificationTriggerTouchListener() { + mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); + } + + public boolean onTouch(View v, MotionEvent event) { +// Slog.d(TAG, String.format("touch: (%.1f, %.1f) initial: (%.1f, %.1f)", +// event.getX(), +// event.getY(), +// mInitialTouchX, +// mInitialTouchY)); + final int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + mVT = VelocityTracker.obtain(); + mInitialTouchX = event.getX(); + mInitialTouchY = event.getY(); + // fall through + case MotionEvent.ACTION_OUTSIDE: + case MotionEvent.ACTION_MOVE: + // check for fling + if (mVT != null) { + mVT.addMovement(event); + mVT.computeCurrentVelocity(1000); // pixels per second + // require a little more oomph once we're already in peekaboo mode + if (mVT.getYVelocity() < -mNotificationFlingVelocity) { + animateExpand(); + mVT.recycle(); + mVT = null; + } + } + return true; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + if (mVT != null) { + if (action == MotionEvent.ACTION_UP + // was this a sloppy tap? + && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop + && Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3) + // dragging off the bottom doesn't count + && (int)event.getY() < v.getBottom()) { + animateExpand(); + } + + mVT.recycle(); + mVT = null; + return true; + } + } + return false; + } + } + private class NotificationIconTouchListener implements View.OnTouchListener { + final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms + final static int NOTIFICATION_PEEK_FADE_DELAY = 5000; // ms + VelocityTracker mVT; + int mPeekIndex; + float mInitialTouchX, mInitialTouchY; + int mTouchSlop; public NotificationIconTouchListener() { + mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } public boolean onTouch(View v, MotionEvent event) { @@ -1137,34 +1206,46 @@ public class TabletStatusBar extends StatusBar implements boolean panelShowing = mNotificationPanel.isShowing(); if (panelShowing) return false; - switch (event.getAction()) { + int numIcons = mIconLayout.getChildCount(); + int newPeekIndex = (int)(event.getX() * numIcons / mIconLayout.getWidth()); + if (newPeekIndex > numIcons - 1) newPeekIndex = numIcons - 1; + else if (newPeekIndex < 0) newPeekIndex = 0; + + final int action = event.getAction(); + switch (action) { case MotionEvent.ACTION_DOWN: mVT = VelocityTracker.obtain(); + mInitialTouchX = event.getX(); + mInitialTouchY = event.getY(); + mPeekIndex = -1; // fall through case MotionEvent.ACTION_OUTSIDE: case MotionEvent.ACTION_MOVE: // peek and switch icons if necessary - int numIcons = mIconLayout.getChildCount(); - int peekIndex = (int)((float)event.getX() * numIcons / mIconLayout.getWidth()); - if (peekIndex > numIcons - 1) peekIndex = numIcons - 1; - else if (peekIndex < 0) peekIndex = 0; - if (!peeking || mNotificationPeekIndex != peekIndex) { - if (DEBUG) Slog.d(TAG, "will peek at notification #" + peekIndex); + if (newPeekIndex != mPeekIndex) { + mPeekIndex = newPeekIndex; + + if (DEBUG) Slog.d(TAG, "will peek at notification #" + mPeekIndex); Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK); - peekMsg.arg1 = peekIndex; + peekMsg.arg1 = mPeekIndex; mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK); - // no delay if we're scrubbing left-right - mHandler.sendMessage(peekMsg); + if (peeking) { + // no delay if we're scrubbing left-right + mHandler.sendMessage(peekMsg); + } else { + // wait for fling + mHandler.sendMessageDelayed(peekMsg, NOTIFICATION_PEEK_HOLD_THRESH); + } } // check for fling if (mVT != null) { mVT.addMovement(event); - mVT.computeCurrentVelocity(1000); + mVT.computeCurrentVelocity(1000); // pixels per second // require a little more oomph once we're already in peekaboo mode if (!panelShowing && ( (peeking && mVT.getYVelocity() < -mNotificationFlingVelocity*3) @@ -1179,9 +1260,24 @@ public class TabletStatusBar extends StatusBar implements case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK); + if (action == MotionEvent.ACTION_UP + // was this a sloppy tap? + && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop + && Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3) + // dragging off the bottom doesn't count + && (int)event.getY() < v.getBottom()) { + Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK); + peekMsg.arg1 = mPeekIndex; + mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK); + mHandler.sendMessage(peekMsg); + peeking = true; // not technically true yet, but the next line will run + } + if (peeking) { - mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK, 5000); + mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK, + NOTIFICATION_PEEK_FADE_DELAY); } + mVT.recycle(); mVT = null; return true; |