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