178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette/* 278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * Copyright (C) 2015 The Android Open Source Project 378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * 478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License"); 578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * you may not use this file except in compliance with the License. 678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * You may obtain a copy of the License at 778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * 878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * http://www.apache.org/licenses/LICENSE-2.0 978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * 1078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * Unless required by applicable law or agreed to in writing, software 1178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS, 1278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * See the License for the specific language governing permissions and 1478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * limitations under the License. 1578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette */ 1678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 1778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverettepackage android.widget; 1878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 19e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mountimport android.annotation.Nullable; 2078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport android.content.Context; 21e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mountimport android.graphics.Rect; 2278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport android.graphics.drawable.Drawable; 2378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport android.util.AttributeSet; 2478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport android.view.View; 25e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mountimport android.view.ViewGroup; 26e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mountimport android.view.ViewGroup.LayoutParams; 27e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount 28e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mountimport com.android.internal.util.Predicate; 29e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mountimport com.android.internal.widget.PagerAdapter; 30e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mountimport com.android.internal.widget.ViewPager; 3178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 3278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport java.util.ArrayList; 3378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 3478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette/** 3578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * This displays a list of months in a calendar format with selectable days. 3678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette */ 3778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteclass DayPickerViewPager extends ViewPager { 3878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1); 3978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 4078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette public DayPickerViewPager(Context context) { 4178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette this(context, null); 4278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 4378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 4478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette public DayPickerViewPager(Context context, AttributeSet attrs) { 4578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette this(context, attrs, 0); 4678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 4778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 4878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr) { 4978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette this(context, attrs, defStyleAttr, 0); 5078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 5178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 5278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr, 5378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette int defStyleRes) { 5478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette super(context, attrs, defStyleAttr, defStyleRes); 5578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 5678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 5778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette @Override 5878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 5978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette populate(); 6078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 6178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette // Everything below is mostly copied from FrameLayout. 6278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette int count = getChildCount(); 6378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 6478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final boolean measureMatchParentChildren = 6578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY || 6678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY; 6778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 6878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette int maxHeight = 0; 6978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette int maxWidth = 0; 7078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette int childState = 0; 7178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 7278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette for (int i = 0; i < count; i++) { 7378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final View child = getChildAt(i); 7478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette if (child.getVisibility() != GONE) { 7578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette measureChild(child, widthMeasureSpec, heightMeasureSpec); 7678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 7778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette maxWidth = Math.max(maxWidth, child.getMeasuredWidth()); 7878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette maxHeight = Math.max(maxHeight, child.getMeasuredHeight()); 7978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette childState = combineMeasuredStates(childState, child.getMeasuredState()); 8078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette if (measureMatchParentChildren) { 8178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette if (lp.width == LayoutParams.MATCH_PARENT || 8278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette lp.height == LayoutParams.MATCH_PARENT) { 8378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette mMatchParentChildren.add(child); 8478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 8578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 8678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 8778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 8878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 8978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette // Account for padding too 9078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette maxWidth += getPaddingLeft() + getPaddingRight(); 9178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette maxHeight += getPaddingTop() + getPaddingBottom(); 9278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 9378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette // Check against our minimum height and width 9478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); 9578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); 9678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 9778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette // Check against our foreground's minimum height and width 9878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final Drawable drawable = getForeground(); 9978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette if (drawable != null) { 10078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); 10178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); 10278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 10378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 10478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), 10578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette resolveSizeAndState(maxHeight, heightMeasureSpec, 10678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette childState << MEASURED_HEIGHT_STATE_SHIFT)); 10778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 10878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette count = mMatchParentChildren.size(); 10978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette if (count > 1) { 11078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette for (int i = 0; i < count; i++) { 11178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final View child = mMatchParentChildren.get(i); 11278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 11378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 11478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final int childWidthMeasureSpec; 11578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final int childHeightMeasureSpec; 11678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 11778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette if (lp.width == LayoutParams.MATCH_PARENT) { 11878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( 11978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), 12078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette MeasureSpec.EXACTLY); 12178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } else { 12278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 12378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette getPaddingLeft() + getPaddingRight(), 12478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette lp.width); 12578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 12678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 12778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette if (lp.height == LayoutParams.MATCH_PARENT) { 12878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( 12978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), 13078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette MeasureSpec.EXACTLY); 13178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } else { 13278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 13378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette getPaddingTop() + getPaddingBottom(), 13478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette lp.height); 13578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 13678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 13778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 13878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 13978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 14078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 14178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette mMatchParentChildren.clear(); 14278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 143e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount 144e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount @Override 145e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 146e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount if (predicate.apply(this)) { 147e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount return this; 148e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount } 149e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount 150e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount // Always try the selected view first. 151e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount final DayPickerPagerAdapter adapter = (DayPickerPagerAdapter) getAdapter(); 152e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount final SimpleMonthView current = adapter.getView(getCurrent()); 153e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount if (current != childToSkip && current != null) { 154e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount final View v = current.findViewByPredicate(predicate); 155e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount if (v != null) { 156e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount return v; 157e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount } 158e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount } 159e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount 160e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount final int len = getChildCount(); 161e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount for (int i = 0; i < len; i++) { 162e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount final View child = getChildAt(i); 163e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount 164e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount if (child != childToSkip && child != current) { 165e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount final View v = child.findViewByPredicate(predicate); 166e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount 167e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount if (v != null) { 168e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount return v; 169e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount } 170e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount } 171e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount } 172e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount 173e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount return null; 174e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount } 175e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount 17678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette} 177