import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
+import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.policy.ScrollAdapter;
public class ExpandHelper implements Gefingerpoken {
private static final String TAG = "ExpandHelper";
protected static final boolean DEBUG = false;
protected static final boolean DEBUG_SCALE = false;
- private static final long EXPAND_DURATION = 250;
+ private static final float EXPAND_DURATION = 0.3f;
// Set to false to disable focus-based gestures (spread-finger vertical pull).
private static final boolean USE_DRAG = true;
private int mGravity;
private ScrollAdapter mScrollAdapter;
+ private FlingAnimationUtils mFlingAnimationUtils;
+ private VelocityTracker mVelocityTracker;
private OnScaleGestureListener mScaleGestureListener
= new ScaleGestureDetector.SimpleOnScaleGestureListener() {
mScaler = new ViewScaler();
mGravity = Gravity.TOP;
mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f);
- mScaleAnimation.setDuration(EXPAND_DURATION);
mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min);
mTouchSlop = configuration.getScaledTouchSlop();
mSGD = new ScaleGestureDetector(context, mScaleGestureListener);
+ mFlingAnimationUtils = new FlingAnimationUtils(context, EXPAND_DURATION);
}
private void updateExpansion() {
if (!isEnabled()) {
return false;
}
+ trackVelocity(ev);
final int action = ev.getAction();
if (DEBUG_SCALE) Log.d(TAG, "intercept: act=" + MotionEvent.actionToString(action) +
" expanding=" + mExpanding +
if (mExpanding) {
mLastMotionY = ev.getRawY();
+ maybeRecycleVelocityTracker(ev);
return true;
} else {
if ((action == MotionEvent.ACTION_MOVE) && 0 != (mExpansionStyle & BLINDS)) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (DEBUG) Log.d(TAG, "up/cancel");
- finishExpanding(false);
+ finishExpanding(false, getCurrentVelocity());
clearView();
break;
}
mLastMotionY = ev.getRawY();
+ maybeRecycleVelocityTracker(ev);
return mExpanding;
}
}
+ private void trackVelocity(MotionEvent event) {
+ int action = event.getActionMasked();
+ switch(action) {
+ case MotionEvent.ACTION_DOWN:
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ } else {
+ mVelocityTracker.clear();
+ }
+ mVelocityTracker.addMovement(event);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ mVelocityTracker.addMovement(event);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void maybeRecycleVelocityTracker(MotionEvent event) {
+ if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
+ || event.getActionMasked() == MotionEvent.ACTION_UP) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ }
+
+ private float getCurrentVelocity() {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.computeCurrentVelocity(1000);
+ return mVelocityTracker.getYVelocity();
+ } else {
+ return 0f;
+ }
+ }
+
public void setEnabled(boolean enable) {
mEnabled = enable;
}
if (!isEnabled()) {
return false;
}
+ trackVelocity(ev);
final int action = ev.getActionMasked();
if (DEBUG_SCALE) Log.d(TAG, "touch: act=" + MotionEvent.actionToString(action) +
" expanding=" + mExpanding +
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (DEBUG) Log.d(TAG, "up/cancel");
- finishExpanding(false);
+ finishExpanding(false, getCurrentVelocity());
clearView();
break;
}
mLastMotionY = ev.getRawY();
+ maybeRecycleVelocityTracker(ev);
return mResizedView != null;
}
return true;
}
- private void finishExpanding(boolean force) {
+ private void finishExpanding(boolean force, float velocity) {
if (!mExpanding) return;
if (DEBUG) Log.d(TAG, "scale in finishing on view: " + mResizedView);
mScaleAnimation.removeListener(this);
}
});
+ mFlingAnimationUtils.apply(mScaleAnimation, currentHeight, targetHeight, velocity);
mScaleAnimation.start();
} else {
mCallback.setUserLockedChild(mResizedView, false);
* Use this to abort any pending expansions in progress.
*/
public void cancel() {
- finishExpanding(true);
+ finishExpanding(true, 0f /* velocity */);
clearView();
// reset the gesture detector