182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague/*
282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague * Copyright (C) 2014 The Android Open Source Project
382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague *
482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague * Licensed under the Apache License, Version 2.0 (the "License");
582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague * you may not use this file except in compliance with the License.
682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague * You may obtain a copy of the License at
782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague *
882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague *      http://www.apache.org/licenses/LICENSE-2.0
982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague *
1082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague * Unless required by applicable law or agreed to in writing, software
1182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague * distributed under the License is distributed on an "AS IS" BASIS,
1282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague * See the License for the specific language governing permissions and
1482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague * limitations under the License.
1582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague */
1682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spraguepackage com.android.camera.widget;
1782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
1854ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Huimport com.google.common.base.Optional;
1954ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu
2082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.animation.Animator;
2182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.animation.AnimatorListenerAdapter;
2282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.animation.AnimatorSet;
2382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.animation.ValueAnimator;
2482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.content.Context;
2582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.content.res.Configuration;
2682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.graphics.Canvas;
2782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.graphics.Paint;
2882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.graphics.RectF;
2918b22b5963e8871e539edf669d96862eec72bb5dSpike Spragueimport android.util.AttributeSet;
3082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.view.View;
3156d43cf80d40379d57ac1db697bc014d5c321b91Spike Spragueimport android.view.ViewGroup;
3282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport android.widget.FrameLayout;
33abf54e2994961395a0feb0b08353e62718443f23Spike Spragueimport android.widget.ImageButton;
3482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
3518b22b5963e8871e539edf669d96862eec72bb5dSpike Spragueimport com.android.camera.MultiToggleImageButton;
3659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Spragueimport com.android.camera.ui.RadioOptions;
3756d43cf80d40379d57ac1db697bc014d5c321b91Spike Spragueimport com.android.camera.ui.TopRightWeightedLayout;
3882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport com.android.camera.util.Gusterpolator;
3982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spragueimport com.android.camera2.R;
4082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
4156d43cf80d40379d57ac1db697bc014d5c321b91Spike Spragueimport java.util.ArrayList;
4256d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague
4382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Spraguepublic class ModeOptions extends FrameLayout {
4482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private int mBackgroundColor;
4582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private final Paint mPaint = new Paint();
46591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague    private boolean mIsHiddenOrHiding;
4782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private RectF mAnimateFrom = new RectF();
4882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private View mViewToShowHide;
4956d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague    private TopRightWeightedLayout mModeOptionsButtons;
5059345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague    private RadioOptions mModeOptionsPano;
5159345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague    private RadioOptions mModeOptionsExposure;
5282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
5382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private AnimatorSet mVisibleAnimator;
5482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private AnimatorSet mHiddenAnimator;
5582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private boolean mDrawCircle;
5682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private boolean mFill;
5782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private static final int RADIUS_ANIMATION_TIME = 250;
5882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private static final int SHOW_ALPHA_ANIMATION_TIME = 350;
5982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private static final int HIDE_ALPHA_ANIMATION_TIME = 200;
6054ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    public static final int PADDING_ANIMATION_TIME = 350;
6182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
6259345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague    private ViewGroup mMainBar;
6359345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague    private ViewGroup mActiveBar;
6459345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague    public static final int BAR_INVALID = -1;
6559345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague    public static final int BAR_STANDARD = 0;
6659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague    public static final int BAR_PANO = 1;
6759345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague
6882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private boolean mIsPortrait;
694df915872c25fe61640a94c7a2c5f27eee1a1048Doris Liu    private float mRadius = 0f;
7082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
7154ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    /**
7254ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu     * A class implementing this interface will receive callback events from
7354ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu     * mode options.
7454ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu     */
7554ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    public interface Listener {
7654ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu        /**
7754ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu         * Called when about to start animating the mode options from hidden
7854ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu         * to visible.
7954ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu         */
8054ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu        public void onBeginToShowModeOptions();
8154ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu
8254ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu        /**
8354ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu         * Called when about to start animating the mode options from visible
8454ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu         * to hidden.
8554ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu         */
8654ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu        public void onBeginToHideModeOptions();
8754ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    }
8854ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu
8954ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    /** The listener. */
9054ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    private Optional<Listener> mListener;
9154ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu
9282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    public ModeOptions(Context context, AttributeSet attrs) {
9382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        super(context, attrs);
9454ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu        mListener = Optional.absent();
9554ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    }
9654ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu
9754ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    /**
9854ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu     * Whether the mode options is hidden or in the middle of fading
9954ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu     * out.
10054ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu     */
10154ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    public boolean isHiddenOrHiding() {
10254ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu        return mIsHiddenOrHiding;
10354ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    }
10454ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu
10554ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    /**
10654ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu     * Sets the listener.
10754ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu     *
10854ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu     * @param listener The listener to be set.
10954ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu     */
11054ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu    public void setListener(Listener listener) {
11154ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu        mListener = Optional.of(listener);
11282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    }
11382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
11482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    public void setViewToShowHide(View v) {
11582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        mViewToShowHide = v;
11682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    }
11782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
11882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    @Override
11982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    public void onFinishInflate() {
120591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague        mIsHiddenOrHiding = true;
12182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        mBackgroundColor = getResources().getColor(R.color.mode_options_background);
12282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        mPaint.setAntiAlias(true);
12382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        mPaint.setColor(mBackgroundColor);
12456d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague        mModeOptionsButtons = (TopRightWeightedLayout) findViewById(R.id.mode_options_buttons);
12559345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        mModeOptionsPano = (RadioOptions) findViewById(R.id.mode_options_pano);
12659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        mModeOptionsExposure = (RadioOptions) findViewById(R.id.mode_options_exposure);
12759345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        mMainBar = mActiveBar = mModeOptionsButtons;
128b6c4a314d0a0a185e6d987298ef9b7f4db8a6a2fSenpo Hu    }
129abf54e2994961395a0feb0b08353e62718443f23Spike Sprague
130b6c4a314d0a0a185e6d987298ef9b7f4db8a6a2fSenpo Hu    public void showExposureOptions() {
131b6c4a314d0a0a185e6d987298ef9b7f4db8a6a2fSenpo Hu        mActiveBar = mModeOptionsExposure;
132b6c4a314d0a0a185e6d987298ef9b7f4db8a6a2fSenpo Hu        mMainBar.setVisibility(View.INVISIBLE);
133b6c4a314d0a0a185e6d987298ef9b7f4db8a6a2fSenpo Hu        mActiveBar.setVisibility(View.VISIBLE);
13482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    }
13582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
13659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague    public void setMainBar(int b) {
13759345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        for (int i = 0; i < getChildCount(); i++) {
13859345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            getChildAt(i).setVisibility(View.INVISIBLE);
13982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        }
14059345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        switch (b) {
14159345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        case BAR_STANDARD:
14259345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            mMainBar = mActiveBar = mModeOptionsButtons;
14359345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            break;
14459345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        case BAR_PANO:
14559345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            mMainBar = mActiveBar = mModeOptionsPano;
14659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            break;
14759345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        }
14859345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        mMainBar.setVisibility(View.VISIBLE);
14959345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague    }
15082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
15159345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague    public int getMainBar() {
15259345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        if (mMainBar == mModeOptionsButtons) {
15359345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            return BAR_STANDARD;
15459345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        }
15559345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        if (mMainBar == mModeOptionsPano) {
15659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            return BAR_PANO;
15759345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        }
15859345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        return BAR_INVALID;
15982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    }
16082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
161abf54e2994961395a0feb0b08353e62718443f23Spike Sprague    @Override
162abf54e2994961395a0feb0b08353e62718443f23Spike Sprague    public void onWindowVisibilityChanged(int visibility) {
163abf54e2994961395a0feb0b08353e62718443f23Spike Sprague        super.onWindowVisibilityChanged(visibility);
164abf54e2994961395a0feb0b08353e62718443f23Spike Sprague        if (visibility != VISIBLE && !mIsHiddenOrHiding) {
165abf54e2994961395a0feb0b08353e62718443f23Spike Sprague            // Collapse mode options when window is not visible.
166abf54e2994961395a0feb0b08353e62718443f23Spike Sprague            setVisibility(INVISIBLE);
16759345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            if (mMainBar != null) {
16859345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                mMainBar.setVisibility(VISIBLE);
16959345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            }
17059345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            if (mActiveBar != null && mActiveBar != mMainBar) {
17159345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                mActiveBar.setVisibility(INVISIBLE);
172abf54e2994961395a0feb0b08353e62718443f23Spike Sprague            }
173abf54e2994961395a0feb0b08353e62718443f23Spike Sprague            if (mViewToShowHide != null) {
174abf54e2994961395a0feb0b08353e62718443f23Spike Sprague                mViewToShowHide.setVisibility(VISIBLE);
175abf54e2994961395a0feb0b08353e62718443f23Spike Sprague            }
176abf54e2994961395a0feb0b08353e62718443f23Spike Sprague            mIsHiddenOrHiding = true;
177abf54e2994961395a0feb0b08353e62718443f23Spike Sprague        }
178abf54e2994961395a0feb0b08353e62718443f23Spike Sprague    }
179abf54e2994961395a0feb0b08353e62718443f23Spike Sprague
18082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    @Override
18182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
18282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        if (changed) {
18382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            mIsPortrait = (getResources().getConfiguration().orientation ==
18482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                           Configuration.ORIENTATION_PORTRAIT);
18582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
18682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            int buttonSize = getResources()
18782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                .getDimensionPixelSize(R.dimen.option_button_circle_size);
18882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            int buttonPadding = getResources()
18982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                .getDimensionPixelSize(R.dimen.mode_options_toggle_padding);
19082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
19182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            float rLeft, rRight, rTop, rBottom;
19282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            if (mIsPortrait) {
19382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                rLeft = getWidth() - buttonPadding - buttonSize;
19482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                rTop = (getHeight() - buttonSize) / 2.0f;
19582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            } else {
19682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                rLeft = buttonPadding;
19782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                rTop = buttonPadding;
19882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            }
19982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            rRight = rLeft + buttonSize;
20082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            rBottom = rTop + buttonSize;
20182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            mAnimateFrom.set(rLeft, rTop, rRight, rBottom);
20282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
20382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            setupAnimators();
20418b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague            setupToggleButtonParams();
20582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        }
20682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
20782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        super.onLayout(changed, left, top, right, bottom);
20882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    }
20982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
21082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    @Override
21182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    public void onDraw(Canvas canvas) {
21282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        if (mDrawCircle) {
2134df915872c25fe61640a94c7a2c5f27eee1a1048Doris Liu            canvas.drawCircle(mAnimateFrom.centerX(), mAnimateFrom.centerY(), mRadius, mPaint);
21482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        } else if (mFill) {
21582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            canvas.drawPaint(mPaint);
21682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        }
21782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        super.onDraw(canvas);
21882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    }
21982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
22018b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague    private void setupToggleButtonParams() {
22118b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague        int size = (mIsPortrait ? getHeight() : getWidth());
22218b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague
22318b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague        for (int i = 0; i < mModeOptionsButtons.getChildCount(); i++) {
22418b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague            View button = mModeOptionsButtons.getChildAt(i);
22518b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague            if (button instanceof MultiToggleImageButton) {
22618b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague                MultiToggleImageButton toggleButton = (MultiToggleImageButton) button;
22718b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague                toggleButton.setParentSize(size);
22818b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague                toggleButton.setAnimDirection(mIsPortrait ?
22918b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague                        MultiToggleImageButton.ANIM_DIRECTION_VERTICAL :
23018b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague                        MultiToggleImageButton.ANIM_DIRECTION_HORIZONTAL);
23118b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague            }
23218b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague        }
23318b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague    }
23418b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague
23582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    private void setupAnimators() {
236fd29a841a046c6a02306adc9e4df1a5eeb466f39Spike Sprague        if (mVisibleAnimator != null) {
237fd29a841a046c6a02306adc9e4df1a5eeb466f39Spike Sprague            mVisibleAnimator.end();
238fd29a841a046c6a02306adc9e4df1a5eeb466f39Spike Sprague        }
239fd29a841a046c6a02306adc9e4df1a5eeb466f39Spike Sprague        if (mHiddenAnimator != null) {
240fd29a841a046c6a02306adc9e4df1a5eeb466f39Spike Sprague            mHiddenAnimator.end();
241fd29a841a046c6a02306adc9e4df1a5eeb466f39Spike Sprague        }
242fd29a841a046c6a02306adc9e4df1a5eeb466f39Spike Sprague
24382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        final float fullSize = (mIsPortrait ? (float) getWidth() : (float) getHeight());
24482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
24582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        // show
24682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        {
24782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            final ValueAnimator radiusAnimator =
24882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                ValueAnimator.ofFloat(mAnimateFrom.width()/2.0f,
24982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    fullSize-mAnimateFrom.width()/2.0f);
25082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            radiusAnimator.setDuration(RADIUS_ANIMATION_TIME);
25182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
25282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                @Override
25382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                public void onAnimationUpdate(ValueAnimator animation) {
2544df915872c25fe61640a94c7a2c5f27eee1a1048Doris Liu                    mRadius = (Float) animation.getAnimatedValue();
25582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    mDrawCircle = true;
25682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    mFill = false;
25782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                }
25882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            });
25982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            radiusAnimator.addListener(new AnimatorListenerAdapter() {
26082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                @Override
26182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                public void onAnimationEnd(Animator animation) {
26282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    mDrawCircle = false;
26382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    mFill = true;
26482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                }
26582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            });
26682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
26756d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague            final ValueAnimator alphaAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
26882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            alphaAnimator.setDuration(SHOW_ALPHA_ANIMATION_TIME);
26982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
27082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                @Override
27182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                public void onAnimationUpdate(ValueAnimator animation) {
27259345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    mActiveBar.setAlpha((Float) animation.getAnimatedValue());
27382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                }
27482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            });
27582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            alphaAnimator.addListener(new AnimatorListenerAdapter() {
27682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                @Override
27782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                public void onAnimationEnd(Animator animation) {
27859345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    mActiveBar.setAlpha(1.0f);
27982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                }
28082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            });
28182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
28256d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague            final int deltaX = getResources()
28356d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague                .getDimensionPixelSize(R.dimen.mode_options_buttons_anim_delta_x);
28459345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            int childCount = mActiveBar.getChildCount();
28556d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague            ArrayList<Animator> paddingAnimators = new ArrayList<Animator>();
28656d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague            for (int i = 0; i < childCount; i++) {
28756d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague                final View button;
28856d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague                if (mIsPortrait) {
28959345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    button = mActiveBar.getChildAt(i);
29056d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague                } else {
29159345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    button = mActiveBar.getChildAt(childCount-1-i);
29282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                }
29382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
29459345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                final ValueAnimator paddingAnimator =
29518b22b5963e8871e539edf669d96862eec72bb5dSpike Sprague                    ValueAnimator.ofFloat(deltaX*(childCount-i), 0.0f);
29659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                paddingAnimator.setDuration(PADDING_ANIMATION_TIME);
29759345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
29859345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    @Override
29959345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    public void onAnimationUpdate(ValueAnimator animation) {
30059345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                        if (mIsPortrait) {
30159345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                            button.setTranslationX((Float) animation.getAnimatedValue());
30259345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                        } else {
30359345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                            button.setTranslationY(-((Float) animation.getAnimatedValue()));
30456d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague                        }
30559345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                        invalidate();
30659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    }
30759345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                });
30856d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague
30959345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                paddingAnimators.add(paddingAnimator);
31056d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague            }
31159345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague
31256d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague            AnimatorSet paddingAnimatorSet = new AnimatorSet();
31356d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague            paddingAnimatorSet.playTogether(paddingAnimators);
31482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
31582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            mVisibleAnimator = new AnimatorSet();
31682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            mVisibleAnimator.setInterpolator(Gusterpolator.INSTANCE);
31756d43cf80d40379d57ac1db697bc014d5c321b91Spike Sprague            mVisibleAnimator.playTogether(radiusAnimator, alphaAnimator, paddingAnimatorSet);
31882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        }
31982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
32082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        // hide
32182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        {
32282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            final ValueAnimator radiusAnimator =
32382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                ValueAnimator.ofFloat(fullSize-mAnimateFrom.width()/2.0f,
32482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    mAnimateFrom.width()/2.0f);
32582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            radiusAnimator.setDuration(RADIUS_ANIMATION_TIME);
32682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
32782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                @Override
32882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                public void onAnimationUpdate(ValueAnimator animation) {
3294df915872c25fe61640a94c7a2c5f27eee1a1048Doris Liu                    mRadius = (Float) animation.getAnimatedValue();
33082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    mDrawCircle = true;
33182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    mFill = false;
33282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    invalidate();
33382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                }
33482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            });
33582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            radiusAnimator.addListener(new AnimatorListenerAdapter() {
33682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                @Override
33782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                public void onAnimationEnd(Animator animation) {
33882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    if (mViewToShowHide != null) {
33982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                        mViewToShowHide.setVisibility(View.VISIBLE);
34082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                        mDrawCircle = false;
34182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                        mFill = false;
34282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                        invalidate();
34382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    }
34482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                }
34582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            });
34682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
34782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            final ValueAnimator alphaAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);
34882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            alphaAnimator.setDuration(HIDE_ALPHA_ANIMATION_TIME);
34982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
35082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                @Override
35182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                public void onAnimationUpdate(ValueAnimator animation) {
35259345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    mActiveBar.setAlpha((Float) animation.getAnimatedValue());
35382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    invalidate();
35482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                }
35582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            });
35682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            alphaAnimator.addListener(new AnimatorListenerAdapter() {
35782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                @Override
35882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                public void onAnimationEnd(Animator animation) {
3592a58938576e6d4220c02cf0b9a8226a1d3bcf176Spike Sprague                    setVisibility(View.INVISIBLE);
36059345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    if (mActiveBar != mMainBar) {
36159345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                        mActiveBar.setAlpha(1.0f);
36259345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                        mActiveBar.setVisibility(View.INVISIBLE);
36359345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    }
36459345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    mMainBar.setAlpha(1.0f);
36559345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    mMainBar.setVisibility(View.VISIBLE);
36659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague                    mActiveBar = mMainBar;
36782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                    invalidate();
36882fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague                }
36982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            });
37082fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
37182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            mHiddenAnimator = new AnimatorSet();
37282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            mHiddenAnimator.setInterpolator(Gusterpolator.INSTANCE);
37382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague            mHiddenAnimator.playTogether(radiusAnimator, alphaAnimator);
37482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        }
37582fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    }
37682fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
37782fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    public void animateVisible() {
378591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague        if (mIsHiddenOrHiding) {
379591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague            if (mViewToShowHide != null) {
380591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague                mViewToShowHide.setVisibility(View.INVISIBLE);
381591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague            }
382591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague            mHiddenAnimator.cancel();
383591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague            mVisibleAnimator.end();
3842a58938576e6d4220c02cf0b9a8226a1d3bcf176Spike Sprague            setVisibility(View.VISIBLE);
385591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague            mVisibleAnimator.start();
38654ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu            if (mListener.isPresent()) {
38754ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu                mListener.get().onBeginToShowModeOptions();
38854ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu            }
38982fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague        }
390591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague        mIsHiddenOrHiding = false;
39182fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    }
39282fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague
39382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    public void animateHidden() {
394591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague        if (!mIsHiddenOrHiding) {
395591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague            mVisibleAnimator.cancel();
396591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague            mHiddenAnimator.end();
397591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague            mHiddenAnimator.start();
39854ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu            if (mListener.isPresent()) {
39954ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu                mListener.get().onBeginToHideModeOptions();
40054ac03ba6ae3e739df74c6d9e35fda9017be07d7Senpo Hu            }
401591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague        }
402591eec6465d29bbc053e164071c4c3a7c260a1d3Spike Sprague        mIsHiddenOrHiding = true;
40382fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague    }
40482fa6ae85f7c07fef480eb1cd0cf7f578b150676Spike Sprague}