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