summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml11
-rw-r--r--core/java/android/view/ScaleGestureDetector.java254
-rw-r--r--core/java/android/webkit/WebView.java27
-rw-r--r--core/java/android/widget/DatePicker.java11
-rw-r--r--core/java/android/widget/NumberPicker.java5
-rw-r--r--graphics/java/android/graphics/SurfaceTexture.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java122
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;