OSDN Git Service

Adjust capture indicator position while open/close mode options.
[android-x86/packages-apps-Camera2.git] / src / com / android / camera / widget / ModeOptions.java
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  */
16 package com.android.camera.widget;
17
18 import com.google.common.base.Optional;
19
20 import android.animation.Animator;
21 import android.animation.AnimatorListenerAdapter;
22 import android.animation.AnimatorSet;
23 import android.animation.ValueAnimator;
24 import android.content.Context;
25 import android.content.res.Configuration;
26 import android.graphics.Canvas;
27 import android.graphics.Paint;
28 import android.graphics.RectF;
29 import android.util.AttributeSet;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.widget.FrameLayout;
33 import android.widget.ImageButton;
34
35 import com.android.camera.MultiToggleImageButton;
36 import com.android.camera.ui.RadioOptions;
37 import com.android.camera.ui.TopRightWeightedLayout;
38 import com.android.camera.util.Gusterpolator;
39 import com.android.camera2.R;
40
41 import java.util.ArrayList;
42
43 public class ModeOptions extends FrameLayout {
44     private int mBackgroundColor;
45     private final Paint mPaint = new Paint();
46     private boolean mIsHiddenOrHiding;
47     private RectF mAnimateFrom = new RectF();
48     private View mViewToShowHide;
49     private TopRightWeightedLayout mModeOptionsButtons;
50     private RadioOptions mModeOptionsPano;
51     private RadioOptions mModeOptionsExposure;
52
53     private AnimatorSet mVisibleAnimator;
54     private AnimatorSet mHiddenAnimator;
55     private boolean mDrawCircle;
56     private boolean mFill;
57     private static final int RADIUS_ANIMATION_TIME = 250;
58     private static final int SHOW_ALPHA_ANIMATION_TIME = 350;
59     private static final int HIDE_ALPHA_ANIMATION_TIME = 200;
60     public static final int PADDING_ANIMATION_TIME = 350;
61
62     private ViewGroup mMainBar;
63     private ViewGroup mActiveBar;
64     public static final int BAR_INVALID = -1;
65     public static final int BAR_STANDARD = 0;
66     public static final int BAR_PANO = 1;
67
68     private boolean mIsPortrait;
69     private float mRadius = 0f;
70
71     /**
72      * A class implementing this interface will receive callback events from
73      * mode options.
74      */
75     public interface Listener {
76         /**
77          * Called when about to start animating the mode options from hidden
78          * to visible.
79          */
80         public void onBeginToShowModeOptions();
81
82         /**
83          * Called when about to start animating the mode options from visible
84          * to hidden.
85          */
86         public void onBeginToHideModeOptions();
87     }
88
89     /** The listener. */
90     private Optional<Listener> mListener;
91
92     public ModeOptions(Context context, AttributeSet attrs) {
93         super(context, attrs);
94         mListener = Optional.absent();
95     }
96
97     /**
98      * Whether the mode options is hidden or in the middle of fading
99      * out.
100      */
101     public boolean isHiddenOrHiding() {
102         return mIsHiddenOrHiding;
103     }
104
105     /**
106      * Sets the listener.
107      *
108      * @param listener The listener to be set.
109      */
110     public void setListener(Listener listener) {
111         mListener = Optional.of(listener);
112     }
113
114     public void setViewToShowHide(View v) {
115         mViewToShowHide = v;
116     }
117
118     @Override
119     public void onFinishInflate() {
120         mIsHiddenOrHiding = true;
121         mBackgroundColor = getResources().getColor(R.color.mode_options_background);
122         mPaint.setAntiAlias(true);
123         mPaint.setColor(mBackgroundColor);
124         mModeOptionsButtons = (TopRightWeightedLayout) findViewById(R.id.mode_options_buttons);
125         mModeOptionsPano = (RadioOptions) findViewById(R.id.mode_options_pano);
126         mModeOptionsExposure = (RadioOptions) findViewById(R.id.mode_options_exposure);
127         mMainBar = mActiveBar = mModeOptionsButtons;
128
129         ImageButton exposureButton = (ImageButton) findViewById(R.id.exposure_button);
130         exposureButton.setOnClickListener(new View.OnClickListener() {
131             @Override
132             public void onClick(View v) {
133                 mActiveBar = mModeOptionsExposure;
134                 mMainBar.setVisibility(View.INVISIBLE);
135                 mActiveBar.setVisibility(View.VISIBLE);
136             }
137         });
138     }
139
140     public void setMainBar(int b) {
141         for (int i = 0; i < getChildCount(); i++) {
142             getChildAt(i).setVisibility(View.INVISIBLE);
143         }
144         switch (b) {
145         case BAR_STANDARD:
146             mMainBar = mActiveBar = mModeOptionsButtons;
147             break;
148         case BAR_PANO:
149             mMainBar = mActiveBar = mModeOptionsPano;
150             break;
151         }
152         mMainBar.setVisibility(View.VISIBLE);
153     }
154
155     public int getMainBar() {
156         if (mMainBar == mModeOptionsButtons) {
157             return BAR_STANDARD;
158         }
159         if (mMainBar == mModeOptionsPano) {
160             return BAR_PANO;
161         }
162         return BAR_INVALID;
163     }
164
165     @Override
166     public void onWindowVisibilityChanged(int visibility) {
167         super.onWindowVisibilityChanged(visibility);
168         if (visibility != VISIBLE && !mIsHiddenOrHiding) {
169             // Collapse mode options when window is not visible.
170             setVisibility(INVISIBLE);
171             if (mMainBar != null) {
172                 mMainBar.setVisibility(VISIBLE);
173             }
174             if (mActiveBar != null && mActiveBar != mMainBar) {
175                 mActiveBar.setVisibility(INVISIBLE);
176             }
177             if (mViewToShowHide != null) {
178                 mViewToShowHide.setVisibility(VISIBLE);
179             }
180             mIsHiddenOrHiding = true;
181         }
182     }
183
184     @Override
185     public void onLayout(boolean changed, int left, int top, int right, int bottom) {
186         if (changed) {
187             mIsPortrait = (getResources().getConfiguration().orientation ==
188                            Configuration.ORIENTATION_PORTRAIT);
189
190             int buttonSize = getResources()
191                 .getDimensionPixelSize(R.dimen.option_button_circle_size);
192             int buttonPadding = getResources()
193                 .getDimensionPixelSize(R.dimen.mode_options_toggle_padding);
194
195             float rLeft, rRight, rTop, rBottom;
196             if (mIsPortrait) {
197                 rLeft = getWidth() - buttonPadding - buttonSize;
198                 rTop = (getHeight() - buttonSize) / 2.0f;
199             } else {
200                 rLeft = buttonPadding;
201                 rTop = buttonPadding;
202             }
203             rRight = rLeft + buttonSize;
204             rBottom = rTop + buttonSize;
205             mAnimateFrom.set(rLeft, rTop, rRight, rBottom);
206
207             setupAnimators();
208             setupToggleButtonParams();
209         }
210
211         super.onLayout(changed, left, top, right, bottom);
212     }
213
214     @Override
215     public void onDraw(Canvas canvas) {
216         if (mDrawCircle) {
217             canvas.drawCircle(mAnimateFrom.centerX(), mAnimateFrom.centerY(), mRadius, mPaint);
218         } else if (mFill) {
219             canvas.drawPaint(mPaint);
220         }
221         super.onDraw(canvas);
222     }
223
224     private void setupToggleButtonParams() {
225         int size = (mIsPortrait ? getHeight() : getWidth());
226
227         for (int i = 0; i < mModeOptionsButtons.getChildCount(); i++) {
228             View button = mModeOptionsButtons.getChildAt(i);
229             if (button instanceof MultiToggleImageButton) {
230                 MultiToggleImageButton toggleButton = (MultiToggleImageButton) button;
231                 toggleButton.setParentSize(size);
232                 toggleButton.setAnimDirection(mIsPortrait ?
233                         MultiToggleImageButton.ANIM_DIRECTION_VERTICAL :
234                         MultiToggleImageButton.ANIM_DIRECTION_HORIZONTAL);
235             }
236         }
237     }
238
239     private void setupAnimators() {
240         if (mVisibleAnimator != null) {
241             mVisibleAnimator.end();
242         }
243         if (mHiddenAnimator != null) {
244             mHiddenAnimator.end();
245         }
246
247         final float fullSize = (mIsPortrait ? (float) getWidth() : (float) getHeight());
248
249         // show
250         {
251             final ValueAnimator radiusAnimator =
252                 ValueAnimator.ofFloat(mAnimateFrom.width()/2.0f,
253                     fullSize-mAnimateFrom.width()/2.0f);
254             radiusAnimator.setDuration(RADIUS_ANIMATION_TIME);
255             radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
256                 @Override
257                 public void onAnimationUpdate(ValueAnimator animation) {
258                     mRadius = (Float) animation.getAnimatedValue();
259                     mDrawCircle = true;
260                     mFill = false;
261                 }
262             });
263             radiusAnimator.addListener(new AnimatorListenerAdapter() {
264                 @Override
265                 public void onAnimationEnd(Animator animation) {
266                     mDrawCircle = false;
267                     mFill = true;
268                 }
269             });
270
271             final ValueAnimator alphaAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
272             alphaAnimator.setDuration(SHOW_ALPHA_ANIMATION_TIME);
273             alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
274                 @Override
275                 public void onAnimationUpdate(ValueAnimator animation) {
276                     mActiveBar.setAlpha((Float) animation.getAnimatedValue());
277                 }
278             });
279             alphaAnimator.addListener(new AnimatorListenerAdapter() {
280                 @Override
281                 public void onAnimationEnd(Animator animation) {
282                     mActiveBar.setAlpha(1.0f);
283                 }
284             });
285
286             final int deltaX = getResources()
287                 .getDimensionPixelSize(R.dimen.mode_options_buttons_anim_delta_x);
288             int childCount = mActiveBar.getChildCount();
289             ArrayList<Animator> paddingAnimators = new ArrayList<Animator>();
290             for (int i = 0; i < childCount; i++) {
291                 final View button;
292                 if (mIsPortrait) {
293                     button = mActiveBar.getChildAt(i);
294                 } else {
295                     button = mActiveBar.getChildAt(childCount-1-i);
296                 }
297
298                 final ValueAnimator paddingAnimator =
299                     ValueAnimator.ofFloat(deltaX*(childCount-i), 0.0f);
300                 paddingAnimator.setDuration(PADDING_ANIMATION_TIME);
301                 paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
302                     @Override
303                     public void onAnimationUpdate(ValueAnimator animation) {
304                         if (mIsPortrait) {
305                             button.setTranslationX((Float) animation.getAnimatedValue());
306                         } else {
307                             button.setTranslationY(-((Float) animation.getAnimatedValue()));
308                         }
309                         invalidate();
310                     }
311                 });
312
313                 paddingAnimators.add(paddingAnimator);
314             }
315
316             AnimatorSet paddingAnimatorSet = new AnimatorSet();
317             paddingAnimatorSet.playTogether(paddingAnimators);
318
319             mVisibleAnimator = new AnimatorSet();
320             mVisibleAnimator.setInterpolator(Gusterpolator.INSTANCE);
321             mVisibleAnimator.playTogether(radiusAnimator, alphaAnimator, paddingAnimatorSet);
322         }
323
324         // hide
325         {
326             final ValueAnimator radiusAnimator =
327                 ValueAnimator.ofFloat(fullSize-mAnimateFrom.width()/2.0f,
328                     mAnimateFrom.width()/2.0f);
329             radiusAnimator.setDuration(RADIUS_ANIMATION_TIME);
330             radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
331                 @Override
332                 public void onAnimationUpdate(ValueAnimator animation) {
333                     mRadius = (Float) animation.getAnimatedValue();
334                     mDrawCircle = true;
335                     mFill = false;
336                     invalidate();
337                 }
338             });
339             radiusAnimator.addListener(new AnimatorListenerAdapter() {
340                 @Override
341                 public void onAnimationEnd(Animator animation) {
342                     if (mViewToShowHide != null) {
343                         mViewToShowHide.setVisibility(View.VISIBLE);
344                         mDrawCircle = false;
345                         mFill = false;
346                         invalidate();
347                     }
348                 }
349             });
350
351             final ValueAnimator alphaAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);
352             alphaAnimator.setDuration(HIDE_ALPHA_ANIMATION_TIME);
353             alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
354                 @Override
355                 public void onAnimationUpdate(ValueAnimator animation) {
356                     mActiveBar.setAlpha((Float) animation.getAnimatedValue());
357                     invalidate();
358                 }
359             });
360             alphaAnimator.addListener(new AnimatorListenerAdapter() {
361                 @Override
362                 public void onAnimationEnd(Animator animation) {
363                     setVisibility(View.INVISIBLE);
364                     if (mActiveBar != mMainBar) {
365                         mActiveBar.setAlpha(1.0f);
366                         mActiveBar.setVisibility(View.INVISIBLE);
367                     }
368                     mMainBar.setAlpha(1.0f);
369                     mMainBar.setVisibility(View.VISIBLE);
370                     mActiveBar = mMainBar;
371                     invalidate();
372                 }
373             });
374
375             mHiddenAnimator = new AnimatorSet();
376             mHiddenAnimator.setInterpolator(Gusterpolator.INSTANCE);
377             mHiddenAnimator.playTogether(radiusAnimator, alphaAnimator);
378         }
379     }
380
381     public void animateVisible() {
382         if (mIsHiddenOrHiding) {
383             if (mViewToShowHide != null) {
384                 mViewToShowHide.setVisibility(View.INVISIBLE);
385             }
386             mHiddenAnimator.cancel();
387             mVisibleAnimator.end();
388             setVisibility(View.VISIBLE);
389             mVisibleAnimator.start();
390             if (mListener.isPresent()) {
391                 mListener.get().onBeginToShowModeOptions();
392             }
393         }
394         mIsHiddenOrHiding = false;
395     }
396
397     public void animateHidden() {
398         if (!mIsHiddenOrHiding) {
399             mVisibleAnimator.cancel();
400             mHiddenAnimator.end();
401             mHiddenAnimator.start();
402             if (mListener.isPresent()) {
403                 mListener.get().onBeginToHideModeOptions();
404             }
405         }
406         mIsHiddenOrHiding = true;
407     }
408 }