2121import android .content .res .TypedArray ;
2222import android .graphics .Canvas ;
2323import android .graphics .Paint ;
24+ import android .graphics .RectF ;
2425import android .graphics .drawable .Drawable ;
2526import android .util .AttributeSet ;
2627import android .util .FloatProperty ;
@@ -44,6 +45,18 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
4445 private static final String TAG = "SlidingChallengeLayout" ;
4546 private static final boolean DEBUG = false ;
4647
48+ // The drag handle is measured in dp above & below the top edge of the
49+ // challenge view; these parameters change based on whether the challenge
50+ // is open or closed.
51+ private static final int DRAG_HANDLE_CLOSED_ABOVE = 32 ; // dp
52+ private static final int DRAG_HANDLE_CLOSED_BELOW = 32 ; // dp
53+ private static final int DRAG_HANDLE_OPEN_ABOVE = 8 ; // dp
54+ private static final int DRAG_HANDLE_OPEN_BELOW = 0 ; // dp
55+
56+ private static final boolean OPEN_ON_CLICK = true ;
57+
58+ private static final int HANDLE_ANIMATE_DURATION = 200 ; // ms
59+
4760 // Drawn to show the drag handle in closed state; crossfades to the challenge view
4861 // when challenge is fully visible
4962 private Drawable mHandleDrawable ;
@@ -82,13 +95,20 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
8295 private VelocityTracker mVelocityTracker ;
8396 private int mMinVelocity ;
8497 private int mMaxVelocity ;
85- private float mGestureStartY ; // where did you touch the screen to start this gesture ?
98+ private float mGestureStartX , mGestureStartY ; // where did you first touch the screen?
8699 private int mGestureStartChallengeBottom ; // where was the challenge at that time?
87- private int mDragHandleSize ; // handle hitrect extension into the challenge view
88- private int mDragHandleHeadroom ; // extend the handle's hitrect this far above the line
100+
101+ private int mDragHandleClosedBelow ; // handle hitrect extension into the challenge view
102+ private int mDragHandleClosedAbove ; // extend the handle's hitrect this far above the line
103+ private int mDragHandleOpenBelow ; // handle hitrect extension into the challenge view
104+ private int mDragHandleOpenAbove ; // extend the handle's hitrect this far above the line
105+
89106 private int mDragHandleEdgeSlop ;
90107 private int mChallengeBottomBound ; // Number of pixels from the top of the challenge view
91108 // that should remain on-screen
109+
110+ private int mTouchSlop ;
111+
92112 float mHandleAlpha ;
93113 float mFrameAlpha ;
94114 private ObjectAnimator mHandleAnimation ;
@@ -125,9 +145,6 @@ public Float get(SlidingChallengeLayout view) {
125145 }
126146 };
127147
128- private static final int DRAG_HANDLE_DEFAULT_SIZE = 32 ; // dp
129- private static final int HANDLE_ANIMATE_DURATION = 200 ; // ms
130-
131148 // True if at least one layout pass has happened since the view was attached.
132149 private boolean mHasLayout ;
133150
@@ -224,20 +241,25 @@ public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle)
224241 mDragHandleEdgeSlop = getResources ().getDimensionPixelSize (
225242 R .dimen .kg_edge_swipe_region_size );
226243
244+ mTouchSlop = ViewConfiguration .get (context ).getScaledTouchSlop ();
245+
227246 setWillNotDraw (false );
228247 }
229248
230249 public void setDragDrawables (Drawable handle , Drawable icon ) {
231250 final float density = getResources ().getDisplayMetrics ().density ;
232- final int defaultSize = (int ) (DRAG_HANDLE_DEFAULT_SIZE * density + 0.5f );
233251 final int handleHeight = handle != null ? handle .getIntrinsicHeight () : 0 ;
234252 final int iconHeight = icon != null ? icon .getIntrinsicHeight () : 0 ;
235- mDragHandleSize = Math .max (handleHeight > 0 ? handleHeight : defaultSize ,
236- iconHeight > 0 ? iconHeight : defaultSize );
237253
238254 // top half of the lock icon, plus another 25% to be sure
239- mDragHandleHeadroom = (int ) (iconHeight * 0.75f );
240- mChallengeBottomBound = (mDragHandleSize + mDragHandleHeadroom + handleHeight ) / 2 ;
255+ mDragHandleClosedAbove = (int ) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f );
256+ mDragHandleClosedBelow = (int ) (DRAG_HANDLE_CLOSED_BELOW * density + 0.5f );
257+ mDragHandleOpenAbove = (int ) (DRAG_HANDLE_OPEN_ABOVE * density + 0.5f );
258+ mDragHandleOpenBelow = (int ) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f );
259+
260+ // how much space to account for in the handle when closed
261+ mChallengeBottomBound =
262+ (mDragHandleClosedBelow + mDragHandleClosedAbove + handleHeight ) / 2 ;
241263
242264 mHandleDrawable = handle ;
243265 mDragIconDrawable = icon ;
@@ -477,9 +499,12 @@ public boolean onInterceptTouchEvent(MotionEvent ev) {
477499 }
478500 mVelocityTracker .addMovement (ev );
479501
502+ //Log.v(TAG, "onIntercept: " + ev);
503+
480504 final int action = ev .getActionMasked ();
481505 switch (action ) {
482506 case MotionEvent .ACTION_DOWN :
507+ mGestureStartX = ev .getX ();
483508 mGestureStartY = ev .getY ();
484509 mBlockDrag = false ;
485510 break ;
@@ -500,7 +525,8 @@ public boolean onInterceptTouchEvent(MotionEvent ev) {
500525 (isInChallengeView (x , y ) && mScrollState == SCROLL_STATE_SETTLING )) &&
501526 mActivePointerId == INVALID_POINTER ) {
502527 mActivePointerId = ev .getPointerId (i );
503- mGestureStartY = ev .getY ();
528+ mGestureStartX = x ;
529+ mGestureStartY = y ;
504530 mGestureStartChallengeBottom = getChallengeBottom ();
505531 mDragging = true ;
506532 } else if (isInChallengeView (x , y )) {
@@ -532,10 +558,13 @@ public boolean onTouchEvent(MotionEvent ev) {
532558 }
533559 mVelocityTracker .addMovement (ev );
534560
561+ //Log.v(TAG, "onTouch: " + ev);
562+
535563 final int action = ev .getActionMasked ();
536564 switch (action ) {
537565 case MotionEvent .ACTION_DOWN :
538566 mBlockDrag = false ;
567+ mGestureStartX = ev .getX ();
539568 mGestureStartY = ev .getY ();
540569 break ;
541570
@@ -551,7 +580,12 @@ public boolean onTouchEvent(MotionEvent ev) {
551580 break ;
552581 }
553582 case MotionEvent .ACTION_UP :
554- if (mDragging ) {
583+ if (OPEN_ON_CLICK
584+ && isInDragHandle (mGestureStartX , mGestureStartY )
585+ && Math .abs (ev .getX () - mGestureStartX ) <= mTouchSlop
586+ && Math .abs (ev .getY () - mGestureStartY ) <= mTouchSlop ) {
587+ showChallenge (true );
588+ } else if (mDragging ) {
555589 mVelocityTracker .computeCurrentVelocity (1000 , mMaxVelocity );
556590 showChallenge ((int ) mVelocityTracker .getYVelocity (mActivePointerId ));
557591 }
@@ -568,6 +602,7 @@ public boolean onTouchEvent(MotionEvent ev) {
568602 if ((isInDragHandle (x , y ) || crossedDragHandle (x , y , mGestureStartY ) ||
569603 (isInChallengeView (x , y ) && mScrollState == SCROLL_STATE_SETTLING ))
570604 && mActivePointerId == INVALID_POINTER ) {
605+ mGestureStartX = x ;
571606 mGestureStartY = y ;
572607 mActivePointerId = ev .getPointerId (i );
573608 mGestureStartChallengeBottom = getChallengeBottom ();
@@ -605,8 +640,11 @@ public boolean onTouchEvent(MotionEvent ev) {
605640 * We only want to add additional vertical space to the drag handle when the panel is fully
606641 * closed.
607642 */
608- private int getDragHandleHeadroom () {
609- return isChallengeShowing () ? 0 : mDragHandleHeadroom ;
643+ private int getDragHandleSizeAbove () {
644+ return isChallengeShowing () ? mDragHandleOpenAbove : mDragHandleClosedAbove ;
645+ }
646+ private int getDragHandleSizeBelow () {
647+ return isChallengeShowing () ? mDragHandleOpenBelow : mDragHandleClosedBelow ;
610648 }
611649
612650 private boolean isInChallengeView (float x , float y ) {
@@ -620,17 +658,17 @@ private boolean isInDragHandle(float x, float y) {
620658 if (mChallengeView == null ) return false ;
621659
622660 return x >= mDragHandleEdgeSlop &&
623- y >= mChallengeView .getTop () - getDragHandleHeadroom () &&
661+ y >= mChallengeView .getTop () - getDragHandleSizeAbove () &&
624662 x < getWidth () - mDragHandleEdgeSlop &&
625- y < mChallengeView .getTop () + mDragHandleSize ;
663+ y < mChallengeView .getTop () + getDragHandleSizeBelow () ;
626664 }
627665
628666 private boolean crossedDragHandle (float x , float y , float initialY ) {
629667 final int challengeTop = mChallengeView .getTop ();
630668 return x >= 0 &&
631669 x < getWidth () &&
632- initialY < (challengeTop - getDragHandleHeadroom ()) &&
633- y > challengeTop + mDragHandleSize ;
670+ initialY < (challengeTop - getDragHandleSizeAbove ()) &&
671+ y > challengeTop + getDragHandleSizeBelow () ;
634672 }
635673
636674 @ Override
@@ -760,20 +798,25 @@ public void draw(Canvas c) {
760798 debugPaint .setColor (0x40FF00CC );
761799 // show the isInDragHandle() rect
762800 c .drawRect (mDragHandleEdgeSlop ,
763- mChallengeView .getTop () - getDragHandleHeadroom (),
801+ mChallengeView .getTop () - getDragHandleSizeAbove (),
764802 getWidth () - mDragHandleEdgeSlop ,
765- mChallengeView .getTop () + mDragHandleSize ,
803+ mChallengeView .getTop () + getDragHandleSizeBelow () ,
766804 debugPaint );
767805 }
768806
769- if (mChallengeView != null && mHandleAlpha > 0 && mHandleDrawable != null ) {
807+ if (mChallengeView != null && mHandleAlpha > 0 ) {
770808 final int top = mChallengeView .getTop ();
771- final int handleHeight = mHandleDrawable . getIntrinsicHeight () ;
809+ final int handleHeight ;
772810 final int challengeLeft = mChallengeView .getLeft ();
773811 final int challengeRight = mChallengeView .getRight ();
774- mHandleDrawable .setBounds (challengeLeft , top , challengeRight , top + handleHeight );
775- mHandleDrawable .setAlpha ((int ) (mHandleAlpha * 0xFF ));
776- mHandleDrawable .draw (c );
812+ if (mHandleDrawable != null ) {
813+ handleHeight = mHandleDrawable .getIntrinsicHeight ();
814+ mHandleDrawable .setBounds (challengeLeft , top , challengeRight , top + handleHeight );
815+ mHandleDrawable .setAlpha ((int ) (mHandleAlpha * 0xFF ));
816+ mHandleDrawable .draw (c );
817+ } else {
818+ handleHeight = 0 ;
819+ }
777820
778821 if (DEBUG ) {
779822 // now show the actual drag handle
0 commit comments