2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.android.camera.widget;
18 import com.google.common.base.Optional;
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;
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;
41 import java.util.ArrayList;
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;
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;
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;
68 private boolean mIsPortrait;
69 private float mRadius = 0f;
72 * A class implementing this interface will receive callback events from
75 public interface Listener {
77 * Called when about to start animating the mode options from hidden
80 public void onBeginToShowModeOptions();
83 * Called when about to start animating the mode options from visible
86 public void onBeginToHideModeOptions();
90 private Optional<Listener> mListener;
92 public ModeOptions(Context context, AttributeSet attrs) {
93 super(context, attrs);
94 mListener = Optional.absent();
98 * Whether the mode options is hidden or in the middle of fading
101 public boolean isHiddenOrHiding() {
102 return mIsHiddenOrHiding;
108 * @param listener The listener to be set.
110 public void setListener(Listener listener) {
111 mListener = Optional.of(listener);
114 public void setViewToShowHide(View v) {
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;
129 ImageButton exposureButton = (ImageButton) findViewById(R.id.exposure_button);
130 exposureButton.setOnClickListener(new View.OnClickListener() {
132 public void onClick(View v) {
133 mActiveBar = mModeOptionsExposure;
134 mMainBar.setVisibility(View.INVISIBLE);
135 mActiveBar.setVisibility(View.VISIBLE);
140 public void setMainBar(int b) {
141 for (int i = 0; i < getChildCount(); i++) {
142 getChildAt(i).setVisibility(View.INVISIBLE);
146 mMainBar = mActiveBar = mModeOptionsButtons;
149 mMainBar = mActiveBar = mModeOptionsPano;
152 mMainBar.setVisibility(View.VISIBLE);
155 public int getMainBar() {
156 if (mMainBar == mModeOptionsButtons) {
159 if (mMainBar == mModeOptionsPano) {
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);
174 if (mActiveBar != null && mActiveBar != mMainBar) {
175 mActiveBar.setVisibility(INVISIBLE);
177 if (mViewToShowHide != null) {
178 mViewToShowHide.setVisibility(VISIBLE);
180 mIsHiddenOrHiding = true;
185 public void onLayout(boolean changed, int left, int top, int right, int bottom) {
187 mIsPortrait = (getResources().getConfiguration().orientation ==
188 Configuration.ORIENTATION_PORTRAIT);
190 int buttonSize = getResources()
191 .getDimensionPixelSize(R.dimen.option_button_circle_size);
192 int buttonPadding = getResources()
193 .getDimensionPixelSize(R.dimen.mode_options_toggle_padding);
195 float rLeft, rRight, rTop, rBottom;
197 rLeft = getWidth() - buttonPadding - buttonSize;
198 rTop = (getHeight() - buttonSize) / 2.0f;
200 rLeft = buttonPadding;
201 rTop = buttonPadding;
203 rRight = rLeft + buttonSize;
204 rBottom = rTop + buttonSize;
205 mAnimateFrom.set(rLeft, rTop, rRight, rBottom);
208 setupToggleButtonParams();
211 super.onLayout(changed, left, top, right, bottom);
215 public void onDraw(Canvas canvas) {
217 canvas.drawCircle(mAnimateFrom.centerX(), mAnimateFrom.centerY(), mRadius, mPaint);
219 canvas.drawPaint(mPaint);
221 super.onDraw(canvas);
224 private void setupToggleButtonParams() {
225 int size = (mIsPortrait ? getHeight() : getWidth());
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);
239 private void setupAnimators() {
240 if (mVisibleAnimator != null) {
241 mVisibleAnimator.end();
243 if (mHiddenAnimator != null) {
244 mHiddenAnimator.end();
247 final float fullSize = (mIsPortrait ? (float) getWidth() : (float) getHeight());
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() {
257 public void onAnimationUpdate(ValueAnimator animation) {
258 mRadius = (Float) animation.getAnimatedValue();
263 radiusAnimator.addListener(new AnimatorListenerAdapter() {
265 public void onAnimationEnd(Animator animation) {
271 final ValueAnimator alphaAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
272 alphaAnimator.setDuration(SHOW_ALPHA_ANIMATION_TIME);
273 alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
275 public void onAnimationUpdate(ValueAnimator animation) {
276 mActiveBar.setAlpha((Float) animation.getAnimatedValue());
279 alphaAnimator.addListener(new AnimatorListenerAdapter() {
281 public void onAnimationEnd(Animator animation) {
282 mActiveBar.setAlpha(1.0f);
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++) {
293 button = mActiveBar.getChildAt(i);
295 button = mActiveBar.getChildAt(childCount-1-i);
298 final ValueAnimator paddingAnimator =
299 ValueAnimator.ofFloat(deltaX*(childCount-i), 0.0f);
300 paddingAnimator.setDuration(PADDING_ANIMATION_TIME);
301 paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
303 public void onAnimationUpdate(ValueAnimator animation) {
305 button.setTranslationX((Float) animation.getAnimatedValue());
307 button.setTranslationY(-((Float) animation.getAnimatedValue()));
313 paddingAnimators.add(paddingAnimator);
316 AnimatorSet paddingAnimatorSet = new AnimatorSet();
317 paddingAnimatorSet.playTogether(paddingAnimators);
319 mVisibleAnimator = new AnimatorSet();
320 mVisibleAnimator.setInterpolator(Gusterpolator.INSTANCE);
321 mVisibleAnimator.playTogether(radiusAnimator, alphaAnimator, paddingAnimatorSet);
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() {
332 public void onAnimationUpdate(ValueAnimator animation) {
333 mRadius = (Float) animation.getAnimatedValue();
339 radiusAnimator.addListener(new AnimatorListenerAdapter() {
341 public void onAnimationEnd(Animator animation) {
342 if (mViewToShowHide != null) {
343 mViewToShowHide.setVisibility(View.VISIBLE);
351 final ValueAnimator alphaAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);
352 alphaAnimator.setDuration(HIDE_ALPHA_ANIMATION_TIME);
353 alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
355 public void onAnimationUpdate(ValueAnimator animation) {
356 mActiveBar.setAlpha((Float) animation.getAnimatedValue());
360 alphaAnimator.addListener(new AnimatorListenerAdapter() {
362 public void onAnimationEnd(Animator animation) {
363 setVisibility(View.INVISIBLE);
364 if (mActiveBar != mMainBar) {
365 mActiveBar.setAlpha(1.0f);
366 mActiveBar.setVisibility(View.INVISIBLE);
368 mMainBar.setAlpha(1.0f);
369 mMainBar.setVisibility(View.VISIBLE);
370 mActiveBar = mMainBar;
375 mHiddenAnimator = new AnimatorSet();
376 mHiddenAnimator.setInterpolator(Gusterpolator.INSTANCE);
377 mHiddenAnimator.playTogether(radiusAnimator, alphaAnimator);
381 public void animateVisible() {
382 if (mIsHiddenOrHiding) {
383 if (mViewToShowHide != null) {
384 mViewToShowHide.setVisibility(View.INVISIBLE);
386 mHiddenAnimator.cancel();
387 mVisibleAnimator.end();
388 setVisibility(View.VISIBLE);
389 mVisibleAnimator.start();
390 if (mListener.isPresent()) {
391 mListener.get().onBeginToShowModeOptions();
394 mIsHiddenOrHiding = false;
397 public void animateHidden() {
398 if (!mIsHiddenOrHiding) {
399 mVisibleAnimator.cancel();
400 mHiddenAnimator.end();
401 mHiddenAnimator.start();
402 if (mListener.isPresent()) {
403 mListener.get().onBeginToHideModeOptions();
406 mIsHiddenOrHiding = true;