11abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/* 21abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Copyright (C) 2015 The Android Open Source Project 31abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 41abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 51abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * you may not use this file except in compliance with the License. 61abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * You may obtain a copy of the License at 71abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 81abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 91abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Unless required by applicable law or agreed to in writing, software 111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * See the License for the specific language governing permissions and 141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * limitations under the License. 151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopackage com.android.tv.tuner.layout; 181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 191abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.Context; 201abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.res.TypedArray; 2165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.graphics.Point; 221abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.graphics.Rect; 2365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.hardware.display.DisplayManager; 241abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.AttributeSet; 251abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.Log; 2665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.view.Display; 271abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.view.View; 281abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.view.ViewGroup; 291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.R; 311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 321abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.Arrays; 331abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.Comparator; 341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/** 361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * A layout that scales its children using the given percentage value. 371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 381abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopublic class ScaledLayout extends ViewGroup { 391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final String TAG = "ScaledLayout"; 401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final boolean DEBUG = false; 411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final Comparator<Rect> mRectTopLeftSorter = new Comparator<Rect>() { 421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public int compare(Rect lhs, Rect rhs) { 441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (lhs.top != rhs.top) { 451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return lhs.top - rhs.top; 461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return lhs.left - rhs.left; 481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko }; 511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private Rect[] mRectArray; 5365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private final int mMaxWidth; 5465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private final int mMaxHeight; 551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public ScaledLayout(Context context) { 571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko this(context, null); 581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public ScaledLayout(Context context, AttributeSet attrs) { 611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko this(context, attrs, 0); 621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public ScaledLayout(Context context, AttributeSet attrs, int defStyle) { 651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko super(context, attrs, defStyle); 6665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko Point size = new Point(); 6765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko DisplayManager displayManager = (DisplayManager) getContext() 6865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko .getSystemService(Context.DISPLAY_SERVICE); 6965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 7065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko display.getRealSize(size); 7165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mMaxWidth = size.x; 7265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mMaxHeight = size.y; 731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko /** 761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * ScaledLayoutParams stores the four scale factors. 771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * <br> 781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Vertical coordinate system: ({@code scaleStartRow} * 100) % ~ ({@code scaleEndRow} * 100) % 791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Horizontal coordinate system: ({@code scaleStartCol} * 100) % ~ ({@code scaleEndCol} * 100) % 801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * <br> 811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * In XML, for example, 821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * <pre> 831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * {@code 841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * <View 851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * app:layout_scaleStartRow="0.1" 861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * app:layout_scaleEndRow="0.5" 871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * app:layout_scaleStartCol="0.4" 881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * app:layout_scaleEndCol="1" /> 891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * } 901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * </pre> 911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public static class ScaledLayoutParams extends ViewGroup.LayoutParams { 931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public static final float SCALE_UNSPECIFIED = -1; 9465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public final float scaleStartRow; 9565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public final float scaleEndRow; 9665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public final float scaleStartCol; 9765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public final float scaleEndCol; 981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public ScaledLayoutParams(float scaleStartRow, float scaleEndRow, 1001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko float scaleStartCol, float scaleEndCol) { 1011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko super(MATCH_PARENT, MATCH_PARENT); 1021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko this.scaleStartRow = scaleStartRow; 1031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko this.scaleEndRow = scaleEndRow; 1041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko this.scaleStartCol = scaleStartCol; 1051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko this.scaleEndCol = scaleEndCol; 1061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public ScaledLayoutParams(Context context, AttributeSet attrs) { 1091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko super(MATCH_PARENT, MATCH_PARENT); 1101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko TypedArray array = 1111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko context.obtainStyledAttributes(attrs, R.styleable.utScaledLayout); 1121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko scaleStartRow = 1131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko array.getFloat(R.styleable.utScaledLayout_layout_scaleStartRow, SCALE_UNSPECIFIED); 1141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko scaleEndRow = 1151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko array.getFloat(R.styleable.utScaledLayout_layout_scaleEndRow, SCALE_UNSPECIFIED); 1161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko scaleStartCol = 1171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko array.getFloat(R.styleable.utScaledLayout_layout_scaleStartCol, SCALE_UNSPECIFIED); 1181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko scaleEndCol = 1191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko array.getFloat(R.styleable.utScaledLayout_layout_scaleEndCol, SCALE_UNSPECIFIED); 1201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko array.recycle(); 1211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public LayoutParams generateLayoutParams(AttributeSet attrs) { 1261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return new ScaledLayoutParams(getContext(), attrs); 1271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko protected boolean checkLayoutParams(LayoutParams p) { 1311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return (p instanceof ScaledLayoutParams); 1321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 1371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 1381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int width = widthSpecSize - getPaddingLeft() - getPaddingRight(); 1391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int height = heightSpecSize - getPaddingTop() - getPaddingBottom(); 1401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (DEBUG) { 1411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Log.d(TAG, String.format("onMeasure width: %d, height: %d", width, height)); 1421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int count = getChildCount(); 1441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mRectArray = new Rect[count]; 1451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko for (int i = 0; i < count; ++i) { 1461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko View child = getChildAt(i); 1471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko ViewGroup.LayoutParams params = child.getLayoutParams(); 1481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko float scaleStartRow, scaleEndRow, scaleStartCol, scaleEndCol; 1491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!(params instanceof ScaledLayoutParams)) { 1501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throw new RuntimeException( 1511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko "A child of ScaledLayout cannot have the UNSPECIFIED scale factors"); 1521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko scaleStartRow = ((ScaledLayoutParams) params).scaleStartRow; 1541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko scaleEndRow = ((ScaledLayoutParams) params).scaleEndRow; 1551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko scaleStartCol = ((ScaledLayoutParams) params).scaleStartCol; 1561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko scaleEndCol = ((ScaledLayoutParams) params).scaleEndCol; 1571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (scaleStartRow < 0 || scaleStartRow > 1) { 1581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throw new RuntimeException("A child of ScaledLayout should have a range of " 1591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko + "scaleStartRow between 0 and 1"); 1601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (scaleEndRow < scaleStartRow || scaleStartRow > 1) { 1621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throw new RuntimeException("A child of ScaledLayout should have a range of " 1631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko + "scaleEndRow between scaleStartRow and 1"); 1641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (scaleEndCol < 0 || scaleEndCol > 1) { 1661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throw new RuntimeException("A child of ScaledLayout should have a range of " 1671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko + "scaleStartCol between 0 and 1"); 1681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (scaleEndCol < scaleStartCol || scaleEndCol > 1) { 1701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throw new RuntimeException("A child of ScaledLayout should have a range of " 1711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko + "scaleEndCol between scaleStartCol and 1"); 1721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (DEBUG) { 1741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Log.d(TAG, String.format("onMeasure child scaleStartRow: %f scaleEndRow: %f " 1751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko + "scaleStartCol: %f scaleEndCol: %f", 1761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko scaleStartRow, scaleEndRow, scaleStartCol, scaleEndCol)); 1771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mRectArray[i] = new Rect((int) (scaleStartCol * width), (int) (scaleStartRow * height), 1791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko (int) (scaleEndCol * width), (int) (scaleEndRow * height)); 18065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko int scaleWidth = (int) (width * (scaleEndCol - scaleStartCol)); 1811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int childWidthSpec = MeasureSpec.makeMeasureSpec( 18265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko scaleWidth > mMaxWidth ? mMaxWidth : scaleWidth, MeasureSpec.EXACTLY); 1831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 1841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko child.measure(childWidthSpec, childHeightSpec); 1851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // If the height of the measured child view is bigger than the height of the calculated 1871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // region by the given ScaleLayoutParams, the height of the region should be increased 1881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // to fit the size of the child view. 1891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (child.getMeasuredHeight() > mRectArray[i].height()) { 1901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int overflowedHeight = child.getMeasuredHeight() - mRectArray[i].height(); 1911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko overflowedHeight = (overflowedHeight + 1) / 2; 1921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mRectArray[i].bottom += overflowedHeight; 1931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mRectArray[i].top -= overflowedHeight; 1941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mRectArray[i].top < 0) { 1951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mRectArray[i].bottom -= mRectArray[i].top; 1961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mRectArray[i].top = 0; 1971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mRectArray[i].bottom > height) { 1991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mRectArray[i].top -= mRectArray[i].bottom - height; 2001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mRectArray[i].bottom = height; 2011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 20365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko int scaleHeight = (int) (height * (scaleEndRow - scaleStartRow)); 2041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko childHeightSpec = MeasureSpec.makeMeasureSpec( 20565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko scaleHeight > mMaxHeight ? mMaxHeight : scaleHeight, MeasureSpec.EXACTLY); 2061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko child.measure(childWidthSpec, childHeightSpec); 2071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Avoid overlapping rectangles. 2101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Step 1. Sort rectangles by position (top-left). 2111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int visibleRectCount = 0; 2121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int[] visibleRectGroup = new int[count]; 2131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Rect[] visibleRectArray = new Rect[count]; 2141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko for (int i = 0; i < count; ++i) { 2151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (getChildAt(i).getVisibility() == View.VISIBLE) { 2161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectGroup[visibleRectCount] = visibleRectCount; 2171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectArray[visibleRectCount] = mRectArray[i]; 2181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko ++visibleRectCount; 2191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Arrays.sort(visibleRectArray, 0, visibleRectCount, mRectTopLeftSorter); 2221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Step 2. Move down if there are overlapping rectangles. 2241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko for (int i = 0; i < visibleRectCount - 1; ++i) { 2251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko for (int j = i + 1; j < visibleRectCount; ++j) { 2261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (Rect.intersects(visibleRectArray[i], visibleRectArray[j])) { 2271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectGroup[j] = visibleRectGroup[i]; 2281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectArray[j].set(visibleRectArray[j].left, 2291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectArray[i].bottom, 2301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectArray[j].right, 2311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectArray[i].bottom + visibleRectArray[j].height()); 2321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Step 3. Move up if there is any overflowed rectangle. 2371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko for (int i = visibleRectCount - 1; i >= 0; --i) { 2381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (visibleRectArray[i].bottom > height) { 2391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int overflowedHeight = visibleRectArray[i].bottom - height; 2401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko for (int j = 0; j <= i; ++j) { 2411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (visibleRectGroup[i] == visibleRectGroup[j]) { 2421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectArray[j].set(visibleRectArray[j].left, 2431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectArray[j].top - overflowedHeight, 2441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectArray[j].right, 2451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko visibleRectArray[j].bottom - overflowedHeight); 2461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko setMeasuredDimension(widthSpecSize, heightSpecSize); 2511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 2541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko protected void onLayout(boolean changed, int l, int t, int r, int b) { 2551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int paddingLeft = getPaddingLeft(); 2561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int paddingTop = getPaddingTop(); 2571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int count = getChildCount(); 2581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko for (int i = 0; i < count; ++i) { 2591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko View child = getChildAt(i); 2601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (child.getVisibility() != GONE) { 2611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int childLeft = paddingLeft + mRectArray[i].left; 2621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int childTop = paddingTop + mRectArray[i].top; 2631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int childBottom = paddingLeft + mRectArray[i].bottom; 2641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int childRight = paddingTop + mRectArray[i].right; 2651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (DEBUG) { 2661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Log.d(TAG, String.format("layoutChild bottom: %d left: %d right: %d top: %d", 2671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko childBottom, childLeft, 2681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko childRight, childTop)); 2691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko child.layout(childLeft, childTop, childRight, childBottom); 2711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko} 275