Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3984)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayout.java

Issue 1553813002: Add ViewGroup for handling pairs of infobar controls (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayoutTest.java » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayout.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayout.java
new file mode 100644
index 0000000000000000000000000000000000000000..0bf011d5076cb2506c0c7c113aac86fcbad4a575
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayout.java
@@ -0,0 +1,189 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.infobar;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.R;
+
+/**
+ * Automatically lays out one or two Views for an infobar, placing them on the same row if possible
+ * and stacking them otherwise.
+ *
+ * Use cases of this Layout include placement of infobar buttons and placement of TextViews inside
+ * of spinner controls (http://goto.google.com/infobar-spec).
+ *
+ * Layout parameters (i.e. margins) are ignored to enforce infobar consistency. Alignment defines
+ * where the controls are placed (for RTL, flip everything):
+ *
+ * ALIGN_START ALIGN_APART ALIGN_END
+ * ----------------------------- ----------------------------- -----------------------------
+ * | PRIMARY SECONDARY | | SECONDARY PRIMARY | | SECONDARY PRIMARY |
+ * ----------------------------- ----------------------------- -----------------------------
+ *
+ * Controls are stacked automatically when they don't fit on the same row, with each control taking
+ * up the full available width and with the primary control sitting on top of the secondary.
+ * -----------------------------
+ * | PRIMARY------------------ |
+ * | SECONDARY---------------- |
+ * -----------------------------
+ *
+ * TODO(dfalcantara): Remove the VisibleForTesting annotations when controls that this land.
+ */
+@VisibleForTesting
+public final class InfoBarDualControlLayout extends ViewGroup {
+ public static final int ALIGN_START = 0;
+ public static final int ALIGN_END = 1;
+ public static final int ALIGN_APART = 2;
+
+ private final int mHorizontalMarginBetweenViews;
+
+ private int mAlignment = ALIGN_START;
+ private int mStackedMargin;
+
+ private boolean mIsStacked;
+ private View mPrimaryView;
+ private View mSecondaryView;
+
+ /**
+ * Construct a new InfoBarDualControlLayout.
+ *
+ * See {@link ViewGroup} for parameter details. attrs may be null if constructed dynamically.
+ */
+ @VisibleForTesting
+ public InfoBarDualControlLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ // Cache dimensions.
+ Resources resources = getContext().getResources();
+ mHorizontalMarginBetweenViews =
+ resources.getDimensionPixelSize(R.dimen.infobar_control_margin_between_items);
+ }
+
+ /**
+ * Define how the controls will be laid out.
+ *
+ * @param alignment One of ALIGN_START, ALIGN_APART, ALIGN_END.
+ */
+ @VisibleForTesting
+ void setAlignment(int alignment) {
+ mAlignment = alignment;
+ }
+
+ /**
+ * Sets the margin between the controls when they're stacked. By default, there is no margin.
+ */
+ @VisibleForTesting
+ void setStackedMargin(int stackedMargin) {
+ mStackedMargin = stackedMargin;
+ }
+
+ @Override
+ public void onViewAdded(View child) {
+ super.onViewAdded(child);
+
+ if (mPrimaryView == null) {
+ mPrimaryView = child;
+ } else if (mSecondaryView == null) {
+ mSecondaryView = child;
+ } else {
+ throw new IllegalStateException("Too many children added to InfoBarDualControlLayout");
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mIsStacked = false;
+
+ // Measure the primary View, allowing it to be as wide as the Layout.
+ int maxWidth = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED
+ ? Integer.MAX_VALUE : MeasureSpec.getSize(widthMeasureSpec);
+ int unspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ measureChild(mPrimaryView, unspecifiedSpec, unspecifiedSpec);
+
+ int layoutWidth = mPrimaryView.getMeasuredWidth();
+ int layoutHeight = mPrimaryView.getMeasuredHeight();
+
+ if (mSecondaryView != null) {
+ // Measure the secondary View, allowing it to be as wide as the layout.
+ measureChild(mSecondaryView, unspecifiedSpec, unspecifiedSpec);
+ int combinedWidth = mPrimaryView.getMeasuredWidth()
+ + mHorizontalMarginBetweenViews + mSecondaryView.getMeasuredWidth();
+
+ if (combinedWidth > maxWidth) {
+ // Stack the Views on top of each other.
+ mIsStacked = true;
+
+ int widthSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY);
+ mPrimaryView.measure(widthSpec, unspecifiedSpec);
+ mSecondaryView.measure(widthSpec, unspecifiedSpec);
+
+ layoutWidth = maxWidth;
+ layoutHeight = mPrimaryView.getMeasuredHeight() + mStackedMargin
+ + mSecondaryView.getMeasuredHeight();
+ } else {
+ // The Views fit side by side. Check which is taller to find the layout height.
+ layoutWidth = combinedWidth;
+ layoutHeight = Math.max(layoutHeight, mSecondaryView.getMeasuredHeight());
+ }
+ }
+
+ setMeasuredDimension(resolveSize(layoutWidth, widthMeasureSpec),
+ resolveSize(layoutHeight, heightMeasureSpec));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ int width = right - left;
+ boolean isRtl = ApiCompatibilityUtils.isLayoutRtl(this);
+ boolean isPrimaryOnRight = (isRtl && mAlignment == ALIGN_START)
+ || (!isRtl && (mAlignment == ALIGN_APART || mAlignment == ALIGN_END));
+
+ int primaryRight = isPrimaryOnRight ? width : mPrimaryView.getMeasuredWidth();
+ int primaryLeft = primaryRight - mPrimaryView.getMeasuredWidth();
+ int primaryHeight = mPrimaryView.getMeasuredHeight();
+ mPrimaryView.layout(primaryLeft, 0, primaryRight, primaryHeight);
+
+ if (mIsStacked) {
+ // Fill out the row. onMeasure() should have already applied the correct width.
+ int secondaryTop = primaryHeight + mStackedMargin;
+ int secondaryBottom = secondaryTop + mSecondaryView.getMeasuredHeight();
+ mSecondaryView.layout(
+ 0, secondaryTop, mSecondaryView.getMeasuredWidth(), secondaryBottom);
+ } else if (mSecondaryView != null) {
+ // Center the secondary View vertically with the primary View.
+ int secondaryHeight = mSecondaryView.getMeasuredHeight();
+ int primaryCenter = primaryHeight / 2;
+ int secondaryTop = primaryCenter - (secondaryHeight / 2);
+ int secondaryBottom = secondaryTop + secondaryHeight;
+
+ // Determine where to place the secondary View.
+ int secondaryLeft;
+ int secondaryRight;
+ if (mAlignment == ALIGN_APART) {
+ // Put the second View on the other side of the Layout from the primary View.
+ secondaryLeft = isPrimaryOnRight ? 0 : width - mSecondaryView.getMeasuredWidth();
+ secondaryRight = secondaryLeft + mSecondaryView.getMeasuredWidth();
+ } else if (isPrimaryOnRight) {
+ // Sit to the left of the primary View.
+ secondaryRight = primaryLeft - mHorizontalMarginBetweenViews;
+ secondaryLeft = secondaryRight - mSecondaryView.getMeasuredWidth();
+ } else {
+ // Sit to the right of the primary View.
+ secondaryLeft = primaryRight + mHorizontalMarginBetweenViews;
+ secondaryRight = secondaryLeft + mSecondaryView.getMeasuredWidth();
+ }
+
+ mSecondaryView.layout(
+ secondaryLeft, secondaryTop, secondaryRight, secondaryBottom);
+ }
+ }
+}
« no previous file with comments | « no previous file | chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayoutTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698