• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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 com.android.widget;
18 
19 import android.graphics.drawable.Drawable;
20 import android.media.update.ViewGroupProvider;
21 import android.util.AttributeSet;
22 import android.view.View;
23 import android.view.ViewGroup;
24 import android.view.ViewGroup.LayoutParams;
25 import android.view.ViewGroup.MarginLayoutParams;
26 
27 import java.util.ArrayList;
28 
29 public class BaseLayout extends ViewGroupImpl {
30     private final ViewGroup mInstance;
31     private final ViewGroupProvider mSuperProvider;
32     private final ViewGroupProvider mPrivateProvider;
33 
34     private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
35 
BaseLayout(ViewGroup instance, ViewGroupProvider superProvider, ViewGroupProvider privateProvider)36     public BaseLayout(ViewGroup instance,
37             ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
38         super(instance, superProvider, privateProvider);
39         mInstance = instance;
40         mSuperProvider = superProvider;
41         mPrivateProvider = privateProvider;
42     }
43 
44     @Override
checkLayoutParams_impl(LayoutParams p)45     public boolean checkLayoutParams_impl(LayoutParams p) {
46         return p instanceof MarginLayoutParams;
47     }
48 
49     @Override
generateDefaultLayoutParams_impl()50     public LayoutParams generateDefaultLayoutParams_impl() {
51         return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
52     }
53 
54     @Override
generateLayoutParams_impl(AttributeSet attrs)55     public LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
56         return new MarginLayoutParams(mInstance.getContext(), attrs);
57     }
58 
59     @Override
generateLayoutParams_impl(LayoutParams lp)60     public LayoutParams generateLayoutParams_impl(LayoutParams lp) {
61         if (lp instanceof MarginLayoutParams) {
62             return lp;
63         }
64         return new MarginLayoutParams(lp);
65     }
66 
67     @Override
onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec)68     public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
69         int count = mInstance.getChildCount();
70 
71         final boolean measureMatchParentChildren =
72                 View.MeasureSpec.getMode(widthMeasureSpec) != View.MeasureSpec.EXACTLY ||
73                         View.MeasureSpec.getMode(heightMeasureSpec) != View.MeasureSpec.EXACTLY;
74         mMatchParentChildren.clear();
75 
76         int maxHeight = 0;
77         int maxWidth = 0;
78         int childState = 0;
79 
80         for (int i = 0; i < count; i++) {
81             final View child = mInstance.getChildAt(i);
82             if (child.getVisibility() != View.GONE) {
83                 mPrivateProvider.measureChildWithMargins_impl(
84                         child, widthMeasureSpec, 0, heightMeasureSpec, 0);
85                 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
86                 maxWidth = Math.max(maxWidth,
87                         child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
88                 maxHeight = Math.max(maxHeight,
89                         child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
90                 childState = childState | child.getMeasuredState();
91                 if (measureMatchParentChildren) {
92                     if (lp.width == LayoutParams.MATCH_PARENT ||
93                             lp.height == LayoutParams.MATCH_PARENT) {
94                         mMatchParentChildren.add(child);
95                     }
96                 }
97             }
98         }
99 
100         // Account for padding too
101         maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
102         maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
103 
104         // Check against our minimum height and width
105         maxHeight = Math.max(maxHeight, mPrivateProvider.getSuggestedMinimumHeight_impl());
106         maxWidth = Math.max(maxWidth, mPrivateProvider.getSuggestedMinimumWidth_impl());
107 
108         // Check against our foreground's minimum height and width
109         final Drawable drawable = mInstance.getForeground();
110         if (drawable != null) {
111             maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
112             maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
113         }
114 
115         mPrivateProvider.setMeasuredDimension_impl(
116                 mInstance.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
117                 mInstance.resolveSizeAndState(maxHeight, heightMeasureSpec,
118                         childState << View.MEASURED_HEIGHT_STATE_SHIFT));
119 
120         count = mMatchParentChildren.size();
121         if (count > 1) {
122             for (int i = 0; i < count; i++) {
123                 final View child = mMatchParentChildren.get(i);
124                 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
125 
126                 final int childWidthMeasureSpec;
127                 if (lp.width == LayoutParams.MATCH_PARENT) {
128                     final int width = Math.max(0, mInstance.getMeasuredWidth()
129                             - getPaddingLeftWithForeground() - getPaddingRightWithForeground()
130                             - lp.leftMargin - lp.rightMargin);
131                     childWidthMeasureSpec = View.MeasureSpec.makeMeasureSpec(
132                             width, View.MeasureSpec.EXACTLY);
133                 } else {
134                     childWidthMeasureSpec = mInstance.getChildMeasureSpec(widthMeasureSpec,
135                             getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
136                                     lp.leftMargin + lp.rightMargin,
137                             lp.width);
138                 }
139 
140                 final int childHeightMeasureSpec;
141                 if (lp.height == LayoutParams.MATCH_PARENT) {
142                     final int height = Math.max(0, mInstance.getMeasuredHeight()
143                             - getPaddingTopWithForeground() - getPaddingBottomWithForeground()
144                             - lp.topMargin - lp.bottomMargin);
145                     childHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
146                             height, View.MeasureSpec.EXACTLY);
147                 } else {
148                     childHeightMeasureSpec = mInstance.getChildMeasureSpec(heightMeasureSpec,
149                             getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
150                                     lp.topMargin + lp.bottomMargin,
151                             lp.height);
152                 }
153 
154                 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
155             }
156         }
157     }
158 
159     @Override
onLayout_impl(boolean changed, int left, int top, int right, int bottom)160     public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
161         final int count = mInstance.getChildCount();
162 
163         final int parentLeft = getPaddingLeftWithForeground();
164         final int parentRight = right - left - getPaddingRightWithForeground();
165 
166         final int parentTop = getPaddingTopWithForeground();
167         final int parentBottom = bottom - top - getPaddingBottomWithForeground();
168 
169         for (int i = 0; i < count; i++) {
170             final View child = mInstance.getChildAt(i);
171             if (child.getVisibility() != View.GONE) {
172                 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
173 
174                 final int width = child.getMeasuredWidth();
175                 final int height = child.getMeasuredHeight();
176 
177                 int childLeft;
178                 int childTop;
179 
180                 childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
181                         lp.leftMargin - lp.rightMargin;
182 
183                 childTop = parentTop + (parentBottom - parentTop - height) / 2 +
184                         lp.topMargin - lp.bottomMargin;
185 
186                 child.layout(childLeft, childTop, childLeft + width, childTop + height);
187             }
188         }
189     }
190 
191     @Override
shouldDelayChildPressedState_impl()192     public boolean shouldDelayChildPressedState_impl() {
193         return false;
194     }
195 
getPaddingLeftWithForeground()196     private int getPaddingLeftWithForeground() {
197         return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingLeft(), 0) :
198                 mInstance.getPaddingLeft() + 0;
199     }
200 
getPaddingRightWithForeground()201     private int getPaddingRightWithForeground() {
202         return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingRight(), 0) :
203                 mInstance.getPaddingRight() + 0;
204     }
205 
getPaddingTopWithForeground()206     private int getPaddingTopWithForeground() {
207         return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingTop(), 0) :
208                 mInstance.getPaddingTop() + 0;
209     }
210 
getPaddingBottomWithForeground()211     private int getPaddingBottomWithForeground() {
212         return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingBottom(), 0) :
213                 mInstance.getPaddingBottom() + 0;
214     }
215 }
216