149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes/* 249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Copyright (C) 2014 The Android Open Source Project 349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * you may not use this file except in compliance with the License. 649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * You may obtain a copy of the License at 749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * http://www.apache.org/licenses/LICENSE-2.0 949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 1049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Unless required by applicable law or agreed to in writing, software 1149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * distributed under the License is distributed on an "AS IS" BASIS, 1249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * See the License for the specific language governing permissions and 1449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * limitations under the License. 1549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 1649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 1766698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banespackage android.support.v7.widget; 1849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 1949c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.content.Context; 2049c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.graphics.Rect; 21c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo; 22d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banesimport android.support.v4.view.ViewCompat; 2349c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.util.AttributeSet; 2419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banesimport android.util.DisplayMetrics; 2519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banesimport android.util.TypedValue; 2649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.FrameLayout; 2749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 28c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport static android.support.annotation.RestrictTo.Scope.GROUP_ID; 29d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banesimport static android.view.View.MeasureSpec.AT_MOST; 30d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banesimport static android.view.View.MeasureSpec.EXACTLY; 31d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banesimport static android.view.View.MeasureSpec.getMode; 3219eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 3349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes/** 3449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @hide 3549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 3649c78900da0d43140fb602431fb93212bd7f6c70Chris Banespublic class ContentFrameLayout extends FrameLayout { 3749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 38b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes public interface OnAttachListener { 39b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes void onDetachedFromWindow(); 40b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes void onAttachedFromWindow(); 41b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes } 42b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes 4319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes private TypedValue mMinWidthMajor; 4419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes private TypedValue mMinWidthMinor; 4519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes private TypedValue mFixedWidthMajor; 4619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes private TypedValue mFixedWidthMinor; 4719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes private TypedValue mFixedHeightMajor; 4819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes private TypedValue mFixedHeightMinor; 4919eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 50d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes private final Rect mDecorPadding; 51d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes 52b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes private OnAttachListener mAttachListener; 53b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes 5449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public ContentFrameLayout(Context context) { 5549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes this(context, null); 5649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 5749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 5849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public ContentFrameLayout(Context context, AttributeSet attrs) { 5949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes this(context, attrs, 0); 6049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 6149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 6249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public ContentFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { 6349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super(context, attrs, defStyleAttr); 64d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes mDecorPadding = new Rect(); 6549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 6649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 6749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 6849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @hide 6949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 70c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette @RestrictTo(GROUP_ID) 7149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void dispatchFitSystemWindows(Rect insets) { 7249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes fitSystemWindows(insets); 7349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 7449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 75b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes public void setAttachListener(OnAttachListener attachListener) { 76b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes mAttachListener = attachListener; 77b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes } 78b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes 79d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes /** 80d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes * Notify this view of the window decor view's padding. We use these values when working out 81d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes * our size for the window size attributes. 82d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes * 83d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes * @hide 84d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes */ 85c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette @RestrictTo(GROUP_ID) 86d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes public void setDecorPadding(int left, int top, int right, int bottom) { 87d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes mDecorPadding.set(left, top, right, bottom); 88d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes if (ViewCompat.isLaidOut(this)) { 89d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes requestLayout(); 90d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes } 91d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes } 92d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes 9319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes @Override 9419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 9519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); 9619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes final boolean isPortrait = metrics.widthPixels < metrics.heightPixels; 9719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 9819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes final int widthMode = getMode(widthMeasureSpec); 9919eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes final int heightMode = getMode(heightMeasureSpec); 10019eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 10119eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes boolean fixedWidth = false; 10219eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (widthMode == AT_MOST) { 10319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes final TypedValue tvw = isPortrait ? mFixedWidthMinor : mFixedWidthMajor; 10419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (tvw != null && tvw.type != TypedValue.TYPE_NULL) { 105d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes int w = 0; 10619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (tvw.type == TypedValue.TYPE_DIMENSION) { 10719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes w = (int) tvw.getDimension(metrics); 10819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } else if (tvw.type == TypedValue.TYPE_FRACTION) { 10919eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes w = (int) tvw.getFraction(metrics.widthPixels, metrics.widthPixels); 11019eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 11119eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (w > 0) { 112d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes w -= (mDecorPadding.left + mDecorPadding.right); 11319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes final int widthSize = MeasureSpec.getSize(widthMeasureSpec); 11419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes widthMeasureSpec = MeasureSpec.makeMeasureSpec( 11519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes Math.min(w, widthSize), EXACTLY); 11619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes fixedWidth = true; 11719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 11819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 11919eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 12019eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 12119eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (heightMode == AT_MOST) { 12219eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes final TypedValue tvh = isPortrait ? mFixedHeightMajor : mFixedHeightMinor; 12319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (tvh != null && tvh.type != TypedValue.TYPE_NULL) { 124d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes int h = 0; 12519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (tvh.type == TypedValue.TYPE_DIMENSION) { 12619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes h = (int) tvh.getDimension(metrics); 12719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } else if (tvh.type == TypedValue.TYPE_FRACTION) { 12819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes h = (int) tvh.getFraction(metrics.heightPixels, metrics.heightPixels); 12919eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 13019eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (h > 0) { 131d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes h -= (mDecorPadding.top + mDecorPadding.bottom); 13219eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes final int heightSize = MeasureSpec.getSize(heightMeasureSpec); 13319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes heightMeasureSpec = MeasureSpec.makeMeasureSpec( 13419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes Math.min(h, heightSize), EXACTLY); 13519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 13619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 13719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 13819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 13919eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 14019eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 14119eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes int width = getMeasuredWidth(); 14219eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes boolean measure = false; 14319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 14419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY); 14519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 14619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (!fixedWidth && widthMode == AT_MOST) { 14719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor; 14819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (tv != null && tv.type != TypedValue.TYPE_NULL) { 149d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes int min = 0; 15019eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (tv.type == TypedValue.TYPE_DIMENSION) { 151d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes min = (int) tv.getDimension(metrics); 15219eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } else if (tv.type == TypedValue.TYPE_FRACTION) { 153d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes min = (int) tv.getFraction(metrics.widthPixels, metrics.widthPixels); 154d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes } 155d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes if (min > 0) { 156d8b7157eae680353a2821dca3c9e52b3aaf737a5Chris Banes min -= (mDecorPadding.left + mDecorPadding.right); 15719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 15819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (width < min) { 15919eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY); 16019eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes measure = true; 16119eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 16219eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 16319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 16419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 16519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (measure) { 16619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 16719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 16819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 16919eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 17019eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes public TypedValue getMinWidthMajor() { 17119eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (mMinWidthMajor == null) mMinWidthMajor = new TypedValue(); 17219eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes return mMinWidthMajor; 17319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 17419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 17519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes public TypedValue getMinWidthMinor() { 17619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (mMinWidthMinor == null) mMinWidthMinor = new TypedValue(); 17719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes return mMinWidthMinor; 17819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 17919eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 18019eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes public TypedValue getFixedWidthMajor() { 18119eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue(); 18219eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes return mFixedWidthMajor; 18319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 18419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 18519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes public TypedValue getFixedWidthMinor() { 18619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue(); 18719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes return mFixedWidthMinor; 18819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 18919eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 19019eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes public TypedValue getFixedHeightMajor() { 19119eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue(); 19219eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes return mFixedHeightMajor; 19319eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 19419eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes 19519eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes public TypedValue getFixedHeightMinor() { 19619eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue(); 19719eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes return mFixedHeightMinor; 19819eaf14cb3cca613f984a32be2fab2534427fb29Chris Banes } 199b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes 200b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes @Override 201b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes protected void onAttachedToWindow() { 202b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes super.onAttachedToWindow(); 203b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes if (mAttachListener != null) { 204b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes mAttachListener.onAttachedFromWindow(); 205b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes } 206b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes } 207b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes 208b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes @Override 209b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes protected void onDetachedFromWindow() { 210b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes super.onDetachedFromWindow(); 211b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes if (mAttachListener != null) { 212b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes mAttachListener.onDetachedFromWindow(); 213b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes } 214b034e4ad40bff78a848d9ed91754e3f9f3492f11Chris Banes } 21549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes} 216