1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.systemui.statusbar.phone; 17 18 import android.animation.Animator; 19 import android.animation.Animator.AnimatorListener; 20 import android.animation.ObjectAnimator; 21 import android.content.Context; 22 import android.util.AttributeSet; 23 import android.view.HapticFeedbackConstants; 24 import android.view.MotionEvent; 25 import android.view.View; 26 import android.view.ViewConfiguration; 27 import android.view.animation.Animation; 28 import android.view.animation.AnimationUtils; 29 30 import com.android.keyguard.AlphaOptimizedImageButton; 31 import com.android.systemui.Interpolators; 32 33 public class SettingsButton extends AlphaOptimizedImageButton { 34 35 private static final boolean TUNER_ENABLE_AVAILABLE = false; 36 37 private static final long LONG_PRESS_LENGTH = 1000; 38 private static final long ACCEL_LENGTH = 750; 39 private static final long FULL_SPEED_LENGTH = 375; 40 private static final long RUN_DURATION = 350; 41 42 private boolean mUpToSpeed; 43 private ObjectAnimator mAnimator; 44 45 private float mSlop; 46 SettingsButton(Context context, AttributeSet attrs)47 public SettingsButton(Context context, AttributeSet attrs) { 48 super(context, attrs); 49 mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 50 } 51 isAnimating()52 public boolean isAnimating() { 53 return mAnimator != null && mAnimator.isRunning(); 54 } 55 isTunerClick()56 public boolean isTunerClick() { 57 return mUpToSpeed; 58 } 59 60 @Override onTouchEvent(MotionEvent event)61 public boolean onTouchEvent(MotionEvent event) { 62 switch (event.getActionMasked()) { 63 case MotionEvent.ACTION_DOWN: 64 if (TUNER_ENABLE_AVAILABLE) postDelayed(mLongPressCallback, LONG_PRESS_LENGTH); 65 break; 66 case MotionEvent.ACTION_UP: 67 if (mUpToSpeed) { 68 startExitAnimation(); 69 } else { 70 cancelLongClick(); 71 } 72 break; 73 case MotionEvent.ACTION_CANCEL: 74 cancelLongClick(); 75 break; 76 case MotionEvent.ACTION_MOVE: 77 float x = event.getX(); 78 float y = event.getY(); 79 if ((x < -mSlop) || (y < -mSlop) || (x > getWidth() + mSlop) 80 || (y > getHeight() + mSlop)) { 81 cancelLongClick(); 82 } 83 break; 84 } 85 return super.onTouchEvent(event); 86 } 87 cancelLongClick()88 private void cancelLongClick() { 89 cancelAnimation(); 90 mUpToSpeed = false; 91 removeCallbacks(mLongPressCallback); 92 } 93 cancelAnimation()94 private void cancelAnimation() { 95 if (mAnimator != null) { 96 mAnimator.removeAllListeners(); 97 mAnimator.cancel(); 98 mAnimator = null; 99 } 100 } 101 startExitAnimation()102 private void startExitAnimation() { 103 animate() 104 .translationX(((View) getParent().getParent()).getWidth() - getX()) 105 .alpha(0) 106 .setDuration(RUN_DURATION) 107 .setInterpolator(AnimationUtils.loadInterpolator(mContext, 108 android.R.interpolator.accelerate_cubic)) 109 .setListener(new AnimatorListener() { 110 @Override 111 public void onAnimationStart(Animator animation) { 112 } 113 114 @Override 115 public void onAnimationRepeat(Animator animation) { 116 } 117 118 @Override 119 public void onAnimationEnd(Animator animation) { 120 setAlpha(1f); 121 setTranslationX(0); 122 cancelLongClick(); 123 } 124 125 @Override 126 public void onAnimationCancel(Animator animation) { 127 } 128 }) 129 .start(); 130 } 131 startAccelSpin()132 protected void startAccelSpin() { 133 cancelAnimation(); 134 mAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, 0, 360); 135 mAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext, 136 android.R.interpolator.accelerate_quad)); 137 mAnimator.setDuration(ACCEL_LENGTH); 138 mAnimator.addListener(new AnimatorListener() { 139 @Override 140 public void onAnimationStart(Animator animation) { 141 } 142 143 @Override 144 public void onAnimationRepeat(Animator animation) { 145 } 146 147 @Override 148 public void onAnimationEnd(Animator animation) { 149 startContinuousSpin(); 150 } 151 152 @Override 153 public void onAnimationCancel(Animator animation) { 154 } 155 }); 156 mAnimator.start(); 157 } 158 startContinuousSpin()159 protected void startContinuousSpin() { 160 cancelAnimation(); 161 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 162 mUpToSpeed = true; 163 mAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, 0, 360); 164 mAnimator.setInterpolator(Interpolators.LINEAR); 165 mAnimator.setDuration(FULL_SPEED_LENGTH); 166 mAnimator.setRepeatCount(Animation.INFINITE); 167 mAnimator.start(); 168 } 169 170 private final Runnable mLongPressCallback = new Runnable() { 171 @Override 172 public void run() { 173 startAccelSpin(); 174 } 175 }; 176 } 177