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 */
16package com.android.systemui.statusbar.phone;
17
18import android.animation.Animator;
19import android.animation.Animator.AnimatorListener;
20import android.animation.ObjectAnimator;
21import android.content.Context;
22import android.util.AttributeSet;
23import android.view.HapticFeedbackConstants;
24import android.view.MotionEvent;
25import android.view.View;
26import android.view.ViewConfiguration;
27import android.view.animation.Animation;
28import android.view.animation.AnimationUtils;
29
30import com.android.keyguard.AlphaOptimizedImageButton;
31import com.android.systemui.Interpolators;
32
33public class SettingsButton extends AlphaOptimizedImageButton {
34
35    private static final long LONG_PRESS_LENGTH = 1000;
36    private static final long ACCEL_LENGTH = 750;
37    private static final long FULL_SPEED_LENGTH = 375;
38    private static final long RUN_DURATION = 350;
39
40    private boolean mUpToSpeed;
41    private ObjectAnimator mAnimator;
42
43    private float mSlop;
44
45    public SettingsButton(Context context, AttributeSet attrs) {
46        super(context, attrs);
47        mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
48    }
49
50    public boolean isAnimating() {
51        return mAnimator != null && mAnimator.isRunning();
52    }
53
54    public boolean isTunerClick() {
55        return mUpToSpeed;
56    }
57
58    @Override
59    public boolean onTouchEvent(MotionEvent event) {
60        switch (event.getActionMasked()) {
61            case MotionEvent.ACTION_DOWN:
62                postDelayed(mLongPressCallback, LONG_PRESS_LENGTH);
63                break;
64            case MotionEvent.ACTION_UP:
65                if (mUpToSpeed) {
66                    startExitAnimation();
67                } else {
68                    cancelLongClick();
69                }
70                break;
71            case MotionEvent.ACTION_CANCEL:
72                cancelLongClick();
73                break;
74            case MotionEvent.ACTION_MOVE:
75                float x = event.getX();
76                float y = event.getY();
77                if ((x < -mSlop) || (y < -mSlop) || (x > getWidth() + mSlop)
78                        || (y > getHeight() + mSlop)) {
79                    cancelLongClick();
80                }
81                break;
82        }
83        return super.onTouchEvent(event);
84    }
85
86    private void cancelLongClick() {
87        cancelAnimation();
88        mUpToSpeed = false;
89        removeCallbacks(mLongPressCallback);
90    }
91
92    private void cancelAnimation() {
93        if (mAnimator != null) {
94            mAnimator.removeAllListeners();
95            mAnimator.cancel();
96            mAnimator = null;
97        }
98    }
99
100    private void startExitAnimation() {
101        animate()
102                .translationX(((View) getParent().getParent()).getWidth() - getX())
103                .alpha(0)
104                .setDuration(RUN_DURATION)
105                .setInterpolator(AnimationUtils.loadInterpolator(mContext,
106                        android.R.interpolator.accelerate_cubic))
107                .setListener(new AnimatorListener() {
108                    @Override
109                    public void onAnimationStart(Animator animation) {
110                    }
111
112                    @Override
113                    public void onAnimationRepeat(Animator animation) {
114                    }
115
116                    @Override
117                    public void onAnimationEnd(Animator animation) {
118                        setAlpha(1f);
119                        setTranslationX(0);
120                        cancelLongClick();
121                    }
122
123                    @Override
124                    public void onAnimationCancel(Animator animation) {
125                    }
126                })
127                .start();
128    }
129
130    protected void startAccelSpin() {
131        cancelAnimation();
132        mAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, 0, 360);
133        mAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
134                android.R.interpolator.accelerate_quad));
135        mAnimator.setDuration(ACCEL_LENGTH);
136        mAnimator.addListener(new AnimatorListener() {
137            @Override
138            public void onAnimationStart(Animator animation) {
139            }
140
141            @Override
142            public void onAnimationRepeat(Animator animation) {
143            }
144
145            @Override
146            public void onAnimationEnd(Animator animation) {
147                startContinuousSpin();
148            }
149
150            @Override
151            public void onAnimationCancel(Animator animation) {
152            }
153        });
154        mAnimator.start();
155    }
156
157    protected void startContinuousSpin() {
158        cancelAnimation();
159        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
160        mUpToSpeed = true;
161        mAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, 0, 360);
162        mAnimator.setInterpolator(Interpolators.LINEAR);
163        mAnimator.setDuration(FULL_SPEED_LENGTH);
164        mAnimator.setRepeatCount(Animation.INFINITE);
165        mAnimator.start();
166    }
167
168    private final Runnable mLongPressCallback = new Runnable() {
169        @Override
170        public void run() {
171            startAccelSpin();
172        }
173    };
174}
175