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