/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.widget; import android.content.Context; import android.content.res.Resources; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import java.util.Calendar; import com.android.internal.R; /** * Displays a selectable list of years. */ class YearPickerView extends ListView { private final YearAdapter mAdapter; private final int mViewSize; private final int mChildSize; private OnYearSelectedListener mOnYearSelectedListener; private long mCurrentTimeMillis; public YearPickerView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.listViewStyle); } public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); final LayoutParams frame = new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); setLayoutParams(frame); final Resources res = context.getResources(); mViewSize = res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height); mChildSize = res.getDimensionPixelOffset(R.dimen.datepicker_year_label_height); setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { final int year = mAdapter.getYearForPosition(position); mAdapter.setSelection(year); if (mOnYearSelectedListener != null) { mOnYearSelectedListener.onYearChanged(YearPickerView.this, year); } } }); mAdapter = new YearAdapter(getContext()); setAdapter(mAdapter); } public void setOnYearSelectedListener(OnYearSelectedListener listener) { mOnYearSelectedListener = listener; } public void setDate(long currentTimeMillis) { mCurrentTimeMillis = currentTimeMillis; } /** * Sets the currently selected year. Jumps immediately to the new year. * * @param year the target year */ public void setYear(final int year) { mAdapter.setSelection(year); post(new Runnable() { @Override public void run() { final int position = mAdapter.getPositionForYear(year); if (position >= 0 && position < getCount()) { setSelectionCentered(position); } } }); } public void setSelectionCentered(int position) { final int offset = mViewSize / 2 - mChildSize / 2; setSelectionFromTop(position, offset); } public void setRange(Calendar min, Calendar max) { mAdapter.setRange(min, max); } private static class YearAdapter extends BaseAdapter { private static final int ITEM_LAYOUT = R.layout.year_label_text_view; private static final int ITEM_TEXT_APPEARANCE = R.style.TextAppearance_Material_DatePicker_List_YearLabel; private static final int ITEM_TEXT_ACTIVATED_APPEARANCE = R.style.TextAppearance_Material_DatePicker_List_YearLabel_Activated; private final LayoutInflater mInflater; private int mActivatedYear; private int mMinYear; private int mCount; public YearAdapter(Context context) { mInflater = LayoutInflater.from(context); } public void setRange(Calendar minDate, Calendar maxDate) { final int minYear = minDate.get(Calendar.YEAR); final int count = maxDate.get(Calendar.YEAR) - minYear + 1; if (mMinYear != minYear || mCount != count) { mMinYear = minYear; mCount = count; notifyDataSetInvalidated(); } } public boolean setSelection(int year) { if (mActivatedYear != year) { mActivatedYear = year; notifyDataSetChanged(); return true; } return false; } @Override public int getCount() { return mCount; } @Override public Integer getItem(int position) { return getYearForPosition(position); } @Override public long getItemId(int position) { return getYearForPosition(position); } public int getPositionForYear(int year) { return year - mMinYear; } public int getYearForPosition(int position) { return mMinYear + position; } @Override public boolean hasStableIds() { return true; } @Override public View getView(int position, View convertView, ViewGroup parent) { final TextView v; final boolean hasNewView = convertView == null; if (hasNewView) { v = (TextView) mInflater.inflate(ITEM_LAYOUT, parent, false); } else { v = (TextView) convertView; } final int year = getYearForPosition(position); final boolean activated = mActivatedYear == year; if (hasNewView || v.isActivated() != activated) { final int textAppearanceResId; if (activated && ITEM_TEXT_ACTIVATED_APPEARANCE != 0) { textAppearanceResId = ITEM_TEXT_ACTIVATED_APPEARANCE; } else { textAppearanceResId = ITEM_TEXT_APPEARANCE; } v.setTextAppearance(textAppearanceResId); v.setActivated(activated); } v.setText(Integer.toString(year)); return v; } @Override public int getItemViewType(int position) { return 0; } @Override public int getViewTypeCount() { return 1; } @Override public boolean isEmpty() { return false; } @Override public boolean areAllItemsEnabled() { return true; } @Override public boolean isEnabled(int position) { return true; } } public int getFirstPositionOffset() { final View firstChild = getChildAt(0); if (firstChild == null) { return 0; } return firstChild.getTop(); } /** @hide */ @Override public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { super.onInitializeAccessibilityEventInternal(event); // There are a bunch of years, so don't bother. if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { event.setFromIndex(0); event.setToIndex(0); } } /** * The callback used to indicate the user changed the year. */ public interface OnYearSelectedListener { /** * Called upon a year change. * * @param view The view associated with this listener. * @param year The year that was set. */ void onYearChanged(YearPickerView view, int year); } }