Loading res/layout-sw600dp/full_month_by_week.xml +5 −1 Original line number Diff line number Diff line Loading @@ -43,6 +43,10 @@ android:layout_height="1px" android:layout_width="match_parent" /> <include android:id="@+id/week_list" layout="@android:layout/list_content"/> <com.android.calendar.month.MonthListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:drawSelectorOnTop="false" /> </LinearLayout> res/layout/full_month_by_week.xml +5 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,10 @@ android:layout_height="1px" android:layout_width="match_parent" /> <include android:id="@+id/week_list" layout="@android:layout/list_content"/> <com.android.calendar.month.MonthListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:drawSelectorOnTop="false" /> </LinearLayout> res/layout/month_by_week.xml +5 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,10 @@ android:layout_height="1dip" android:background="@color/month_grid_lines" /> <include android:id="@+id/week_list" layout="@android:layout/list_content"/> <com.android.calendar.month.MonthListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:drawSelectorOnTop="false" /> </LinearLayout> src/com/android/calendar/month/MonthByWeekFragment.java +2 −91 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.content.CursorLoader; import android.content.Loader; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.provider.CalendarContract.Attendees; Loading @@ -32,8 +31,6 @@ import android.provider.CalendarContract.Instances; import android.text.format.DateUtils; import android.text.format.Time; import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; Loading Loading @@ -85,30 +82,15 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements private CursorLoader mLoader; private Uri mEventUri; private GestureDetector mGestureDetector; private final Time mDesiredDay = new Time(); private volatile boolean mShouldLoad = true; private boolean mUserScrolled = false; private static float mScale = 0; private int mEventsLoadingDelay; private boolean mShowCalendarControls; private boolean mIsDetached; // These define the behavior of the fling. Below MIN_VELOCITY_FOR_FLING, do the system fling // behavior. Between MIN_VELOCITY_FOR_FLING and MULTIPLE_MONTH_VELOCITY_THRESHOLD, do one month // fling. Above MULTIPLE_MONTH_VELOCITY_THRESHOLD, do multiple month flings according to the // fling strength. When doing multiple month fling, the velocity is reduced by this threshold // to prevent moving from one month fling to 4 months and above flings. private static int MIN_VELOCITY_FOR_FLING = 750; private static int MULTIPLE_MONTH_VELOCITY_THRESHOLD = 4000; private static int FLING_VELOCITY_DIVIDER = 500; private static int FLING_TIME = 1000; private final Rect mFirstViewRect = new Rect(); private final Runnable mTZUpdater = new Runnable() { @Override public void run() { Loading Loading @@ -225,67 +207,6 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements } } class MonthGestureListener extends SimpleOnGestureListener { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // Small flings are just that, do not change the behavior if (Math.abs(velocityY) < MIN_VELOCITY_FOR_FLING) { return false; } // Below the threshold, fling one month. Above the threshold , fling according // to the speed of the fling. int monthsToJump; if (Math.abs(velocityY) < MULTIPLE_MONTH_VELOCITY_THRESHOLD) { if (velocityY < 0) { monthsToJump = 1; } else { // value here is zero and not -1 since by the time the fling is detected // the list moved back one month. monthsToJump = 0; } } else { if (velocityY < 0) { monthsToJump = 1 - (int)((velocityY + MULTIPLE_MONTH_VELOCITY_THRESHOLD) / FLING_VELOCITY_DIVIDER); } else { monthsToJump = -(int)((velocityY - MULTIPLE_MONTH_VELOCITY_THRESHOLD) / FLING_VELOCITY_DIVIDER); } } // Get the day at the top right corner int day = getUpperRightJulianDay(); // Get the day of the first day of the next/previous month // (according to scroll direction) mTempTime.setJulianDay(day); mTempTime.monthDay = 1; mTempTime.month += monthsToJump; long timeInMillis = mTempTime.normalize(true); // Since each view is 7 days, round the target day up to make sure the scroll will be // at least one view. int scrollToDay = Time.getJulianDay(timeInMillis, mTempTime.gmtoff) + ((monthsToJump > 0) ? 6 : 0); // Since all views have the same height, scroll by pixels instead of "to position". // Compensate for the top view offset from the top. View firstView = mListView.getChildAt(0); int firstViewHeight = firstView.getHeight(); // Get visible part length firstView.getLocalVisibleRect(mFirstViewRect); int topViewVisiblePart = mFirstViewRect.bottom - mFirstViewRect.top; int viewsToFling = (scrollToDay - day) / 7 - ((monthsToJump <= 0) ? 1 : 0); int offset = (viewsToFling > 0) ? -(firstViewHeight - topViewVisiblePart) : topViewVisiblePart - LIST_TOP_OFFSET; // Fling mListView.smoothScrollBy(viewsToFling * firstViewHeight + offset, FLING_TIME); return true; } } @Override public void onAttach(Activity activity) { super.onAttach(activity); Loading @@ -295,7 +216,6 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements } mIsDetached = false; mGestureDetector = new GestureDetector(activity, new MonthGestureListener()); ViewConfiguration viewConfig = ViewConfiguration.get(activity); mMinimumTwoMonthFlingVelocity = viewConfig.getScaledMaximumFlingVelocity() / 2; Resources res = activity.getResources(); Loading @@ -305,16 +225,7 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements if (mShowCalendarControls) { mEventsLoadingDelay = res.getInteger(R.integer.calendar_controls_animation_time); } if (mScale == 0) { mScale = res.getDisplayMetrics().density; mShowDetailsInMonth = res.getBoolean(R.bool.show_details_in_month); if (mScale != 1) { MIN_VELOCITY_FOR_FLING *= mScale; MULTIPLE_MONTH_VELOCITY_THRESHOLD *= mScale; FLING_VELOCITY_DIVIDER *= mScale; } } } @Override Loading Loading @@ -569,7 +480,7 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements @Override public boolean onTouch(View v, MotionEvent event) { mDesiredDay.setToNow(); return mGestureDetector.onTouchEvent(event); return false; // TODO post a cleanup to push us back onto the grid if something went // wrong in a scroll such as the user stopping the view but not // scrolling Loading src/com/android/calendar/month/MonthListView.java 0 → 100644 +197 −0 Original line number Diff line number Diff line /* * Copyright (C) 2012 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 com.android.calendar.month; import android.content.Context; import android.graphics.Rect; import android.os.SystemClock; import android.text.format.Time; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.widget.ListView; import com.android.calendar.Utils; public class MonthListView extends ListView { private static final String TAG = "MonthListView"; VelocityTracker mTracker; private static float mScale = 0; // These define the behavior of the fling. Below MIN_VELOCITY_FOR_FLING, do the system fling // behavior. Between MIN_VELOCITY_FOR_FLING and MULTIPLE_MONTH_VELOCITY_THRESHOLD, do one month // fling. Above MULTIPLE_MONTH_VELOCITY_THRESHOLD, do multiple month flings according to the // fling strength. When doing multiple month fling, the velocity is reduced by this threshold // to prevent moving from one month fling to 4 months and above flings. private static int MIN_VELOCITY_FOR_FLING = 1500; private static int MULTIPLE_MONTH_VELOCITY_THRESHOLD = 2000; private static int FLING_VELOCITY_DIVIDER = 500; private static int FLING_TIME = 1000; // disposable variable used for time calculations protected Time mTempTime; private long mDownActionTime; private final Rect mFirstViewRect = new Rect(); Context mListContext; // Updates the time zone when it changes private final Runnable mTimezoneUpdater = new Runnable() { @Override public void run() { if (mTempTime != null && mListContext != null) { mTempTime.timezone = Utils.getTimeZone(mListContext, mTimezoneUpdater); } } }; public MonthListView(Context context) { super(context); init(context); } public MonthListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public MonthListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context c) { mListContext = c; mTracker = VelocityTracker.obtain(); mTempTime = new Time(Utils.getTimeZone(c,mTimezoneUpdater)); if (mScale == 0) { mScale = c.getResources().getDisplayMetrics().density; if (mScale != 1) { MIN_VELOCITY_FOR_FLING *= mScale; MULTIPLE_MONTH_VELOCITY_THRESHOLD *= mScale; FLING_VELOCITY_DIVIDER *= mScale; } } } @Override public boolean onTouchEvent(MotionEvent ev) { return processEvent(ev) || super.onTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return processEvent(ev) || super.onInterceptTouchEvent(ev); } private boolean processEvent (MotionEvent ev) { switch (ev.getAction() & MotionEvent.ACTION_MASK) { // Since doFling sends a cancel, make sure not to process it. case MotionEvent.ACTION_CANCEL: return false; // Start tracking movement velocity case MotionEvent.ACTION_DOWN: mTracker.clear(); mDownActionTime = SystemClock.uptimeMillis(); break; // Accumulate velocity and do a custom fling when above threshold case MotionEvent.ACTION_UP: mTracker.addMovement(ev); mTracker.computeCurrentVelocity(1000); // in pixels per second float vel = mTracker.getYVelocity (); if (Math.abs(vel) > MIN_VELOCITY_FOR_FLING) { doFling(vel); return true; } break; default: mTracker.addMovement(ev); break; } return false; } // Do a "snap to start of month" fling private void doFling(float velocityY) { // Stop the list-view movement and take over MotionEvent cancelEvent = MotionEvent.obtain(mDownActionTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_CANCEL, 0, 0, 0); onTouchEvent(cancelEvent); // Below the threshold, fling one month. Above the threshold , fling // according to the speed of the fling. int monthsToJump; if (Math.abs(velocityY) < MULTIPLE_MONTH_VELOCITY_THRESHOLD) { if (velocityY < 0) { monthsToJump = 1; } else { // value here is zero and not -1 since by the time the fling is // detected the list moved back one month. monthsToJump = 0; } } else { if (velocityY < 0) { monthsToJump = 1 - (int) ((velocityY + MULTIPLE_MONTH_VELOCITY_THRESHOLD) / FLING_VELOCITY_DIVIDER); } else { monthsToJump = -(int) ((velocityY - MULTIPLE_MONTH_VELOCITY_THRESHOLD) / FLING_VELOCITY_DIVIDER); } } // Get the day at the top right corner int day = getUpperRightJulianDay(); // Get the day of the first day of the next/previous month // (according to scroll direction) mTempTime.setJulianDay(day); mTempTime.monthDay = 1; mTempTime.month += monthsToJump; long timeInMillis = mTempTime.normalize(false); // Since each view is 7 days, round the target day up to make sure the // scroll will be at least one view. int scrollToDay = Time.getJulianDay(timeInMillis, mTempTime.gmtoff) + ((monthsToJump > 0) ? 6 : 0); // Since all views have the same height, scroll by pixels instead of // "to position". // Compensate for the top view offset from the top. View firstView = getChildAt(0); int firstViewHeight = firstView.getHeight(); // Get visible part length firstView.getLocalVisibleRect(mFirstViewRect); int topViewVisiblePart = mFirstViewRect.bottom - mFirstViewRect.top; int viewsToFling = (scrollToDay - day) / 7 - ((monthsToJump <= 0) ? 1 : 0); int offset = (viewsToFling > 0) ? -(firstViewHeight - topViewVisiblePart + SimpleDayPickerFragment.LIST_TOP_OFFSET) : (topViewVisiblePart - SimpleDayPickerFragment.LIST_TOP_OFFSET); // Fling smoothScrollBy(viewsToFling * firstViewHeight + offset, FLING_TIME); } // Returns the julian day of the day in the upper right corner private int getUpperRightJulianDay() { SimpleWeekView child = (SimpleWeekView) getChildAt(0); if (child == null) { return -1; } return child.getFirstJulianDay() + SimpleDayPickerFragment.DAYS_PER_WEEK - 1; } } Loading
res/layout-sw600dp/full_month_by_week.xml +5 −1 Original line number Diff line number Diff line Loading @@ -43,6 +43,10 @@ android:layout_height="1px" android:layout_width="match_parent" /> <include android:id="@+id/week_list" layout="@android:layout/list_content"/> <com.android.calendar.month.MonthListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:drawSelectorOnTop="false" /> </LinearLayout>
res/layout/full_month_by_week.xml +5 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,10 @@ android:layout_height="1px" android:layout_width="match_parent" /> <include android:id="@+id/week_list" layout="@android:layout/list_content"/> <com.android.calendar.month.MonthListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:drawSelectorOnTop="false" /> </LinearLayout>
res/layout/month_by_week.xml +5 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,10 @@ android:layout_height="1dip" android:background="@color/month_grid_lines" /> <include android:id="@+id/week_list" layout="@android:layout/list_content"/> <com.android.calendar.month.MonthListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:drawSelectorOnTop="false" /> </LinearLayout>
src/com/android/calendar/month/MonthByWeekFragment.java +2 −91 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.content.CursorLoader; import android.content.Loader; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.provider.CalendarContract.Attendees; Loading @@ -32,8 +31,6 @@ import android.provider.CalendarContract.Instances; import android.text.format.DateUtils; import android.text.format.Time; import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; Loading Loading @@ -85,30 +82,15 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements private CursorLoader mLoader; private Uri mEventUri; private GestureDetector mGestureDetector; private final Time mDesiredDay = new Time(); private volatile boolean mShouldLoad = true; private boolean mUserScrolled = false; private static float mScale = 0; private int mEventsLoadingDelay; private boolean mShowCalendarControls; private boolean mIsDetached; // These define the behavior of the fling. Below MIN_VELOCITY_FOR_FLING, do the system fling // behavior. Between MIN_VELOCITY_FOR_FLING and MULTIPLE_MONTH_VELOCITY_THRESHOLD, do one month // fling. Above MULTIPLE_MONTH_VELOCITY_THRESHOLD, do multiple month flings according to the // fling strength. When doing multiple month fling, the velocity is reduced by this threshold // to prevent moving from one month fling to 4 months and above flings. private static int MIN_VELOCITY_FOR_FLING = 750; private static int MULTIPLE_MONTH_VELOCITY_THRESHOLD = 4000; private static int FLING_VELOCITY_DIVIDER = 500; private static int FLING_TIME = 1000; private final Rect mFirstViewRect = new Rect(); private final Runnable mTZUpdater = new Runnable() { @Override public void run() { Loading Loading @@ -225,67 +207,6 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements } } class MonthGestureListener extends SimpleOnGestureListener { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // Small flings are just that, do not change the behavior if (Math.abs(velocityY) < MIN_VELOCITY_FOR_FLING) { return false; } // Below the threshold, fling one month. Above the threshold , fling according // to the speed of the fling. int monthsToJump; if (Math.abs(velocityY) < MULTIPLE_MONTH_VELOCITY_THRESHOLD) { if (velocityY < 0) { monthsToJump = 1; } else { // value here is zero and not -1 since by the time the fling is detected // the list moved back one month. monthsToJump = 0; } } else { if (velocityY < 0) { monthsToJump = 1 - (int)((velocityY + MULTIPLE_MONTH_VELOCITY_THRESHOLD) / FLING_VELOCITY_DIVIDER); } else { monthsToJump = -(int)((velocityY - MULTIPLE_MONTH_VELOCITY_THRESHOLD) / FLING_VELOCITY_DIVIDER); } } // Get the day at the top right corner int day = getUpperRightJulianDay(); // Get the day of the first day of the next/previous month // (according to scroll direction) mTempTime.setJulianDay(day); mTempTime.monthDay = 1; mTempTime.month += monthsToJump; long timeInMillis = mTempTime.normalize(true); // Since each view is 7 days, round the target day up to make sure the scroll will be // at least one view. int scrollToDay = Time.getJulianDay(timeInMillis, mTempTime.gmtoff) + ((monthsToJump > 0) ? 6 : 0); // Since all views have the same height, scroll by pixels instead of "to position". // Compensate for the top view offset from the top. View firstView = mListView.getChildAt(0); int firstViewHeight = firstView.getHeight(); // Get visible part length firstView.getLocalVisibleRect(mFirstViewRect); int topViewVisiblePart = mFirstViewRect.bottom - mFirstViewRect.top; int viewsToFling = (scrollToDay - day) / 7 - ((monthsToJump <= 0) ? 1 : 0); int offset = (viewsToFling > 0) ? -(firstViewHeight - topViewVisiblePart) : topViewVisiblePart - LIST_TOP_OFFSET; // Fling mListView.smoothScrollBy(viewsToFling * firstViewHeight + offset, FLING_TIME); return true; } } @Override public void onAttach(Activity activity) { super.onAttach(activity); Loading @@ -295,7 +216,6 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements } mIsDetached = false; mGestureDetector = new GestureDetector(activity, new MonthGestureListener()); ViewConfiguration viewConfig = ViewConfiguration.get(activity); mMinimumTwoMonthFlingVelocity = viewConfig.getScaledMaximumFlingVelocity() / 2; Resources res = activity.getResources(); Loading @@ -305,16 +225,7 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements if (mShowCalendarControls) { mEventsLoadingDelay = res.getInteger(R.integer.calendar_controls_animation_time); } if (mScale == 0) { mScale = res.getDisplayMetrics().density; mShowDetailsInMonth = res.getBoolean(R.bool.show_details_in_month); if (mScale != 1) { MIN_VELOCITY_FOR_FLING *= mScale; MULTIPLE_MONTH_VELOCITY_THRESHOLD *= mScale; FLING_VELOCITY_DIVIDER *= mScale; } } } @Override Loading Loading @@ -569,7 +480,7 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements @Override public boolean onTouch(View v, MotionEvent event) { mDesiredDay.setToNow(); return mGestureDetector.onTouchEvent(event); return false; // TODO post a cleanup to push us back onto the grid if something went // wrong in a scroll such as the user stopping the view but not // scrolling Loading
src/com/android/calendar/month/MonthListView.java 0 → 100644 +197 −0 Original line number Diff line number Diff line /* * Copyright (C) 2012 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 com.android.calendar.month; import android.content.Context; import android.graphics.Rect; import android.os.SystemClock; import android.text.format.Time; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.widget.ListView; import com.android.calendar.Utils; public class MonthListView extends ListView { private static final String TAG = "MonthListView"; VelocityTracker mTracker; private static float mScale = 0; // These define the behavior of the fling. Below MIN_VELOCITY_FOR_FLING, do the system fling // behavior. Between MIN_VELOCITY_FOR_FLING and MULTIPLE_MONTH_VELOCITY_THRESHOLD, do one month // fling. Above MULTIPLE_MONTH_VELOCITY_THRESHOLD, do multiple month flings according to the // fling strength. When doing multiple month fling, the velocity is reduced by this threshold // to prevent moving from one month fling to 4 months and above flings. private static int MIN_VELOCITY_FOR_FLING = 1500; private static int MULTIPLE_MONTH_VELOCITY_THRESHOLD = 2000; private static int FLING_VELOCITY_DIVIDER = 500; private static int FLING_TIME = 1000; // disposable variable used for time calculations protected Time mTempTime; private long mDownActionTime; private final Rect mFirstViewRect = new Rect(); Context mListContext; // Updates the time zone when it changes private final Runnable mTimezoneUpdater = new Runnable() { @Override public void run() { if (mTempTime != null && mListContext != null) { mTempTime.timezone = Utils.getTimeZone(mListContext, mTimezoneUpdater); } } }; public MonthListView(Context context) { super(context); init(context); } public MonthListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public MonthListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context c) { mListContext = c; mTracker = VelocityTracker.obtain(); mTempTime = new Time(Utils.getTimeZone(c,mTimezoneUpdater)); if (mScale == 0) { mScale = c.getResources().getDisplayMetrics().density; if (mScale != 1) { MIN_VELOCITY_FOR_FLING *= mScale; MULTIPLE_MONTH_VELOCITY_THRESHOLD *= mScale; FLING_VELOCITY_DIVIDER *= mScale; } } } @Override public boolean onTouchEvent(MotionEvent ev) { return processEvent(ev) || super.onTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return processEvent(ev) || super.onInterceptTouchEvent(ev); } private boolean processEvent (MotionEvent ev) { switch (ev.getAction() & MotionEvent.ACTION_MASK) { // Since doFling sends a cancel, make sure not to process it. case MotionEvent.ACTION_CANCEL: return false; // Start tracking movement velocity case MotionEvent.ACTION_DOWN: mTracker.clear(); mDownActionTime = SystemClock.uptimeMillis(); break; // Accumulate velocity and do a custom fling when above threshold case MotionEvent.ACTION_UP: mTracker.addMovement(ev); mTracker.computeCurrentVelocity(1000); // in pixels per second float vel = mTracker.getYVelocity (); if (Math.abs(vel) > MIN_VELOCITY_FOR_FLING) { doFling(vel); return true; } break; default: mTracker.addMovement(ev); break; } return false; } // Do a "snap to start of month" fling private void doFling(float velocityY) { // Stop the list-view movement and take over MotionEvent cancelEvent = MotionEvent.obtain(mDownActionTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_CANCEL, 0, 0, 0); onTouchEvent(cancelEvent); // Below the threshold, fling one month. Above the threshold , fling // according to the speed of the fling. int monthsToJump; if (Math.abs(velocityY) < MULTIPLE_MONTH_VELOCITY_THRESHOLD) { if (velocityY < 0) { monthsToJump = 1; } else { // value here is zero and not -1 since by the time the fling is // detected the list moved back one month. monthsToJump = 0; } } else { if (velocityY < 0) { monthsToJump = 1 - (int) ((velocityY + MULTIPLE_MONTH_VELOCITY_THRESHOLD) / FLING_VELOCITY_DIVIDER); } else { monthsToJump = -(int) ((velocityY - MULTIPLE_MONTH_VELOCITY_THRESHOLD) / FLING_VELOCITY_DIVIDER); } } // Get the day at the top right corner int day = getUpperRightJulianDay(); // Get the day of the first day of the next/previous month // (according to scroll direction) mTempTime.setJulianDay(day); mTempTime.monthDay = 1; mTempTime.month += monthsToJump; long timeInMillis = mTempTime.normalize(false); // Since each view is 7 days, round the target day up to make sure the // scroll will be at least one view. int scrollToDay = Time.getJulianDay(timeInMillis, mTempTime.gmtoff) + ((monthsToJump > 0) ? 6 : 0); // Since all views have the same height, scroll by pixels instead of // "to position". // Compensate for the top view offset from the top. View firstView = getChildAt(0); int firstViewHeight = firstView.getHeight(); // Get visible part length firstView.getLocalVisibleRect(mFirstViewRect); int topViewVisiblePart = mFirstViewRect.bottom - mFirstViewRect.top; int viewsToFling = (scrollToDay - day) / 7 - ((monthsToJump <= 0) ? 1 : 0); int offset = (viewsToFling > 0) ? -(firstViewHeight - topViewVisiblePart + SimpleDayPickerFragment.LIST_TOP_OFFSET) : (topViewVisiblePart - SimpleDayPickerFragment.LIST_TOP_OFFSET); // Fling smoothScrollBy(viewsToFling * firstViewHeight + offset, FLING_TIME); } // Returns the julian day of the day in the upper right corner private int getUpperRightJulianDay() { SimpleWeekView child = (SimpleWeekView) getChildAt(0); if (child == null) { return -1; } return child.getFirstJulianDay() + SimpleDayPickerFragment.DAYS_PER_WEEK - 1; } }