ModeOptions.java revision 591eec6465d29bbc053e164071c4c3a7c260a1d3
1/*
2 * Copyright (C) 2014 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.camera.widget;
17
18import android.animation.Animator;
19import android.animation.AnimatorListenerAdapter;
20import android.animation.AnimatorSet;
21import android.animation.ObjectAnimator;
22import android.animation.ValueAnimator;
23import android.content.Context;
24import android.content.res.Configuration;
25import android.graphics.Canvas;
26import android.graphics.Path;
27import android.graphics.Paint;
28import android.graphics.RectF;
29import android.view.Gravity;
30import android.view.View;
31import android.widget.FrameLayout;
32import android.widget.LinearLayout;
33import android.util.AttributeSet;
34
35import com.android.camera.util.Gusterpolator;
36import com.android.camera2.R;
37
38public class ModeOptions extends FrameLayout {
39    private int mBackgroundColor;
40    private final Paint mPaint = new Paint();
41    private final Path mPath = new Path();
42    private boolean mIsHiddenOrHiding;
43    private RectF mAnimateFrom = new RectF();
44    private View mViewToShowHide;
45    private View mModeOptionsButtons;
46
47    private AnimatorSet mVisibleAnimator;
48    private AnimatorSet mHiddenAnimator;
49    private boolean mDrawCircle;
50    private boolean mFill;
51    private static final int RADIUS_ANIMATION_TIME = 250;
52    private static final int SHOW_ALPHA_ANIMATION_TIME = 350;
53    private static final int HIDE_ALPHA_ANIMATION_TIME = 200;
54    private static final int PADDING_ANIMATION_TIME = 90;
55
56    private int mParentSize;
57    private boolean mIsPortrait;
58
59    public ModeOptions(Context context, AttributeSet attrs) {
60        super(context, attrs);
61    }
62
63    public void setViewToShowHide(View v) {
64        mViewToShowHide = v;
65    }
66
67    @Override
68    public void onFinishInflate() {
69        mIsHiddenOrHiding = true;
70        mBackgroundColor = getResources().getColor(R.color.mode_options_background);
71        mPaint.setAntiAlias(true);
72        mPaint.setColor(mBackgroundColor);
73        mModeOptionsButtons = findViewById(R.id.mode_options_buttons);
74    }
75
76    @Override
77    public void onConfigurationChanged(Configuration config) {
78        super.onConfigurationChanged(config);
79
80        FrameLayout.LayoutParams params =
81            (FrameLayout.LayoutParams) mModeOptionsButtons.getLayoutParams();
82
83        if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
84            params.gravity = Gravity.RIGHT;
85        } else {
86            params.gravity = Gravity.TOP;
87        }
88
89        mVisibleAnimator.end();
90        mHiddenAnimator.end();
91
92        mModeOptionsButtons.setLayoutParams(params);
93    }
94
95
96    @Override
97    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
98        if (changed) {
99            mIsPortrait = (getResources().getConfiguration().orientation ==
100                           Configuration.ORIENTATION_PORTRAIT);
101
102            int buttonSize = getResources()
103                .getDimensionPixelSize(R.dimen.option_button_circle_size);
104            int buttonPadding = getResources()
105                .getDimensionPixelSize(R.dimen.mode_options_toggle_padding);
106
107            float rLeft, rRight, rTop, rBottom;
108            View parent = (View) getParent();
109            if (mIsPortrait) {
110                rLeft = getWidth() - buttonPadding - buttonSize;
111                rTop = (getHeight() - buttonSize) / 2.0f;
112
113                mParentSize = parent.getWidth();
114            } else {
115                rLeft = buttonPadding;
116                rTop = buttonPadding;
117
118                mParentSize = parent.getHeight();
119            }
120            rRight = rLeft + buttonSize;
121            rBottom = rTop + buttonSize;
122            mAnimateFrom.set(rLeft, rTop, rRight, rBottom);
123
124            setupAnimators();
125        }
126
127        super.onLayout(changed, left, top, right, bottom);
128    }
129
130    @Override
131    public void onDraw(Canvas canvas) {
132        if (mDrawCircle) {
133            canvas.drawPath(mPath, mPaint);
134        } else if (mFill) {
135            canvas.drawPaint(mPaint);
136        }
137        super.onDraw(canvas);
138    }
139
140    private void setupAnimators() {
141        final float fullSize = (mIsPortrait ? (float) getWidth() : (float) getHeight());
142
143        // show
144        {
145            final ValueAnimator radiusAnimator =
146                ValueAnimator.ofFloat(mAnimateFrom.width()/2.0f,
147                    fullSize-mAnimateFrom.width()/2.0f);
148            radiusAnimator.setDuration(RADIUS_ANIMATION_TIME);
149            radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
150                @Override
151                public void onAnimationUpdate(ValueAnimator animation) {
152                    mPath.reset();
153                    mPath.addCircle(mAnimateFrom.centerX(),
154                        mAnimateFrom.centerY(),
155                        (Float) animation.getAnimatedValue(),
156                        Path.Direction.CW);
157                    mDrawCircle = true;
158                    mFill = false;
159                    invalidate();
160                }
161            });
162            radiusAnimator.addListener(new AnimatorListenerAdapter() {
163                @Override
164                public void onAnimationEnd(Animator animation) {
165                    mPath.reset();
166                    mDrawCircle = false;
167                    mFill = true;
168                    invalidate();
169                }
170            });
171
172            final ValueAnimator alphaAnimator = ValueAnimator.ofFloat(1.0f, 1.0f);
173            alphaAnimator.setDuration(SHOW_ALPHA_ANIMATION_TIME);
174            alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
175                @Override
176                public void onAnimationUpdate(ValueAnimator animation) {
177                    mModeOptionsButtons.setAlpha((Float) animation.getAnimatedValue());
178                    invalidate();
179                }
180            });
181            alphaAnimator.addListener(new AnimatorListenerAdapter() {
182                @Override
183                public void onAnimationEnd(Animator animation) {
184                    mModeOptionsButtons.setAlpha(1.0f);
185                    invalidate();
186                }
187            });
188
189            final ValueAnimator paddingAnimator = ValueAnimator.ofInt(mParentSize, 0);
190            paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
191                @Override
192                public void onAnimationUpdate(ValueAnimator animation) {
193                    if (mIsPortrait) {
194                        mModeOptionsButtons
195                            .setPadding((Integer) animation.getAnimatedValue(), 0, 0, 0);
196                    } else {
197                        mModeOptionsButtons
198                            .setPadding(0, 0, 0, (Integer) animation.getAnimatedValue());
199                    }
200                    requestLayout();
201                    invalidate();
202                }
203            });
204            paddingAnimator.setDuration(PADDING_ANIMATION_TIME);
205            paddingAnimator.addListener(new AnimatorListenerAdapter() {
206                @Override
207                public void onAnimationEnd(Animator animation) {
208                    mModeOptionsButtons
209                        .setPadding(0, 0, 0, 0);
210
211                    requestLayout();
212                    invalidate();
213                }
214            });
215
216            mVisibleAnimator = new AnimatorSet();
217            mVisibleAnimator.setInterpolator(Gusterpolator.INSTANCE);
218            mVisibleAnimator.playTogether(radiusAnimator, alphaAnimator, paddingAnimator);
219        }
220
221        // hide
222        {
223            final ValueAnimator radiusAnimator =
224                ValueAnimator.ofFloat(fullSize-mAnimateFrom.width()/2.0f,
225                    mAnimateFrom.width()/2.0f);
226            radiusAnimator.setDuration(RADIUS_ANIMATION_TIME);
227            radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
228                @Override
229                public void onAnimationUpdate(ValueAnimator animation) {
230                    mPath.reset();
231                    mPath.addCircle(mAnimateFrom.centerX(),
232                        mAnimateFrom.centerY(),
233                        (Float) animation.getAnimatedValue(),
234                        Path.Direction.CW);
235                    mDrawCircle = true;
236                    mFill = false;
237                    invalidate();
238                }
239            });
240            radiusAnimator.addListener(new AnimatorListenerAdapter() {
241                @Override
242                public void onAnimationEnd(Animator animation) {
243                    if (mViewToShowHide != null) {
244                        mPath.reset();
245                        mViewToShowHide.setVisibility(View.VISIBLE);
246                        mDrawCircle = false;
247                        mFill = false;
248                        invalidate();
249                    }
250                }
251            });
252
253            final ValueAnimator alphaAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);
254            alphaAnimator.setDuration(HIDE_ALPHA_ANIMATION_TIME);
255            alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
256                @Override
257                public void onAnimationUpdate(ValueAnimator animation) {
258                    mModeOptionsButtons.setAlpha((Float) animation.getAnimatedValue());
259                    invalidate();
260                }
261            });
262            alphaAnimator.addListener(new AnimatorListenerAdapter() {
263                @Override
264                public void onAnimationEnd(Animator animation) {
265                    mModeOptionsButtons.setAlpha(0.0f);
266                    mModeOptionsButtons.setVisibility(View.INVISIBLE);
267                    invalidate();
268                }
269            });
270
271            mHiddenAnimator = new AnimatorSet();
272            mHiddenAnimator.setInterpolator(Gusterpolator.INSTANCE);
273            mHiddenAnimator.playTogether(radiusAnimator, alphaAnimator);
274        }
275    }
276
277    public void animateVisible() {
278        if (mIsHiddenOrHiding) {
279            if (mViewToShowHide != null) {
280                mViewToShowHide.setVisibility(View.INVISIBLE);
281            }
282            mHiddenAnimator.cancel();
283            mVisibleAnimator.end();
284            mModeOptionsButtons.setVisibility(View.VISIBLE);
285            mVisibleAnimator.start();
286        }
287        mIsHiddenOrHiding = false;
288    }
289
290    public void animateHidden() {
291        if (!mIsHiddenOrHiding) {
292            mVisibleAnimator.cancel();
293            mHiddenAnimator.end();
294            mHiddenAnimator.start();
295        }
296        mIsHiddenOrHiding = true;
297    }
298}