package com.android.systemui.widget; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import com.android.systemui.ui.SwipeView; import com.android.systemui.util.AnimationUtil; public class BounceSwipeView extends SwipeView { private static final int ANIMATION_DURATION = 120; private static final int FRAME_DURATION = 30; private static final int NUMBER_OF_FRAMES = ANIMATION_DURATION/FRAME_DURATION; private static final boolean BOUNCING_ON_LEFT = true; private static final boolean BOUNCING_ON_RIGHT = false; private boolean mAtEdge = false; private float mAtEdgeStartPosition; private float mAtEdgePreviousPosition; private int mPaddingLeft; private int mPaddingRight; private OnTouchListener mOnTouchListener; private int mPaddingStartValue; Handler mEaseAnimationFrameHandler; private int mCurrentAnimationFrame; private int mPaddingChange; private boolean mBouncingSide; private SharedPreferences mSharedPreferences; private Context mContext; private boolean mBounceEnabled = true; public BounceSwipeView(Context context) { super(context); mContext = context; initBounceSwipeView(); } public BounceSwipeView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; initBounceSwipeView(); } public BounceSwipeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mContext = context; initBounceSwipeView(); } private void initBounceSwipeView() { super.setOnTouchListener(new BounceViewOnTouchListener()); mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); mEaseAnimationFrameHandler = new Handler() { public void handleMessage(Message msg) { int newPadding = AnimationUtil.quadraticOutEase(mCurrentAnimationFrame, mPaddingStartValue, -mPaddingChange, NUMBER_OF_FRAMES); if(mBouncingSide == BOUNCING_ON_LEFT) { BounceSwipeView.super.setPadding(newPadding, getPaddingTop(), getPaddingRight(), getPaddingBottom()); } else if(mBouncingSide == BOUNCING_ON_RIGHT) { BounceSwipeView.super.setPadding(getPaddingLeft(), getPaddingTop(), newPadding, getPaddingBottom()); } mCurrentAnimationFrame++; if(mCurrentAnimationFrame <= NUMBER_OF_FRAMES) { mEaseAnimationFrameHandler.sendEmptyMessageDelayed(0, FRAME_DURATION); } } }; } @Override public void setPadding(int left, int top, int right, int bottom) { mPaddingLeft = left; mPaddingRight = right; super.setPadding(left,top,right,bottom); } @Override public void setOnTouchListener(View.OnTouchListener onTouchListener) { mOnTouchListener = onTouchListener; } public void setBounceEnabled(boolean enabled) { mBounceEnabled = enabled; } public boolean getBounceEnabled() { return mBounceEnabled; } private class BounceViewOnTouchListener implements View.OnTouchListener { public boolean onTouch(View view, MotionEvent ev) { if(mOnTouchListener!=null && mOnTouchListener.onTouch(view, ev)) { return true; } if(mBounceEnabled) { switch(ev.getAction()) { case MotionEvent.ACTION_MOVE : int maxScrollAmount = (getPageCount()-1)*getPageWidth()-getPageWidth()%2; if(getScrollX()==0 && !mAtEdge || getScrollX()==maxScrollAmount && !mAtEdge) { mAtEdge = true; mAtEdgeStartPosition = ev.getX(); mAtEdgePreviousPosition = ev.getX(); } else if(getScrollX()==0) { mAtEdgePreviousPosition = ev.getX(); mBouncingSide=BOUNCING_ON_LEFT; BounceSwipeView.super.setPadding((int) (mAtEdgePreviousPosition-mAtEdgeStartPosition)/2, getPaddingTop(), getPaddingRight(), getPaddingBottom()); return true; } else if(getScrollX()>=maxScrollAmount) { mAtEdgePreviousPosition = ev.getX(); mBouncingSide=BOUNCING_ON_RIGHT; int newRightPadding = (int) (mAtEdgeStartPosition-mAtEdgePreviousPosition)/2; if(newRightPadding>=mPaddingRight) { BounceSwipeView.super.setPadding(getPaddingLeft(), getPaddingTop(), newRightPadding, getPaddingBottom()); } else { BounceSwipeView.super.setPadding(getPaddingLeft(), getPaddingTop(), mPaddingRight, getPaddingBottom()); } scrollTo((int) (maxScrollAmount+(mAtEdgeStartPosition-mAtEdgePreviousPosition)/2), getScrollY()); return true; } else { mAtEdge = false; } break; case MotionEvent.ACTION_UP : if(mAtEdge) { mAtEdge = false; mAtEdgePreviousPosition = 0; mAtEdgeStartPosition = 0; doBounceBackEaseAnimation(); return true; } break; } } return false; } } private void doBounceBackEaseAnimation() { if(mBouncingSide == BOUNCING_ON_LEFT) { mPaddingChange = getPaddingLeft() - mPaddingLeft; mPaddingStartValue = getPaddingLeft(); } else if(mBouncingSide == BOUNCING_ON_RIGHT) { mPaddingChange = getPaddingRight() - mPaddingRight; mPaddingStartValue = getPaddingRight(); } mCurrentAnimationFrame = 0; mEaseAnimationFrameHandler.removeMessages(0); mEaseAnimationFrameHandler.sendEmptyMessage(0); } /* * Animation that can be used to show you are at the end when using some * kind of control to go to the next page, rather than swiping * */ public void doAtEdgeAnimation() { if(getCurrentPage()==0) { mBouncingSide = BOUNCING_ON_LEFT; BounceSwipeView.super.setPadding(getPaddingLeft()+50, getPaddingTop(), getPaddingRight(), getPaddingBottom()); } else if(getCurrentPage()==getPageCount()-1) { mBouncingSide = BOUNCING_ON_RIGHT; BounceSwipeView.super.setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight()+50, getPaddingBottom()); scrollTo(getScrollX()+50,getScrollY()); } doBounceBackEaseAnimation(); } }