1 /*
2  * Copyright (C) 2015 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.widget;
18 
19 import android.content.Context;
20 import android.graphics.drawable.Drawable;
21 import android.util.AttributeSet;
22 import android.view.View;
23 
24 import com.android.internal.widget.ViewPager;
25 
26 import java.util.ArrayList;
27 import java.util.function.Predicate;
28 
29 /**
30  * This displays a list of months in a calendar format with selectable days.
31  */
32 class DayPickerViewPager extends ViewPager {
33     private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
34 
DayPickerViewPager(Context context)35     public DayPickerViewPager(Context context) {
36         this(context, null);
37     }
38 
DayPickerViewPager(Context context, AttributeSet attrs)39     public DayPickerViewPager(Context context, AttributeSet attrs) {
40         this(context, attrs, 0);
41     }
42 
DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr)43     public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
44         this(context, attrs, defStyleAttr, 0);
45     }
46 
DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)47     public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr,
48             int defStyleRes) {
49         super(context, attrs, defStyleAttr, defStyleRes);
50     }
51 
52     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)53     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
54         populate();
55 
56         // Everything below is mostly copied from FrameLayout.
57         int count = getChildCount();
58 
59         final boolean measureMatchParentChildren =
60                 MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
61                         MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
62 
63         int maxHeight = 0;
64         int maxWidth = 0;
65         int childState = 0;
66 
67         for (int i = 0; i < count; i++) {
68             final View child = getChildAt(i);
69             if (child.getVisibility() != GONE) {
70                 measureChild(child, widthMeasureSpec, heightMeasureSpec);
71                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
72                 maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
73                 maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
74                 childState = combineMeasuredStates(childState, child.getMeasuredState());
75                 if (measureMatchParentChildren) {
76                     if (lp.width == LayoutParams.MATCH_PARENT ||
77                             lp.height == LayoutParams.MATCH_PARENT) {
78                         mMatchParentChildren.add(child);
79                     }
80                 }
81             }
82         }
83 
84         // Account for padding too
85         maxWidth += getPaddingLeft() + getPaddingRight();
86         maxHeight += getPaddingTop() + getPaddingBottom();
87 
88         // Check against our minimum height and width
89         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
90         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
91 
92         // Check against our foreground's minimum height and width
93         final Drawable drawable = getForeground();
94         if (drawable != null) {
95             maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
96             maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
97         }
98 
99         setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
100                 resolveSizeAndState(maxHeight, heightMeasureSpec,
101                         childState << MEASURED_HEIGHT_STATE_SHIFT));
102 
103         count = mMatchParentChildren.size();
104         if (count > 1) {
105             for (int i = 0; i < count; i++) {
106                 final View child = mMatchParentChildren.get(i);
107 
108                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
109                 final int childWidthMeasureSpec;
110                 final int childHeightMeasureSpec;
111 
112                 if (lp.width == LayoutParams.MATCH_PARENT) {
113                     childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
114                             getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
115                             MeasureSpec.EXACTLY);
116                 } else {
117                     childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
118                             getPaddingLeft() + getPaddingRight(),
119                             lp.width);
120                 }
121 
122                 if (lp.height == LayoutParams.MATCH_PARENT) {
123                     childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
124                             getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
125                             MeasureSpec.EXACTLY);
126                 } else {
127                     childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
128                             getPaddingTop() + getPaddingBottom(),
129                             lp.height);
130                 }
131 
132                 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
133             }
134         }
135 
136         mMatchParentChildren.clear();
137     }
138 
139     @Override
findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)140     protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
141             View childToSkip) {
142         if (predicate.test(this)) {
143             return (T) this;
144         }
145 
146         // Always try the selected view first.
147         final DayPickerPagerAdapter adapter = (DayPickerPagerAdapter) getAdapter();
148         final SimpleMonthView current = adapter.getView(getCurrent());
149         if (current != childToSkip && current != null) {
150             final View v = current.findViewByPredicate(predicate);
151             if (v != null) {
152                 return (T) v;
153             }
154         }
155 
156         final int len = getChildCount();
157         for (int i = 0; i < len; i++) {
158             final View child = getChildAt(i);
159 
160             if (child != childToSkip && child != current) {
161                 final View v = child.findViewByPredicate(predicate);
162 
163                 if (v != null) {
164                     return (T) v;
165                 }
166             }
167         }
168 
169         return null;
170     }
171 
172 }
173