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 17package android.widget; 18 19import android.content.Context; 20import android.graphics.drawable.Drawable; 21import android.util.AttributeSet; 22import android.view.View; 23 24import com.android.internal.widget.ViewPager; 25 26import java.util.ArrayList; 27import java.util.function.Predicate; 28 29/** 30 * This displays a list of months in a calendar format with selectable days. 31 */ 32class DayPickerViewPager extends ViewPager { 33 private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1); 34 35 public DayPickerViewPager(Context context) { 36 this(context, null); 37 } 38 39 public DayPickerViewPager(Context context, AttributeSet attrs) { 40 this(context, attrs, 0); 41 } 42 43 public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr) { 44 this(context, attrs, defStyleAttr, 0); 45 } 46 47 public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr, 48 int defStyleRes) { 49 super(context, attrs, defStyleAttr, defStyleRes); 50 } 51 52 @Override 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 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