1 /* 2 * Copyright (C) 2014 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 17 package android.support.v7.internal.widget; 18 19 import android.content.Context; 20 import android.graphics.Rect; 21 import android.support.v4.view.ViewCompat; 22 import android.util.AttributeSet; 23 import android.util.DisplayMetrics; 24 import android.util.TypedValue; 25 import android.widget.FrameLayout; 26 27 import static android.view.View.MeasureSpec.AT_MOST; 28 import static android.view.View.MeasureSpec.EXACTLY; 29 import static android.view.View.MeasureSpec.getMode; 30 31 /** 32 * @hide 33 */ 34 public class ContentFrameLayout extends FrameLayout { 35 36 private TypedValue mMinWidthMajor; 37 private TypedValue mMinWidthMinor; 38 private TypedValue mFixedWidthMajor; 39 private TypedValue mFixedWidthMinor; 40 private TypedValue mFixedHeightMajor; 41 private TypedValue mFixedHeightMinor; 42 43 private final Rect mDecorPadding; 44 ContentFrameLayout(Context context)45 public ContentFrameLayout(Context context) { 46 this(context, null); 47 } 48 ContentFrameLayout(Context context, AttributeSet attrs)49 public ContentFrameLayout(Context context, AttributeSet attrs) { 50 this(context, attrs, 0); 51 } 52 ContentFrameLayout(Context context, AttributeSet attrs, int defStyleAttr)53 public ContentFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { 54 super(context, attrs, defStyleAttr); 55 mDecorPadding = new Rect(); 56 } 57 58 /** 59 * @hide 60 */ dispatchFitSystemWindows(Rect insets)61 public void dispatchFitSystemWindows(Rect insets) { 62 fitSystemWindows(insets); 63 } 64 65 /** 66 * Notify this view of the window decor view's padding. We use these values when working out 67 * our size for the window size attributes. 68 * 69 * @hide 70 */ setDecorPadding(int left, int top, int right, int bottom)71 public void setDecorPadding(int left, int top, int right, int bottom) { 72 mDecorPadding.set(left, top, right, bottom); 73 if (ViewCompat.isLaidOut(this)) { 74 requestLayout(); 75 } 76 } 77 78 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)79 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 80 final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); 81 final boolean isPortrait = metrics.widthPixels < metrics.heightPixels; 82 83 final int widthMode = getMode(widthMeasureSpec); 84 final int heightMode = getMode(heightMeasureSpec); 85 86 boolean fixedWidth = false; 87 if (widthMode == AT_MOST) { 88 final TypedValue tvw = isPortrait ? mFixedWidthMinor : mFixedWidthMajor; 89 if (tvw != null && tvw.type != TypedValue.TYPE_NULL) { 90 int w = 0; 91 if (tvw.type == TypedValue.TYPE_DIMENSION) { 92 w = (int) tvw.getDimension(metrics); 93 } else if (tvw.type == TypedValue.TYPE_FRACTION) { 94 w = (int) tvw.getFraction(metrics.widthPixels, metrics.widthPixels); 95 } 96 if (w > 0) { 97 w -= (mDecorPadding.left + mDecorPadding.right); 98 final int widthSize = MeasureSpec.getSize(widthMeasureSpec); 99 widthMeasureSpec = MeasureSpec.makeMeasureSpec( 100 Math.min(w, widthSize), EXACTLY); 101 fixedWidth = true; 102 } 103 } 104 } 105 106 if (heightMode == AT_MOST) { 107 final TypedValue tvh = isPortrait ? mFixedHeightMajor : mFixedHeightMinor; 108 if (tvh != null && tvh.type != TypedValue.TYPE_NULL) { 109 int h = 0; 110 if (tvh.type == TypedValue.TYPE_DIMENSION) { 111 h = (int) tvh.getDimension(metrics); 112 } else if (tvh.type == TypedValue.TYPE_FRACTION) { 113 h = (int) tvh.getFraction(metrics.heightPixels, metrics.heightPixels); 114 } 115 if (h > 0) { 116 h -= (mDecorPadding.top + mDecorPadding.bottom); 117 final int heightSize = MeasureSpec.getSize(heightMeasureSpec); 118 heightMeasureSpec = MeasureSpec.makeMeasureSpec( 119 Math.min(h, heightSize), EXACTLY); 120 } 121 } 122 } 123 124 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 125 126 int width = getMeasuredWidth(); 127 boolean measure = false; 128 129 widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY); 130 131 if (!fixedWidth && widthMode == AT_MOST) { 132 final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor; 133 if (tv != null && tv.type != TypedValue.TYPE_NULL) { 134 int min = 0; 135 if (tv.type == TypedValue.TYPE_DIMENSION) { 136 min = (int) tv.getDimension(metrics); 137 } else if (tv.type == TypedValue.TYPE_FRACTION) { 138 min = (int) tv.getFraction(metrics.widthPixels, metrics.widthPixels); 139 } 140 if (min > 0) { 141 min -= (mDecorPadding.left + mDecorPadding.right); 142 } 143 if (width < min) { 144 widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY); 145 measure = true; 146 } 147 } 148 } 149 150 if (measure) { 151 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 152 } 153 } 154 getMinWidthMajor()155 public TypedValue getMinWidthMajor() { 156 if (mMinWidthMajor == null) mMinWidthMajor = new TypedValue(); 157 return mMinWidthMajor; 158 } 159 getMinWidthMinor()160 public TypedValue getMinWidthMinor() { 161 if (mMinWidthMinor == null) mMinWidthMinor = new TypedValue(); 162 return mMinWidthMinor; 163 } 164 getFixedWidthMajor()165 public TypedValue getFixedWidthMajor() { 166 if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue(); 167 return mFixedWidthMajor; 168 } 169 getFixedWidthMinor()170 public TypedValue getFixedWidthMinor() { 171 if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue(); 172 return mFixedWidthMinor; 173 } 174 getFixedHeightMajor()175 public TypedValue getFixedHeightMajor() { 176 if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue(); 177 return mFixedHeightMajor; 178 } 179 getFixedHeightMinor()180 public TypedValue getFixedHeightMinor() { 181 if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue(); 182 return mFixedHeightMinor; 183 } 184 } 185