@@ -67,6 +67,7 @@ public interface OnTriggerListener {
6767 public void onReleased (View v , int handle );
6868 public void onTrigger (View v , int target );
6969 public void onGrabbedStateChange (View v , int handle );
70+ public void onFinishFinalAnimation ();
7071 }
7172
7273 // Tuneable parameters for animation
@@ -77,9 +78,13 @@ public interface OnTriggerListener {
7778 private static final int HIDE_ANIMATION_DELAY = 200 ;
7879 private static final int HIDE_ANIMATION_DURATION = 200 ;
7980 private static final int SHOW_ANIMATION_DURATION = 200 ;
80- private static final int SHOW_ANIMATION_DELAY = 0 ;
81+ private static final int SHOW_ANIMATION_DELAY = 50 ;
8182 private static final float TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.3f ;
82- private static final float TARGET_INITIAL_POSITION_SCALE = 0.8f ;
83+ private static final float TARGET_SCALE_SELECTED = 0.8f ;
84+ private static final long INITIAL_SHOW_HANDLE_DURATION = 200 ;
85+ private static final float TARGET_SCALE_UNSELECTED = 1.0f ;
86+ private static final float RING_SCALE_UNSELECTED = 0.5f ;
87+ private static final float RING_SCALE_SELECTED = 1.5f ;
8388
8489 private TimeInterpolator mChevronAnimationInterpolator = Ease .Quad .easeOut ;
8590
@@ -126,6 +131,15 @@ public void start() {
126131 }
127132 }
128133
134+ public void cancel () {
135+ final int count = size ();
136+ for (int i = 0 ; i < count ; i ++) {
137+ Tweener anim = get (i );
138+ anim .animator .cancel ();
139+ }
140+ clear ();
141+ }
142+
129143 public void stop () {
130144 final int count = size ();
131145 for (int i = 0 ; i < count ; i ++) {
@@ -143,13 +157,15 @@ public void setSuspended(boolean suspend) {
143157 private AnimatorListener mResetListener = new AnimatorListenerAdapter () {
144158 public void onAnimationEnd (Animator animator ) {
145159 switchToState (STATE_IDLE , mWaveCenterX , mWaveCenterY );
160+ dispatchOnFinishFinalAnimation ();
146161 }
147162 };
148163
149164 private AnimatorListener mResetListenerWithPing = new AnimatorListenerAdapter () {
150165 public void onAnimationEnd (Animator animator ) {
151166 ping ();
152167 switchToState (STATE_IDLE , mWaveCenterX , mWaveCenterY );
168+ dispatchOnFinishFinalAnimation ();
153169 }
154170 };
155171
@@ -349,7 +365,7 @@ private void switchToState(int state, float x, float y) {
349365 stopHandleAnimation ();
350366 deactivateTargets ();
351367 showTargets (true );
352- mHandleDrawable . setState ( TargetDrawable . STATE_ACTIVE );
368+ activateHandle ( );
353369 setGrabbedState (OnTriggerListener .CENTER_HANDLE );
354370 if (AccessibilityManager .getInstance (mContext ).isEnabled ()) {
355371 announceTargets ();
@@ -368,6 +384,19 @@ private void switchToState(int state, float x, float y) {
368384 }
369385 }
370386
387+ private void activateHandle () {
388+ mHandleDrawable .setState (TargetDrawable .STATE_ACTIVE );
389+ if (mAlwaysTrackFinger ) {
390+ mHandleAnimations .stop ();
391+ mHandleDrawable .setAlpha (0.0f );
392+ mHandleAnimations .add (Tweener .to (mHandleDrawable , INITIAL_SHOW_HANDLE_DURATION ,
393+ "ease" , Ease .Cubic .easeIn ,
394+ "alpha" , 1.0f ,
395+ "onUpdate" , mUpdateListener ));
396+ mHandleAnimations .start ();
397+ }
398+ }
399+
371400 /**
372401 * Animation used to attract user's attention to the target button.
373402 * Assumes mChevronDrawables is an a list with an even number of chevrons filled with
@@ -463,6 +492,12 @@ private void dispatchGrabbedEvent(int whichHandler) {
463492 }
464493 }
465494
495+ private void dispatchOnFinishFinalAnimation () {
496+ if (mOnTriggerListener != null ) {
497+ mOnTriggerListener .onFinishFinalAnimation ();
498+ }
499+ }
500+
466501 private void doFinish () {
467502 final int activeTarget = mActiveTarget ;
468503 boolean targetHit = activeTarget != -1 ;
@@ -471,8 +506,9 @@ private void doFinish() {
471506 hideTargets (true );
472507
473508 // Highlight the selected one
474- mHandleDrawable . setAlpha ( targetHit ? 0.0f : 1.0f );
509+ mHandleAnimations . cancel ( );
475510 if (targetHit ) {
511+ mHandleDrawable .setAlpha (0.0f );
476512 mTargetDrawables .get (activeTarget ).setState (TargetDrawable .STATE_ACTIVE );
477513 hideUnselected (activeTarget );
478514
@@ -483,12 +519,11 @@ private void doFinish() {
483519
484520 // Animate handle back to the center based on current state.
485521 int delay = targetHit ? RETURN_TO_HOME_DELAY : 0 ;
486- int duration = targetHit ? 0 : RETURN_TO_HOME_DURATION ;
487- mHandleAnimations .stop ();
522+ int duration = RETURN_TO_HOME_DURATION ;
488523 mHandleAnimations .add (Tweener .to (mHandleDrawable , duration ,
489524 "ease" , Ease .Quart .easeOut ,
490525 "delay" , delay ,
491- "alpha" , 1.0f ,
526+ "alpha" , mAlwaysTrackFinger ? 0.0f : 1.0f ,
492527 "x" , 0 ,
493528 "y" , 0 ,
494529 "onUpdate" , mUpdateListener ,
@@ -508,26 +543,29 @@ private void hideUnselected(int active) {
508543 }
509544
510545 private void hideTargets (boolean animate ) {
511- mTargetAnimations .stop ();
546+ mTargetAnimations .cancel ();
512547 // Note: these animations should complete at the same time so that we can swap out
513548 // the target assets asynchronously from the setTargetResources() call.
514549 mAnimatingTargets = animate ;
515550 final int duration = animate ? HIDE_ANIMATION_DURATION : 0 ;
516551 final int delay = animate ? HIDE_ANIMATION_DELAY : 0 ;
552+ final boolean targetSelected = mActiveTarget != -1 ;
553+
554+ final float targetScale = targetSelected ? TARGET_SCALE_SELECTED : TARGET_SCALE_UNSELECTED ;
517555 final int length = mTargetDrawables .size ();
518556 for (int i = 0 ; i < length ; i ++) {
519557 TargetDrawable target = mTargetDrawables .get (i );
520558 target .setState (TargetDrawable .STATE_INACTIVE );
521559 mTargetAnimations .add (Tweener .to (target , duration ,
522560 "ease" , Ease .Cubic .easeOut ,
523561 "alpha" , 0.0f ,
524- "scaleX" , TARGET_INITIAL_POSITION_SCALE ,
525- "scaleY" , TARGET_INITIAL_POSITION_SCALE ,
562+ "scaleX" , targetScale ,
563+ "scaleY" , targetScale ,
526564 "delay" , delay ,
527565 "onUpdate" , mUpdateListener ));
528566 }
529567
530- float ringScaleTarget = mActiveTarget != - 1 ? 1.5f : 0.5f ;
568+ final float ringScaleTarget = targetSelected ? RING_SCALE_SELECTED : RING_SCALE_UNSELECTED ;
531569 mTargetAnimations .add (Tweener .to (mOuterRing , duration ,
532570 "ease" , Ease .Cubic .easeOut ,
533571 "alpha" , 0.0f ,
@@ -544,23 +582,22 @@ private void showTargets(boolean animate) {
544582 mTargetAnimations .stop ();
545583 mAnimatingTargets = animate ;
546584 final int delay = animate ? SHOW_ANIMATION_DELAY : 0 ;
585+ final int duration = animate ? SHOW_ANIMATION_DURATION : 0 ;
547586 final int length = mTargetDrawables .size ();
548587 for (int i = 0 ; i < length ; i ++) {
549588 TargetDrawable target = mTargetDrawables .get (i );
550589 target .setState (TargetDrawable .STATE_INACTIVE );
551- target .setScaleX (TARGET_INITIAL_POSITION_SCALE );
552- target .setScaleY (TARGET_INITIAL_POSITION_SCALE );
553- mTargetAnimations .add (Tweener .to (target , animate ? SHOW_ANIMATION_DURATION : 0 ,
590+ target .setScaleX (TARGET_SCALE_SELECTED );
591+ target .setScaleY (TARGET_SCALE_SELECTED );
592+ mTargetAnimations .add (Tweener .to (target , duration ,
554593 "ease" , Ease .Cubic .easeOut ,
555594 "alpha" , 1.0f ,
556595 "scaleX" , 1.0f ,
557596 "scaleY" , 1.0f ,
558597 "delay" , delay ,
559598 "onUpdate" , mUpdateListener ));
560599 }
561- mOuterRing .setScaleX (0.5f );
562- mOuterRing .setScaleY (0.5f );
563- mTargetAnimations .add (Tweener .to (mOuterRing , animate ? SHOW_ANIMATION_DURATION : 0 ,
600+ mTargetAnimations .add (Tweener .to (mOuterRing , duration ,
564601 "ease" , Ease .Cubic .easeOut ,
565602 "alpha" , 1.0f ,
566603 "scaleX" , 1.0f ,
@@ -572,10 +609,6 @@ private void showTargets(boolean animate) {
572609 mTargetAnimations .start ();
573610 }
574611
575- private void stopTargetAnimation () {
576- mTargetAnimations .stop ();
577- }
578-
579612 private void vibrate () {
580613 if (mVibrator != null ) {
581614 mVibrator .vibrate (mVibrationDuration );
@@ -708,7 +741,7 @@ public void ping() {
708741 public void reset (boolean animate ) {
709742 stopChevronAnimation ();
710743 stopHandleAnimation ();
711- stopTargetAnimation ();
744+ mTargetAnimations . stop ();
712745 hideChevrons ();
713746 hideTargets (animate );
714747 mHandleDrawable .setX (0 );
@@ -760,7 +793,7 @@ private void moveHandleTo(float x, float y, boolean animate) {
760793 private void handleDown (MotionEvent event ) {
761794 if (!trySwitchToFirstTouchState (event .getX (), event .getY ())) {
762795 mDragging = false ;
763- stopTargetAnimation ();
796+ mTargetAnimations . cancel ();
764797 ping ();
765798 }
766799 }
@@ -815,8 +848,8 @@ private void handleMove(MotionEvent event) {
815848 // For more than one target, snap to the closest one less than hitRadius away.
816849 float best = Float .MAX_VALUE ;
817850 final float hitRadius2 = mHitRadius * mHitRadius ;
851+ // Find first target in range
818852 for (int i = 0 ; i < ntargets ; i ++) {
819- // Snap to the first target in range
820853 TargetDrawable target = targets .get (i );
821854 float dx = limitX - target .getX ();
822855 float dy = limitY - target .getY ();
@@ -842,10 +875,15 @@ private void handleMove(MotionEvent event) {
842875 float newX = singleTarget ? x : target .getX ();
843876 float newY = singleTarget ? y : target .getY ();
844877 moveHandleTo (newX , newY , false );
878+ mHandleAnimations .cancel ();
879+ mHandleDrawable .setAlpha (0.0f );
845880 } else {
846881 switchToState (STATE_TRACKING , x , y );
882+ if (mActiveTarget != -1 ) {
883+ mHandleAnimations .cancel ();
884+ mHandleDrawable .setAlpha (1.0f );
885+ }
847886 moveHandleTo (x , y , false );
848- mHandleDrawable .setAlpha (1.0f );
849887 }
850888
851889 // Draw handle outside parent's bounds
@@ -857,15 +895,13 @@ private void handleMove(MotionEvent event) {
857895 TargetDrawable target = targets .get (mActiveTarget );
858896 if (target .hasState (TargetDrawable .STATE_FOCUSED )) {
859897 target .setState (TargetDrawable .STATE_INACTIVE );
860- mHandleDrawable .setAlpha (1.0f );
861898 }
862899 }
863900 // Focus the new target
864901 if (activeTarget != -1 ) {
865902 TargetDrawable target = targets .get (activeTarget );
866903 if (target .hasState (TargetDrawable .STATE_FOCUSED )) {
867904 target .setState (TargetDrawable .STATE_FOCUSED );
868- mHandleDrawable .setAlpha (0.0f );
869905 }
870906 dispatchGrabbedEvent (activeTarget );
871907 if (AccessibilityManager .getInstance (mContext ).isEnabled ()) {
0 commit comments