BottomBar.java revision b92910e04c4da91fc4ea5a9484b83f9ecba1c896
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;
2239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
230744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.content.Context;
240744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.content.res.Configuration;
2556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgrenimport android.os.Handler;
2656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgrenimport android.os.HandlerThread;
2756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgrenimport android.os.Looper;
280744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.util.AttributeSet;
290744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.view.Gravity;
304efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgrenimport android.view.MotionEvent;
310744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.view.View;
323b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Spragueimport android.view.ViewGroup;
330744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.widget.FrameLayout;
341648c36927501ff32bf2918e8a445118d5208731Erin Dahlgrenimport android.widget.LinearLayout;
350744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
3639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport com.android.camera.ShutterButton;
374efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgrenimport com.android.camera.ToggleImageButton;
3839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport com.android.camera.util.Gusterpolator;
3939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport com.android.camera2.R;
4039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
4139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.graphics.Canvas;
4239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.graphics.Path;
4339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.graphics.Paint;
4439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.graphics.drawable.Drawable;
4539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Spragueimport android.graphics.drawable.TransitionDrawable;
4670da918464276b110c43868caa272c97baadb89eDoris Liu
470744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen/**
480744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * BottomBar swaps its width and height on rotation. In addition, it also changes
490744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * gravity and layout orientation based on the new orientation. Specifically, in
500744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * landscape it aligns to the right side of its parent and lays out its children
510744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * vertically, whereas in portrait, it stays at the bottom of the parent and has
520744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * a horizontal layout orientation.
5339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague*/
5470da918464276b110c43868caa272c97baadb89eDoris Liupublic class BottomBar extends FrameLayout
5556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    implements PreviewStatusListener.PreviewAreaSizeChangedListener,
5656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren               PreviewOverlay.OnPreviewTouchedListener {
573b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague
5870da918464276b110c43868caa272c97baadb89eDoris Liu    private static final String TAG = "BottomBar";
5939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
6056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private static final int BOTTOMBAR_OPTIONS_TIMEOUT_MS = 2000;
6156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
6239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private static final float CIRCLE_RADIUS = 64.0f;
6339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private static final int CIRCLE_ANIM_DURATION_MS = 450;
6439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
6570da918464276b110c43868caa272c97baadb89eDoris Liu    private int mWidth;
6670da918464276b110c43868caa272c97baadb89eDoris Liu    private int mHeight;
6770da918464276b110c43868caa272c97baadb89eDoris Liu    private float mOffsetShorterEdge;
6870da918464276b110c43868caa272c97baadb89eDoris Liu    private float mOffsetLongerEdge;
6970da918464276b110c43868caa272c97baadb89eDoris Liu
7070da918464276b110c43868caa272c97baadb89eDoris Liu    private final int mOptimalHeight;
7170da918464276b110c43868caa272c97baadb89eDoris Liu    private boolean mOverLayBottomBar;
720744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
7356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private ToggleImageButton mOptionsToggle;
7456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
7556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private TopRightMostOverlay mOptionsOverlay;
7656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private TopRightWeightedLayout mOptionsLayout;
774efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    private FrameLayout mCaptureLayout;
784efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    private TopRightWeightedLayout mIntentLayout;
7956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private boolean mIsCaptureIntent = false;
8056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
8156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    /**
8256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * A generic Runnable for setting the options toggle
8356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * to the capture layout state and performing the state
8456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * transition.
8556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     */
8656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private final Runnable mCloseOptionsRunnable =
8756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        new Runnable() {
8856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            @Override
8956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            public void run() {
9056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                if (mOptionsToggle != null) {
9156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                    mOptionsToggle.setState(0, true);
9256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                }
9356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            }
9456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        };
954efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
9639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private ShutterButton mShutterButton;
9739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
9839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private int mBackgroundColor;
99b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    private int mBackgroundPressedColor;
100b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    private int mBackgroundAlpha = 0xff;
101b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
10239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private Paint mCirclePaint = new Paint();
10339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private Path mCirclePath = new Path();
10439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
1050744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    public BottomBar(Context context, AttributeSet attrs) {
1060744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        super(context, attrs);
10770da918464276b110c43868caa272c97baadb89eDoris Liu        mOptimalHeight = getResources().getDimensionPixelSize(R.dimen.bottom_bar_height_optimal);
1080744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
1090744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
110b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    private void setPaintColor(int alpha, int color) {
111b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        mCirclePaint.setColor((alpha << 24) | (color & 0x00ffffff));
112b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    }
113b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
1144efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    @Override
1154efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    public void onFinishInflate() {
11656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsOverlay
11756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            = (TopRightMostOverlay) findViewById(R.id.bottombar_options_overlay);
11856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsLayout
11956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            = (TopRightWeightedLayout) findViewById(R.id.bottombar_options);
1204efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mCaptureLayout
1214efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren            = (FrameLayout) findViewById(R.id.bottombar_capture);
1224efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mIntentLayout
1234efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren            = (TopRightWeightedLayout) findViewById(R.id.bottombar_intent);
124b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
12539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mShutterButton
12639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            = (ShutterButton) findViewById(R.id.shutter_button);
127b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        mShutterButton.setOnTouchListener(new OnTouchListener() {
128b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague            @Override
129b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague            public boolean onTouch(View v, MotionEvent event) {
130b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                if (MotionEvent.ACTION_DOWN == event.getActionMasked()) {
131b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                    setPaintColor(mBackgroundAlpha, mBackgroundPressedColor);
132b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                    invalidate();
133b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                } else if (MotionEvent.ACTION_UP == event.getActionMasked()) {
134b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                    setPaintColor(mBackgroundAlpha, mBackgroundColor);
135b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                    invalidate();
136b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                }
137b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
138b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague                return false;
139b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague            }
140b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        });
14156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
14256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsOverlay.setOnTouchListener(new View.OnTouchListener() {
14339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            @Override
14439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            public boolean onTouch(View v, MotionEvent event) {
14539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
14639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    // close options immediately.
14739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    closeModeOptionsDelayed(BOTTOMBAR_OPTIONS_TIMEOUT_MS);
14856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                }
14939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                // Let touch event reach mode options or shutter.
15039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                return false;
15139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            }
15239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        });
15356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    }
15456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
15556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    @Override
15656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    public void onPreviewTouched(MotionEvent ev) {
15756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        // close options immediately.
15856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        closeModeOptionsDelayed(0);
15956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    }
16056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
16156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    /**
16256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * Schedule (or re-schedule) the options menu to be closed
16356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * after a number of milliseconds.  If the options menu
16456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * is already closed, nothing is scheduled.
16556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     */
16656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private void closeModeOptionsDelayed(int milliseconds) {
16756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        // Check that the bottom bar options are visible.
16856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        if (mOptionsLayout.getVisibility() != View.VISIBLE) {
16956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            return;
17056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        }
17156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
17256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        // Remove queued callbacks.
17356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        removeCallbacks(mCloseOptionsRunnable);
17456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
17556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        // Close the bottom bar options view in n milliseconds.
17656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        postDelayed(mCloseOptionsRunnable, milliseconds);
1774efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
1784efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
1794efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
1804efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Initializes the bottom bar toggle for switching between
18156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * capture and the bottom bar options.
1824efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
18356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    public void setupToggle(boolean isCaptureIntent) {
18456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mIsCaptureIntent = isCaptureIntent;
18556688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
1864efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        // Of type ToggleImageButton because ToggleButton
1874efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        // has a non-removable spacing for text on the right-hand side.
18856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsToggle = (ToggleImageButton) findViewById(R.id.bottombar_options_toggle);
18956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsToggle.setState(0, false);
19056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsToggle.setOnStateChangeListener(new ToggleImageButton.OnStateChangeListener() {
1913b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague            @Override
19256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren            public void stateChanged(View view, boolean toOptions) {
19356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                if (toOptions) {
19456688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                    if (mIsCaptureIntent) {
1953b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague                        hideIntentLayout();
1963b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague                    }
19756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                    transitionToOptions();
1983b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague                } else {
19956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren                    if (mIsCaptureIntent) {
2003b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague                        transitionToIntentLayout();
2014efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren                    } else {
2023b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague                        transitionToCapture();
2034efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren                    }
2044efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren                }
2053b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague            }
2063b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague        });
20756688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsOverlay.setReferenceViewParent(mOptionsLayout);
2084efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2094efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2104efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
2114efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Hide the intent layout.  This is necessary for switching between
21256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * the intent capture layout and the bottom bar options.
2134efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
2144efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    private void hideIntentLayout() {
2154efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mIntentLayout.setVisibility(View.INVISIBLE);
2164efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2174efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2184efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
21956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * Perform a transition from the bottom bar options layout to the
22056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * bottom bar capture layout.
2214efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
2224efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    private void transitionToCapture() {
22356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsLayout.setVisibility(View.INVISIBLE);
2244efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mCaptureLayout.setVisibility(View.VISIBLE);
2254efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2264efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2274efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
22856688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * Perform a transition from the bottom bar capture layout to the
22956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren     * bottom bar options layout.
2304efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
23156688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren    private void transitionToOptions() {
2323b92e2f8e6d91af1b83c8bee95bd93e7153b96daSpike Sprague        mCaptureLayout.setVisibility(View.INVISIBLE);
23356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsLayout.setVisibility(View.VISIBLE);
2344efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2354efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2360744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    /**
2374efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Perform a transition to the global intent layout.  The current
2384efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * layout state of the bottom bar is irrelevant.
2390f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague     */
2404efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    public void transitionToIntentLayout() {
2414efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mCaptureLayout.setVisibility(View.VISIBLE);
24256688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsLayout.setVisibility(View.INVISIBLE);
24356688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsOverlay.setVisibility(View.VISIBLE);
2444efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mIntentLayout.setVisibility(View.VISIBLE);
2454efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2464efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        View button;
2474efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button = mIntentLayout.findViewById(R.id.done_button);
2484efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button.setVisibility(View.INVISIBLE);
2494efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button = mIntentLayout.findViewById(R.id.retake_button);
2504efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button.setVisibility(View.INVISIBLE);
2514efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2524efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2534efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
2544efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Perform a transition to the global intent review layout.
2554efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * The current layout state of the bottom bar is irrelevant.
2564efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
2574efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    public void transitionToIntentReviewLayout() {
2584efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mCaptureLayout.setVisibility(View.INVISIBLE);
25956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsLayout.setVisibility(View.INVISIBLE);
26056688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren        mOptionsOverlay.setVisibility(View.INVISIBLE);
2614efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
2624efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        View button;
2634efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button = mIntentLayout.findViewById(R.id.done_button);
2644efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button.setVisibility(View.VISIBLE);
2654efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button = mIntentLayout.findViewById(R.id.retake_button);
2664efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        button.setVisibility(View.VISIBLE);
2674efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mIntentLayout.setVisibility(View.VISIBLE);
2680f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague    }
2690f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
27070da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
27170da918464276b110c43868caa272c97baadb89eDoris Liu    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
27270da918464276b110c43868caa272c97baadb89eDoris Liu        mWidth = MeasureSpec.getSize(widthMeasureSpec);
27370da918464276b110c43868caa272c97baadb89eDoris Liu        mHeight = MeasureSpec.getSize(heightMeasureSpec);
27470da918464276b110c43868caa272c97baadb89eDoris Liu        if (mWidth == 0 || mHeight == 0) {
27570da918464276b110c43868caa272c97baadb89eDoris Liu            return;
27670da918464276b110c43868caa272c97baadb89eDoris Liu        }
27770da918464276b110c43868caa272c97baadb89eDoris Liu
27870da918464276b110c43868caa272c97baadb89eDoris Liu        if (mOffsetShorterEdge != 0 && mOffsetLongerEdge != 0) {
27970da918464276b110c43868caa272c97baadb89eDoris Liu            float previewAspectRatio =
28070da918464276b110c43868caa272c97baadb89eDoris Liu                    mOffsetLongerEdge / mOffsetShorterEdge;
28170da918464276b110c43868caa272c97baadb89eDoris Liu            if (previewAspectRatio < 1.0) {
28270da918464276b110c43868caa272c97baadb89eDoris Liu                previewAspectRatio = 1.0f/previewAspectRatio;
28370da918464276b110c43868caa272c97baadb89eDoris Liu            }
28470da918464276b110c43868caa272c97baadb89eDoris Liu            float screenAspectRatio = (float) mWidth / (float) mHeight;
28570da918464276b110c43868caa272c97baadb89eDoris Liu            if (screenAspectRatio < 1.0) {
28670da918464276b110c43868caa272c97baadb89eDoris Liu                screenAspectRatio = 1.0f/screenAspectRatio;
28770da918464276b110c43868caa272c97baadb89eDoris Liu            }
28870da918464276b110c43868caa272c97baadb89eDoris Liu            if (previewAspectRatio >= screenAspectRatio) {
28970da918464276b110c43868caa272c97baadb89eDoris Liu                mOverLayBottomBar = true;
29039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                setBackgroundAlpha(128);
29170da918464276b110c43868caa272c97baadb89eDoris Liu            } else {
29270da918464276b110c43868caa272c97baadb89eDoris Liu                mOverLayBottomBar = false;
29339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                setBackgroundAlpha(255);
29470da918464276b110c43868caa272c97baadb89eDoris Liu            }
29570da918464276b110c43868caa272c97baadb89eDoris Liu        }
29670da918464276b110c43868caa272c97baadb89eDoris Liu
29770da918464276b110c43868caa272c97baadb89eDoris Liu        // Calculates the width and height needed for the bar.
29870da918464276b110c43868caa272c97baadb89eDoris Liu        int barWidth, barHeight;
29970da918464276b110c43868caa272c97baadb89eDoris Liu        if (mWidth > mHeight) {
3001648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            // TODO: The bottom bar should not need to care about the
3011648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            // the type of its parent.  Handle this in the parent layout.
3021648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            ((LinearLayout.LayoutParams) getLayoutParams()).gravity = Gravity.RIGHT;
30370da918464276b110c43868caa272c97baadb89eDoris Liu            if ((mOffsetLongerEdge == 0 && mOffsetShorterEdge == 0) || mOverLayBottomBar) {
30470da918464276b110c43868caa272c97baadb89eDoris Liu                barWidth = mOptimalHeight;
30570da918464276b110c43868caa272c97baadb89eDoris Liu                barHeight = mHeight;
30670da918464276b110c43868caa272c97baadb89eDoris Liu            } else {
30770da918464276b110c43868caa272c97baadb89eDoris Liu                barWidth = (int) (mWidth - mOffsetLongerEdge);
30870da918464276b110c43868caa272c97baadb89eDoris Liu                barHeight = mHeight;
30970da918464276b110c43868caa272c97baadb89eDoris Liu            }
3100744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        } else {
3111648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            ((LinearLayout.LayoutParams) getLayoutParams()).gravity = Gravity.BOTTOM;
31270da918464276b110c43868caa272c97baadb89eDoris Liu            if ((mOffsetLongerEdge == 0 && mOffsetShorterEdge == 0) || mOverLayBottomBar) {
31370da918464276b110c43868caa272c97baadb89eDoris Liu                barWidth = mWidth;
31470da918464276b110c43868caa272c97baadb89eDoris Liu                barHeight = mOptimalHeight;
31570da918464276b110c43868caa272c97baadb89eDoris Liu            } else {
31670da918464276b110c43868caa272c97baadb89eDoris Liu                barWidth = mWidth;
31770da918464276b110c43868caa272c97baadb89eDoris Liu                barHeight = (int) (mHeight - mOffsetLongerEdge);
31870da918464276b110c43868caa272c97baadb89eDoris Liu            }
3190744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
32039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
32139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mCirclePath.addCircle(
32239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            barWidth/2,
32339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            barHeight/2,
32439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            (int)(diagonalLength(barWidth, barHeight)/2),
32539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            Path.Direction.CW);
32639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
32770da918464276b110c43868caa272c97baadb89eDoris Liu        super.onMeasure(MeasureSpec.makeMeasureSpec(barWidth, MeasureSpec.EXACTLY),
32870da918464276b110c43868caa272c97baadb89eDoris Liu                MeasureSpec.makeMeasureSpec(barHeight, MeasureSpec.EXACTLY));
32970da918464276b110c43868caa272c97baadb89eDoris Liu    }
33070da918464276b110c43868caa272c97baadb89eDoris Liu
33170da918464276b110c43868caa272c97baadb89eDoris Liu    private void adjustBottomBar(float scaledTextureWidth,
33270da918464276b110c43868caa272c97baadb89eDoris Liu                                 float scaledTextureHeight) {
33370da918464276b110c43868caa272c97baadb89eDoris Liu        setOffset(scaledTextureWidth, scaledTextureHeight);
33470da918464276b110c43868caa272c97baadb89eDoris Liu    }
33570da918464276b110c43868caa272c97baadb89eDoris Liu
33670da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
337482de029dc20e0a577388a602985fb31c3200309Doris Liu    public void onPreviewAreaSizeChanged(float scaledTextureWidth,
338482de029dc20e0a577388a602985fb31c3200309Doris Liu                                         float scaledTextureHeight) {
33970da918464276b110c43868caa272c97baadb89eDoris Liu        adjustBottomBar(scaledTextureWidth, scaledTextureHeight);
34070da918464276b110c43868caa272c97baadb89eDoris Liu    }
34170da918464276b110c43868caa272c97baadb89eDoris Liu
34270da918464276b110c43868caa272c97baadb89eDoris Liu    private void setOffset(float scaledTextureWidth, float scaledTextureHeight) {
34370da918464276b110c43868caa272c97baadb89eDoris Liu        float offsetLongerEdge, offsetShorterEdge;
34470da918464276b110c43868caa272c97baadb89eDoris Liu        if (scaledTextureHeight > scaledTextureWidth) {
34570da918464276b110c43868caa272c97baadb89eDoris Liu            offsetLongerEdge = scaledTextureHeight;
34670da918464276b110c43868caa272c97baadb89eDoris Liu            offsetShorterEdge = scaledTextureWidth;
3470744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        } else {
34870da918464276b110c43868caa272c97baadb89eDoris Liu            offsetLongerEdge = scaledTextureWidth;
34970da918464276b110c43868caa272c97baadb89eDoris Liu            offsetShorterEdge = scaledTextureHeight;
35070da918464276b110c43868caa272c97baadb89eDoris Liu        }
35170da918464276b110c43868caa272c97baadb89eDoris Liu        if (mOffsetLongerEdge != offsetLongerEdge || mOffsetShorterEdge != offsetShorterEdge) {
35270da918464276b110c43868caa272c97baadb89eDoris Liu            mOffsetLongerEdge = offsetLongerEdge;
35370da918464276b110c43868caa272c97baadb89eDoris Liu            mOffsetShorterEdge = offsetShorterEdge;
35470da918464276b110c43868caa272c97baadb89eDoris Liu            requestLayout();
3550744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
3560744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
3570744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
3580744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    @Override
3590744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    protected void onConfigurationChanged(Configuration config) {
3600744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        super.onConfigurationChanged(config);
3610744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
3620744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
363e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    // prevent touches on bottom bar (not its children)
364e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    // from triggering a touch event on preview area
365e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    @Override
366e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    public boolean onTouchEvent(MotionEvent event) {
367e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague        return true;
368e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    }
36939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
37039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    @Override
37139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void onDraw(Canvas canvas) {
37239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        canvas.drawPath(mCirclePath, mCirclePaint);
37339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
37439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        super.onDraw(canvas);
37539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
37639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
37739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    @Override
37839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void setBackgroundColor(int color) {
37939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mBackgroundColor = color;
380b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        setPaintColor(mBackgroundAlpha, mBackgroundColor);
381b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    }
382b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
383b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    public void setBackgroundPressedColor(int color) {
384b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        mBackgroundPressedColor = color;
38539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
38639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
38739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void setBackgroundAlpha(int alpha) {
388b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        mBackgroundAlpha = alpha;
389b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague        setPaintColor(mBackgroundAlpha, mBackgroundColor);
39039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
39139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
39239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private double diagonalLength(double w, double h) {
39339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        return Math.sqrt((w*w) + (h*h));
39439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
39539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private double diagonalLength() {
39639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        return diagonalLength(getWidth(), getHeight());
39739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
39839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
39939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    private TransitionDrawable crossfadeDrawable(Drawable from, Drawable to) {
40039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        Drawable [] arrayDrawable = new Drawable[2];
40139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        arrayDrawable[0] = from;
40239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        arrayDrawable[1] = to;
40339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        TransitionDrawable transitionDrawable = new TransitionDrawable(arrayDrawable);
40439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        transitionDrawable.setCrossFadeEnabled(true);
40539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        return transitionDrawable;
40639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
40739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
40839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    /**
40939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     * Set the shutter button's icon resource
41039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     */
41139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void setShutterButtonIcon(int resId) {
41239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mShutterButton.setImageResource(resId);
41339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
41439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
41539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    /**
41639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     * Animates bar to a single stop button
41739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     */
41839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void animateToCircle(int resId) {
41939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        final ValueAnimator radiusAnimator = ValueAnimator.ofFloat(
42039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                                                 (float) diagonalLength()/2,
42139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                                                 CIRCLE_RADIUS);
42239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.setDuration(CIRCLE_ANIM_DURATION_MS);
42339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.setInterpolator(Gusterpolator.INSTANCE);
42439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
42539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
42639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            @Override
42739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            public void onAnimationUpdate(ValueAnimator animation) {
42839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mCirclePath.reset();
42939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mCirclePath.addCircle(
43039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    getWidth()/2,
43139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    getHeight()/2,
43239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    (Float) animation.getAnimatedValue(),
43339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    Path.Direction.CW);
43439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
43539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                invalidate();
43639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            }
43739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        });
43839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
43939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        TransitionDrawable transitionDrawable = crossfadeDrawable(
44039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mShutterButton.getDrawable(),
44139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                getResources().getDrawable(resId));
44239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mShutterButton.setImageDrawable(transitionDrawable);
44339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
44439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        View optionsOverlay = findViewById(R.id.bottombar_options_overlay);
44539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        optionsOverlay.setVisibility(View.INVISIBLE);
44639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
44739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
44839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        transitionDrawable.startTransition(CIRCLE_ANIM_DURATION_MS);
44939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.start();
45039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
45139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
45239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    /**
45339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     * Animates bar to full width / length with video capture icon
45439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     */
45539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    public void animateToFullSize(int resId) {
45639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        final ValueAnimator radiusAnimator = ValueAnimator.ofFloat(
45739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                                                 CIRCLE_RADIUS,
45839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                                                 (float) diagonalLength()/2);
45939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.setDuration(CIRCLE_ANIM_DURATION_MS);
46039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.setInterpolator(Gusterpolator.INSTANCE);
46139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
46239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            @Override
46339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            public void onAnimationUpdate(ValueAnimator animation) {
46439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mCirclePath.reset();
46539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mCirclePath.addCircle(
46639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    getWidth()/2,
46739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    getHeight()/2,
46839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    (Float) animation.getAnimatedValue(),
46939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                    Path.Direction.CW);
47039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
47139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                invalidate();
47239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            }
47339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        });
47439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.addListener(new AnimatorListenerAdapter() {
47539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            @Override
47639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            public void onAnimationEnd(Animator animation) {
47739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                View optionsOverlay = findViewById(R.id.bottombar_options_overlay);
47839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                optionsOverlay.setVisibility(View.VISIBLE);
47939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague            }
48039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        });
48139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
48239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        TransitionDrawable transitionDrawable = crossfadeDrawable(
48339f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                mShutterButton.getDrawable(),
48439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague                getResources().getDrawable(resId));
48539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        mShutterButton.setImageDrawable(transitionDrawable);
48639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
48739f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        transitionDrawable.startTransition(CIRCLE_ANIM_DURATION_MS);
48839f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague        radiusAnimator.start();
48939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
4900744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen}
491