summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorDanny Baumann <dannybaumann@web.de>2011-11-11 14:47:03 +0100
committerDanny Baumann <dannybaumann@web.de>2011-12-10 13:20:18 +0100
commitb7915e0e25db6c86f000a8dbc5edf343d20d9ec5 (patch)
tree82aa25917bec5544c909304332db877caa6b3fe4 /packages
parentad3d4bb0f5bb352516e74b56d7618befe27ddd91 (diff)
downloadframeworks_base-b7915e0e25db6c86f000a8dbc5edf343d20d9ec5.zip
frameworks_base-b7915e0e25db6c86f000a8dbc5edf343d20d9ec5.tar.gz
frameworks_base-b7915e0e25db6c86f000a8dbc5edf343d20d9ec5.tar.bz2
Fix usability of swipe-to-clear feature.
Previously, the outer ScrollView did capture the motion events when the Y distance became too large. This caused swipe-to-clear to only work when moving the finger in an exact horizontal line. Fix that by redirecting all motion events to the swiped notification as soon as its recognized as being swiped.
Diffstat (limited to 'packages')
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ItemTouchDispatcher.java87
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LatestItemContainer.java98
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java6
4 files changed, 174 insertions, 52 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
index 3d85f27..3367154 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
@@ -28,6 +28,7 @@ import android.util.Slog;
public class ExpandedView extends LinearLayout {
StatusBarService mService;
+ ItemTouchDispatcher mTouchDispatcher;
int mPrevHeight = -1;
public ExpandedView(Context context, AttributeSet attrs) {
@@ -46,14 +47,28 @@ public class ExpandedView extends LinearLayout {
}
@Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- int height = bottom - top;
- if (height != mPrevHeight) {
- //Slog.d(StatusBarService.TAG, "height changed old=" + mPrevHeight
- // + " new=" + height);
- mPrevHeight = height;
- mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
- }
- }
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (mTouchDispatcher.needsInterceptTouch()) {
+ return true;
+ }
+ return super.onInterceptTouchEvent(event);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ mTouchDispatcher.handleTouchEvent(event);
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ int height = bottom - top;
+ if (height != mPrevHeight) {
+ //Slog.d(StatusBarService.TAG, "height changed old=" + mPrevHeight
+ // + " new=" + height);
+ mPrevHeight = height;
+ mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ItemTouchDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/ItemTouchDispatcher.java
new file mode 100644
index 0000000..0ed29ba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ItemTouchDispatcher.java
@@ -0,0 +1,87 @@
+/*
+* Copyright (C) 2010 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.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.systemui.R;
+
+public class ItemTouchDispatcher {
+ private final GestureDetector mGestureDetector;
+ private LatestItemContainer mItem;
+ /* stored as class member to avoid garbage creation */
+ private int[] mItemLocation = new int[2];
+
+ public ItemTouchDispatcher(final Context context) {
+ mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float vX, float vY) {
+ final ViewConfiguration vc = ViewConfiguration.get(context);
+ int minDistance = vc.getScaledTouchSlop();
+ int distance = (int) Math.abs(e2.getX() - e1.getX());
+ if (distance > minDistance && Math.abs(vX) > Math.abs(vY)) {
+ mItem.finishSwipe(vX > 0);
+ mItem = null;
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+
+ public void setItem(LatestItemContainer item) {
+ mItem = item;
+ }
+
+ public boolean needsInterceptTouch() {
+ return mItem != null;
+ }
+
+ public boolean handleTouchEvent(MotionEvent event) {
+ /*
+ * We are called from different sources, so make sure we use a
+ * consistent coordinate system.
+ */
+ MotionEvent real = MotionEvent.obtain(event);
+ real.setLocation(event.getRawX(), event.getRawY());
+
+ boolean handled = mGestureDetector.onTouchEvent(real);
+
+ if (mItem != null) {
+ /*
+ * Convert coordinates to item coordinates
+ */
+ mItem.getLocationOnScreen(mItemLocation);
+ real.offsetLocation(mItemLocation[0], mItemLocation[1]);
+ mItem.dispatchTouchEvent(real);
+
+ switch (real.getAction() & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mItem.stopSwipe();
+ mItem = null;
+ break;
+ }
+ }
+
+ real.recycle();
+ return handled;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemContainer.java
index 7209663..2a5bf1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemContainer.java
@@ -20,8 +20,9 @@ import android.content.Context;
import android.graphics.Point;
import android.os.Handler;
import android.util.AttributeSet;
-import android.view.GestureDetector;
import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
@@ -29,71 +30,86 @@ import android.widget.LinearLayout;
import com.android.systemui.R;
public class LatestItemContainer extends LinearLayout {
- private final GestureDetector mGestureDetector;
-
+ private boolean mIsDragged = false;
+ private ItemTouchDispatcher mDispatcher = null;
private Runnable mSwipeCallback = null;
-
private final Handler mHandler = new Handler();
-
private final Point mStartPoint = new Point();
+ private int mTouchSlop;
public LatestItemContainer(final Context context, AttributeSet attrs) {
super(context, attrs);
+ final ViewConfiguration vc = ViewConfiguration.get(context);
+ mTouchSlop = vc.getScaledTouchSlop();
+ }
- mGestureDetector = new GestureDetector(context,
- new GestureDetector.SimpleOnGestureListener() {
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float vX, float vY) {
- if (mSwipeCallback != null) {
- if (Math.abs(vX) > Math.abs(vY)) {
- int id;
- if (vX > 0) {
- id = R.anim.slide_out_right_basic;
- } else {
- id = R.anim.slide_out_left_basic;
- }
- Animation animation = AnimationUtils.loadAnimation(context, id);
- startAnimation(animation);
- mHandler.postDelayed(mSwipeCallback, animation.getDuration());
- return true;
- }
- }
- return false;
- }
- });
+ public void finishSwipe(boolean toRight) {
+ int id = toRight ? R.anim.slide_out_right_basic : R.anim.slide_out_left_basic;
+ Animation animation = AnimationUtils.loadAnimation(getContext(), id);
+ startAnimation(animation);
+ mHandler.postDelayed(mSwipeCallback, animation.getDuration());
+ mIsDragged = false;
+ }
+
+ public void stopSwipe() {
+ reset();
+ mIsDragged = false;
}
@Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mSwipeCallback != null) {
- boolean handled = mGestureDetector.onTouchEvent(event);
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ if (mDispatcher != null) {
+ boolean handled = false;
+
+ /*
+ * Only call into dispatcher when we're not registered with it yet,
+ * otherwise we get into a loop
+ */
+ if (!mIsDragged) {
+ handled = mDispatcher.handleTouchEvent(event);
+ }
+
switch (event.getAction() & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_OUTSIDE:
- case MotionEvent.ACTION_CANCEL:
- reset();
+ case MotionEvent.ACTION_DOWN:
+ mStartPoint.set((int) event.getX(), (int) event.getY());
break;
- case MotionEvent.ACTION_UP:
- if (!handled) {
- reset();
- }
- return handled;
case MotionEvent.ACTION_MOVE:
int diffX = ((int) event.getX()) - mStartPoint.x;
+ int diffY = ((int) event.getY()) - mStartPoint.y;
+ if (Math.abs(diffX) > mTouchSlop && Math.abs(diffX) > Math.abs(diffY)) {
+ mIsDragged = true;
+ mDispatcher.setItem(this);
+ }
scrollTo(-diffX, 0);
break;
- case MotionEvent.ACTION_DOWN:
- mStartPoint.x = (int) event.getX();
+ case MotionEvent.ACTION_UP:
+ if (!handled) {
+ reset();
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ /*
+ * Ignore cancel events after registering with the dispatcher
+ * as they will appear sometimes (when ExpandedView takes over
+ * event control). The dispatcher will call stopSwipe() when
+ * the gesture is aborted.
+ */
+ if (!mIsDragged) {
+ reset();
+ }
break;
}
}
- return super.onInterceptTouchEvent(event);
+
+ return super.dispatchTouchEvent(event);
}
private void reset() {
scrollTo(0, 0);
}
- public void setOnSwipeCallback(Runnable callback) {
+ public void setOnSwipeCallback(ItemTouchDispatcher dispatcher, Runnable callback) {
+ mDispatcher = dispatcher;
mSwipeCallback = callback;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index e4ac0be..2f8d112 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -148,6 +148,7 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks
NotificationData mLatest = new NotificationData();
TextView mLatestTitle;
LinearLayout mLatestItems;
+ ItemTouchDispatcher mTouchDispatcher;
// position
int[] mPositionTmp = new int[2];
boolean mExpanded;
@@ -371,6 +372,8 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks
private void makeStatusBarView(Context context) {
Resources res = context.getResources();
+ mTouchDispatcher = new ItemTouchDispatcher(this);
+
mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
//Check for compact carrier layout and apply if enabled
@@ -379,6 +382,7 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks
ExpandedView expanded = (ExpandedView)View.inflate(context,
R.layout.status_bar_expanded, null);
expanded.mService = this;
+ expanded.mTouchDispatcher = mTouchDispatcher;
CmStatusBarView sb = (CmStatusBarView)View.inflate(context, R.layout.status_bar, null);
sb.mService = this;
@@ -720,7 +724,7 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LatestItemContainer row = (LatestItemContainer) inflater.inflate(R.layout.status_bar_latest_event, parent, false);
if ((n.flags & Notification.FLAG_ONGOING_EVENT) == 0 && (n.flags & Notification.FLAG_NO_CLEAR) == 0) {
- row.setOnSwipeCallback(new Runnable() {
+ row.setOnSwipeCallback(mTouchDispatcher, new Runnable() {
public void run() {
try {
mBarService.onNotificationClear(notification.pkg, notification.tag, notification.id);