BottomBar.java revision e3b0e946924e45f6788db69aaa8f48a2d81031f0
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
190744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.content.Context;
200744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.content.res.Configuration;
210744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.util.AttributeSet;
220744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.view.Gravity;
230f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Spragueimport android.view.LayoutInflater;
240744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.view.View;
250744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.widget.FrameLayout;
260744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.widget.GridLayout;
270744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.widget.LinearLayout;
28e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Spragueimport android.view.MotionEvent;
290744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
300744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen/**
310744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * BottomBar swaps its width and height on rotation. In addition, it also changes
320744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * gravity and layout orientation based on the new orientation. Specifically, in
330744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * landscape it aligns to the right side of its parent and lays out its children
340744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * vertically, whereas in portrait, it stays at the bottom of the parent and has
350744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * a horizontal layout orientation.
360744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen *
370744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * In addition to adjusting itself, this class also makes sure its children are
380744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen * always spaced evenly in the new orientation.
390744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen */
400744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenpublic class BottomBar extends FrameLayout {
410744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    private final int mPaddingStart;
420744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    private final int mPaddingEnd;
430744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
440744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    public BottomBar(Context context, AttributeSet attrs) {
450744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        super(context, attrs);
460744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (context.getResources().getConfiguration().orientation
470744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                == Configuration.ORIENTATION_LANDSCAPE) {
480744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            mPaddingStart = getPaddingTop();
490744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            mPaddingEnd = getPaddingBottom();
500744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        } else {
510744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            // Portrait mode
520744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            mPaddingStart = getPaddingLeft();
530744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            mPaddingEnd = getPaddingRight();
540744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
550744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
560744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
570744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    /**
580f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague     * Sets the bottom bar buttons given a layout id
590f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague     */
600f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague    public void setButtonLayout(int buttonLayoutId) {
61eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague        removeAllViews();
620f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
630f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague                Context.LAYOUT_INFLATER_SERVICE);
640f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague        inflater.inflate(buttonLayoutId, this, true);
650f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague    }
660f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
670f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague    /**
680744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen     * Adjust layout orientation, width, height and gravity based on new orientation.
690744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen     */
700744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    private void adjustSelf(Configuration configuration) {
710744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
720744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        int shortEdge;
730744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (lp.width != FrameLayout.LayoutParams.MATCH_PARENT) {
740744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            shortEdge = lp.width;
750744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        } else {
760744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            shortEdge = lp.height;
770744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
780744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
790744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            lp.width = FrameLayout.LayoutParams.MATCH_PARENT;
800744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            lp.height = shortEdge;
810744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            lp.gravity = Gravity.BOTTOM;
820744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            setLayoutParams(lp);
830744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        } else {
840744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            lp.height = FrameLayout.LayoutParams.MATCH_PARENT;
850744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            lp.width = shortEdge;
860744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            lp.gravity = Gravity.RIGHT;
870744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            setLayoutParams(lp);
880744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
890744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
900744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
910744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    @Override
920744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    protected void onConfigurationChanged(Configuration config) {
930744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        super.onConfigurationChanged(config);
940744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        adjustSelf(config);
950744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
960744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
970744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    /**
980744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen     * Custom layout call that aims to space all children evenly in the given rect.
990744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen     */
1000744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    @Override
1010744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
1020744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        final int childCount = getChildCount();
1030744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (childCount == 0) {
1040744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            return;
1050744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
1060744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        // Convert parent coordinates into child coordinates
1070744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        right -= left;
1080744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        bottom -= top;
1090744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        left = 0;
1100744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        top = 0;
1110744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
1120744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        // Evenly space all children
1130744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (bottom < right) {
1140744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            // Portrait mode
1150744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            int centerY = (top + bottom) / 2;
1160744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            int perChildHorizontalSpace = (right - left - mPaddingStart - mPaddingEnd) / childCount;
1170744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            for (int i = 0; i < childCount; i++) {
1180744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                int centerX = mPaddingStart + perChildHorizontalSpace * i
1190744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                        + perChildHorizontalSpace / 2;
1200744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                View child = getChildAt(i);
1210744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                int childWidth = child.getMeasuredWidth();
1220744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                int childHeight = child.getMeasuredHeight();
1230744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                child.layout(centerX - childWidth / 2, centerY - childHeight / 2,
1240744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                        centerX + childWidth / 2, centerY + childHeight / 2);
1250744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            }
1260744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        } else {
1270744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            // Landscape
1280744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            int centerX = (left + right) / 2;
1290744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            int perChildVerticalSpace = (bottom - top - mPaddingStart - mPaddingEnd) / childCount;
1300744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            // Layout children from bottom up so that they remain nearly the same position
1310744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            // as when they were in portrait
1320744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            for (int i = 0; i < childCount; i++) {
1330744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                int centerY = mPaddingStart + perChildVerticalSpace * (childCount - 1 - i)
1340744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                        + perChildVerticalSpace / 2;
1350744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                View child = getChildAt(i);
1360744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                int childWidth = child.getMeasuredWidth();
1370744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                int childHeight = child.getMeasuredHeight();
1380744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                child.layout(centerX - childWidth / 2, centerY - childHeight / 2,
1390744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                        centerX + childWidth / 2, centerY + childHeight / 2);
1400744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            }
1410744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
1420744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
1430744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
144e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    // prevent touches on bottom bar (not its children)
145e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    // from triggering a touch event on preview area
146e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    @Override
147e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    public boolean onTouchEvent(MotionEvent event) {
148e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague        return true;
149e3b0e946924e45f6788db69aaa8f48a2d81031f0Spike Sprague    }
1500744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen}
151