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