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 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
47    public SettingsButton(Context context, AttributeSet attrs) {
48        super(context, attrs);
49        mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
50    }
51
52    public boolean isAnimating() {
53        return mAnimator != null && mAnimator.isRunning();
54    }
55
56    public boolean isTunerClick() {
57        return mUpToSpeed;
58    }
59
60    @Override
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
88    private void cancelLongClick() {
89        cancelAnimation();
90        mUpToSpeed = false;
91        removeCallbacks(mLongPressCallback);
92    }
93
94    private void cancelAnimation() {
95        if (mAnimator != null) {
96            mAnimator.removeAllListeners();
97            mAnimator.cancel();
98            mAnimator = null;
99        }
100    }
101
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
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
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