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