DayPickerView.java revision 3e9818e0267619fecebd55095ab26c53eff92e93
13e9818e0267619fecebd55095ab26c53eff92e93James Kung/* 23e9818e0267619fecebd55095ab26c53eff92e93James Kung * Copyright (C) 2013 The Android Open Source Project 33e9818e0267619fecebd55095ab26c53eff92e93James Kung * 43e9818e0267619fecebd55095ab26c53eff92e93James Kung * Licensed under the Apache License, Version 2.0 (the "License"); 53e9818e0267619fecebd55095ab26c53eff92e93James Kung * you may not use this file except in compliance with the License. 63e9818e0267619fecebd55095ab26c53eff92e93James Kung * You may obtain a copy of the License at 73e9818e0267619fecebd55095ab26c53eff92e93James Kung * 83e9818e0267619fecebd55095ab26c53eff92e93James Kung * http://www.apache.org/licenses/LICENSE-2.0 93e9818e0267619fecebd55095ab26c53eff92e93James Kung * 103e9818e0267619fecebd55095ab26c53eff92e93James Kung * Unless required by applicable law or agreed to in writing, software 113e9818e0267619fecebd55095ab26c53eff92e93James Kung * distributed under the License is distributed on an "AS IS" BASIS, 123e9818e0267619fecebd55095ab26c53eff92e93James Kung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133e9818e0267619fecebd55095ab26c53eff92e93James Kung * See the License for the specific language governing permissions and 143e9818e0267619fecebd55095ab26c53eff92e93James Kung * limitations under the License. 153e9818e0267619fecebd55095ab26c53eff92e93James Kung */ 163e9818e0267619fecebd55095ab26c53eff92e93James Kung 173e9818e0267619fecebd55095ab26c53eff92e93James Kungpackage com.android.datetimepicker.date; 183e9818e0267619fecebd55095ab26c53eff92e93James Kung 193e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.content.Context; 203e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.database.DataSetObserver; 213e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.os.Handler; 223e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.text.format.Time; 233e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.util.Log; 243e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.view.View; 253e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.view.ViewConfiguration; 263e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.widget.AbsListView; 273e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.widget.AbsListView.OnScrollListener; 283e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.widget.ListView; 293e9818e0267619fecebd55095ab26c53eff92e93James Kung 303e9818e0267619fecebd55095ab26c53eff92e93James Kungimport com.android.datetimepicker.date.SimpleMonthAdapter.CalendarDay; 313e9818e0267619fecebd55095ab26c53eff92e93James Kung 323e9818e0267619fecebd55095ab26c53eff92e93James Kungimport java.util.Calendar; 333e9818e0267619fecebd55095ab26c53eff92e93James Kungimport java.util.Locale; 343e9818e0267619fecebd55095ab26c53eff92e93James Kung 353e9818e0267619fecebd55095ab26c53eff92e93James Kung/** 363e9818e0267619fecebd55095ab26c53eff92e93James Kung * This displays a list of months in a calendar format with selectable days. 373e9818e0267619fecebd55095ab26c53eff92e93James Kung */ 383e9818e0267619fecebd55095ab26c53eff92e93James Kungpublic class DayPickerView extends ListView implements OnScrollListener { 393e9818e0267619fecebd55095ab26c53eff92e93James Kung 403e9818e0267619fecebd55095ab26c53eff92e93James Kung private static final String TAG = "MonthFragment"; 413e9818e0267619fecebd55095ab26c53eff92e93James Kung 423e9818e0267619fecebd55095ab26c53eff92e93James Kung // Affects when the month selection will change while scrolling up 433e9818e0267619fecebd55095ab26c53eff92e93James Kung protected static final int SCROLL_HYST_WEEKS = 2; 443e9818e0267619fecebd55095ab26c53eff92e93James Kung // How long the GoTo fling animation should last 453e9818e0267619fecebd55095ab26c53eff92e93James Kung protected static final int GOTO_SCROLL_DURATION = 250; 463e9818e0267619fecebd55095ab26c53eff92e93James Kung // How long to wait after receiving an onScrollStateChanged notification 473e9818e0267619fecebd55095ab26c53eff92e93James Kung // before acting on it 483e9818e0267619fecebd55095ab26c53eff92e93James Kung protected static final int SCROLL_CHANGE_DELAY = 40; 493e9818e0267619fecebd55095ab26c53eff92e93James Kung // The number of days to display in each week 503e9818e0267619fecebd55095ab26c53eff92e93James Kung public static final int DAYS_PER_WEEK = 7; 513e9818e0267619fecebd55095ab26c53eff92e93James Kung public static int LIST_TOP_OFFSET = -1; // so that the top line will be 523e9818e0267619fecebd55095ab26c53eff92e93James Kung // under the separator 533e9818e0267619fecebd55095ab26c53eff92e93James Kung // You can override these numbers to get a different appearance 543e9818e0267619fecebd55095ab26c53eff92e93James Kung protected int mNumWeeks = 6; 553e9818e0267619fecebd55095ab26c53eff92e93James Kung protected boolean mShowWeekNumber = false; 563e9818e0267619fecebd55095ab26c53eff92e93James Kung protected int mDaysPerWeek = 7; 573e9818e0267619fecebd55095ab26c53eff92e93James Kung 583e9818e0267619fecebd55095ab26c53eff92e93James Kung // These affect the scroll speed and feel 593e9818e0267619fecebd55095ab26c53eff92e93James Kung protected float mFriction = 1.0f; 603e9818e0267619fecebd55095ab26c53eff92e93James Kung 613e9818e0267619fecebd55095ab26c53eff92e93James Kung protected Context mContext; 623e9818e0267619fecebd55095ab26c53eff92e93James Kung protected Handler mHandler; 633e9818e0267619fecebd55095ab26c53eff92e93James Kung 643e9818e0267619fecebd55095ab26c53eff92e93James Kung protected float mMinimumFlingVelocity; 653e9818e0267619fecebd55095ab26c53eff92e93James Kung 663e9818e0267619fecebd55095ab26c53eff92e93James Kung // highlighted time 673e9818e0267619fecebd55095ab26c53eff92e93James Kung protected CalendarDay mSelectedDay = new CalendarDay(); 683e9818e0267619fecebd55095ab26c53eff92e93James Kung protected SimpleMonthAdapter mAdapter; 693e9818e0267619fecebd55095ab26c53eff92e93James Kung 703e9818e0267619fecebd55095ab26c53eff92e93James Kung protected CalendarDay mTempDay = new CalendarDay(); 713e9818e0267619fecebd55095ab26c53eff92e93James Kung 723e9818e0267619fecebd55095ab26c53eff92e93James Kung private static float mScale = 0; 733e9818e0267619fecebd55095ab26c53eff92e93James Kung // When the week starts; numbered like Time.<WEEKDAY> (e.g. SUNDAY=0). 743e9818e0267619fecebd55095ab26c53eff92e93James Kung protected int mFirstDayOfWeek; 753e9818e0267619fecebd55095ab26c53eff92e93James Kung // The first day that is visible in the view 763e9818e0267619fecebd55095ab26c53eff92e93James Kung protected Time mFirstVisibleDay = new Time(); 773e9818e0267619fecebd55095ab26c53eff92e93James Kung // The last name announced by accessibility 783e9818e0267619fecebd55095ab26c53eff92e93James Kung protected CharSequence mPrevMonthName; 793e9818e0267619fecebd55095ab26c53eff92e93James Kung // which month should be displayed/highlighted [0-11] 803e9818e0267619fecebd55095ab26c53eff92e93James Kung protected int mCurrentMonthDisplayed; 813e9818e0267619fecebd55095ab26c53eff92e93James Kung // used for tracking during a scroll 823e9818e0267619fecebd55095ab26c53eff92e93James Kung protected long mPreviousScrollPosition; 833e9818e0267619fecebd55095ab26c53eff92e93James Kung // used for tracking what state listview is in 843e9818e0267619fecebd55095ab26c53eff92e93James Kung protected int mPreviousScrollState = OnScrollListener.SCROLL_STATE_IDLE; 853e9818e0267619fecebd55095ab26c53eff92e93James Kung // used for tracking what state listview is in 863e9818e0267619fecebd55095ab26c53eff92e93James Kung protected int mCurrentScrollState = OnScrollListener.SCROLL_STATE_IDLE; 873e9818e0267619fecebd55095ab26c53eff92e93James Kung 883e9818e0267619fecebd55095ab26c53eff92e93James Kung private final DatePickerController mController; 893e9818e0267619fecebd55095ab26c53eff92e93James Kung 903e9818e0267619fecebd55095ab26c53eff92e93James Kung // This causes an update of the view at midnight 913e9818e0267619fecebd55095ab26c53eff92e93James Kung protected Runnable mTodayUpdater = new Runnable() { 923e9818e0267619fecebd55095ab26c53eff92e93James Kung @Override 933e9818e0267619fecebd55095ab26c53eff92e93James Kung public void run() { 943e9818e0267619fecebd55095ab26c53eff92e93James Kung Time midnight = new Time(mFirstVisibleDay.timezone); 953e9818e0267619fecebd55095ab26c53eff92e93James Kung midnight.setToNow(); 963e9818e0267619fecebd55095ab26c53eff92e93James Kung long currentMillis = midnight.toMillis(true); 973e9818e0267619fecebd55095ab26c53eff92e93James Kung 983e9818e0267619fecebd55095ab26c53eff92e93James Kung midnight.hour = 0; 993e9818e0267619fecebd55095ab26c53eff92e93James Kung midnight.minute = 0; 1003e9818e0267619fecebd55095ab26c53eff92e93James Kung midnight.second = 0; 1013e9818e0267619fecebd55095ab26c53eff92e93James Kung midnight.monthDay++; 1023e9818e0267619fecebd55095ab26c53eff92e93James Kung long millisToMidnight = midnight.normalize(true) - currentMillis; 1033e9818e0267619fecebd55095ab26c53eff92e93James Kung mHandler.postDelayed(this, millisToMidnight); 1043e9818e0267619fecebd55095ab26c53eff92e93James Kung 1053e9818e0267619fecebd55095ab26c53eff92e93James Kung if (mAdapter != null) { 1063e9818e0267619fecebd55095ab26c53eff92e93James Kung mAdapter.notifyDataSetChanged(); 1073e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1083e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1093e9818e0267619fecebd55095ab26c53eff92e93James Kung }; 1103e9818e0267619fecebd55095ab26c53eff92e93James Kung 1113e9818e0267619fecebd55095ab26c53eff92e93James Kung // This allows us to update our position when a day is tapped 1123e9818e0267619fecebd55095ab26c53eff92e93James Kung protected DataSetObserver mObserver = new DataSetObserver() { 1133e9818e0267619fecebd55095ab26c53eff92e93James Kung @Override 1143e9818e0267619fecebd55095ab26c53eff92e93James Kung public void onChanged() { 1153e9818e0267619fecebd55095ab26c53eff92e93James Kung CalendarDay day = mAdapter.getSelectedDay(); 1163e9818e0267619fecebd55095ab26c53eff92e93James Kung if (day.year != mSelectedDay.year || day.day != mSelectedDay.day) { 1173e9818e0267619fecebd55095ab26c53eff92e93James Kung goTo(day, true, true, false); 1183e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1193e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1203e9818e0267619fecebd55095ab26c53eff92e93James Kung }; 1213e9818e0267619fecebd55095ab26c53eff92e93James Kung 1223e9818e0267619fecebd55095ab26c53eff92e93James Kung public DayPickerView(Context context, DatePickerController controller) { 1233e9818e0267619fecebd55095ab26c53eff92e93James Kung super(context); 1243e9818e0267619fecebd55095ab26c53eff92e93James Kung mHandler = new Handler(); 1253e9818e0267619fecebd55095ab26c53eff92e93James Kung mController = controller; 1263e9818e0267619fecebd55095ab26c53eff92e93James Kung setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 1273e9818e0267619fecebd55095ab26c53eff92e93James Kung setDrawSelectorOnTop(false); 1283e9818e0267619fecebd55095ab26c53eff92e93James Kung init(context); 1293e9818e0267619fecebd55095ab26c53eff92e93James Kung setCalendarDate(controller.getSelectedDay()); 1303e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1313e9818e0267619fecebd55095ab26c53eff92e93James Kung 1323e9818e0267619fecebd55095ab26c53eff92e93James Kung public void setCalendarDate(CalendarDay day) { 1333e9818e0267619fecebd55095ab26c53eff92e93James Kung goTo(day, false, true, true); 1343e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1353e9818e0267619fecebd55095ab26c53eff92e93James Kung 1363e9818e0267619fecebd55095ab26c53eff92e93James Kung public void init(Context context) { 1373e9818e0267619fecebd55095ab26c53eff92e93James Kung mContext = context; 1383e9818e0267619fecebd55095ab26c53eff92e93James Kung String tz = Time.getCurrentTimezone(); 1393e9818e0267619fecebd55095ab26c53eff92e93James Kung ViewConfiguration viewConfig = ViewConfiguration.get(context); 1403e9818e0267619fecebd55095ab26c53eff92e93James Kung mMinimumFlingVelocity = viewConfig.getScaledMinimumFlingVelocity(); 1413e9818e0267619fecebd55095ab26c53eff92e93James Kung 1423e9818e0267619fecebd55095ab26c53eff92e93James Kung mFirstVisibleDay.timezone = tz; 1433e9818e0267619fecebd55095ab26c53eff92e93James Kung mFirstVisibleDay.normalize(true); 1443e9818e0267619fecebd55095ab26c53eff92e93James Kung 1453e9818e0267619fecebd55095ab26c53eff92e93James Kung setUpListView(); 1463e9818e0267619fecebd55095ab26c53eff92e93James Kung setUpAdapter(); 1473e9818e0267619fecebd55095ab26c53eff92e93James Kung setAdapter(mAdapter); 1483e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1493e9818e0267619fecebd55095ab26c53eff92e93James Kung 1503e9818e0267619fecebd55095ab26c53eff92e93James Kung public void onChange() { 1513e9818e0267619fecebd55095ab26c53eff92e93James Kung setUpAdapter(); 1523e9818e0267619fecebd55095ab26c53eff92e93James Kung setAdapter(mAdapter); 1533e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1543e9818e0267619fecebd55095ab26c53eff92e93James Kung 1553e9818e0267619fecebd55095ab26c53eff92e93James Kung /** 1563e9818e0267619fecebd55095ab26c53eff92e93James Kung * Creates a new adapter if necessary and sets up its parameters. Override 1573e9818e0267619fecebd55095ab26c53eff92e93James Kung * this method to provide a custom adapter. 1583e9818e0267619fecebd55095ab26c53eff92e93James Kung */ 1593e9818e0267619fecebd55095ab26c53eff92e93James Kung protected void setUpAdapter() { 1603e9818e0267619fecebd55095ab26c53eff92e93James Kung if (mAdapter == null) { 1613e9818e0267619fecebd55095ab26c53eff92e93James Kung mAdapter = new SimpleMonthAdapter(getContext(), mController); 1623e9818e0267619fecebd55095ab26c53eff92e93James Kung mAdapter.registerDataSetObserver(mObserver); 1633e9818e0267619fecebd55095ab26c53eff92e93James Kung } else { 1643e9818e0267619fecebd55095ab26c53eff92e93James Kung mAdapter.setSelectedDay(mSelectedDay); 1653e9818e0267619fecebd55095ab26c53eff92e93James Kung mAdapter.notifyDataSetChanged(); 1663e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1673e9818e0267619fecebd55095ab26c53eff92e93James Kung // refresh the view with the new parameters 1683e9818e0267619fecebd55095ab26c53eff92e93James Kung mAdapter.notifyDataSetChanged(); 1693e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1703e9818e0267619fecebd55095ab26c53eff92e93James Kung 1713e9818e0267619fecebd55095ab26c53eff92e93James Kung /* 1723e9818e0267619fecebd55095ab26c53eff92e93James Kung * Sets all the required fields for the list view. Override this method to 1733e9818e0267619fecebd55095ab26c53eff92e93James Kung * set a different list view behavior. 1743e9818e0267619fecebd55095ab26c53eff92e93James Kung */ 1753e9818e0267619fecebd55095ab26c53eff92e93James Kung protected void setUpListView() { 1763e9818e0267619fecebd55095ab26c53eff92e93James Kung // Transparent background on scroll 1773e9818e0267619fecebd55095ab26c53eff92e93James Kung setCacheColorHint(0); 1783e9818e0267619fecebd55095ab26c53eff92e93James Kung // No dividers 1793e9818e0267619fecebd55095ab26c53eff92e93James Kung setDivider(null); 1803e9818e0267619fecebd55095ab26c53eff92e93James Kung // Items are clickable 1813e9818e0267619fecebd55095ab26c53eff92e93James Kung setItemsCanFocus(true); 1823e9818e0267619fecebd55095ab26c53eff92e93James Kung // The thumb gets in the way, so disable it 1833e9818e0267619fecebd55095ab26c53eff92e93James Kung setFastScrollEnabled(false); 1843e9818e0267619fecebd55095ab26c53eff92e93James Kung setVerticalScrollBarEnabled(false); 1853e9818e0267619fecebd55095ab26c53eff92e93James Kung setOnScrollListener(this); 1863e9818e0267619fecebd55095ab26c53eff92e93James Kung setFadingEdgeLength(0); 1873e9818e0267619fecebd55095ab26c53eff92e93James Kung // Make the scrolling behavior nicer 1883e9818e0267619fecebd55095ab26c53eff92e93James Kung setFriction(ViewConfiguration.getScrollFriction() * mFriction); 1893e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1903e9818e0267619fecebd55095ab26c53eff92e93James Kung 1913e9818e0267619fecebd55095ab26c53eff92e93James Kung @Override 1923e9818e0267619fecebd55095ab26c53eff92e93James Kung public void onAttachedToWindow() { 1933e9818e0267619fecebd55095ab26c53eff92e93James Kung super.onAttachedToWindow(); 1943e9818e0267619fecebd55095ab26c53eff92e93James Kung setUpAdapter(); 1953e9818e0267619fecebd55095ab26c53eff92e93James Kung doResumeUpdates(); 1963e9818e0267619fecebd55095ab26c53eff92e93James Kung } 1973e9818e0267619fecebd55095ab26c53eff92e93James Kung 1983e9818e0267619fecebd55095ab26c53eff92e93James Kung @Override 1993e9818e0267619fecebd55095ab26c53eff92e93James Kung public void onDetachedFromWindow() { 2003e9818e0267619fecebd55095ab26c53eff92e93James Kung super.onDetachedFromWindow(); 2013e9818e0267619fecebd55095ab26c53eff92e93James Kung mHandler.removeCallbacks(mTodayUpdater); 2023e9818e0267619fecebd55095ab26c53eff92e93James Kung } 2033e9818e0267619fecebd55095ab26c53eff92e93James Kung 2043e9818e0267619fecebd55095ab26c53eff92e93James Kung // @Override 2053e9818e0267619fecebd55095ab26c53eff92e93James Kung // public void onSaveInstanceState(Bundle outState) { 2063e9818e0267619fecebd55095ab26c53eff92e93James Kung // outState.putLong(KEY_CURRENT_TIME, mSelectedDay.toMillis(true)); 2073e9818e0267619fecebd55095ab26c53eff92e93James Kung // } 2083e9818e0267619fecebd55095ab26c53eff92e93James Kung 2093e9818e0267619fecebd55095ab26c53eff92e93James Kung /** 2103e9818e0267619fecebd55095ab26c53eff92e93James Kung * Updates the user preference fields. Override this to use a different 2113e9818e0267619fecebd55095ab26c53eff92e93James Kung * preference space. 2123e9818e0267619fecebd55095ab26c53eff92e93James Kung */ 2133e9818e0267619fecebd55095ab26c53eff92e93James Kung protected void doResumeUpdates() { 2143e9818e0267619fecebd55095ab26c53eff92e93James Kung // Get default week start based on locale, subtracting one for use with 2153e9818e0267619fecebd55095ab26c53eff92e93James Kung // android Time. 2163e9818e0267619fecebd55095ab26c53eff92e93James Kung Calendar cal = Calendar.getInstance(Locale.getDefault()); 2173e9818e0267619fecebd55095ab26c53eff92e93James Kung mFirstDayOfWeek = cal.getFirstDayOfWeek() - 1; 2183e9818e0267619fecebd55095ab26c53eff92e93James Kung 2193e9818e0267619fecebd55095ab26c53eff92e93James Kung mShowWeekNumber = false; 2203e9818e0267619fecebd55095ab26c53eff92e93James Kung 2213e9818e0267619fecebd55095ab26c53eff92e93James Kung goTo(mSelectedDay, false, false, false); 2223e9818e0267619fecebd55095ab26c53eff92e93James Kung mAdapter.setSelectedDay(mSelectedDay); 2233e9818e0267619fecebd55095ab26c53eff92e93James Kung mTodayUpdater.run(); 2243e9818e0267619fecebd55095ab26c53eff92e93James Kung } 2253e9818e0267619fecebd55095ab26c53eff92e93James Kung 2263e9818e0267619fecebd55095ab26c53eff92e93James Kung /** 2273e9818e0267619fecebd55095ab26c53eff92e93James Kung * This moves to the specified time in the view. If the time is not already 2283e9818e0267619fecebd55095ab26c53eff92e93James Kung * in range it will move the list so that the first of the month containing 2293e9818e0267619fecebd55095ab26c53eff92e93James Kung * the time is at the top of the view. If the new time is already in view 2303e9818e0267619fecebd55095ab26c53eff92e93James Kung * the list will not be scrolled unless forceScroll is true. This time may 2313e9818e0267619fecebd55095ab26c53eff92e93James Kung * optionally be highlighted as selected as well. 2323e9818e0267619fecebd55095ab26c53eff92e93James Kung * 2333e9818e0267619fecebd55095ab26c53eff92e93James Kung * @param time The time to move to 2343e9818e0267619fecebd55095ab26c53eff92e93James Kung * @param animate Whether to scroll to the given time or just redraw at the 2353e9818e0267619fecebd55095ab26c53eff92e93James Kung * new location 2363e9818e0267619fecebd55095ab26c53eff92e93James Kung * @param setSelected Whether to set the given time as selected 2373e9818e0267619fecebd55095ab26c53eff92e93James Kung * @param forceScroll Whether to recenter even if the time is already 2383e9818e0267619fecebd55095ab26c53eff92e93James Kung * visible 2393e9818e0267619fecebd55095ab26c53eff92e93James Kung * @return Whether or not the view animated to the new location 2403e9818e0267619fecebd55095ab26c53eff92e93James Kung */ 2413e9818e0267619fecebd55095ab26c53eff92e93James Kung public boolean goTo(CalendarDay day, boolean animate, boolean setSelected, boolean forceScroll) { 2423e9818e0267619fecebd55095ab26c53eff92e93James Kung 2433e9818e0267619fecebd55095ab26c53eff92e93James Kung // Set the selected day 2443e9818e0267619fecebd55095ab26c53eff92e93James Kung if (setSelected) { 2453e9818e0267619fecebd55095ab26c53eff92e93James Kung mSelectedDay.set(day); 2463e9818e0267619fecebd55095ab26c53eff92e93James Kung } 2473e9818e0267619fecebd55095ab26c53eff92e93James Kung 2483e9818e0267619fecebd55095ab26c53eff92e93James Kung mTempDay.set(day); 2493e9818e0267619fecebd55095ab26c53eff92e93James Kung // Get the week we're going to 2503e9818e0267619fecebd55095ab26c53eff92e93James Kung // TODO push Util function into Calendar public api. 2513e9818e0267619fecebd55095ab26c53eff92e93James Kung int position = (day.year - mController.getMinYear()) 2523e9818e0267619fecebd55095ab26c53eff92e93James Kung * SimpleMonthAdapter.MONTHS_IN_YEAR + day.month; 2533e9818e0267619fecebd55095ab26c53eff92e93James Kung 2543e9818e0267619fecebd55095ab26c53eff92e93James Kung View child; 2553e9818e0267619fecebd55095ab26c53eff92e93James Kung int i = 0; 2563e9818e0267619fecebd55095ab26c53eff92e93James Kung int top = 0; 2573e9818e0267619fecebd55095ab26c53eff92e93James Kung // Find a child that's completely in the view 2583e9818e0267619fecebd55095ab26c53eff92e93James Kung do { 2593e9818e0267619fecebd55095ab26c53eff92e93James Kung child = getChildAt(i++); 2603e9818e0267619fecebd55095ab26c53eff92e93James Kung if (child == null) { 2613e9818e0267619fecebd55095ab26c53eff92e93James Kung break; 2623e9818e0267619fecebd55095ab26c53eff92e93James Kung } 2633e9818e0267619fecebd55095ab26c53eff92e93James Kung top = child.getTop(); 2643e9818e0267619fecebd55095ab26c53eff92e93James Kung if (Log.isLoggable(TAG, Log.DEBUG)) { 2653e9818e0267619fecebd55095ab26c53eff92e93James Kung Log.d(TAG, "child at " + (i - 1) + " has top " + top); 2663e9818e0267619fecebd55095ab26c53eff92e93James Kung } 2673e9818e0267619fecebd55095ab26c53eff92e93James Kung } while (top < 0); 2683e9818e0267619fecebd55095ab26c53eff92e93James Kung 2693e9818e0267619fecebd55095ab26c53eff92e93James Kung // Compute the first and last position visible 2703e9818e0267619fecebd55095ab26c53eff92e93James Kung int selectedPosition; 2713e9818e0267619fecebd55095ab26c53eff92e93James Kung if (child != null) { 2723e9818e0267619fecebd55095ab26c53eff92e93James Kung selectedPosition = getPositionForView(child); 2733e9818e0267619fecebd55095ab26c53eff92e93James Kung } else { 2743e9818e0267619fecebd55095ab26c53eff92e93James Kung selectedPosition = 0; 2753e9818e0267619fecebd55095ab26c53eff92e93James Kung } 2763e9818e0267619fecebd55095ab26c53eff92e93James Kung 2773e9818e0267619fecebd55095ab26c53eff92e93James Kung if (setSelected) { 2783e9818e0267619fecebd55095ab26c53eff92e93James Kung mAdapter.setSelectedDay(mSelectedDay); 2793e9818e0267619fecebd55095ab26c53eff92e93James Kung } 2803e9818e0267619fecebd55095ab26c53eff92e93James Kung 2813e9818e0267619fecebd55095ab26c53eff92e93James Kung if (Log.isLoggable(TAG, Log.DEBUG)) { 2823e9818e0267619fecebd55095ab26c53eff92e93James Kung Log.d(TAG, "GoTo position " + position); 2833e9818e0267619fecebd55095ab26c53eff92e93James Kung } 2843e9818e0267619fecebd55095ab26c53eff92e93James Kung // Check if the selected day is now outside of our visible range 2853e9818e0267619fecebd55095ab26c53eff92e93James Kung // and if so scroll to the month that contains it 2863e9818e0267619fecebd55095ab26c53eff92e93James Kung if (position != selectedPosition || forceScroll) { 2873e9818e0267619fecebd55095ab26c53eff92e93James Kung setMonthDisplayed(mTempDay); 2883e9818e0267619fecebd55095ab26c53eff92e93James Kung mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING; 2893e9818e0267619fecebd55095ab26c53eff92e93James Kung if (animate) { 2903e9818e0267619fecebd55095ab26c53eff92e93James Kung smoothScrollToPositionFromTop( 2913e9818e0267619fecebd55095ab26c53eff92e93James Kung position, LIST_TOP_OFFSET, GOTO_SCROLL_DURATION); 2923e9818e0267619fecebd55095ab26c53eff92e93James Kung return true; 2933e9818e0267619fecebd55095ab26c53eff92e93James Kung } else { 2943e9818e0267619fecebd55095ab26c53eff92e93James Kung setSelectionFromTop(position, LIST_TOP_OFFSET); 2953e9818e0267619fecebd55095ab26c53eff92e93James Kung onScrollStateChanged(this, OnScrollListener.SCROLL_STATE_IDLE); 2963e9818e0267619fecebd55095ab26c53eff92e93James Kung } 2973e9818e0267619fecebd55095ab26c53eff92e93James Kung } else if (setSelected) { 2983e9818e0267619fecebd55095ab26c53eff92e93James Kung setMonthDisplayed(mSelectedDay); 2993e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3003e9818e0267619fecebd55095ab26c53eff92e93James Kung return false; 3013e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3023e9818e0267619fecebd55095ab26c53eff92e93James Kung 3033e9818e0267619fecebd55095ab26c53eff92e93James Kung /** 3043e9818e0267619fecebd55095ab26c53eff92e93James Kung * Updates the title and selected month if the view has moved to a new 3053e9818e0267619fecebd55095ab26c53eff92e93James Kung * month. 3063e9818e0267619fecebd55095ab26c53eff92e93James Kung */ 3073e9818e0267619fecebd55095ab26c53eff92e93James Kung @Override 3083e9818e0267619fecebd55095ab26c53eff92e93James Kung public void onScroll( 3093e9818e0267619fecebd55095ab26c53eff92e93James Kung AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 3103e9818e0267619fecebd55095ab26c53eff92e93James Kung SimpleMonthView child = (SimpleMonthView) view.getChildAt(0); 3113e9818e0267619fecebd55095ab26c53eff92e93James Kung if (child == null) { 3123e9818e0267619fecebd55095ab26c53eff92e93James Kung return; 3133e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3143e9818e0267619fecebd55095ab26c53eff92e93James Kung 3153e9818e0267619fecebd55095ab26c53eff92e93James Kung // Figure out where we are 3163e9818e0267619fecebd55095ab26c53eff92e93James Kung long currScroll = view.getFirstVisiblePosition() * child.getHeight() - child.getBottom(); 3173e9818e0267619fecebd55095ab26c53eff92e93James Kung mPreviousScrollPosition = currScroll; 3183e9818e0267619fecebd55095ab26c53eff92e93James Kung mPreviousScrollState = mCurrentScrollState; 3193e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3203e9818e0267619fecebd55095ab26c53eff92e93James Kung 3213e9818e0267619fecebd55095ab26c53eff92e93James Kung /** 3223e9818e0267619fecebd55095ab26c53eff92e93James Kung * Sets the month displayed at the top of this view based on time. Override 3233e9818e0267619fecebd55095ab26c53eff92e93James Kung * to add custom events when the title is changed. 3243e9818e0267619fecebd55095ab26c53eff92e93James Kung */ 3253e9818e0267619fecebd55095ab26c53eff92e93James Kung protected void setMonthDisplayed(CalendarDay date) { 3263e9818e0267619fecebd55095ab26c53eff92e93James Kung mCurrentMonthDisplayed = date.month; 3273e9818e0267619fecebd55095ab26c53eff92e93James Kung invalidateViews(); 3283e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3293e9818e0267619fecebd55095ab26c53eff92e93James Kung 3303e9818e0267619fecebd55095ab26c53eff92e93James Kung @Override 3313e9818e0267619fecebd55095ab26c53eff92e93James Kung public void onScrollStateChanged(AbsListView view, int scrollState) { 3323e9818e0267619fecebd55095ab26c53eff92e93James Kung // use a post to prevent re-entering onScrollStateChanged before it 3333e9818e0267619fecebd55095ab26c53eff92e93James Kung // exits 3343e9818e0267619fecebd55095ab26c53eff92e93James Kung mScrollStateChangedRunnable.doScrollStateChange(view, scrollState); 3353e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3363e9818e0267619fecebd55095ab26c53eff92e93James Kung 3373e9818e0267619fecebd55095ab26c53eff92e93James Kung protected ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable(); 3383e9818e0267619fecebd55095ab26c53eff92e93James Kung 3393e9818e0267619fecebd55095ab26c53eff92e93James Kung protected class ScrollStateRunnable implements Runnable { 3403e9818e0267619fecebd55095ab26c53eff92e93James Kung private int mNewState; 3413e9818e0267619fecebd55095ab26c53eff92e93James Kung 3423e9818e0267619fecebd55095ab26c53eff92e93James Kung /** 3433e9818e0267619fecebd55095ab26c53eff92e93James Kung * Sets up the runnable with a short delay in case the scroll state 3443e9818e0267619fecebd55095ab26c53eff92e93James Kung * immediately changes again. 3453e9818e0267619fecebd55095ab26c53eff92e93James Kung * 3463e9818e0267619fecebd55095ab26c53eff92e93James Kung * @param view The list view that changed state 3473e9818e0267619fecebd55095ab26c53eff92e93James Kung * @param scrollState The new state it changed to 3483e9818e0267619fecebd55095ab26c53eff92e93James Kung */ 3493e9818e0267619fecebd55095ab26c53eff92e93James Kung public void doScrollStateChange(AbsListView view, int scrollState) { 3503e9818e0267619fecebd55095ab26c53eff92e93James Kung mHandler.removeCallbacks(this); 3513e9818e0267619fecebd55095ab26c53eff92e93James Kung mNewState = scrollState; 3523e9818e0267619fecebd55095ab26c53eff92e93James Kung mHandler.postDelayed(this, SCROLL_CHANGE_DELAY); 3533e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3543e9818e0267619fecebd55095ab26c53eff92e93James Kung 3553e9818e0267619fecebd55095ab26c53eff92e93James Kung @Override 3563e9818e0267619fecebd55095ab26c53eff92e93James Kung public void run() { 3573e9818e0267619fecebd55095ab26c53eff92e93James Kung mCurrentScrollState = mNewState; 3583e9818e0267619fecebd55095ab26c53eff92e93James Kung if (Log.isLoggable(TAG, Log.DEBUG)) { 3593e9818e0267619fecebd55095ab26c53eff92e93James Kung Log.d(TAG, 3603e9818e0267619fecebd55095ab26c53eff92e93James Kung "new scroll state: " + mNewState + " old state: " + mPreviousScrollState); 3613e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3623e9818e0267619fecebd55095ab26c53eff92e93James Kung // Fix the position after a scroll or a fling ends 3633e9818e0267619fecebd55095ab26c53eff92e93James Kung if (mNewState == OnScrollListener.SCROLL_STATE_IDLE 3643e9818e0267619fecebd55095ab26c53eff92e93James Kung && mPreviousScrollState != OnScrollListener.SCROLL_STATE_IDLE 3653e9818e0267619fecebd55095ab26c53eff92e93James Kung && mPreviousScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 3663e9818e0267619fecebd55095ab26c53eff92e93James Kung mPreviousScrollState = mNewState; 3673e9818e0267619fecebd55095ab26c53eff92e93James Kung int i = 0; 3683e9818e0267619fecebd55095ab26c53eff92e93James Kung View child = getChildAt(i); 3693e9818e0267619fecebd55095ab26c53eff92e93James Kung while (child != null && child.getBottom() <= 0) { 3703e9818e0267619fecebd55095ab26c53eff92e93James Kung child = getChildAt(++i); 3713e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3723e9818e0267619fecebd55095ab26c53eff92e93James Kung if (child == null) { 3733e9818e0267619fecebd55095ab26c53eff92e93James Kung // The view is no longer visible, just return 3743e9818e0267619fecebd55095ab26c53eff92e93James Kung return; 3753e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3763e9818e0267619fecebd55095ab26c53eff92e93James Kung int firstPosition = getFirstVisiblePosition(); 3773e9818e0267619fecebd55095ab26c53eff92e93James Kung int lastPosition = getLastVisiblePosition(); 3783e9818e0267619fecebd55095ab26c53eff92e93James Kung boolean scroll = firstPosition != 0 && lastPosition != getCount() - 1; 3793e9818e0267619fecebd55095ab26c53eff92e93James Kung final int top = child.getTop(); 3803e9818e0267619fecebd55095ab26c53eff92e93James Kung final int bottom = child.getBottom(); 3813e9818e0267619fecebd55095ab26c53eff92e93James Kung final int midpoint = getHeight() / 2; 3823e9818e0267619fecebd55095ab26c53eff92e93James Kung if (scroll && top < LIST_TOP_OFFSET) { 3833e9818e0267619fecebd55095ab26c53eff92e93James Kung if (bottom > midpoint) { 3843e9818e0267619fecebd55095ab26c53eff92e93James Kung smoothScrollBy(top, GOTO_SCROLL_DURATION); 3853e9818e0267619fecebd55095ab26c53eff92e93James Kung } else { 3863e9818e0267619fecebd55095ab26c53eff92e93James Kung smoothScrollBy(bottom, GOTO_SCROLL_DURATION); 3873e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3883e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3893e9818e0267619fecebd55095ab26c53eff92e93James Kung } else { 3903e9818e0267619fecebd55095ab26c53eff92e93James Kung mPreviousScrollState = mNewState; 3913e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3923e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3933e9818e0267619fecebd55095ab26c53eff92e93James Kung } 3943e9818e0267619fecebd55095ab26c53eff92e93James Kung} 395