2929import android .util .AttributeSet ;
3030import android .util .FloatProperty ;
3131import android .util .Log ;
32+ import android .util .MathUtils ;
3233import android .util .Property ;
3334import android .view .MotionEvent ;
3435import android .view .VelocityTracker ;
3536import android .view .View ;
3637import android .view .ViewConfiguration ;
3738import android .view .ViewGroup ;
39+ import android .view .accessibility .AccessibilityManager ;
3840import android .view .animation .Interpolator ;
3941import android .widget .Scroller ;
4042
@@ -56,18 +58,15 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
5658 private static final int DRAG_HANDLE_OPEN_ABOVE = 8 ; // dp
5759 private static final int DRAG_HANDLE_OPEN_BELOW = 0 ; // dp
5860
59- private static final boolean OPEN_ON_CLICK = true ;
60-
6161 private static final int HANDLE_ANIMATE_DURATION = 200 ; // ms
6262
6363 // Drawn to show the drag handle in closed state; crossfades to the challenge view
6464 // when challenge is fully visible
65- private Drawable mHandleDrawable ;
6665 private Drawable mFrameDrawable ;
67- private Drawable mDragIconDrawable ;
6866 private boolean mEdgeCaptured ;
6967
7068 // Initialized during measurement from child layoutparams
69+ private View mExpandChallengeView ;
7170 private View mChallengeView ;
7271 private View mScrimView ;
7372 private View mWidgetsView ;
@@ -113,6 +112,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
113112 // that should remain on-screen
114113
115114 private int mTouchSlop ;
115+ private int mTouchSlopSquare ;
116116
117117 float mHandleAlpha ;
118118 float mFrameAlpha ;
@@ -184,6 +184,15 @@ public void onClick(View v) {
184184 }
185185 };
186186
187+ private final OnClickListener mExpandChallengeClickListener = new OnClickListener () {
188+ @ Override
189+ public void onClick (View v ) {
190+ if (!isChallengeShowing ()) {
191+ showChallenge (true );
192+ }
193+ }
194+ };
195+
187196 /**
188197 * Listener interface that reports changes in scroll state of the challenge area.
189198 */
@@ -235,13 +244,6 @@ public SlidingChallengeLayout(Context context, AttributeSet attrs) {
235244 public SlidingChallengeLayout (Context context , AttributeSet attrs , int defStyle ) {
236245 super (context , attrs , defStyle );
237246
238- final TypedArray a = context .obtainStyledAttributes (attrs ,
239- R .styleable .SlidingChallengeLayout , defStyle , 0 );
240- setDragDrawables (a .getDrawable (R .styleable .SlidingChallengeLayout_dragHandle ),
241- a .getDrawable (R .styleable .SlidingChallengeLayout_dragIcon ));
242-
243- a .recycle ();
244-
245247 mScroller = new Scroller (context , sMotionInterpolator );
246248
247249 final ViewConfiguration vc = ViewConfiguration .get (context );
@@ -252,6 +254,7 @@ public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle)
252254 mDragHandleEdgeSlop = res .getDimensionPixelSize (R .dimen .kg_edge_swipe_region_size );
253255
254256 mTouchSlop = ViewConfiguration .get (context ).getScaledTouchSlop ();
257+ mTouchSlopSquare = mTouchSlop * mTouchSlop ;
255258
256259 final float density = res .getDisplayMetrics ().density ;
257260
@@ -267,15 +270,6 @@ public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle)
267270 setWillNotDraw (false );
268271 }
269272
270- public void setDragDrawables (Drawable handle , Drawable icon ) {
271- mHandleDrawable = handle ;
272- mDragIconDrawable = icon ;
273- }
274-
275- public void setDragIconDrawable (Drawable d ) {
276- mDragIconDrawable = d ;
277- }
278-
279273 public void showHandle (boolean visible ) {
280274 if (visible ) {
281275 if (mHandleAnimation != null ) {
@@ -469,7 +463,27 @@ void animateChallengeTo(int y, int velocity) {
469463 }
470464
471465 private void setChallengeShowing (boolean showChallenge ) {
466+ if (mChallengeShowing == showChallenge ) {
467+ return ;
468+ }
472469 mChallengeShowing = showChallenge ;
470+ if (mChallengeShowing ) {
471+ mExpandChallengeView .setVisibility (View .INVISIBLE );
472+ mChallengeView .setVisibility (View .VISIBLE );
473+ if (AccessibilityManager .getInstance (mContext ).isEnabled ()) {
474+ mChallengeView .requestAccessibilityFocus ();
475+ mChallengeView .announceForAccessibility (mContext .getString (
476+ R .string .keyguard_accessibility_unlock_area_expanded ));
477+ }
478+ } else {
479+ mExpandChallengeView .setVisibility (View .VISIBLE );
480+ mChallengeView .setVisibility (View .INVISIBLE );
481+ if (AccessibilityManager .getInstance (mContext ).isEnabled ()) {
482+ mExpandChallengeView .requestAccessibilityFocus ();
483+ mChallengeView .announceForAccessibility (mContext .getString (
484+ R .string .keyguard_accessibility_unlock_area_collapsed ));
485+ }
486+ }
473487 }
474488
475489 /**
@@ -573,12 +587,12 @@ public boolean onInterceptTouchEvent(MotionEvent ev) {
573587 for (int i = 0 ; i < count ; i ++) {
574588 final float x = ev .getX (i );
575589 final float y = ev .getY (i );
576-
577- if (! mIsBouncing &&
578- ( isInDragHandle ( x , y ) || crossedDragHandle ( x , y , mGestureStartY ) ||
579- ( isInChallengeView ( x , y ) &&
580- ( mScrollState == SCROLL_STATE_SETTLING || ! mChallengeShowing ))) &&
581- mActivePointerId == INVALID_POINTER ) {
590+ if (! mIsBouncing && mActivePointerId == INVALID_POINTER
591+ && (( isInDragHandle ( x , y ) && MathUtils . sq ( x - mGestureStartX )
592+ + MathUtils . sq ( y - mGestureStartY ) > mTouchSlopSquare )
593+ || crossedDragHandle ( x , y , mGestureStartY )
594+ || ( isInChallengeView ( x , y ) && ( mScrollState == SCROLL_STATE_SETTLING
595+ || ! mChallengeShowing ))) ) {
582596 mActivePointerId = ev .getPointerId (i );
583597 mGestureStartX = x ;
584598 mGestureStartY = y ;
@@ -634,12 +648,7 @@ public boolean onTouchEvent(MotionEvent ev) {
634648 break ;
635649 }
636650 case MotionEvent .ACTION_UP :
637- if (OPEN_ON_CLICK
638- && isInDragHandle (mGestureStartX , mGestureStartY )
639- && Math .abs (ev .getX () - mGestureStartX ) <= mTouchSlop
640- && Math .abs (ev .getY () - mGestureStartY ) <= mTouchSlop ) {
641- showChallenge (true );
642- } else if (mDragging ) {
651+ if (mDragging ) {
643652 mVelocityTracker .computeCurrentVelocity (1000 , mMaxVelocity );
644653 showChallenge ((int ) mVelocityTracker .getYVelocity (mActivePointerId ));
645654 }
@@ -749,19 +758,19 @@ private int getDragHandleSizeBelow() {
749758 }
750759
751760 private boolean isInChallengeView (float x , float y ) {
752- if (mChallengeView == null ) return false ;
753-
754- return x >= mChallengeView .getLeft () && y >= mChallengeView .getTop () &&
755- x < mChallengeView .getRight () && y < mChallengeView .getBottom ();
761+ return isPointInView (x , y , mChallengeView );
756762 }
757763
758764 private boolean isInDragHandle (float x , float y ) {
759- if (mChallengeView == null ) return false ;
765+ return isPointInView (x , y , mExpandChallengeView );
766+ }
760767
761- return x >= mDragHandleEdgeSlop &&
762- y >= mChallengeView .getTop () - getDragHandleSizeAbove () &&
763- x < getWidth () - mDragHandleEdgeSlop &&
764- y < mChallengeView .getTop () + getDragHandleSizeBelow ();
768+ private boolean isPointInView (float x , float y , View view ) {
769+ if (view == null ) {
770+ return false ;
771+ }
772+ return x >= view .getLeft () && y >= view .getTop ()
773+ && x < view .getRight () && y < view .getBottom ();
765774 }
766775
767776 private boolean crossedDragHandle (float x , float y , float initialY ) {
@@ -786,15 +795,16 @@ protected void onMeasure(int widthSpec, int heightSpec) {
786795
787796 // Find one and only one challenge view.
788797 final View oldChallengeView = mChallengeView ;
798+ final View oldExpandChallengeView = mChallengeView ;
789799 mChallengeView = null ;
800+ mExpandChallengeView = null ;
790801 final int count = getChildCount ();
791802
792803 // First iteration through the children finds special children and sets any associated
793804 // state.
794805 for (int i = 0 ; i < count ; i ++) {
795806 final View child = getChildAt (i );
796807 final LayoutParams lp = (LayoutParams ) child .getLayoutParams ();
797-
798808 if (lp .childType == LayoutParams .CHILD_TYPE_CHALLENGE ) {
799809 if (mChallengeView != null ) {
800810 throw new IllegalStateException (
@@ -806,31 +816,42 @@ protected void onMeasure(int widthSpec, int heightSpec) {
806816 }
807817 // We're going to play silly games with the frame's background drawable later.
808818 mFrameDrawable = mChallengeView .getBackground ();
809-
810819 if (!mHasLayout ) {
811820 // Set up the margin correctly based on our content for the first run.
812821 mHasGlowpad = child .findViewById (R .id .keyguard_selector_view ) != null ;
813822 lp .leftMargin = lp .rightMargin = getChallengeMargin (true );
814823 }
824+ } else if (lp .childType == LayoutParams .CHILD_TYPE_EXPAND_CHALLENGE_HANDLE ) {
825+ if (mExpandChallengeView != null ) {
826+ throw new IllegalStateException (
827+ "There may only be one child with layout_childType"
828+ + "=\" expandChallengeHandle\" " );
829+ }
830+ mExpandChallengeView = child ;
831+ if (mExpandChallengeView != oldExpandChallengeView ) {
832+ mExpandChallengeView .setVisibility (mChallengeShowing ? INVISIBLE : VISIBLE );
833+ mExpandChallengeView .setOnClickListener (mExpandChallengeClickListener );
834+ }
815835 } else if (lp .childType == LayoutParams .CHILD_TYPE_SCRIM ) {
816836 setScrimView (child );
817837 } else if (lp .childType == LayoutParams .CHILD_TYPE_WIDGETS ) {
818838 mWidgetsView = child ;
819839 }
820-
821- if (child .getVisibility () == GONE ) continue ;
822840 }
823841
824842 // We want to measure the challenge view first, since the KeyguardWidgetPager
825843 // needs to do things its measure pass that are dependent on the challenge view
826844 // having been measured.
827- if (mChallengeView != null ) {
845+ if (mChallengeView != null && mChallengeView . getVisibility () != View . GONE ) {
828846 measureChildWithMargins (mChallengeView , widthSpec , 0 , heightSpec , 0 );
829847 }
830848
831849 // Measure the rest of the children
832850 for (int i = 0 ; i < count ; i ++) {
833851 final View child = getChildAt (i );
852+ if (child .getVisibility () == GONE ) {
853+ continue ;
854+ }
834855 // Don't measure the challenge view twice!
835856 if (child != mChallengeView ) {
836857 measureChildWithMargins (child , widthSpec , 0 , heightSpec , 0 );
@@ -869,6 +890,8 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) {
869890 * (1 - mChallengeOffset ));
870891 child .setAlpha (getChallengeAlpha ());
871892 child .layout (left , bottom - childHeight , left + childWidth , bottom );
893+ } else if (lp .childType == LayoutParams .CHILD_TYPE_EXPAND_CHALLENGE_HANDLE ) {
894+ child .layout (0 , b - mChallengeBottomBound , width , b );
872895 } else {
873896 // Non-challenge views lay out from the upper left, layered.
874897 child .layout (paddingLeft + lp .leftMargin ,
@@ -886,33 +909,11 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) {
886909 }
887910 }
888911
889- public void computeScroll () {
890- super .computeScroll ();
891-
892- if (!mScroller .isFinished ()) {
893- if (mChallengeView == null ) {
894- // Can't scroll if the view is missing.
895- Log .e (TAG , "Challenge view missing in computeScroll" );
896- mScroller .abortAnimation ();
897- return ;
898- }
899-
900- mScroller .computeScrollOffset ();
901- moveChallengeTo (mScroller .getCurrY ());
902-
903- if (mScroller .isFinished ()) {
904- post (mEndScrollRunnable );
905- }
906- }
907- }
908-
909912 @ Override
910913 public void draw (Canvas c ) {
911914 super .draw (c );
912-
913- final Paint debugPaint ;
914915 if (DEBUG ) {
915- debugPaint = new Paint ();
916+ final Paint debugPaint = new Paint ();
916917 debugPaint .setColor (0x40FF00CC );
917918 // show the isInDragHandle() rect
918919 c .drawRect (mDragHandleEdgeSlop ,
@@ -921,46 +922,24 @@ public void draw(Canvas c) {
921922 mChallengeView .getTop () + getDragHandleSizeBelow (),
922923 debugPaint );
923924 }
925+ }
924926
925- if (mChallengeView != null && mHandleAlpha > 0 ) {
926- final int top = mChallengeView .getTop ();
927- final int handleHeight ;
928- final int challengeLeft = mChallengeView .getLeft ();
929- final int challengeRight = mChallengeView .getRight ();
930- if (mHandleDrawable != null ) {
931- handleHeight = mHandleDrawable .getIntrinsicHeight ();
932- mHandleDrawable .setBounds (challengeLeft , top , challengeRight , top + handleHeight );
933- mHandleDrawable .setAlpha ((int ) (mHandleAlpha * 0xFF ));
934- mHandleDrawable .draw (c );
935- } else {
936- handleHeight = 0 ;
937- }
927+ public void computeScroll () {
928+ super .computeScroll ();
938929
939- if (DEBUG ) {
940- // now show the actual drag handle
941- debugPaint . setStyle ( Paint . Style . STROKE );
942- debugPaint . setStrokeWidth ( 1 );
943- debugPaint . setColor ( 0xFF80FF00 );
944- c . drawRect ( challengeLeft , top , challengeRight , top + handleHeight , debugPaint ) ;
930+ if (! mScroller . isFinished () ) {
931+ if ( mChallengeView == null ) {
932+ // Can't scroll if the view is missing.
933+ Log . e ( TAG , "Challenge view missing in computeScroll" );
934+ mScroller . abortAnimation ( );
935+ return ;
945936 }
946937
947- if (mDragIconDrawable != null ) {
948- final int closedTop = getLayoutBottom () - mDragHandleClosedBelow ;
949- final int iconWidth = mDragIconDrawable .getIntrinsicWidth ();
950- final int iconHeight = mDragIconDrawable .getIntrinsicHeight ();
951- final int iconLeft = (challengeLeft + challengeRight - iconWidth ) / 2 ;
952- final int iconTop = closedTop +
953- (mDragHandleClosedBelow - mDragHandleClosedAbove - iconHeight ) / 2 ;
954- mDragIconDrawable .setBounds (iconLeft , iconTop , iconLeft + iconWidth ,
955- iconTop + iconHeight );
956- mDragIconDrawable .setAlpha ((int ) (mHandleAlpha * 0xFF ));
957- mDragIconDrawable .draw (c );
958-
959- if (DEBUG ) {
960- debugPaint .setColor (0xFF00FF00 );
961- c .drawRect (iconLeft , iconTop , iconLeft + iconWidth ,
962- iconTop + iconHeight , debugPaint );
963- }
938+ mScroller .computeScrollOffset ();
939+ moveChallengeTo (mScroller .getCurrY ());
940+
941+ if (mScroller .isFinished ()) {
942+ post (mEndScrollRunnable );
964943 }
965944 }
966945 }
@@ -1096,6 +1075,7 @@ public static class LayoutParams extends MarginLayoutParams {
10961075 public static final int CHILD_TYPE_CHALLENGE = 2 ;
10971076 public static final int CHILD_TYPE_SCRIM = 4 ;
10981077 public static final int CHILD_TYPE_WIDGETS = 5 ;
1078+ public static final int CHILD_TYPE_EXPAND_CHALLENGE_HANDLE = 6 ;
10991079
11001080 public LayoutParams () {
11011081 this (MATCH_PARENT , WRAP_CONTENT );
0 commit comments