BottomBar.java revision 217512ce074220090a8ede01adf0406a70f4958f
10744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen/*
20744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * Copyright (C) 2013 The Android Open Source Project
30744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen *
40744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * Licensed under the Apache License, Version 2.0 (the "License");
50744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * you may not use this file except in compliance with the License.
60744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * You may obtain a copy of the License at
70744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen *
80744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen *      http://www.apache.org/licenses/LICENSE-2.0
90744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen *
100744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * Unless required by applicable law or agreed to in writing, software
110744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * distributed under the License is distributed on an "AS IS" BASIS,
120744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * See the License for the specific language governing permissions and
140744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * limitations under the License.
150744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen */
160744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
170744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenpackage com.android.camera.ui;
180744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
1939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.animation.Animator;
2039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.animation.AnimatorListenerAdapter;
2139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.animation.ValueAnimator;
220744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.content.Context;
230744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.content.res.Configuration;
24a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liuimport android.graphics.RectF;
250744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.util.AttributeSet;
260744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.view.Gravity;
274efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgrenimport android.view.MotionEvent;
280744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.view.View;
290744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.widget.FrameLayout;
301648c36927501ff32bf2918e8a445118d5208731Erin Dahlgrenimport android.widget.LinearLayout;
310744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
3239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport com.android.camera.ShutterButton;
334efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgrenimport com.android.camera.ToggleImageButton;
3439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport com.android.camera.util.Gusterpolator;
3539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport com.android.camera2.R;
3639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
3739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.graphics.Canvas;
3839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.graphics.Path;
3939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.graphics.Paint;
4039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.graphics.drawable.Drawable;
4139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.graphics.drawable.TransitionDrawable;
4270da918464276b110c43868caa272c97baadb89eDoris Liu
430744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen/**
440744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * BottomBar swaps its width and height on rotation. In addition, it also changes
450744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * gravity and layout orientation based on the new orientation. Specifically, in
460744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * landscape it aligns to the right side of its parent and lays out its children
470744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * vertically, whereas in portrait, it stays at the bottom of the parent and has
480744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * a horizontal layout orientation.
4939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague*/
5070da918464276b110c43868caa272c97baadb89eDoris Liupublic class BottomBar extends FrameLayout
5156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    implements PreviewStatusListener.PreviewAreaSizeChangedListener,
5256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren               PreviewOverlay.OnPreviewTouchedListener {
533b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague
5470da918464276b110c43868caa272c97baadb89eDoris Liu    private static final String TAG = "BottomBar";
5539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
5656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private static final int BOTTOMBAR_OPTIONS_TIMEOUT_MS = 2000;
5756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
5839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private static final float CIRCLE_RADIUS = 64.0f;
59217512ce074220090a8ede01adf0406a70f4958fSpike Sprague    private static final int CIRCLE_ANIM_DURATION_MS = 300;
6039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
6170da918464276b110c43868caa272c97baadb89eDoris Liu    private int mWidth;
6270da918464276b110c43868caa272c97baadb89eDoris Liu    private int mHeight;
6370da918464276b110c43868caa272c97baadb89eDoris Liu    private float mOffsetShorterEdge;
6470da918464276b110c43868caa272c97baadb89eDoris Liu    private float mOffsetLongerEdge;
6570da918464276b110c43868caa272c97baadb89eDoris Liu
6670da918464276b110c43868caa272c97baadb89eDoris Liu    private final int mOptimalHeight;
6770da918464276b110c43868caa272c97baadb89eDoris Liu    private boolean mOverLayBottomBar;
680744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
6956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private ToggleImageButton mOptionsToggle;
7056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
7156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private TopRightMostOverlay mOptionsOverlay;
7256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private TopRightWeightedLayout mOptionsLayout;
734efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    private FrameLayout mCaptureLayout;
744efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    private TopRightWeightedLayout mIntentLayout;
7556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private boolean mIsCaptureIntent = false;
7656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
7756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    /**
7856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * A generic Runnable for setting the options toggle
7956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * to the capture layout state and performing the state
8056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * transition.
8156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     */
8256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private final Runnable mCloseOptionsRunnable =
8356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        new Runnable() {
8456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            @Override
8556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            public void run() {
8656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                if (mOptionsToggle != null) {
8756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                    mOptionsToggle.setState(0, true);
8856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                }
8956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            }
9056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        };
914efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
9239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private ShutterButton mShutterButton;
9339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
9439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private int mBackgroundColor;
95b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    private int mBackgroundPressedColor;
96b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    private int mBackgroundAlpha = 0xff;
97b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
9839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private Paint mCirclePaint = new Paint();
9939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private Path mCirclePath = new Path();
10039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
1010744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    public BottomBar(Context context, AttributeSet attrs) {
1020744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        super(context, attrs);
10370da918464276b110c43868caa272c97baadb89eDoris Liu        mOptimalHeight = getResources().getDimensionPixelSize(R.dimen.bottom_bar_height_optimal);
1040744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
1050744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
106cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague    private void setPaintColor(int alpha, int color, boolean isCaptureChange) {
107cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague        int computedColor = (alpha << 24) | (color & 0x00ffffff);
108cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague        mCirclePaint.setColor(computedColor);
109cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague        if (!isCaptureChange) {
110cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague            mOptionsToggle.setBackgroundColor(computedColor);
111cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague        }
112eaa4d37f8bfb25ffea438f9045867140a63ba0e1Spike Sprague        invalidate();
113b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    }
114b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
115cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague    private void setPaintColor(int alpha, int color) {
116cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague        setPaintColor(alpha, color, false);
117cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague    }
118cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague
1194efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    @Override
1204efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    public void onFinishInflate() {
12156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsOverlay
12256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            = (TopRightMostOverlay) findViewById(R.id.bottombar_options_overlay);
12356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsLayout
12456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            = (TopRightWeightedLayout) findViewById(R.id.bottombar_options);
1254efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mCaptureLayout
1264efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren            = (FrameLayout) findViewById(R.id.bottombar_capture);
1274efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mIntentLayout
1284efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren            = (TopRightWeightedLayout) findViewById(R.id.bottombar_intent);
129b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
13039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mShutterButton
13139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            = (ShutterButton) findViewById(R.id.shutter_button);
132b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        mShutterButton.setOnTouchListener(new OnTouchListener() {
133b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague            @Override
134b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague            public boolean onTouch(View v, MotionEvent event) {
135b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                if (MotionEvent.ACTION_DOWN == event.getActionMasked()) {
136cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague                    setPaintColor(mBackgroundAlpha, mBackgroundPressedColor, true);
137b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                    invalidate();
138b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                } else if (MotionEvent.ACTION_UP == event.getActionMasked()) {
139cf9010d314a5a263a3f0e9fa9abf16a80f26d281Spike Sprague                    setPaintColor(mBackgroundAlpha, mBackgroundColor, true);
140b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                    invalidate();
141b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                }
142b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
143b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                return false;
144b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague            }
145b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        });
14656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
14756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsOverlay.setOnTouchListener(new View.OnTouchListener() {
14839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            @Override
14939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            public boolean onTouch(View v, MotionEvent event) {
15039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
15139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    // close options immediately.
15239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    closeModeOptionsDelayed(BOTTOMBAR_OPTIONS_TIMEOUT_MS);
15356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                }
15439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                // Let touch event reach mode options or shutter.
15539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                return false;
15639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            }
15739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        });
15856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    }
15956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
16056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    @Override
16156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    public void onPreviewTouched(MotionEvent ev) {
16256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        // close options immediately.
16356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        closeModeOptionsDelayed(0);
16456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    }
16556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
16656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    /**
16756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * Schedule (or re-schedule) the options menu to be closed
16856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * after a number of milliseconds.  If the options menu
16956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * is already closed, nothing is scheduled.
17056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     */
17156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private void closeModeOptionsDelayed(int milliseconds) {
17256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        // Check that the bottom bar options are visible.
17356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        if (mOptionsLayout.getVisibility() != View.VISIBLE) {
17456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            return;
17556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        }
17656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
17756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        // Remove queued callbacks.
17856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        removeCallbacks(mCloseOptionsRunnable);
17956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
18056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        // Close the bottom bar options view in n milliseconds.
18156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        postDelayed(mCloseOptionsRunnable, milliseconds);
1824efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
1834efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
1844efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
1854efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Initializes the bottom bar toggle for switching between
18656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * capture and the bottom bar options.
1874efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
18856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    public void setupToggle(boolean isCaptureIntent) {
18956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mIsCaptureIntent = isCaptureIntent;
19056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
1914efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        // Of type ToggleImageButton because ToggleButton
1924efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        // has a non-removable spacing for text on the right-hand side.
19356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsToggle = (ToggleImageButton) findViewById(R.id.bottombar_options_toggle);
19456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsToggle.setState(0, false);
19556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsToggle.setOnStateChangeListener(new ToggleImageButton.OnStateChangeListener() {
1963b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague            @Override
19756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            public void stateChanged(View view, boolean toOptions) {
19856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                if (toOptions) {
19956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                    if (mIsCaptureIntent) {
2003b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague                        hideIntentLayout();
2013b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague                    }
20256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                    transitionToOptions();
2033b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague                } else {
20456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                    if (mIsCaptureIntent) {
2053b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague                        transitionToIntentLayout();
2064efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren                    } else {
2073b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague                        transitionToCapture();
2084efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren                    }
2094efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren                }
2103b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague            }
2113b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague        });
21256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsOverlay.setReferenceViewParent(mOptionsLayout);
2134efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2144efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2154efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
2164efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Hide the intent layout.  This is necessary for switching between
21756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * the intent capture layout and the bottom bar options.
2184efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
2194efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    private void hideIntentLayout() {
2204efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mIntentLayout.setVisibility(View.INVISIBLE);
2214efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2224efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2234efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
22456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * Perform a transition from the bottom bar options layout to the
22556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * bottom bar capture layout.
2264efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
2274efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    private void transitionToCapture() {
22856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsLayout.setVisibility(View.INVISIBLE);
2294efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mCaptureLayout.setVisibility(View.VISIBLE);
2304efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2314efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2324efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
23356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * Perform a transition from the bottom bar capture layout to the
23456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * bottom bar options layout.
2354efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
23656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private void transitionToOptions() {
2373b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague        mCaptureLayout.setVisibility(View.INVISIBLE);
23856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsLayout.setVisibility(View.VISIBLE);
2394efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2404efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2410744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    /**
2424efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Perform a transition to the global intent layout.  The current
2434efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * layout state of the bottom bar is irrelevant.
2440f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague     */
2454efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    public void transitionToIntentLayout() {
2464efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mCaptureLayout.setVisibility(View.VISIBLE);
24756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsLayout.setVisibility(View.INVISIBLE);
24856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsOverlay.setVisibility(View.VISIBLE);
2494efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mIntentLayout.setVisibility(View.VISIBLE);
2504efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2514efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        View button;
2524efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button = mIntentLayout.findViewById(R.id.done_button);
2534efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button.setVisibility(View.INVISIBLE);
2544efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button = mIntentLayout.findViewById(R.id.retake_button);
2554efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button.setVisibility(View.INVISIBLE);
2564efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2574efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2584efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
2594efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Perform a transition to the global intent review layout.
2604efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * The current layout state of the bottom bar is irrelevant.
2614efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
2624efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    public void transitionToIntentReviewLayout() {
2634efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mCaptureLayout.setVisibility(View.INVISIBLE);
26456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsLayout.setVisibility(View.INVISIBLE);
26556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsOverlay.setVisibility(View.INVISIBLE);
2664efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2674efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        View button;
2684efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button = mIntentLayout.findViewById(R.id.done_button);
2694efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button.setVisibility(View.VISIBLE);
2704efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button = mIntentLayout.findViewById(R.id.retake_button);
2714efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button.setVisibility(View.VISIBLE);
2724efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mIntentLayout.setVisibility(View.VISIBLE);
2730f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague    }
2740f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
27570da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
27670da918464276b110c43868caa272c97baadb89eDoris Liu    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
27770da918464276b110c43868caa272c97baadb89eDoris Liu        mWidth = MeasureSpec.getSize(widthMeasureSpec);
27870da918464276b110c43868caa272c97baadb89eDoris Liu        mHeight = MeasureSpec.getSize(heightMeasureSpec);
27970da918464276b110c43868caa272c97baadb89eDoris Liu        if (mWidth == 0 || mHeight == 0) {
28070da918464276b110c43868caa272c97baadb89eDoris Liu            return;
28170da918464276b110c43868caa272c97baadb89eDoris Liu        }
28270da918464276b110c43868caa272c97baadb89eDoris Liu
28370da918464276b110c43868caa272c97baadb89eDoris Liu        if (mOffsetShorterEdge != 0 && mOffsetLongerEdge != 0) {
28470da918464276b110c43868caa272c97baadb89eDoris Liu            float previewAspectRatio =
28570da918464276b110c43868caa272c97baadb89eDoris Liu                    mOffsetLongerEdge / mOffsetShorterEdge;
28670da918464276b110c43868caa272c97baadb89eDoris Liu            if (previewAspectRatio < 1.0) {
28770da918464276b110c43868caa272c97baadb89eDoris Liu                previewAspectRatio = 1.0f/previewAspectRatio;
28870da918464276b110c43868caa272c97baadb89eDoris Liu            }
28970da918464276b110c43868caa272c97baadb89eDoris Liu            float screenAspectRatio = (float) mWidth / (float) mHeight;
29070da918464276b110c43868caa272c97baadb89eDoris Liu            if (screenAspectRatio < 1.0) {
29170da918464276b110c43868caa272c97baadb89eDoris Liu                screenAspectRatio = 1.0f/screenAspectRatio;
29270da918464276b110c43868caa272c97baadb89eDoris Liu            }
29370da918464276b110c43868caa272c97baadb89eDoris Liu            if (previewAspectRatio >= screenAspectRatio) {
29470da918464276b110c43868caa272c97baadb89eDoris Liu                mOverLayBottomBar = true;
29539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                setBackgroundAlpha(128);
29670da918464276b110c43868caa272c97baadb89eDoris Liu            } else {
29770da918464276b110c43868caa272c97baadb89eDoris Liu                mOverLayBottomBar = false;
29839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                setBackgroundAlpha(255);
29970da918464276b110c43868caa272c97baadb89eDoris Liu            }
30070da918464276b110c43868caa272c97baadb89eDoris Liu        }
30170da918464276b110c43868caa272c97baadb89eDoris Liu
30270da918464276b110c43868caa272c97baadb89eDoris Liu        // Calculates the width and height needed for the bar.
30370da918464276b110c43868caa272c97baadb89eDoris Liu        int barWidth, barHeight;
30470da918464276b110c43868caa272c97baadb89eDoris Liu        if (mWidth > mHeight) {
3051648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            // TODO: The bottom bar should not need to care about the
3061648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            // the type of its parent.  Handle this in the parent layout.
3071648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            ((LinearLayout.LayoutParams) getLayoutParams()).gravity = Gravity.RIGHT;
30870da918464276b110c43868caa272c97baadb89eDoris Liu            if ((mOffsetLongerEdge == 0 && mOffsetShorterEdge == 0) || mOverLayBottomBar) {
30970da918464276b110c43868caa272c97baadb89eDoris Liu                barWidth = mOptimalHeight;
31070da918464276b110c43868caa272c97baadb89eDoris Liu                barHeight = mHeight;
31170da918464276b110c43868caa272c97baadb89eDoris Liu            } else {
31270da918464276b110c43868caa272c97baadb89eDoris Liu                barWidth = (int) (mWidth - mOffsetLongerEdge);
31370da918464276b110c43868caa272c97baadb89eDoris Liu                barHeight = mHeight;
31470da918464276b110c43868caa272c97baadb89eDoris Liu            }
3150744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        } else {
3161648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            ((LinearLayout.LayoutParams) getLayoutParams()).gravity = Gravity.BOTTOM;
31770da918464276b110c43868caa272c97baadb89eDoris Liu            if ((mOffsetLongerEdge == 0 && mOffsetShorterEdge == 0) || mOverLayBottomBar) {
31870da918464276b110c43868caa272c97baadb89eDoris Liu                barWidth = mWidth;
31970da918464276b110c43868caa272c97baadb89eDoris Liu                barHeight = mOptimalHeight;
32070da918464276b110c43868caa272c97baadb89eDoris Liu            } else {
32170da918464276b110c43868caa272c97baadb89eDoris Liu                barWidth = mWidth;
32270da918464276b110c43868caa272c97baadb89eDoris Liu                barHeight = (int) (mHeight - mOffsetLongerEdge);
32370da918464276b110c43868caa272c97baadb89eDoris Liu            }
3240744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
32539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
32639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mCirclePath.addCircle(
32739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            barWidth/2,
32839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            barHeight/2,
32939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            (int)(diagonalLength(barWidth, barHeight)/2),
33039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            Path.Direction.CW);
33139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
33270da918464276b110c43868caa272c97baadb89eDoris Liu        super.onMeasure(MeasureSpec.makeMeasureSpec(barWidth, MeasureSpec.EXACTLY),
33370da918464276b110c43868caa272c97baadb89eDoris Liu                MeasureSpec.makeMeasureSpec(barHeight, MeasureSpec.EXACTLY));
33470da918464276b110c43868caa272c97baadb89eDoris Liu    }
33570da918464276b110c43868caa272c97baadb89eDoris Liu
33670da918464276b110c43868caa272c97baadb89eDoris Liu    private void adjustBottomBar(float scaledTextureWidth,
33770da918464276b110c43868caa272c97baadb89eDoris Liu                                 float scaledTextureHeight) {
33870da918464276b110c43868caa272c97baadb89eDoris Liu        setOffset(scaledTextureWidth, scaledTextureHeight);
33970da918464276b110c43868caa272c97baadb89eDoris Liu    }
34070da918464276b110c43868caa272c97baadb89eDoris Liu
34170da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
342a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu    public void onPreviewAreaSizeChanged(RectF previewArea) {
343a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu        adjustBottomBar(previewArea.width(), previewArea.height());
34470da918464276b110c43868caa272c97baadb89eDoris Liu    }
34570da918464276b110c43868caa272c97baadb89eDoris Liu
34670da918464276b110c43868caa272c97baadb89eDoris Liu    private void setOffset(float scaledTextureWidth, float scaledTextureHeight) {
34770da918464276b110c43868caa272c97baadb89eDoris Liu        float offsetLongerEdge, offsetShorterEdge;
34870da918464276b110c43868caa272c97baadb89eDoris Liu        if (scaledTextureHeight > scaledTextureWidth) {
34970da918464276b110c43868caa272c97baadb89eDoris Liu            offsetLongerEdge = scaledTextureHeight;
35070da918464276b110c43868caa272c97baadb89eDoris Liu            offsetShorterEdge = scaledTextureWidth;
3510744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        } else {
35270da918464276b110c43868caa272c97baadb89eDoris Liu            offsetLongerEdge = scaledTextureWidth;
35370da918464276b110c43868caa272c97baadb89eDoris Liu            offsetShorterEdge = scaledTextureHeight;
35470da918464276b110c43868caa272c97baadb89eDoris Liu        }
35570da918464276b110c43868caa272c97baadb89eDoris Liu        if (mOffsetLongerEdge != offsetLongerEdge || mOffsetShorterEdge != offsetShorterEdge) {
35670da918464276b110c43868caa272c97baadb89eDoris Liu            mOffsetLongerEdge = offsetLongerEdge;
35770da918464276b110c43868caa272c97baadb89eDoris Liu            mOffsetShorterEdge = offsetShorterEdge;
35870da918464276b110c43868caa272c97baadb89eDoris Liu            requestLayout();
3590744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
3600744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
3610744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
3620744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    @Override
3630744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    protected void onConfigurationChanged(Configuration config) {
3640744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        super.onConfigurationChanged(config);
3650744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
3660744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
367e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    // prevent touches on bottom bar (not its children)
368e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    // from triggering a touch event on preview area
369e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    @Override
370e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    public boolean onTouchEvent(MotionEvent event) {
371e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague        return true;
372e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    }
37339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
37439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    @Override
37539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void onDraw(Canvas canvas) {
37639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        canvas.drawPath(mCirclePath, mCirclePaint);
37739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
37839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        super.onDraw(canvas);
37939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
38039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
38139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    @Override
38239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void setBackgroundColor(int color) {
38339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mBackgroundColor = color;
384b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        setPaintColor(mBackgroundAlpha, mBackgroundColor);
385b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    }
386b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
387b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    public void setBackgroundPressedColor(int color) {
388b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        mBackgroundPressedColor = color;
38939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
39039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
39139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void setBackgroundAlpha(int alpha) {
392b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        mBackgroundAlpha = alpha;
393b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        setPaintColor(mBackgroundAlpha, mBackgroundColor);
39439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
39539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
39639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private double diagonalLength(double w, double h) {
39739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        return Math.sqrt((w*w) + (h*h));
39839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
39939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private double diagonalLength() {
40039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        return diagonalLength(getWidth(), getHeight());
40139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
40239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
40339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private TransitionDrawable crossfadeDrawable(Drawable from, Drawable to) {
40439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        Drawable [] arrayDrawable = new Drawable[2];
40539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        arrayDrawable[0] = from;
40639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        arrayDrawable[1] = to;
40739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        TransitionDrawable transitionDrawable = new TransitionDrawable(arrayDrawable);
40839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        transitionDrawable.setCrossFadeEnabled(true);
40939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        return transitionDrawable;
41039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
41139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
41239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    /**
41339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     * Set the shutter button's icon resource
41439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     */
41539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void setShutterButtonIcon(int resId) {
41639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mShutterButton.setImageResource(resId);
41739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
41839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
41939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    /**
42039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     * Animates bar to a single stop button
42139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     */
42239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void animateToCircle(int resId) {
42339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        final ValueAnimator radiusAnimator = ValueAnimator.ofFloat(
42439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                                                 (float) diagonalLength()/2,
42539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                                                 CIRCLE_RADIUS);
42639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.setDuration(CIRCLE_ANIM_DURATION_MS);
42739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.setInterpolator(Gusterpolator.INSTANCE);
42839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
42939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
43039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            @Override
43139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            public void onAnimationUpdate(ValueAnimator animation) {
43239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mCirclePath.reset();
43339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mCirclePath.addCircle(
43439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    getWidth()/2,
43539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    getHeight()/2,
43639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    (Float) animation.getAnimatedValue(),
43739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    Path.Direction.CW);
43839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
43939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                invalidate();
44039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            }
44139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        });
44239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
44339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        TransitionDrawable transitionDrawable = crossfadeDrawable(
44439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mShutterButton.getDrawable(),
44539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                getResources().getDrawable(resId));
44639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mShutterButton.setImageDrawable(transitionDrawable);
44739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
44839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        View optionsOverlay = findViewById(R.id.bottombar_options_overlay);
44939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        optionsOverlay.setVisibility(View.INVISIBLE);
45039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
45139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
45239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        transitionDrawable.startTransition(CIRCLE_ANIM_DURATION_MS);
45339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.start();
45439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
45539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
45639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    /**
45739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     * Animates bar to full width / length with video capture icon
45839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     */
45939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void animateToFullSize(int resId) {
46039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        final ValueAnimator radiusAnimator = ValueAnimator.ofFloat(
46139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                                                 CIRCLE_RADIUS,
46239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                                                 (float) diagonalLength()/2);
46339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.setDuration(CIRCLE_ANIM_DURATION_MS);
46439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.setInterpolator(Gusterpolator.INSTANCE);
46539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
46639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            @Override
46739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            public void onAnimationUpdate(ValueAnimator animation) {
46839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mCirclePath.reset();
46939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mCirclePath.addCircle(
47039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    getWidth()/2,
47139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    getHeight()/2,
47239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    (Float) animation.getAnimatedValue(),
47339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    Path.Direction.CW);
47439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
47539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                invalidate();
47639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            }
47739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        });
47839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.addListener(new AnimatorListenerAdapter() {
47939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            @Override
48039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            public void onAnimationEnd(Animator animation) {
48139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                View optionsOverlay = findViewById(R.id.bottombar_options_overlay);
48239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                optionsOverlay.setVisibility(View.VISIBLE);
48339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            }
48439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        });
48539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
48639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        TransitionDrawable transitionDrawable = crossfadeDrawable(
48739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mShutterButton.getDrawable(),
48839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                getResources().getDrawable(resId));
48939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mShutterButton.setImageDrawable(transitionDrawable);
49039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
49139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        transitionDrawable.startTransition(CIRCLE_ANIM_DURATION_MS);
49239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.start();
49339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
4940744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen}
495