1bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/* 2bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Copyright (C) 2014 The Android Open Source Project 3bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 4bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Licensed under the Apache License, Version 2.0 (the "License"); 5bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * you may not use this file except in compliance with the License. 6bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You may obtain a copy of the License at 7bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 8bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * http://www.apache.org/licenses/LICENSE-2.0 9bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 10bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Unless required by applicable law or agreed to in writing, software 11bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * distributed under the License is distributed on an "AS IS" BASIS, 12bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * See the License for the specific language governing permissions and 14bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * limitations under the License. 15bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 16bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 17bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Megliopackage android.widget; 18bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 19bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.Context; 20bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.Resources; 21bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.util.AttributeSet; 22bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.View; 23bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.ViewGroup; 24bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityEvent; 25bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 26bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Calendar; 27bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 28bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport com.android.internal.R; 29bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 30bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/** 31bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Displays a selectable list of years. 32bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 33bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioclass YearPickerView extends ListView implements AdapterView.OnItemClickListener, 34bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio OnDateChangedListener { 3550eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette private final Calendar mMinDate = Calendar.getInstance(); 3650eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette private final Calendar mMaxDate = Calendar.getInstance(); 3750eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette 3850eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette private final YearAdapter mAdapter; 3950eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette private final int mViewSize; 4050eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette private final int mChildSize; 4150eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette 42bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private DatePickerController mController; 4350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette 44bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mSelectedPosition = -1; 45bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mYearSelectedCircleColor; 46bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 47bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public YearPickerView(Context context) { 48bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio this(context, null); 49bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 50bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 51bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public YearPickerView(Context context, AttributeSet attrs) { 52518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette this(context, attrs, R.attr.listViewStyle); 53bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 54bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 55bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr) { 56bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio this(context, attrs, defStyleAttr, 0); 57bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 58bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 59bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 60bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super(context, attrs, defStyleAttr, defStyleRes); 61bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 6260727e07c6ef72e2f494266939c02494a3df28f8Alan Viverette final LayoutParams frame = new LayoutParams( 6360727e07c6ef72e2f494266939c02494a3df28f8Alan Viverette LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 64bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setLayoutParams(frame); 65bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 6660727e07c6ef72e2f494266939c02494a3df28f8Alan Viverette final Resources res = context.getResources(); 67bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mViewSize = res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height); 68bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mChildSize = res.getDimensionPixelOffset(R.dimen.datepicker_year_label_height); 69bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 70bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setVerticalFadingEdgeEnabled(true); 71bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setFadingEdgeLength(mChildSize / 3); 72bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 73bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int paddingTop = res.getDimensionPixelSize( 74bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio R.dimen.datepicker_year_picker_padding_top); 75bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setPadding(0, paddingTop, 0, 0); 76bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 77bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setOnItemClickListener(this); 78bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setDividerHeight(0); 7950eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette 8050eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette mAdapter = new YearAdapter(getContext(), R.layout.year_label_text_view); 8150eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette setAdapter(mAdapter); 8250eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette } 8350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette 8450eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette public void setRange(Calendar min, Calendar max) { 8550eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette mMinDate.setTimeInMillis(min.getTimeInMillis()); 8650eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette mMaxDate.setTimeInMillis(max.getTimeInMillis()); 8750eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette 8850eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette updateAdapterData(); 89bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 90bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 91bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void init(DatePickerController controller) { 92bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mController = controller; 93bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mController.registerOnDateChangedListener(this); 94bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 95bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio updateAdapterData(); 96bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 97bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onDateChanged(); 98bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 99bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 100bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void setYearSelectedCircleColor(int color) { 101bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (color != mYearSelectedCircleColor) { 102bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mYearSelectedCircleColor = color; 103bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 104bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio requestLayout(); 105bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 106bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 107bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public int getYearSelectedCircleColor() { 108bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return mYearSelectedCircleColor; 109bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 110bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 111bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void updateAdapterData() { 112bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mAdapter.clear(); 11350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette 11450eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette final int maxYear = mMaxDate.get(Calendar.YEAR); 11550eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette for (int year = mMinDate.get(Calendar.YEAR); year <= maxYear; year++) { 116bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mAdapter.add(year); 117bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 118bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 119bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 120bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 121bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 122bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mController.tryVibrate(); 123bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (position != mSelectedPosition) { 124bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mSelectedPosition = position; 125bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mAdapter.notifyDataSetChanged(); 126bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 127bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mController.onYearSelected(mAdapter.getItem(position)); 128bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 129bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 130bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio void setItemTextAppearance(int resId) { 131bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mAdapter.setItemTextAppearance(resId); 132bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 133bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 134bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private class YearAdapter extends ArrayAdapter<Integer> { 135bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int mItemTextAppearanceResId; 136bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 137bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public YearAdapter(Context context, int resource) { 138bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super(context, resource); 139bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 140bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 141bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 142bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public View getView(int position, View convertView, ViewGroup parent) { 143bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio TextViewWithCircularIndicator v = (TextViewWithCircularIndicator) 144bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super.getView(position, convertView, parent); 145bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio v.setTextAppearance(getContext(), mItemTextAppearanceResId); 146bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio v.requestLayout(); 147bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int year = getItem(position); 148bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio boolean selected = mController.getSelectedDay().get(Calendar.YEAR) == year; 149bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio v.setDrawIndicator(selected); 150bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (selected) { 151bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio v.setCircleColor(mYearSelectedCircleColor); 152bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 153bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return v; 154bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 155bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 156bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void setItemTextAppearance(int resId) { 157bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mItemTextAppearanceResId = resId; 158bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 159bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 160bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 161bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void postSetSelectionCentered(final int position) { 162bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio postSetSelectionFromTop(position, mViewSize / 2 - mChildSize / 2); 163bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 164bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 165bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void postSetSelectionFromTop(final int position, final int offset) { 166bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio post(new Runnable() { 167bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 168bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 169bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void run() { 170bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setSelectionFromTop(position, offset); 171bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio requestLayout(); 172bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 173bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio }); 174bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 175bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 176bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public int getFirstPositionOffset() { 177bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final View firstChild = getChildAt(0); 178bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (firstChild == null) { 179bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return 0; 180bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 181bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return firstChild.getTop(); 182bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 183bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 184bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 185bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void onDateChanged() { 186bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio updateAdapterData(); 187bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mAdapter.notifyDataSetChanged(); 188bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio postSetSelectionCentered( 18950eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette mController.getSelectedDay().get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR)); 190bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 191bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 192bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 193bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 194bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super.onInitializeAccessibilityEvent(event); 19550eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette 196bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 197bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setFromIndex(0); 198bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setToIndex(0); 199bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 200bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 201bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio}