11f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu/* 21f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * Copyright (C) 2014 The Android Open Source Project 31f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * 41f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 51f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * in compliance with the License. You may obtain a copy of the License at 61f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * 71f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * http://www.apache.org/licenses/LICENSE-2.0 81f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * 91f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * Unless required by applicable law or agreed to in writing, software distributed under the License 101f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 111f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * or implied. See the License for the specific language governing permissions and limitations under 121f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * the License. 131f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu */ 141f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gupackage android.support.v17.leanback.widget; 151f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 161f000f84b9f8db8778b941a6a1bf60f3d349545dDake Guimport android.content.Context; 171f000f84b9f8db8778b941a6a1bf60f3d349545dDake Guimport android.graphics.drawable.Drawable; 181f000f84b9f8db8778b941a6a1bf60f3d349545dDake Guimport android.util.AttributeSet; 191f000f84b9f8db8778b941a6a1bf60f3d349545dDake Guimport android.view.Gravity; 201f000f84b9f8db8778b941a6a1bf60f3d349545dDake Guimport android.view.View; 21a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnataimport android.view.ViewGroup; 221f000f84b9f8db8778b941a6a1bf60f3d349545dDake Guimport android.widget.FrameLayout; 231f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 241f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu/** 251f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * Subclass of FrameLayout that support scale layout area size for children. 261f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * @hide 271f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu */ 281f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gupublic class ScaleFrameLayout extends FrameLayout { 291f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 301f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu private static final int DEFAULT_CHILD_GRAVITY = Gravity.TOP | Gravity.START; 311f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 321f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu private float mLayoutScaleX = 1f; 331f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu private float mLayoutScaleY = 1f; 341f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 35a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata private float mChildScale = 1f; 36a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata 371f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu public ScaleFrameLayout(Context context) { 381f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu this(context ,null); 391f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 401f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 411f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu public ScaleFrameLayout(Context context, AttributeSet attrs) { 421f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu this(context, attrs, 0); 431f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 441f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 451f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu public ScaleFrameLayout(Context context, AttributeSet attrs, 461f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu int defStyle) { 471f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu super(context, attrs, defStyle); 481f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 491f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 501f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu public void setLayoutScaleX(float scaleX) { 511f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu if (scaleX != mLayoutScaleX) { 521f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu mLayoutScaleX = scaleX; 531f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu requestLayout(); 541f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 551f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 561f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 571f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu public void setLayoutScaleY(float scaleY) { 581f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu if (scaleY != mLayoutScaleY) { 591f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu mLayoutScaleY = scaleY; 601f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu requestLayout(); 611f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 621f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 631f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 64a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata public void setChildScale(float scale) { 65a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata if (mChildScale != scale) { 66a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata mChildScale = scale; 67a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata for (int i = 0; i < getChildCount(); i++) { 68a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata getChildAt(i).setScaleX(scale); 69a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata getChildAt(i).setScaleY(scale); 70a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata } 71a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata } 72a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata } 73a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata 74a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata @Override 75a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata public void addView(View child, int index, ViewGroup.LayoutParams params) { 76a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata super.addView(child, index, params); 77a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata child.setScaleX(mChildScale); 78a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata child.setScaleY(mChildScale); 79a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata } 80a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata 811f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu @Override 82be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu protected boolean addViewInLayout (View child, int index, ViewGroup.LayoutParams params, 83be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu boolean preventRequestLayout) { 84be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu boolean ret = super.addViewInLayout(child, index, params, preventRequestLayout); 85be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu if (ret) { 86be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu child.setScaleX(mChildScale); 87be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu child.setScaleY(mChildScale); 88be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu } 89be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu return ret; 90be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu } 91be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu 92be5bcc2e3b3bbe468c1425b2919e1fa072af1854Dake Gu @Override 931f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 941f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final int count = getChildCount(); 951f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 961f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final int parentLeft, parentRight; 978e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing final int layoutDirection = getLayoutDirection(); 988e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing final float pivotX = (layoutDirection == View.LAYOUT_DIRECTION_RTL) ? 998e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing getWidth() - getPivotX() : 1008e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing getPivotX(); 1011f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu if (mLayoutScaleX != 1f) { 1021f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu parentLeft = getPaddingLeft() + (int)(pivotX - pivotX / mLayoutScaleX + 0.5f); 1031f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu parentRight = (int)(pivotX + (right - left - pivotX) / mLayoutScaleX + 0.5f) 1041f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu - getPaddingRight(); 1051f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } else { 1061f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu parentLeft = getPaddingLeft(); 1071f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu parentRight = right - left - getPaddingRight(); 1081f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1091f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1101f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final int parentTop, parentBottom; 1113595aa0cbdaa8e754365ca94a0b9eb8fc52b9796Dake Gu final float pivotY = getPivotY(); 1121f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu if (mLayoutScaleY != 1f) { 1131f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu parentTop = getPaddingTop() + (int)(pivotY - pivotY / mLayoutScaleY + 0.5f); 1141f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu parentBottom = (int)(pivotY + (bottom - top - pivotY) / mLayoutScaleY + 0.5f) 1151f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu - getPaddingBottom(); 1161f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } else { 1171f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu parentTop = getPaddingTop(); 1181f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu parentBottom = bottom - top - getPaddingBottom(); 1191f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1201f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1211f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu for (int i = 0; i < count; i++) { 1221f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final View child = getChildAt(i); 1231f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu if (child.getVisibility() != GONE) { 1241f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1251f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1261f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final int width = child.getMeasuredWidth(); 1271f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final int height = child.getMeasuredHeight(); 1281f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1291f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu int childLeft; 1301f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu int childTop; 1311f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1321f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu int gravity = lp.gravity; 1331f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu if (gravity == -1) { 1341f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu gravity = DEFAULT_CHILD_GRAVITY; 1351f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1361f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1371f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); 1381f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; 1391f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1401f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { 1411f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu case Gravity.CENTER_HORIZONTAL: 1421f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu childLeft = parentLeft + (parentRight - parentLeft - width) / 2 + 1431f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu lp.leftMargin - lp.rightMargin; 1441f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu break; 1451f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu case Gravity.RIGHT: 1461f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu childLeft = parentRight - width - lp.rightMargin; 1471f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu break; 1481f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu case Gravity.LEFT: 1491f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu default: 1501f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu childLeft = parentLeft + lp.leftMargin; 1511f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1521f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1531f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu switch (verticalGravity) { 1541f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu case Gravity.TOP: 1551f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu childTop = parentTop + lp.topMargin; 1561f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu break; 1571f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu case Gravity.CENTER_VERTICAL: 1581f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu childTop = parentTop + (parentBottom - parentTop - height) / 2 + 1591f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu lp.topMargin - lp.bottomMargin; 1601f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu break; 1611f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu case Gravity.BOTTOM: 1621f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu childTop = parentBottom - height - lp.bottomMargin; 1631f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu break; 1641f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu default: 1651f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu childTop = parentTop + lp.topMargin; 1661f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1671f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1681f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu child.layout(childLeft, childTop, childLeft + width, childTop + height); 1693595aa0cbdaa8e754365ca94a0b9eb8fc52b9796Dake Gu // synchronize child pivot to be same as ScaleFrameLayout's pivot 1703595aa0cbdaa8e754365ca94a0b9eb8fc52b9796Dake Gu child.setPivotX(pivotX - childLeft); 1713595aa0cbdaa8e754365ca94a0b9eb8fc52b9796Dake Gu child.setPivotY(pivotY - childTop); 1721f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1731f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1741f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1751f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1761f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu private static int getScaledMeasureSpec(int measureSpec, float scale) { 1771f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu return scale == 1f ? measureSpec : MeasureSpec.makeMeasureSpec( 1781f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu (int) (MeasureSpec.getSize(measureSpec) / scale + 0.5f), 1791f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu MeasureSpec.getMode(measureSpec)); 1801f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1811f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1821f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu @Override 1831f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1841f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu if (mLayoutScaleX != 1f || mLayoutScaleY != 1f) { 1851f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final int scaledWidthMeasureSpec = 1861f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu getScaledMeasureSpec(widthMeasureSpec, mLayoutScaleX); 1871f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu final int scaledHeightMeasureSpec = 1881f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu getScaledMeasureSpec(heightMeasureSpec, mLayoutScaleY); 1891f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu super.onMeasure(scaledWidthMeasureSpec, scaledHeightMeasureSpec); 1901f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu setMeasuredDimension((int)(getMeasuredWidth() * mLayoutScaleX + 0.5f), 1911f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu (int)(getMeasuredHeight() * mLayoutScaleY + 0.5f)); 1921f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } else { 1931f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu super.onMeasure(widthMeasureSpec, heightMeasureSpec); 1941f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1951f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 1961f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu 1971f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu /** 1981f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu * setForeground() is not supported, throws UnsupportedOperationException() when called. 1991f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu */ 2001f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu @Override 2011f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu public void setForeground(Drawable d) { 2021f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu throw new UnsupportedOperationException(); 2031f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu } 204a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata 2051f000f84b9f8db8778b941a6a1bf60f3d349545dDake Gu} 206