1d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// found in the LICENSE file.
4d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)package org.chromium.chrome.browser.infobar;
6d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
7d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.content.Context;
808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liuimport android.content.res.Resources;
908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liuimport android.content.res.TypedArray;
1008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liuimport android.graphics.Color;
1108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liuimport android.graphics.drawable.Drawable;
12d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.text.TextUtils;
13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.text.method.LinkMovementMethod;
1408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liuimport android.view.Gravity;
15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.view.LayoutInflater;
16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.view.View;
17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.view.ViewGroup;
18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.widget.Button;
19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.widget.ImageButton;
20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.widget.ImageView;
21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.widget.TextView;
22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liuimport org.chromium.base.ApiCompatibilityUtils;
24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import org.chromium.chrome.R;
25d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
26d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)/**
2708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu * Layout that arranges an InfoBar's views. An InfoBarLayout consists of:
28d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * - A message describing the action that the user can take.
29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * - A close button on the right side.
3008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu * - (optional) An icon representing the infobar's purpose on the left side.
3108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu * - (optional) Additional "custom" views (e.g. a checkbox and text, or a pair of spinners)
3208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu * - (optional) One or two buttons with text at the bottom.
33d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) *
3408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu * When adding custom views, widths and heights defined in the LayoutParams will be ignored.
3508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu * However, setting a minimum width in another way, like TextView.getMinWidth(), should still be
3608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu * obeyed.
37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) *
38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * Logic for what happens when things are clicked should be implemented by the InfoBarView.
39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) */
40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)public class InfoBarLayout extends ViewGroup implements View.OnClickListener {
41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * Parameters used for laying out children.
44d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
4508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private static class LayoutParams extends ViewGroup.LayoutParams {
46d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
4708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        public int startMargin;
4808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        public int endMargin;
4908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        public int topMargin;
5008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        public int bottomMargin;
51d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // Where this view will be laid out. These values are assigned in onMeasure() and used in
5308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // onLayout().
5408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        public int start;
5508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        public int top;
56d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        LayoutParams(int startMargin, int topMargin, int endMargin, int bottomMargin) {
5808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            super(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
5908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            this.startMargin = startMargin;
6008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            this.topMargin = topMargin;
6108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            this.endMargin = endMargin;
6208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            this.bottomMargin = bottomMargin;
6308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        }
6408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    }
65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private static class Group {
6708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        public View[] views;
6808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
6908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        /**
7008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu         * The gravity of each view in Group. Must be either Gravity.START, Gravity.END, or
7108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu         * Gravity.FILL_HORIZONTAL.
7208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu         */
7308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        public int gravity = Gravity.START;
7408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
7508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        /** Whether the views are vertically stacked. */
7608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        public boolean isStacked;
7708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
7808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        void setHorizontalMode(int horizontalSpacing, int startMargin, int endMargin) {
7908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            isStacked = false;
8008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            for (int i = 0; i < views.length; i++) {
8108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                LayoutParams lp = (LayoutParams) views[i].getLayoutParams();
8208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                lp.startMargin = i == 0 ? startMargin : horizontalSpacing;
8308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                lp.topMargin = 0;
8408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                lp.endMargin = i == views.length - 1 ? endMargin : 0;
8508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                lp.bottomMargin = 0;
8608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            }
87d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
89d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
9008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        void setVerticalMode(int verticalSpacing, int bottomMargin) {
9108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            isStacked = true;
9208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            for (int i = 0; i < views.length; i++) {
9308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                LayoutParams lp = (LayoutParams) views[i].getLayoutParams();
9408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                lp.startMargin = 0;
9508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                lp.topMargin = i == 0 ? 0 : verticalSpacing;
9608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                lp.endMargin = 0;
9708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                lp.bottomMargin = i == views.length - 1 ? bottomMargin : 0;
9808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            }
99d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
10208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private static final int ROW_MAIN = 1;
10308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private static final int ROW_OTHER = 2;
104d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
10508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private final int mMargin;
10608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private final int mIconSize;
10708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private final int mMinWidth;
10808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private final int mAccentColor;
10908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
11008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private final InfoBarView mInfoBarView;
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private final TextView mMessageView;
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private final ImageButton mCloseButton;
11308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private ImageView mIconView;
114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
11508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private Group mMainGroup;
11608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private Group mCustomGroup;
11708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private Group mButtonGroup;
118d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
119d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
12008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * These values are used during onMeasure() to track where the next view will be placed.
12108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     *
12208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * mWidth is the infobar width.
12308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * [mStart, mEnd) is the range of unoccupied space on the current row.
12408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * mTop and mBottom are the top and bottom of the current row.
12508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     *
12608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * These values, along with a view's gravity, are used to position the next view.
12708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * These values are updated after placing a view and after starting a new row.
128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
12908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private int mWidth;
13008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private int mStart;
13108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private int mEnd;
13208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private int mTop;
13308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private int mBottom;
134d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
135d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
13608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Constructs a layout for the specified InfoBar. After calling this, be sure to set the
13708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * message, the buttons, and/or the custom content using setMessage(), setButtons(), and
13808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * setCustomContent().
13908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     *
140d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * @param context The context used to render.
141d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * @param infoBarView InfoBarView that listens to events.
142d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * @param iconResourceId ID of the icon to use for the InfoBar.
14308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * @param message The message to show in the infobar.
144d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
14508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    public InfoBarLayout(Context context, InfoBarView infoBarView, int iconResourceId,
14608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            CharSequence message) {
147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        super(context);
148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        mInfoBarView = infoBarView;
149d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
150d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        // Grab the dimensions.
15108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        Resources res = getResources();
15208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mMargin = res.getDimensionPixelOffset(R.dimen.infobar_margin);
15308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mIconSize = res.getDimensionPixelSize(R.dimen.infobar_icon_size);
15408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mMinWidth = res.getDimensionPixelSize(R.dimen.infobar_min_width);
15508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mAccentColor = res.getColor(R.color.infobar_accent_blue);
156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
15708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // Set up the close button. Apply padding so it has a big touch target.
15808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mCloseButton = new ImageButton(context);
159d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        mCloseButton.setId(R.id.infobar_close_button);
16008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mCloseButton.setImageResource(R.drawable.infobar_close_button);
16108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        TypedArray a = getContext().obtainStyledAttributes(
16208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                new int [] {android.R.attr.selectableItemBackground});
16308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        Drawable closeButtonBackground = a.getDrawable(0);
16408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        a.recycle();
16508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        ApiCompatibilityUtils.setBackgroundForView(mCloseButton, closeButtonBackground);
16608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mCloseButton.setPadding(mMargin, mMargin, mMargin, mMargin);
167d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        mCloseButton.setOnClickListener(this);
16808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mCloseButton.setContentDescription(res.getString(R.string.infobar_close));
16908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mCloseButton.setLayoutParams(new LayoutParams(0, -mMargin, -mMargin, -mMargin));
17008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        addView(mCloseButton);
171d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
172d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        // Set up the icon.
173d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (iconResourceId != 0) {
17408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mIconView = new ImageView(context);
175d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            mIconView.setImageResource(iconResourceId);
17608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mIconView.setFocusable(false);
17708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mIconView.setLayoutParams(new LayoutParams(0, 0, mMargin / 2, 0));
17808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mIconView.getLayoutParams().width = mIconSize;
17908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mIconView.getLayoutParams().height = mIconSize;
180d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
181d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
18208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // Set up the message view.
18308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mMessageView = (TextView) LayoutInflater.from(context).inflate(R.layout.infobar_text, null);
18408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mMessageView.setText(message, TextView.BufferType.SPANNABLE);
185d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        mMessageView.setMovementMethod(LinkMovementMethod.getInstance());
18608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mMessageView.setLinkTextColor(mAccentColor);
18708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mMessageView.setLayoutParams(new LayoutParams(0, mMargin / 4, 0, 0));
18808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
18908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (mIconView != null) {
19008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mMainGroup = addGroup(mIconView, mMessageView);
191d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        } else {
19208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mMainGroup = addGroup(mMessageView);
193d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
194d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
195d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
196d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
19708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Sets the message to show on the infobar.
198d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
19908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    public void setMessage(CharSequence message) {
20008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mMessageView.setText(message, TextView.BufferType.SPANNABLE);
201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
20408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Sets the custom content of the infobar. These views will be displayed in addition to the
20508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * standard infobar controls (icon, text, buttons). Depending on the available space, view1 and
20608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * view2 will be laid out:
20708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     *  - Side by side on the main row,
20808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     *  - Side by side on a separate row, each taking up half the width of the infobar,
20908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     *  - Stacked above each other on two separate rows, taking up the full width of the infobar.
210d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
21108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    public void setCustomContent(View view1, View view2) {
21208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mCustomGroup = addGroup(view1, view2);
213d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
215d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
21608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Sets the custom content of the infobar to a single view. This view will be displayed in
21708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * addition to the standard infobar controls. Depending on the available space, the view will be
21808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * displayed:
21908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     *  - On the main row, start-aligned or end-aligned depending on whether there are also
22008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     *    buttons on the main row, OR
22108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     *  - On a separate row, start-aligned
222d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
22308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    public void setCustomContent(View view) {
22408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mCustomGroup = addGroup(view);
225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
226d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
22708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    /**
22808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Calls setButtons(primaryText, secondaryText, null).
22908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     */
23008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    public void setButtons(String primaryText, String secondaryText) {
23108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        setButtons(primaryText, secondaryText, null);
232d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
233d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
234d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
23508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Adds one, two, or three buttons to the layout.
236d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     *
23708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * @param primaryText Text for the primary button.
23808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * @param secondaryText Text for the secondary button, or null if there isn't a second button.
23908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * @param tertiaryText Text for the tertiary button, or null if there isn't a third button.
240d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
24108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    public void setButtons(String primaryText, String secondaryText, String tertiaryText) {
24208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (TextUtils.isEmpty(primaryText)) return;
24308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
24408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        LayoutInflater inflater = LayoutInflater.from(getContext());
24508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        Button primaryButton = (Button) inflater.inflate(R.layout.infobar_button, null);
24608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        primaryButton.setId(R.id.button_primary);
24708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        primaryButton.setOnClickListener(this);
24808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        primaryButton.setText(primaryText);
24908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        primaryButton.setBackgroundResource(R.drawable.btn_infobar_blue);
25008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        primaryButton.setTextColor(Color.WHITE);
25108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
25208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (TextUtils.isEmpty(secondaryText)) {
25308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mButtonGroup = addGroup(primaryButton);
25408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            return;
255d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
256d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
25708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        Button secondaryButton = (Button) inflater.inflate(R.layout.infobar_button, null);
25808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        secondaryButton.setId(R.id.button_secondary);
25908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        secondaryButton.setOnClickListener(this);
26008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        secondaryButton.setText(secondaryText);
26108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        secondaryButton.setTextColor(mAccentColor);
262d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
26308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (TextUtils.isEmpty(tertiaryText)) {
26408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mButtonGroup = addGroup(secondaryButton, primaryButton);
26508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            return;
266d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
267d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
26808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        Button tertiaryButton = (Button) inflater.inflate(R.layout.infobar_button, null);
26908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        tertiaryButton.setId(R.id.button_tertiary);
27008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        tertiaryButton.setOnClickListener(this);
27108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        tertiaryButton.setText(tertiaryText);
27208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        tertiaryButton.setPadding(mMargin / 2, tertiaryButton.getPaddingTop(), mMargin / 2,
27308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                tertiaryButton.getPaddingBottom());
27408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        tertiaryButton.setTextColor(
27508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                getContext().getResources().getColor(R.color.infobar_tertiary_button_text));
276d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
27708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mButtonGroup = addGroup(tertiaryButton, secondaryButton, primaryButton);
278d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
279d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
280d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
28108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Adds a group of Views that are measured and laid out together.
282d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
28308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private Group addGroup(View... views) {
28408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        Group group = new Group();
28508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        group.views = views;
286d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
28708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        for (View v : views) {
28808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            addView(v);
289d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
29008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        return group;
291d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
292d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
29308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    @Override
29408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    protected LayoutParams generateDefaultLayoutParams() {
29508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        return new LayoutParams(0, 0, 0, 0);
296d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
297d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
29808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    @Override
29908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
30008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // Place all the views in the positions already determined during onMeasure().
30108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        int width = right - left;
30208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        boolean isRtl = ApiCompatibilityUtils.isLayoutRtl(this);
303d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
30408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        for (int i = 0; i < getChildCount(); i++) {
30508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            View child = getChildAt(i);
30608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            LayoutParams lp = (LayoutParams) child.getLayoutParams();
30708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            int childLeft = lp.start;
30808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            int childRight = lp.start + child.getMeasuredWidth();
30908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
31008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            if (isRtl) {
31108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                int tmp = width - childRight;
31208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                childRight = width - childLeft;
31308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                childLeft = tmp;
314d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            }
315d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
31608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            child.layout(childLeft, lp.top, childRight, lp.top + child.getMeasuredHeight());
317d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
318d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
319d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
32008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    /**
32108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Measures *and* assigns positions to all of the views in the infobar. These positions are
32208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * saved in each view's LayoutParams (lp.start and lp.top) and used during onLayout(). All of
32308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * the interesting logic happens inside onMeasure(); onLayout() just assigns the already-
32408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * determined positions and mirrors everything for RTL, if needed.
32508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     */
326d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    @Override
327d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
328d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        assert getLayoutParams().height == LayoutParams.WRAP_CONTENT
329d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                : "InfoBar heights cannot be constrained.";
330d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
33108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // Measure all children without imposing any size constraints on them. This determines how
33208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // big each child wants to be.
33308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        int unspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
33408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        for (int i = 0; i < getChildCount(); i++) {
33508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            measureChild(getChildAt(i), unspecifiedSpec, unspecifiedSpec);
336d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
337d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
33808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // Avoid overlapping views, division by zero, infinite heights, and other fun problems that
33908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // could arise with extremely narrow infobars.
34008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mWidth = Math.max(MeasureSpec.getSize(widthMeasureSpec), mMinWidth);
34108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mTop = mBottom = 0;
34208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        placeGroups();
343d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
34408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        setMeasuredDimension(mWidth, resolveSize(mBottom, heightMeasureSpec));
345d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
346d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
347d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
34808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Assigns positions to all of the views in the infobar. The icon, text, and close button are
34908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * placed on the main row. The custom content and finally the buttons are placed on the main row
35008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * if they fit. Otherwise, they go on their own rows.
351d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
35208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private void placeGroups() {
35308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        startRow();
35408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        placeChild(mCloseButton, Gravity.END);
35508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        placeGroup(mMainGroup);
35608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
35708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        int customGroupWidth = 0;
35808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (mCustomGroup != null) {
35908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            updateCustomGroupForRow(ROW_MAIN);
36008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            customGroupWidth = getWidthWithMargins(mCustomGroup);
36108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        }
36208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
36308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        int buttonGroupWidth = 0;
36408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (mButtonGroup != null) {
36508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            updateButtonGroupForRow(ROW_MAIN);
36608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            buttonGroupWidth = getWidthWithMargins(mButtonGroup);
36708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        }
36808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
36908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        boolean customGroupOnMainRow = customGroupWidth <= availableWidth();
37008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        boolean buttonGroupOnMainRow = customGroupWidth + buttonGroupWidth <= availableWidth();
37108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
37208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (mCustomGroup != null) {
37308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            if (customGroupOnMainRow) {
37408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                mCustomGroup.gravity = (mButtonGroup != null && buttonGroupOnMainRow)
37508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                        ? Gravity.START : Gravity.END;
376d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            } else {
37708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                startRow();
37808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                updateCustomGroupForRow(ROW_OTHER);
379d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            }
38008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            placeGroup(mCustomGroup);
381d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
38208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
38308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (mButtonGroup != null) {
38408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            if (!buttonGroupOnMainRow) {
38508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                startRow();
38608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                updateButtonGroupForRow(ROW_OTHER);
38708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
38808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                // If the infobar consists of just a main row and a buttons row, the buttons must be
38908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                // at least 32dp below the bottom of the message text.
39008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                if (mCustomGroup == null) {
39108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                    LayoutParams lp = (LayoutParams) mMessageView.getLayoutParams();
39208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                    int messageBottom = lp.top + mMessageView.getMeasuredHeight();
39308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                    mTop = Math.max(mTop, messageBottom + 2 * mMargin);
39408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                }
39508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            }
39608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            placeGroup(mButtonGroup);
397d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
398d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
39908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        startRow();
400d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
40108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // If everything fits on a single row, center everything vertically.
40208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (buttonGroupOnMainRow) {
40308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            int layoutHeight = mBottom;
40408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            for (int i = 0; i < getChildCount(); i++) {
40508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                View child = getChildAt(i);
40608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                int extraSpace = layoutHeight - child.getMeasuredHeight();
40708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                LayoutParams lp = (LayoutParams) child.getLayoutParams();
40808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                lp.top = extraSpace / 2;
40908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            }
41008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        }
411d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
412d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
413d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
41408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Places a group of views on the current row, or stacks them over multiple rows if
41508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * group.isStacked is true. mStart, mEnd, and mBottom are updated to reflect the space taken by
41608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * the group.
417d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
41808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private void placeGroup(Group group) {
41908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (group.gravity == Gravity.END) {
42008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            for (int i = group.views.length - 1; i >= 0; i--) {
42108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                placeChild(group.views[i], group.gravity);
42208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                if (group.isStacked && i != 0) startRow();
423d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            }
42408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        } else {  // group.gravity is Gravity.START or Gravity.FILL_HORIZONTAL
42508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            for (int i = 0; i < group.views.length; i++) {
42608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                placeChild(group.views[i], group.gravity);
42708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                if (group.isStacked && i != group.views.length - 1) startRow();
428d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            }
429d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
430d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
431d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
432d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
43308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Places a single view on the current row, and updates the view's layout parameters to remember
43408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * its position. mStart, mEnd, and mBottom are updated to reflect the space taken by the view.
435d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
43608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private void placeChild(View child, int gravity) {
43708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        LayoutParams lp = (LayoutParams) child.getLayoutParams();
438d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
43908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        int availableWidth = Math.max(0, mEnd - mStart - lp.startMargin - lp.endMargin);
44008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (child.getMeasuredWidth() > availableWidth || gravity == Gravity.FILL_HORIZONTAL) {
44108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            measureChildWithFixedWidth(child, availableWidth);
44208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        }
443d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
44408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (gravity == Gravity.START || gravity == Gravity.FILL_HORIZONTAL) {
44508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            lp.start = mStart + lp.startMargin;
44608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mStart = lp.start + child.getMeasuredWidth() + lp.endMargin;
44708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        } else {  // gravity == Gravity.END
44808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            lp.start = mEnd - lp.endMargin - child.getMeasuredWidth();
44908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mEnd = lp.start - lp.startMargin;
450d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
451d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
45208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        lp.top = mTop + lp.topMargin;
45308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mBottom = Math.max(mBottom, lp.top + child.getMeasuredHeight() + lp.bottomMargin);
454d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
455d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
456d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
45708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Advances the current position to the next row and adds margins on the left, right, and top
45808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * of the new row.
459d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
46008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private void startRow() {
46108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mStart = mMargin;
46208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mEnd = mWidth - mMargin;
46308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mTop = mBottom + mMargin;
46408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mBottom = mTop;
46508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    }
46608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
46708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private int availableWidth() {
46808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        return mEnd - mStart;
469d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
470d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
471d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
47208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * @return The width of the group, including the items' margins.
473d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
47408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private int getWidthWithMargins(Group group) {
47508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (group.isStacked) return getWidthWithMargins(group.views[0]);
47608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
47708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        int width = 0;
47808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        for (View v : group.views) {
47908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            width += getWidthWithMargins(v);
480d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
48108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        return width;
48208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    }
48308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
48408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private int getWidthWithMargins(View child) {
48508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        LayoutParams lp = (LayoutParams) child.getLayoutParams();
48608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        return child.getMeasuredWidth() + lp.startMargin + lp.endMargin;
48708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    }
48808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
48908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private void measureChildWithFixedWidth(View child, int width) {
49008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
49108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
49208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        child.measure(widthSpec, heightSpec);
493d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
494d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
495d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
49608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * The button group has different layout properties (margins, gravity, etc) when placed on the
49708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * main row as opposed to on a separate row. This updates the layout properties of the button
49808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * group to prepare for placing it on either the main row or a separate row.
49908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     *
50008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * @param row One of ROW_MAIN or ROW_OTHER.
501d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
50208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private void updateButtonGroupForRow(int row) {
50308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        int startEndMargin = row == ROW_MAIN ? mMargin : 0;
50408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mButtonGroup.setHorizontalMode(mMargin / 2, startEndMargin, startEndMargin);
50508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mButtonGroup.gravity = Gravity.END;
50608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
50708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (row == ROW_OTHER && mButtonGroup.views.length >= 2) {
50808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            int extraWidth = availableWidth() - getWidthWithMargins(mButtonGroup);
50908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            if (extraWidth < 0) {
51008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                // Group is too wide to fit on a single row, so stack the group items vertically.
51108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                mButtonGroup.setVerticalMode(mMargin / 2, 0);
51208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                mButtonGroup.gravity = Gravity.FILL_HORIZONTAL;
51308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            } else if (mButtonGroup.views.length == 3) {
51408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                // Align tertiary button at the start and the other two buttons at the end.
51508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                ((LayoutParams) mButtonGroup.views[0].getLayoutParams()).endMargin += extraWidth;
51608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            }
51708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        }
518d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
519d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
520d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
52108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu     * Analagous to updateButtonGroupForRow(), but for the custom group istead of the button group.
522d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
52308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu    private void updateCustomGroupForRow(int row) {
52408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        int startEndMargin = row == ROW_MAIN ? mMargin : 0;
52508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mCustomGroup.setHorizontalMode(mMargin, startEndMargin, startEndMargin);
52608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        mCustomGroup.gravity = Gravity.START;
52708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
52808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (row == ROW_OTHER && mCustomGroup.views.length == 2) {
52908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            int extraWidth = availableWidth() - getWidthWithMargins(mCustomGroup);
53008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            if (extraWidth < 0) {
53108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                // Group is too wide to fit on a single row, so stack the group items vertically.
53208fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                mCustomGroup.setVerticalMode(0, mMargin);
53308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                mCustomGroup.gravity = Gravity.FILL_HORIZONTAL;
53408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            } else {
53508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                // Expand the children to take up the entire row.
53608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                View view0 = mCustomGroup.views[0];
53708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                View view1 = mCustomGroup.views[1];
53808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                int extraWidth0 = extraWidth / 2;
53908fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                int extraWidth1 = extraWidth - extraWidth0;
54008fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                measureChildWithFixedWidth(view0, view0.getMeasuredWidth() + extraWidth0);
54108fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu                measureChildWithFixedWidth(view1, view1.getMeasuredWidth() + extraWidth1);
542d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            }
543d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
544d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
545d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
546d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
547d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * Listens for View clicks.
548d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * Classes that override this function MUST call this one.
549d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * @param view View that was clicked on.
550d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
551d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    @Override
552d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    public void onClick(View view) {
55308fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // Disable the infobar controls unless the user clicked the tertiary button, which by
55408fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        // convention is the "learn more" link.
55508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        if (view.getId() != R.id.button_tertiary) {
55608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mInfoBarView.setControlsEnabled(false);
55708fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        }
55808fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu
559d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (view.getId() == R.id.infobar_close_button) {
560d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            mInfoBarView.onCloseButtonClicked();
561d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        } else if (view.getId() == R.id.button_primary) {
562d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            mInfoBarView.onButtonClicked(true);
563d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        } else if (view.getId() == R.id.button_secondary) {
564d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            mInfoBarView.onButtonClicked(false);
56508fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu        } else if (view.getId() == R.id.button_tertiary) {
56608fd22434aed8d58d4e04bbbc0df2a942440bcc5Bo Liu            mInfoBarView.onLinkClicked();
567d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
568d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
569d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
570