1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.internal.view.menu; 17 18 import com.android.internal.R; 19 20 import android.content.Context; 21 import android.content.res.Configuration; 22 import android.content.res.TypedArray; 23 import android.util.AttributeSet; 24 import android.view.Gravity; 25 import android.view.View; 26 import android.view.ViewDebug; 27 import android.view.ViewGroup; 28 import android.view.accessibility.AccessibilityEvent; 29 import android.widget.LinearLayout; 30 31 /** 32 * @hide 33 */ 34 public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvoker, MenuView { 35 private static final String TAG = "ActionMenuView"; 36 37 static final int MIN_CELL_SIZE = 56; // dips 38 static final int GENERATED_ITEM_PADDING = 4; // dips 39 40 private MenuBuilder mMenu; 41 42 private boolean mReserveOverflow; 43 private ActionMenuPresenter mPresenter; 44 private boolean mFormatItems; 45 private int mFormatItemsWidth; 46 private int mMinCellSize; 47 private int mGeneratedItemPadding; 48 private int mMeasuredExtraWidth; 49 private int mMaxItemHeight; 50 ActionMenuView(Context context)51 public ActionMenuView(Context context) { 52 this(context, null); 53 } 54 ActionMenuView(Context context, AttributeSet attrs)55 public ActionMenuView(Context context, AttributeSet attrs) { 56 super(context, attrs); 57 setBaselineAligned(false); 58 final float density = context.getResources().getDisplayMetrics().density; 59 mMinCellSize = (int) (MIN_CELL_SIZE * density); 60 mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density); 61 62 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, 63 R.attr.actionBarStyle, 0); 64 mMaxItemHeight = a.getDimensionPixelSize(R.styleable.ActionBar_height, 0); 65 a.recycle(); 66 } 67 setPresenter(ActionMenuPresenter presenter)68 public void setPresenter(ActionMenuPresenter presenter) { 69 mPresenter = presenter; 70 } 71 isExpandedFormat()72 public boolean isExpandedFormat() { 73 return mFormatItems; 74 } 75 setMaxItemHeight(int maxItemHeight)76 public void setMaxItemHeight(int maxItemHeight) { 77 mMaxItemHeight = maxItemHeight; 78 requestLayout(); 79 } 80 81 @Override onConfigurationChanged(Configuration newConfig)82 public void onConfigurationChanged(Configuration newConfig) { 83 super.onConfigurationChanged(newConfig); 84 mPresenter.updateMenuView(false); 85 86 if (mPresenter != null && mPresenter.isOverflowMenuShowing()) { 87 mPresenter.hideOverflowMenu(); 88 mPresenter.showOverflowMenu(); 89 } 90 } 91 92 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)93 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 94 // If we've been given an exact size to match, apply special formatting during layout. 95 final boolean wasFormatted = mFormatItems; 96 mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY; 97 98 if (wasFormatted != mFormatItems) { 99 mFormatItemsWidth = 0; // Reset this when switching modes 100 } 101 102 // Special formatting can change whether items can fit as action buttons. 103 // Kick the menu and update presenters when this changes. 104 final int widthSize = MeasureSpec.getMode(widthMeasureSpec); 105 if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) { 106 mFormatItemsWidth = widthSize; 107 mMenu.onItemsChanged(true); 108 } 109 110 if (mFormatItems) { 111 onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec); 112 } else { 113 // Previous measurement at exact format may have set margins - reset them. 114 final int childCount = getChildCount(); 115 for (int i = 0; i < childCount; i++) { 116 final View child = getChildAt(i); 117 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 118 lp.leftMargin = lp.rightMargin = 0; 119 } 120 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 121 } 122 } 123 onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec)124 private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) { 125 // We already know the width mode is EXACTLY if we're here. 126 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 127 int widthSize = MeasureSpec.getSize(widthMeasureSpec); 128 int heightSize = MeasureSpec.getSize(heightMeasureSpec); 129 130 final int widthPadding = getPaddingLeft() + getPaddingRight(); 131 final int heightPadding = getPaddingTop() + getPaddingBottom(); 132 133 final int itemHeightSpec = heightMode == MeasureSpec.EXACTLY 134 ? MeasureSpec.makeMeasureSpec(heightSize - heightPadding, MeasureSpec.EXACTLY) 135 : MeasureSpec.makeMeasureSpec( 136 Math.min(mMaxItemHeight, heightSize - heightPadding), MeasureSpec.AT_MOST); 137 138 widthSize -= widthPadding; 139 140 // Divide the view into cells. 141 final int cellCount = widthSize / mMinCellSize; 142 final int cellSizeRemaining = widthSize % mMinCellSize; 143 144 if (cellCount == 0) { 145 // Give up, nothing fits. 146 setMeasuredDimension(widthSize, 0); 147 return; 148 } 149 150 final int cellSize = mMinCellSize + cellSizeRemaining / cellCount; 151 152 int cellsRemaining = cellCount; 153 int maxChildHeight = 0; 154 int maxCellsUsed = 0; 155 int expandableItemCount = 0; 156 int visibleItemCount = 0; 157 boolean hasOverflow = false; 158 159 // This is used as a bitfield to locate the smallest items present. Assumes childCount < 64. 160 long smallestItemsAt = 0; 161 162 final int childCount = getChildCount(); 163 for (int i = 0; i < childCount; i++) { 164 final View child = getChildAt(i); 165 if (child.getVisibility() == GONE) continue; 166 167 final boolean isGeneratedItem = child instanceof ActionMenuItemView; 168 visibleItemCount++; 169 170 if (isGeneratedItem) { 171 // Reset padding for generated menu item views; it may change below 172 // and views are recycled. 173 child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0); 174 } 175 176 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 177 lp.expanded = false; 178 lp.extraPixels = 0; 179 lp.cellsUsed = 0; 180 lp.expandable = false; 181 lp.leftMargin = 0; 182 lp.rightMargin = 0; 183 lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText(); 184 185 // Overflow always gets 1 cell. No more, no less. 186 final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining; 187 188 final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable, 189 itemHeightSpec, heightPadding); 190 191 maxCellsUsed = Math.max(maxCellsUsed, cellsUsed); 192 if (lp.expandable) expandableItemCount++; 193 if (lp.isOverflowButton) hasOverflow = true; 194 195 cellsRemaining -= cellsUsed; 196 maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight()); 197 if (cellsUsed == 1) smallestItemsAt |= (1 << i); 198 } 199 200 // When we have overflow and a single expanded (text) item, we want to try centering it 201 // visually in the available space even though overflow consumes some of it. 202 final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2; 203 204 // Divide space for remaining cells if we have items that can expand. 205 // Try distributing whole leftover cells to smaller items first. 206 207 boolean needsExpansion = false; 208 while (expandableItemCount > 0 && cellsRemaining > 0) { 209 int minCells = Integer.MAX_VALUE; 210 long minCellsAt = 0; // Bit locations are indices of relevant child views 211 int minCellsItemCount = 0; 212 for (int i = 0; i < childCount; i++) { 213 final View child = getChildAt(i); 214 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 215 216 // Don't try to expand items that shouldn't. 217 if (!lp.expandable) continue; 218 219 // Mark indices of children that can receive an extra cell. 220 if (lp.cellsUsed < minCells) { 221 minCells = lp.cellsUsed; 222 minCellsAt = 1 << i; 223 minCellsItemCount = 1; 224 } else if (lp.cellsUsed == minCells) { 225 minCellsAt |= 1 << i; 226 minCellsItemCount++; 227 } 228 } 229 230 // Items that get expanded will always be in the set of smallest items when we're done. 231 smallestItemsAt |= minCellsAt; 232 233 if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop. 234 235 // We have enough cells, all minimum size items will be incremented. 236 minCells++; 237 238 for (int i = 0; i < childCount; i++) { 239 final View child = getChildAt(i); 240 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 241 if ((minCellsAt & (1 << i)) == 0) { 242 // If this item is already at our small item count, mark it for later. 243 if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i; 244 continue; 245 } 246 247 if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) { 248 // Add padding to this item such that it centers. 249 child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0); 250 } 251 lp.cellsUsed++; 252 lp.expanded = true; 253 cellsRemaining--; 254 } 255 256 needsExpansion = true; 257 } 258 259 // Divide any space left that wouldn't divide along cell boundaries 260 // evenly among the smallest items 261 262 final boolean singleItem = !hasOverflow && visibleItemCount == 1; 263 if (cellsRemaining > 0 && smallestItemsAt != 0 && 264 (cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) { 265 float expandCount = Long.bitCount(smallestItemsAt); 266 267 if (!singleItem) { 268 // The items at the far edges may only expand by half in order to pin to either side. 269 if ((smallestItemsAt & 1) != 0) { 270 LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams(); 271 if (!lp.preventEdgeOffset) expandCount -= 0.5f; 272 } 273 if ((smallestItemsAt & (1 << (childCount - 1))) != 0) { 274 LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams()); 275 if (!lp.preventEdgeOffset) expandCount -= 0.5f; 276 } 277 } 278 279 final int extraPixels = expandCount > 0 ? 280 (int) (cellsRemaining * cellSize / expandCount) : 0; 281 282 for (int i = 0; i < childCount; i++) { 283 if ((smallestItemsAt & (1 << i)) == 0) continue; 284 285 final View child = getChildAt(i); 286 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 287 if (child instanceof ActionMenuItemView) { 288 // If this is one of our views, expand and measure at the larger size. 289 lp.extraPixels = extraPixels; 290 lp.expanded = true; 291 if (i == 0 && !lp.preventEdgeOffset) { 292 // First item gets part of its new padding pushed out of sight. 293 // The last item will get this implicitly from layout. 294 lp.leftMargin = -extraPixels / 2; 295 } 296 needsExpansion = true; 297 } else if (lp.isOverflowButton) { 298 lp.extraPixels = extraPixels; 299 lp.expanded = true; 300 lp.rightMargin = -extraPixels / 2; 301 needsExpansion = true; 302 } else { 303 // If we don't know what it is, give it some margins instead 304 // and let it center within its space. We still want to pin 305 // against the edges. 306 if (i != 0) { 307 lp.leftMargin = extraPixels / 2; 308 } 309 if (i != childCount - 1) { 310 lp.rightMargin = extraPixels / 2; 311 } 312 } 313 } 314 315 cellsRemaining = 0; 316 } 317 318 // Remeasure any items that have had extra space allocated to them. 319 if (needsExpansion) { 320 for (int i = 0; i < childCount; i++) { 321 final View child = getChildAt(i); 322 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 323 324 if (!lp.expanded) continue; 325 326 final int width = lp.cellsUsed * cellSize + lp.extraPixels; 327 child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 328 itemHeightSpec); 329 } 330 } 331 332 if (heightMode != MeasureSpec.EXACTLY) { 333 heightSize = maxChildHeight; 334 } 335 336 setMeasuredDimension(widthSize, heightSize); 337 mMeasuredExtraWidth = cellsRemaining * cellSize; 338 } 339 340 /** 341 * Measure a child view to fit within cell-based formatting. The child's width 342 * will be measured to a whole multiple of cellSize. 343 * 344 * <p>Sets the expandable and cellsUsed fields of LayoutParams. 345 * 346 * @param child Child to measure 347 * @param cellSize Size of one cell 348 * @param cellsRemaining Number of cells remaining that this view can expand to fill 349 * @param parentHeightMeasureSpec MeasureSpec used by the parent view 350 * @param parentHeightPadding Padding present in the parent view 351 * @return Number of cells this child was measured to occupy 352 */ measureChildForCells(View child, int cellSize, int cellsRemaining, int parentHeightMeasureSpec, int parentHeightPadding)353 static int measureChildForCells(View child, int cellSize, int cellsRemaining, 354 int parentHeightMeasureSpec, int parentHeightPadding) { 355 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 356 357 final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) - 358 parentHeightPadding; 359 final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec); 360 final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode); 361 362 final ActionMenuItemView itemView = child instanceof ActionMenuItemView ? 363 (ActionMenuItemView) child : null; 364 final boolean hasText = itemView != null && itemView.hasText(); 365 366 int cellsUsed = 0; 367 if (cellsRemaining > 0 && (!hasText || cellsRemaining >= 2)) { 368 final int childWidthSpec = MeasureSpec.makeMeasureSpec( 369 cellSize * cellsRemaining, MeasureSpec.AT_MOST); 370 child.measure(childWidthSpec, childHeightSpec); 371 372 final int measuredWidth = child.getMeasuredWidth(); 373 cellsUsed = measuredWidth / cellSize; 374 if (measuredWidth % cellSize != 0) cellsUsed++; 375 if (hasText && cellsUsed < 2) cellsUsed = 2; 376 } 377 378 final boolean expandable = !lp.isOverflowButton && hasText; 379 lp.expandable = expandable; 380 381 lp.cellsUsed = cellsUsed; 382 final int targetWidth = cellsUsed * cellSize; 383 child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY), 384 childHeightSpec); 385 return cellsUsed; 386 } 387 388 @Override onLayout(boolean changed, int left, int top, int right, int bottom)389 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 390 if (!mFormatItems) { 391 super.onLayout(changed, left, top, right, bottom); 392 return; 393 } 394 395 final int childCount = getChildCount(); 396 final int midVertical = (top + bottom) / 2; 397 final int dividerWidth = getDividerWidth(); 398 int overflowWidth = 0; 399 int nonOverflowWidth = 0; 400 int nonOverflowCount = 0; 401 int widthRemaining = right - left - getPaddingRight() - getPaddingLeft(); 402 boolean hasOverflow = false; 403 final boolean isLayoutRtl = isLayoutRtl(); 404 for (int i = 0; i < childCount; i++) { 405 final View v = getChildAt(i); 406 if (v.getVisibility() == GONE) { 407 continue; 408 } 409 410 LayoutParams p = (LayoutParams) v.getLayoutParams(); 411 if (p.isOverflowButton) { 412 overflowWidth = v.getMeasuredWidth(); 413 if (hasDividerBeforeChildAt(i)) { 414 overflowWidth += dividerWidth; 415 } 416 417 int height = v.getMeasuredHeight(); 418 int r; 419 int l; 420 if (isLayoutRtl) { 421 l = getPaddingLeft() + p.leftMargin; 422 r = l + overflowWidth; 423 } else { 424 r = getWidth() - getPaddingRight() - p.rightMargin; 425 l = r - overflowWidth; 426 } 427 int t = midVertical - (height / 2); 428 int b = t + height; 429 v.layout(l, t, r, b); 430 431 widthRemaining -= overflowWidth; 432 hasOverflow = true; 433 } else { 434 final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin; 435 nonOverflowWidth += size; 436 widthRemaining -= size; 437 if (hasDividerBeforeChildAt(i)) { 438 nonOverflowWidth += dividerWidth; 439 } 440 nonOverflowCount++; 441 } 442 } 443 444 if (childCount == 1 && !hasOverflow) { 445 // Center a single child 446 final View v = getChildAt(0); 447 final int width = v.getMeasuredWidth(); 448 final int height = v.getMeasuredHeight(); 449 final int midHorizontal = (right - left) / 2; 450 final int l = midHorizontal - width / 2; 451 final int t = midVertical - height / 2; 452 v.layout(l, t, l + width, t + height); 453 return; 454 } 455 456 final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1); 457 final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0); 458 459 if (isLayoutRtl) { 460 int startRight = getWidth() - getPaddingRight(); 461 for (int i = 0; i < childCount; i++) { 462 final View v = getChildAt(i); 463 final LayoutParams lp = (LayoutParams) v.getLayoutParams(); 464 if (v.getVisibility() == GONE || lp.isOverflowButton) { 465 continue; 466 } 467 468 startRight -= lp.rightMargin; 469 int width = v.getMeasuredWidth(); 470 int height = v.getMeasuredHeight(); 471 int t = midVertical - height / 2; 472 v.layout(startRight - width, t, startRight, t + height); 473 startRight -= width + lp.leftMargin + spacerSize; 474 } 475 } else { 476 int startLeft = getPaddingLeft(); 477 for (int i = 0; i < childCount; i++) { 478 final View v = getChildAt(i); 479 final LayoutParams lp = (LayoutParams) v.getLayoutParams(); 480 if (v.getVisibility() == GONE || lp.isOverflowButton) { 481 continue; 482 } 483 484 startLeft += lp.leftMargin; 485 int width = v.getMeasuredWidth(); 486 int height = v.getMeasuredHeight(); 487 int t = midVertical - height / 2; 488 v.layout(startLeft, t, startLeft + width, t + height); 489 startLeft += width + lp.rightMargin + spacerSize; 490 } 491 } 492 } 493 494 @Override onDetachedFromWindow()495 public void onDetachedFromWindow() { 496 super.onDetachedFromWindow(); 497 mPresenter.dismissPopupMenus(); 498 } 499 isOverflowReserved()500 public boolean isOverflowReserved() { 501 return mReserveOverflow; 502 } 503 setOverflowReserved(boolean reserveOverflow)504 public void setOverflowReserved(boolean reserveOverflow) { 505 mReserveOverflow = reserveOverflow; 506 } 507 508 @Override generateDefaultLayoutParams()509 protected LayoutParams generateDefaultLayoutParams() { 510 LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, 511 LayoutParams.WRAP_CONTENT); 512 params.gravity = Gravity.CENTER_VERTICAL; 513 return params; 514 } 515 516 @Override generateLayoutParams(AttributeSet attrs)517 public LayoutParams generateLayoutParams(AttributeSet attrs) { 518 return new LayoutParams(getContext(), attrs); 519 } 520 521 @Override generateLayoutParams(ViewGroup.LayoutParams p)522 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 523 if (p != null) { 524 final LayoutParams result = p instanceof LayoutParams 525 ? new LayoutParams((LayoutParams) p) 526 : new LayoutParams(p); 527 if (result.gravity <= Gravity.NO_GRAVITY) { 528 result.gravity = Gravity.CENTER_VERTICAL; 529 } 530 return result; 531 } 532 return generateDefaultLayoutParams(); 533 } 534 535 @Override checkLayoutParams(ViewGroup.LayoutParams p)536 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 537 return p != null && p instanceof LayoutParams; 538 } 539 generateOverflowButtonLayoutParams()540 public LayoutParams generateOverflowButtonLayoutParams() { 541 LayoutParams result = generateDefaultLayoutParams(); 542 result.isOverflowButton = true; 543 return result; 544 } 545 invokeItem(MenuItemImpl item)546 public boolean invokeItem(MenuItemImpl item) { 547 return mMenu.performItemAction(item, 0); 548 } 549 getWindowAnimations()550 public int getWindowAnimations() { 551 return 0; 552 } 553 initialize(MenuBuilder menu)554 public void initialize(MenuBuilder menu) { 555 mMenu = menu; 556 } 557 558 @Override hasDividerBeforeChildAt(int childIndex)559 protected boolean hasDividerBeforeChildAt(int childIndex) { 560 if (childIndex == 0) { 561 return false; 562 } 563 final View childBefore = getChildAt(childIndex - 1); 564 final View child = getChildAt(childIndex); 565 boolean result = false; 566 if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) { 567 result |= ((ActionMenuChildView) childBefore).needsDividerAfter(); 568 } 569 if (childIndex > 0 && child instanceof ActionMenuChildView) { 570 result |= ((ActionMenuChildView) child).needsDividerBefore(); 571 } 572 return result; 573 } 574 dispatchPopulateAccessibilityEvent(AccessibilityEvent event)575 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 576 return false; 577 } 578 579 public interface ActionMenuChildView { needsDividerBefore()580 public boolean needsDividerBefore(); needsDividerAfter()581 public boolean needsDividerAfter(); 582 } 583 584 public static class LayoutParams extends LinearLayout.LayoutParams { 585 @ViewDebug.ExportedProperty(category = "layout") 586 public boolean isOverflowButton; 587 @ViewDebug.ExportedProperty(category = "layout") 588 public int cellsUsed; 589 @ViewDebug.ExportedProperty(category = "layout") 590 public int extraPixels; 591 @ViewDebug.ExportedProperty(category = "layout") 592 public boolean expandable; 593 @ViewDebug.ExportedProperty(category = "layout") 594 public boolean preventEdgeOffset; 595 596 public boolean expanded; 597 LayoutParams(Context c, AttributeSet attrs)598 public LayoutParams(Context c, AttributeSet attrs) { 599 super(c, attrs); 600 } 601 LayoutParams(ViewGroup.LayoutParams other)602 public LayoutParams(ViewGroup.LayoutParams other) { 603 super(other); 604 } 605 LayoutParams(LayoutParams other)606 public LayoutParams(LayoutParams other) { 607 super((LinearLayout.LayoutParams) other); 608 isOverflowButton = other.isOverflowButton; 609 } 610 LayoutParams(int width, int height)611 public LayoutParams(int width, int height) { 612 super(width, height); 613 isOverflowButton = false; 614 } 615 LayoutParams(int width, int height, boolean isOverflowButton)616 public LayoutParams(int width, int height, boolean isOverflowButton) { 617 super(width, height); 618 this.isOverflowButton = isOverflowButton; 619 } 620 } 621 } 622