The change makes PagedTileLayout only use excess space from QSPanel
after other views have been measured and the padding has been accounted
for (see LinearLayout#measureVertical).
PagedTileLayout caches the last height to be measured so as to minimize
the number of times the number of rows is recalculated (and prevent
loops).
Also, fixed the calculation in TileLayout#updateMaxRows to match the
height calculation in TileLayout#onMeasure.
Test: manual, stress testing with multiple pages, adding and removing
tiles, starting and disconnecting VPN, changing display size
Bug:
122714773
Change-Id: I5c85f03cfc79e341244d213fd92307821db80889
<com.android.systemui.qs.PagedTileLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="0dp"
android:layout_weight="1"
android:clipChildren="true"
android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom">
private int mLayoutDirection;
private int mHorizontalClipBound;
private final Rect mClippingRect;
+ private int mLastMaxHeight = -1;
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int nTiles = mTiles.size();
- if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+ // If we have no reason to recalculate the number of rows, skip this step. In particular,
+ // if the height passed by its parent is the same as the last time, we try not to remeasure.
+ if (mDistributeTiles || mLastMaxHeight != MeasureSpec.getSize(heightMeasureSpec)) {
+ mLastMaxHeight = MeasureSpec.getSize(heightMeasureSpec);
// Only change the pages if the number of rows or columns (from updateResources) has
// changed or the tiles have changed
if (mPages.get(0).updateMaxRows(heightMeasureSpec, nTiles) || mDistributeTiles) {
if (navBelow) {
maxQs -= getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
}
- mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.AT_MOST));
+ // Measure with EXACTLY. That way, PagedTileLayout will only use excess height and will be
+ // measured last, after other views and padding is accounted for.
+ mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.EXACTLY));
int width = mQSPanel.getMeasuredWidth();
int height = layoutParams.topMargin + layoutParams.bottomMargin
+ mQSPanel.getMeasuredHeight() + getPaddingBottom();
addView(mDivider);
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // We want all the logic of LinearLayout#onMeasure, and for it to assign the excess space
+ // not used by the other children to PagedTileLayout. However, in this case, LinearLayout
+ // assumes that PagedTileLayout would use all the excess space. This is not the case as
+ // PagedTileLayout height is quantized (because it shows a certain number of rows).
+ // Therefore, after everything is measured, we need to make sure that we add up the correct
+ // total height
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int height = getPaddingBottom() + getPaddingTop();
+ int numChildren = getChildCount();
+ for (int i = 0; i < numChildren; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE) height += child.getMeasuredHeight();
+ }
+ setMeasuredDimension(getMeasuredWidth(), height);
+ }
+
public View getDivider() {
return mDivider;
}
* @param tilesCount Upper limit on the number of tiles to show. to prevent empty rows.
*/
public boolean updateMaxRows(int heightMeasureSpec, int tilesCount) {
- final int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mCellMarginTop;
+ final int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mCellMarginTop
+ + mCellMarginVertical;
final int previousRows = mRows;
mRows = availableHeight / (mCellHeight + mCellMarginVertical);
if (mRows >= mMaxAllowedRows) {