DayView.java revision b5e3c17201b2c08ca9f3fd33f4585e1ec8fa71b1
1146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/* 2146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 3146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 4146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * you may not use this file except in compliance with the License. 6146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * You may obtain a copy of the License at 7146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 8146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 10146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * See the License for the specific language governing permissions and 14146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * limitations under the License. 15146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 16146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 17146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectpackage com.android.calendar; 18146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chanimport com.android.calendar.CalendarController.EventType; 2083b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chanimport com.android.calendar.CalendarController.ViewType; 2183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan 2246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chanimport android.animation.Animator; 2346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chanimport android.animation.AnimatorListenerAdapter; 2446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chanimport android.animation.ObjectAnimator; 2546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chanimport android.animation.TypeEvaluator; 2646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chanimport android.animation.ValueAnimator; 27146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.ContentResolver; 28146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.ContentUris; 29146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Context; 30146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.res.Resources; 31146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.res.TypedArray; 32146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.database.Cursor; 3325996100d6ea61888ebe54d7708a9a371bb12a55RoboErikimport android.graphics.BitmapFactory; 34146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Canvas; 3525996100d6ea61888ebe54d7708a9a371bb12a55RoboErikimport android.graphics.Color; 36146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Paint; 37e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErikimport android.graphics.Paint.Align; 3825996100d6ea61888ebe54d7708a9a371bb12a55RoboErikimport android.graphics.PorterDuff; 39dd95df57c8c5a58a85c4c0effad5652dec14f621Erikimport android.graphics.Paint.Style; 4025996100d6ea61888ebe54d7708a9a371bb12a55RoboErikimport android.graphics.Shader.TileMode; 41146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Rect; 42146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Typeface; 4325996100d6ea61888ebe54d7708a9a371bb12a55RoboErikimport android.graphics.drawable.BitmapDrawable; 44c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawaimport android.graphics.drawable.Drawable; 45146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.net.Uri; 46146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Handler; 47a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Attendees; 48a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Calendars; 49a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Events; 503e7015267340b09d142dfcd3ff8acda257711023Shachar Shemeshimport android.text.Layout.Alignment; 51e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErikimport android.text.Spannable; 52e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErikimport android.text.SpannableString; 53e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErikimport android.text.SpannableStringBuilder; 54f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chanimport android.text.StaticLayout; 553e7015267340b09d142dfcd3ff8acda257711023Shachar Shemeshimport android.text.TextPaint; 56f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chanimport android.text.TextUtils; 57146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.DateFormat; 58146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.DateUtils; 59146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.Time; 60e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErikimport android.text.style.StyleSpan; 61146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.util.Log; 62146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ContextMenu; 63dd95df57c8c5a58a85c4c0effad5652dec14f621Erikimport android.view.ContextMenu.ContextMenuInfo; 64ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.GestureDetector; 65146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.Gravity; 66146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.KeyEvent; 67146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.LayoutInflater; 68146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.MenuItem; 69146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.MotionEvent; 70d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chanimport android.view.ScaleGestureDetector; 71146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.View; 72146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ViewConfiguration; 73146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ViewGroup; 74146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.WindowManager; 75259b8f9a21fffd3858218581e9daaf689b6b888fErikimport android.view.accessibility.AccessibilityEvent; 7646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chanimport android.view.animation.AccelerateDecelerateInterpolator; 77ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.animation.Animation; 782c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chanimport android.view.animation.Interpolator; 79ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.animation.TranslateAnimation; 80146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.ImageView; 813f6328f579b05c02606572c777541b97aa04f9f3Michael Chanimport android.widget.OverScroller; 82146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.PopupWindow; 83146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.TextView; 84ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.widget.ViewSwitcher; 85146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 86146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport java.util.ArrayList; 87c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawaimport java.util.Arrays; 88146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport java.util.Calendar; 89259b8f9a21fffd3858218581e9daaf689b6b888fErikimport java.util.Formatter; 90b5e3c17201b2c08ca9f3fd33f4585e1ec8fa71b1RoboErikimport java.util.Iterator; 91259b8f9a21fffd3858218581e9daaf689b6b888fErikimport java.util.Locale; 920d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chanimport java.util.regex.Matcher; 930d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chanimport java.util.regex.Pattern; 94146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 95146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/** 96d190418220467c02327dd9b3ae1eae238889720bMichael Chan * View for multi-day view. So far only 1 and 7 day have been tested. 97d190418220467c02327dd9b3ae1eae238889720bMichael Chan */ 98d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chanpublic class DayView extends View implements View.OnCreateContextMenuListener, 99cd405a28e6821b116dcf3c531805d0c90b6cc08cErik ScaleGestureDetector.OnScaleGestureListener, View.OnClickListener, View.OnLongClickListener 100cd405a28e6821b116dcf3c531805d0c90b6cc08cErik { 101d190418220467c02327dd9b3ae1eae238889720bMichael Chan private static String TAG = "DayView"; 102d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan private static boolean DEBUG = false; 103259b8f9a21fffd3858218581e9daaf689b6b888fErik private static final String HOUR_FORMAT_12H = "%A %I%p"; 104259b8f9a21fffd3858218581e9daaf689b6b888fErik private static final String HOUR_FORMAT_24H = "%A %H"; 105259b8f9a21fffd3858218581e9daaf689b6b888fErik private static final String PERIOD_SPACE = ". "; 106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 107705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan private static float mScale = 0; // Used for supporting different screen densities 108666fc5e8ddbac15c951aad738bd818ee307eae42Erik private static final long INVALID_EVENT_ID = -1; //This is used for remembering a null event 1092fda24534978f55711526dbde747aa50d68dec40RoboErik // Duration of the allday expansion 110ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan private static final long ANIMATION_DURATION = 400; 1112fda24534978f55711526dbde747aa50d68dec40RoboErik // duration of the more allday event text fade 1122fda24534978f55711526dbde747aa50d68dec40RoboErik private static final long ANIMATION_SECONDARY_DURATION = 200; 113705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan 1144484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan private static final int MENU_AGENDA = 2; 1154484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan private static final int MENU_DAY = 3; 1164484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan private static final int MENU_EVENT_VIEW = 5; 1174484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan private static final int MENU_EVENT_CREATE = 6; 1184484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan private static final int MENU_EVENT_EDIT = 7; 1194484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan private static final int MENU_EVENT_DELETE = 8; 1204484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan 12111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan private static int DEFAULT_CELL_HEIGHT = 64; 122d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan private static int MAX_CELL_HEIGHT = 150; 123d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan private static int MIN_Y_SPAN = 100; 124d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private boolean mOnFlingCalled; 1264f58287a1e02325337e39073a50bbb880094099fRoboErik private boolean mStartingScroll = false; 127666fc5e8ddbac15c951aad738bd818ee307eae42Erik /** 128666fc5e8ddbac15c951aad738bd818ee307eae42Erik * ID of the last event which was displayed with the toast popup. 129666fc5e8ddbac15c951aad738bd818ee307eae42Erik * 130666fc5e8ddbac15c951aad738bd818ee307eae42Erik * This is used to prevent popping up multiple quick views for the same event, especially 131666fc5e8ddbac15c951aad738bd818ee307eae42Erik * during calendar syncs. This becomes valid when an event is selected, either by default 132666fc5e8ddbac15c951aad738bd818ee307eae42Erik * on starting calendar or by scrolling to an event. It becomes invalid when the user 133666fc5e8ddbac15c951aad738bd818ee307eae42Erik * explicitly scrolls to an empty time slot, changes views, or deletes the event. 134666fc5e8ddbac15c951aad738bd818ee307eae42Erik */ 135666fc5e8ddbac15c951aad738bd818ee307eae42Erik private long mLastPopupEventID; 136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 137ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan protected Context mContext; 138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final String[] CALENDARS_PROJECTION = new String[] { 140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Calendars._ID, // 0 141ef2add9145f058ea103ade2870a8ba899b9ed1c9RoboErik Calendars.CALENDAR_ACCESS_LEVEL, // 1 1426d34cec523930368976bc8d358d0a6de1da3462cMichael Chan Calendars.OWNER_ACCOUNT, // 2 143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project }; 144146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int CALENDARS_INDEX_ACCESS_LEVEL = 1; 1456d34cec523930368976bc8d358d0a6de1da3462cMichael Chan private static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2; 146146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final String CALENDARS_WHERE = Calendars._ID + "=%d"; 147146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final String[] ATTENDEES_PROJECTION = new String[] { 149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Attendees._ID, // 0 150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Attendees.ATTENDEE_RELATIONSHIP, // 1 151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project }; 152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ATTENDEES_INDEX_RELATIONSHIP = 1; 153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=%d"; 154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int FROM_NONE = 0; 156146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int FROM_ABOVE = 1; 157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int FROM_BELOW = 2; 158146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int FROM_LEFT = 4; 159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int FROM_RIGHT = 8; 160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 161a505627659f6bfba8869eac8089f7030f2d0d92cErik private static final int ACCESS_LEVEL_NONE = 0; 162a505627659f6bfba8869eac8089f7030f2d0d92cErik private static final int ACCESS_LEVEL_DELETE = 1; 163a505627659f6bfba8869eac8089f7030f2d0d92cErik private static final int ACCESS_LEVEL_EDIT = 2; 164a505627659f6bfba8869eac8089f7030f2d0d92cErik 165d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan private static int mHorizontalSnapBackThreshold = 128; 166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private ContinueScroll mContinueScroll = new ContinueScroll(); 168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Make this visible within the package for more informative debugging 170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Time mBaseDate; 171bd0e834aea317236d574f8738fe11a51fdc87968Erik private Time mCurrentTime; 172bd0e834aea317236d574f8738fe11a51fdc87968Erik //Update the current time line every five minutes if the window is left open that long 173bd0e834aea317236d574f8738fe11a51fdc87968Erik private static final int UPDATE_CURRENT_TIME_DELAY = 300000; 174bd0e834aea317236d574f8738fe11a51fdc87968Erik private UpdateCurrentTime mUpdateCurrentTime = new UpdateCurrentTime(); 175bd0e834aea317236d574f8738fe11a51fdc87968Erik private int mTodayJulianDay; 176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Typeface mBold = Typeface.DEFAULT_BOLD; 178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mFirstJulianDay; 179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mLastJulianDay; 180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 181146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mMonthLength; 182487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan private int mFirstVisibleDate; 183487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan private int mFirstVisibleDayOfWeek; 184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int[] mEarliestStartHour; // indexed by the week day offset 185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private boolean[] mHasAllDayEvent; // indexed by the week day offset 1868f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan private String mAllDayString; 187259b8f9a21fffd3858218581e9daaf689b6b888fErik private String mEventCountTemplate; 188259b8f9a21fffd3858218581e9daaf689b6b888fErik 189259b8f9a21fffd3858218581e9daaf689b6b888fErik protected static StringBuilder mStringBuilder = new StringBuilder(50); 190259b8f9a21fffd3858218581e9daaf689b6b888fErik // TODO recreate formatter when locale changes 191259b8f9a21fffd3858218581e9daaf689b6b888fErik protected static Formatter mFormatter = new Formatter(mStringBuilder, Locale.getDefault()); 192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 193731f1cb808b7586b93615b408ab2636081fab0dcErik private Runnable mTZUpdater = new Runnable() { 194731f1cb808b7586b93615b408ab2636081fab0dcErik @Override 195731f1cb808b7586b93615b408ab2636081fab0dcErik public void run() { 196731f1cb808b7586b93615b408ab2636081fab0dcErik String tz = Utils.getTimeZone(mContext, this); 197731f1cb808b7586b93615b408ab2636081fab0dcErik mBaseDate.timezone = tz; 198731f1cb808b7586b93615b408ab2636081fab0dcErik mBaseDate.normalize(true); 199731f1cb808b7586b93615b408ab2636081fab0dcErik mCurrentTime.switchTimezone(tz); 200731f1cb808b7586b93615b408ab2636081fab0dcErik invalidate(); 201731f1cb808b7586b93615b408ab2636081fab0dcErik } 202731f1cb808b7586b93615b408ab2636081fab0dcErik }; 203731f1cb808b7586b93615b408ab2636081fab0dcErik 20446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() { 20546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan @Override 20646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan public void onAnimationStart(Animator animation) { 20746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mScrolling = true; 20846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 20946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 21046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan @Override 21146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan public void onAnimationCancel(Animator animation) { 21246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mScrolling = false; 21346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 21446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 21546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan @Override 21646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan public void onAnimationEnd(Animator animation) { 21746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mScrolling = false; 21846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan resetSelectedHour(); 21946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan invalidate(); 22046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 22146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan }; 22246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * This variable helps to avoid unnecessarily reloading events by keeping 225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * track of the start millis parameter used for the most recent loading 226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * of events. If the next reload matches this, then the events are not 227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * reloaded. To force a reload, set this to zero (this is set to zero 228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * in the method clearCachedEvents()). 229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private long mLastReloadMillis; 231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private ArrayList<Event> mEvents = new ArrayList<Event>(); 23308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan private ArrayList<Event> mAllDayEvents = new ArrayList<Event>(); 23408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan private StaticLayout[] mLayouts = null; 23508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan private StaticLayout[] mAllDayLayouts = null; 236e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private StaticLayout mAllDayTextLayout = null; 237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mSelectionDay; // Julian day 238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mSelectionHour; 239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2402fda24534978f55711526dbde747aa50d68dec40RoboErik boolean mSelectionAllday; 241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2423eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan /** Width of a day or non-conflicting event */ 243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mCellWidth; 244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 245146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Pre-allocate these objects and re-use them 246146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Rect mRect = new Rect(); 247146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Rect mDestRect = new Rect(); 248259b8f9a21fffd3858218581e9daaf689b6b888fErik private Rect mSelectionRect = new Rect(); 2492fda24534978f55711526dbde747aa50d68dec40RoboErik // This encloses the more allDay events icon 2502fda24534978f55711526dbde747aa50d68dec40RoboErik private Rect mExpandAllDayRect = new Rect(); 251e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // TODO Clean up paint usage 252146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Paint mPaint = new Paint(); 253146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Paint mEventTextPaint = new Paint(); 254146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Paint mSelectionPaint = new Paint(); 25502041687c35441e8a21cb763f1fc3a26525292efDavid Brown private float[] mLines; 256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 257487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan private int mFirstDayOfWeek; // First day of the week 258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private PopupWindow mPopup; 260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private View mPopupView; 261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // The number of milliseconds to show the popup window 263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int POPUP_DISMISS_DELAY = 3000; 264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private DismissPopup mDismissPopup = new DismissPopup(); 265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private boolean mRemeasure = true; 267146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 268146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private final EventLoader mEventLoader; 269146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project protected final EventGeometry mEventGeometry; 270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 271e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static float GRID_LINE_LEFT_MARGIN = 0; 272000ba1109e2f4e527e9227fe341598ceeb3fbca6Michael Chan private static final float GRID_LINE_INNER_WIDTH = 1; 2733eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan 274146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int DAY_GAP = 1; 275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int HOUR_GAP = 1; 2762fda24534978f55711526dbde747aa50d68dec40RoboErik // This is the standard height of an allday event with no restrictions 2779c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan private static int SINGLE_ALLDAY_HEIGHT = 34; 2782fda24534978f55711526dbde747aa50d68dec40RoboErik /** 2792fda24534978f55711526dbde747aa50d68dec40RoboErik * This is the minimum desired height of a allday event. 2802fda24534978f55711526dbde747aa50d68dec40RoboErik * When unexpanded, allday events will use this height. 2812fda24534978f55711526dbde747aa50d68dec40RoboErik * When expanded allDay events will attempt to grow to fit all 2822fda24534978f55711526dbde747aa50d68dec40RoboErik * events at this height. 2832fda24534978f55711526dbde747aa50d68dec40RoboErik */ 2842fda24534978f55711526dbde747aa50d68dec40RoboErik private static float MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT = 28.0F; // in pixels 2852fda24534978f55711526dbde747aa50d68dec40RoboErik /** 2862fda24534978f55711526dbde747aa50d68dec40RoboErik * This is how big the unexpanded allday height is allowed to be. 2872fda24534978f55711526dbde747aa50d68dec40RoboErik * It will get adjusted based on screen size 2882fda24534978f55711526dbde747aa50d68dec40RoboErik */ 2892fda24534978f55711526dbde747aa50d68dec40RoboErik private static int MAX_UNEXPANDED_ALLDAY_HEIGHT = 2902fda24534978f55711526dbde747aa50d68dec40RoboErik (int) (MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT * 4); 2912fda24534978f55711526dbde747aa50d68dec40RoboErik /** 2922fda24534978f55711526dbde747aa50d68dec40RoboErik * This is the minimum size reserved for displaying regular events. 2932fda24534978f55711526dbde747aa50d68dec40RoboErik * The expanded allDay region can't expand into this. 2942fda24534978f55711526dbde747aa50d68dec40RoboErik */ 2952fda24534978f55711526dbde747aa50d68dec40RoboErik private static int MIN_HOURS_HEIGHT = 180; 29625996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static int ALLDAY_TOP_MARGIN = 1; 2972fda24534978f55711526dbde747aa50d68dec40RoboErik // The largest a single allDay event will become. 298f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan private static int MAX_HEIGHT_OF_ONE_ALLDAY_EVENT = 34; 299e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 3008f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan private static int HOURS_TOP_MARGIN = 2; 301e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int HOURS_LEFT_MARGIN = 2; 3028f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan private static int HOURS_RIGHT_MARGIN = 4; 3038f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan private static int HOURS_MARGIN = HOURS_LEFT_MARGIN + HOURS_RIGHT_MARGIN; 304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 305bd0e834aea317236d574f8738fe11a51fdc87968Erik private static int CURRENT_TIME_LINE_HEIGHT = 2; 306bd0e834aea317236d574f8738fe11a51fdc87968Erik private static int CURRENT_TIME_LINE_BORDER_WIDTH = 1; 3071ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private static final int CURRENT_TIME_LINE_SIDE_BUFFER = 2; 308bd0e834aea317236d574f8738fe11a51fdc87968Erik 309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /* package */ static final int MINUTES_PER_HOUR = 60; 310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /* package */ static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * 24; 311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /* package */ static final int MILLIS_PER_MINUTE = 60 * 1000; 312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /* package */ static final int MILLIS_PER_HOUR = (3600 * 1000); 313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /* package */ static final int MILLIS_PER_DAY = MILLIS_PER_HOUR * 24; 314146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 31525996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static final int DECLINED_ALPHA = 0x66000000; 316f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan private static final int DATE_HEADER_ALPHA = 0x26000000; 317f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan private static final int DATE_HEADER_TODAY_ALPHA = 0x99000000; 3182fda24534978f55711526dbde747aa50d68dec40RoboErik // More events text will transition between invisible and this alpha 3192fda24534978f55711526dbde747aa50d68dec40RoboErik private static final int MORE_EVENTS_MAX_ALPHA = 0x4C; 320e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int DAY_HEADER_ONE_DAY_LEFT_MARGIN = 0; 321e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int DAY_HEADER_ONE_DAY_RIGHT_MARGIN = 5; 322e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int DAY_HEADER_ONE_DAY_BOTTOM_MARGIN = 6; 323e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int DAY_HEADER_LEFT_MARGIN = 5; 324e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int DAY_HEADER_RIGHT_MARGIN = 4; 325e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int DAY_HEADER_BOTTOM_MARGIN = 3; 3263eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan private static float DAY_HEADER_FONT_SIZE = 14; 3278f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan private static float DATE_HEADER_FONT_SIZE = 32; 3283eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan private static float NORMAL_FONT_SIZE = 12; 3293eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan private static float EVENT_TEXT_FONT_SIZE = 12; 330e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static float HOURS_TEXT_SIZE = 12; 331e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static float ALLDAY_TEXT_SIZE = 12; 332e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static float AMPM_TEXT_SIZE = 9; 3338f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan private static int MIN_HOURS_WIDTH = 96; 334705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan private static int MIN_CELL_WIDTH_FOR_TEXT = 27; 335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int MAX_EVENT_TEXT_LEN = 500; 3362fda24534978f55711526dbde747aa50d68dec40RoboErik // smallest height to draw an event with 33725996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static float MIN_EVENT_HEIGHT = 24.0F; // in pixels 3381ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private static int CALENDAR_COLOR_SQUARE_SIZE = 10; 33925996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static int EVENT_RECT_TOP_MARGIN = 1; 34025996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static int EVENT_RECT_BOTTOM_MARGIN = 1; 34125996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static int EVENT_RECT_LEFT_MARGIN = 2; 34225996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static int EVENT_RECT_RIGHT_MARGIN = 1; 34325996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static int EVENT_RECT_STROKE_WIDTH = 2; 3441ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private static int EVENT_TEXT_TOP_MARGIN = 2; 34525996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static int EVENT_TEXT_BOTTOM_MARGIN = 2; 34625996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static int EVENT_TEXT_LEFT_MARGIN = 2; 34725996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private static int EVENT_TEXT_RIGHT_MARGIN = 2; 348e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int ALL_DAY_EVENT_RECT_BOTTOM_MARGIN = 1; 3491ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private static int EVENT_ALL_DAY_TEXT_TOP_MARGIN = EVENT_TEXT_TOP_MARGIN; 3501ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private static int EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN = EVENT_TEXT_BOTTOM_MARGIN; 3511ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private static int EVENT_ALL_DAY_TEXT_LEFT_MARGIN = EVENT_TEXT_LEFT_MARGIN; 3521ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private static int EVENT_ALL_DAY_TEXT_RIGHT_MARGIN = EVENT_TEXT_RIGHT_MARGIN; 3532fda24534978f55711526dbde747aa50d68dec40RoboErik // margins and sizing for the expand allday icon 354cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik private static int EXPAND_ALL_DAY_BOTTOM_MARGIN = 10; 3552fda24534978f55711526dbde747aa50d68dec40RoboErik // sizing for "box +n" in allDay events 3562fda24534978f55711526dbde747aa50d68dec40RoboErik private static int EVENT_SQUARE_WIDTH = 10; 3572fda24534978f55711526dbde747aa50d68dec40RoboErik private static int EVENT_LINE_PADDING = 4; 358146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 359146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static int mPressedColor; 360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static int mEventTextColor; 3612fda24534978f55711526dbde747aa50d68dec40RoboErik private static int mMoreEventsTextColor; 362f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan 36364b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok private static int mWeek_saturdayColor; 36464b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok private static int mWeek_sundayColor; 365d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan private static int mCalendarDateBannerTextColor; 366d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan private static int mCalendarAmPmLabel; 367ba902466b19b11d587468e354edc58e542707747Michael Chan private static int mCalendarGridAreaSelected; 3683eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan private static int mCalendarGridLineInnerHorizontalColor; 3693eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan private static int mCalendarGridLineInnerVerticalColor; 370e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int mTodayBgColor; 371e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int mBgColor; 3728f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan private static int mCalendarHourLabelColor; 3732fda24534978f55711526dbde747aa50d68dec40RoboErik private static int mMoreAlldayEventsTextAlpha = MORE_EVENTS_MAX_ALPHA; 374146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 37595d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan private float mAnimationDistance = 0; 376146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mViewStartX; 377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mViewStartY; 378146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mMaxViewStartY; 379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mViewHeight; 380146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mViewWidth; 38146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan private int mGridAreaHeight = -1; 382d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan private static int mCellHeight = 0; // shared among all DayViews 383d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan private static int mMinCellHeight = 32; 384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mScrollStartY; 385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mPreviousDirection; 386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 387d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan /** 388d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan * Vertical distance or span between the two touch points at the start of a 389d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan * scaling gesture 390d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan */ 391d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan private float mStartingSpanY = 0; 392d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan /** Height of 1 hour in pixels at the start of a scaling gesture */ 393d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan private int mCellHeightBeforeScaleGesture; 394d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan /** The hour at the center two touch points */ 395d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan private float mGestureCenterHour = 0; 396d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan /** 397d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan * Flag to decide whether to handle the up event. Cases where up events 398d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan * should be ignored are 1) right after a scale gesture and 2) finger was 399d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan * down before app launch 400d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan */ 401d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan private boolean mHandleActionUp = true; 402d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 403146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mHoursTextHeight; 4042fda24534978f55711526dbde747aa50d68dec40RoboErik /** 4052fda24534978f55711526dbde747aa50d68dec40RoboErik * The height of the area used for allday events 4062fda24534978f55711526dbde747aa50d68dec40RoboErik */ 4072fda24534978f55711526dbde747aa50d68dec40RoboErik private int mAlldayHeight; 4082fda24534978f55711526dbde747aa50d68dec40RoboErik /** 4092fda24534978f55711526dbde747aa50d68dec40RoboErik * The height of the allday event area used during animation 4102fda24534978f55711526dbde747aa50d68dec40RoboErik */ 4112fda24534978f55711526dbde747aa50d68dec40RoboErik private int mAnimateDayHeight = 0; 4122fda24534978f55711526dbde747aa50d68dec40RoboErik /** 4132fda24534978f55711526dbde747aa50d68dec40RoboErik * The height of an individual allday event during animation 4142fda24534978f55711526dbde747aa50d68dec40RoboErik */ 4152fda24534978f55711526dbde747aa50d68dec40RoboErik private int mAnimateDayEventHeight = (int) MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT; 4162fda24534978f55711526dbde747aa50d68dec40RoboErik /** 417cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik * Whether to use the expand or collapse icon. 4182fda24534978f55711526dbde747aa50d68dec40RoboErik */ 41997326ee1ea9b1bb17e0e2bcfe344352d4bb03001RoboErik private static boolean mUseExpandIcon = true; 4202fda24534978f55711526dbde747aa50d68dec40RoboErik /** 4212fda24534978f55711526dbde747aa50d68dec40RoboErik * The height of the day names/numbers 4222fda24534978f55711526dbde747aa50d68dec40RoboErik */ 4233eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan private static int DAY_HEADER_HEIGHT = 45; 424f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan /** 425e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik * The height of the day names/numbers for multi-day views 426e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik */ 427e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int MULTI_DAY_HEADER_HEIGHT = DAY_HEADER_HEIGHT; 428e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik /** 429e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik * The height of the day names/numbers when viewing a single day 430e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik */ 431e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private static int ONE_DAY_HEADER_HEIGHT = DAY_HEADER_HEIGHT; 432e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik /** 433f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan * Max of all day events in a given day in this view. 434f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan */ 4352fda24534978f55711526dbde747aa50d68dec40RoboErik private int mMaxAlldayEvents; 4362fda24534978f55711526dbde747aa50d68dec40RoboErik /** 4372fda24534978f55711526dbde747aa50d68dec40RoboErik * A count of the number of allday events that were not drawn for each day 4382fda24534978f55711526dbde747aa50d68dec40RoboErik */ 4392fda24534978f55711526dbde747aa50d68dec40RoboErik private int[] mSkippedAlldayEvents; 4402fda24534978f55711526dbde747aa50d68dec40RoboErik /** 4412fda24534978f55711526dbde747aa50d68dec40RoboErik * The number of allDay events at which point we start hiding allDay events. 4422fda24534978f55711526dbde747aa50d68dec40RoboErik */ 4432fda24534978f55711526dbde747aa50d68dec40RoboErik private int mMaxUnexpandedAlldayEventCount = 4; 4442fda24534978f55711526dbde747aa50d68dec40RoboErik /** 4452fda24534978f55711526dbde747aa50d68dec40RoboErik * Whether or not to expand the allDay area to fill the screen 4462fda24534978f55711526dbde747aa50d68dec40RoboErik */ 4472fda24534978f55711526dbde747aa50d68dec40RoboErik private static boolean mShowAllAllDayEvents = false; 448146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 449146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project protected int mNumDays = 7; 450146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mNumHours = 10; 4513eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan 4523eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan /** Width of the time line (list of hours) to the left. */ 453146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mHoursWidth; 454146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mDateStrWidth; 45546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan /** Top of the scrollable region i.e. below date labels and all day events */ 456146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mFirstCell; 45746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan /** First fully visibile hour */ 458146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mFirstHour = -1; 45946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan /** Distance between the mFirstCell and the top of first fully visible hour. */ 460146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mFirstHourOffset; 461146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private String[] mHourStrs; 462146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private String[] mDayStrs; 463146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private String[] mDayStrs2Letter; 464146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private boolean mIs24HourFormat; 465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 466146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private ArrayList<Event> mSelectedEvents = new ArrayList<Event>(); 467146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private boolean mComputeSelectedEvents; 4688307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik private boolean mUpdateToast; 469146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Event mSelectedEvent; 470146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Event mPrevSelectedEvent; 471146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Rect mPrevBox = new Rect(); 472146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project protected final Resources mResources; 4733eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan protected final Drawable mCurrentTimeLine; 4743eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan protected final Drawable mTodayHeaderDrawable; 4752fda24534978f55711526dbde747aa50d68dec40RoboErik protected final Drawable mExpandAlldayDrawable; 476cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik protected final Drawable mCollapseAlldayDrawable; 477f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan protected Drawable mAcceptedOrTentativeEventBoxDrawable; 47825996100d6ea61888ebe54d7708a9a371bb12a55RoboErik protected BitmapDrawable mDeclinedBgDrawable; 479146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private String mAmString; 480146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private String mPmString; 481146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private DeleteEventHelper mDeleteEventHelper; 4826d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan private static int sCounter = 0; 483146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 484146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private ContextMenuHandler mContextMenuHandler = new ContextMenuHandler(); 485146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 486d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan ScaleGestureDetector mScaleGestureDetector; 487d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 488146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 489146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * The initial state of the touch mode when we enter this view. 490146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 491146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int TOUCH_MODE_INITIAL_STATE = 0; 492146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 493146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 494146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Indicates we just received the touch event and we are waiting to see if 495146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * it is a tap or a scroll gesture. 496146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 497146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int TOUCH_MODE_DOWN = 1; 498146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 499146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 500146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Indicates the touch gesture is a vertical scroll 501146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 502146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int TOUCH_MODE_VSCROLL = 0x20; 503146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 504146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 505146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Indicates the touch gesture is a horizontal scroll 506146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 507146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int TOUCH_MODE_HSCROLL = 0x40; 508146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 509146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mTouchMode = TOUCH_MODE_INITIAL_STATE; 510146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 511146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 512146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * The selection modes are HIDDEN, PRESSED, SELECTED, and LONGPRESS. 513146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 514146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int SELECTION_HIDDEN = 0; 515ef2185bf0c7a80154a79788915db04d4f9e7ad4dMichael Chan private static final int SELECTION_PRESSED = 1; // D-pad down but not up yet 516146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int SELECTION_SELECTED = 2; 517146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int SELECTION_LONGPRESS = 3; 518146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 519146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int mSelectionMode = SELECTION_HIDDEN; 520146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 521146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private boolean mScrolling = false; 522146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 5234f58287a1e02325337e39073a50bbb880094099fRoboErik private float mInitialScrollX; 5244f58287a1e02325337e39073a50bbb880094099fRoboErik private float mInitialScrollY; 5252fda24534978f55711526dbde747aa50d68dec40RoboErik 5262fda24534978f55711526dbde747aa50d68dec40RoboErik // Animates the height of the allday region 5272fda24534978f55711526dbde747aa50d68dec40RoboErik ObjectAnimator mAlldayAnimator; 5282fda24534978f55711526dbde747aa50d68dec40RoboErik // Animates the height of events in the allday region 5292fda24534978f55711526dbde747aa50d68dec40RoboErik ObjectAnimator mAlldayEventAnimator; 5302fda24534978f55711526dbde747aa50d68dec40RoboErik // Animates the transparency of the more events text 5312fda24534978f55711526dbde747aa50d68dec40RoboErik ObjectAnimator mMoreAlldayEventsAnimator; 5322fda24534978f55711526dbde747aa50d68dec40RoboErik // whether or not an event is stopping because it was cancelled 5332fda24534978f55711526dbde747aa50d68dec40RoboErik private boolean mCancellingAnimations = false; 5342fda24534978f55711526dbde747aa50d68dec40RoboErik // tracks whether a touch originated in the allday area 5352fda24534978f55711526dbde747aa50d68dec40RoboErik private boolean mTouchStartedInAlldayArea = false; 5362fda24534978f55711526dbde747aa50d68dec40RoboErik 537ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan private CalendarController mController; 538ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan private ViewSwitcher mViewSwitcher; 539ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan private GestureDetector mGestureDetector; 5403f6328f579b05c02606572c777541b97aa04f9f3Michael Chan private OverScroller mScroller; 5412c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan private ScrollInterpolator mHScrollInterpolator; 542705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan 543d190418220467c02327dd9b3ae1eae238889720bMichael Chan public DayView(Context context, CalendarController controller, 54475d9b567e1fd3b9c6945cd0afe28781f5a19c6c8Michael Chan ViewSwitcher viewSwitcher, EventLoader eventLoader, int numDays) { 545ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan super(context); 5462fda24534978f55711526dbde747aa50d68dec40RoboErik mResources = context.getResources(); 54709b1b2e1e7eb9bc291d4e70c993471d3c9ffa799Michael Chan 548e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik DATE_HEADER_FONT_SIZE = (int) mResources.getDimension(R.dimen.date_header_text_size); 549e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik DAY_HEADER_FONT_SIZE = (int) mResources.getDimension(R.dimen.day_label_text_size); 550e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik ONE_DAY_HEADER_HEIGHT = (int) mResources.getDimension(R.dimen.one_day_header_height); 551e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik DAY_HEADER_BOTTOM_MARGIN = (int) mResources.getDimension(R.dimen.day_header_bottom_margin); 552e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik EXPAND_ALL_DAY_BOTTOM_MARGIN = (int) mResources.getDimension(R.dimen.all_day_bottom_margin); 553e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik HOURS_TEXT_SIZE = (int) mResources.getDimension(R.dimen.hours_text_size); 554e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik AMPM_TEXT_SIZE = (int) mResources.getDimension(R.dimen.ampm_text_size); 555e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik ALLDAY_TEXT_SIZE = (int) mResources.getDimension(R.dimen.allday_text_size); 556e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik MIN_HOURS_WIDTH = (int) mResources.getDimension(R.dimen.min_hours_width); 557e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik HOURS_LEFT_MARGIN = (int) mResources.getDimension(R.dimen.hours_left_margin); 558e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik HOURS_RIGHT_MARGIN = (int) mResources.getDimension(R.dimen.hours_right_margin); 559e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik MULTI_DAY_HEADER_HEIGHT = (int) mResources.getDimension(R.dimen.day_header_height); 56009b1b2e1e7eb9bc291d4e70c993471d3c9ffa799Michael Chan 561705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan if (mScale == 0) { 562e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 5632fda24534978f55711526dbde747aa50d68dec40RoboErik mScale = mResources.getDisplayMetrics().density; 564705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan if (mScale != 1) { 565705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan SINGLE_ALLDAY_HEIGHT *= mScale; 566705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan ALLDAY_TOP_MARGIN *= mScale; 567f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan MAX_HEIGHT_OF_ONE_ALLDAY_EVENT *= mScale; 568705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan 569705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan NORMAL_FONT_SIZE *= mScale; 570705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan EVENT_TEXT_FONT_SIZE *= mScale; 5718f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan GRID_LINE_LEFT_MARGIN *= mScale; 5728f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan HOURS_TOP_MARGIN *= mScale; 573705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan MIN_CELL_WIDTH_FOR_TEXT *= mScale; 574705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan MIN_EVENT_HEIGHT *= mScale; 5752fda24534978f55711526dbde747aa50d68dec40RoboErik MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT *= mScale; 5762fda24534978f55711526dbde747aa50d68dec40RoboErik MAX_UNEXPANDED_ALLDAY_HEIGHT *= mScale; 5772fda24534978f55711526dbde747aa50d68dec40RoboErik mAnimateDayEventHeight = (int) MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT; 578705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan 579bd0e834aea317236d574f8738fe11a51fdc87968Erik CURRENT_TIME_LINE_HEIGHT *= mScale; 580bd0e834aea317236d574f8738fe11a51fdc87968Erik CURRENT_TIME_LINE_BORDER_WIDTH *= mScale; 581bd0e834aea317236d574f8738fe11a51fdc87968Erik 582d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan MIN_Y_SPAN *= mScale; 583d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan MAX_CELL_HEIGHT *= mScale; 584697157470a6f0d8e7b806af9b4fb7fbe0bccae87Erik DEFAULT_CELL_HEIGHT *= mScale; 5853eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan DAY_HEADER_HEIGHT *= mScale; 5863eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan DAY_HEADER_LEFT_MARGIN *= mScale; 5873eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan DAY_HEADER_RIGHT_MARGIN *= mScale; 5883eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan DAY_HEADER_ONE_DAY_LEFT_MARGIN *= mScale; 5893eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan DAY_HEADER_ONE_DAY_RIGHT_MARGIN *= mScale; 5903eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan DAY_HEADER_ONE_DAY_BOTTOM_MARGIN *= mScale; 5913eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan CALENDAR_COLOR_SQUARE_SIZE *= mScale; 5923eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan EVENT_TEXT_TOP_MARGIN *= mScale; 5933eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan EVENT_TEXT_BOTTOM_MARGIN *= mScale; 5943eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan EVENT_TEXT_LEFT_MARGIN *= mScale; 5953eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan EVENT_TEXT_RIGHT_MARGIN *= mScale; 5969c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan EVENT_ALL_DAY_TEXT_TOP_MARGIN *= mScale; 5979c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN *= mScale; 5989c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan EVENT_ALL_DAY_TEXT_LEFT_MARGIN *= mScale; 5999c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan EVENT_ALL_DAY_TEXT_RIGHT_MARGIN *= mScale; 60011ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan EVENT_RECT_TOP_MARGIN *= mScale; 60111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan EVENT_RECT_BOTTOM_MARGIN *= mScale; 60225996100d6ea61888ebe54d7708a9a371bb12a55RoboErik ALL_DAY_EVENT_RECT_BOTTOM_MARGIN *= mScale; 60311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan EVENT_RECT_LEFT_MARGIN *= mScale; 60411ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan EVENT_RECT_RIGHT_MARGIN *= mScale; 60525996100d6ea61888ebe54d7708a9a371bb12a55RoboErik EVENT_RECT_STROKE_WIDTH *= mScale; 606cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik EXPAND_ALL_DAY_BOTTOM_MARGIN *= mScale; 6072fda24534978f55711526dbde747aa50d68dec40RoboErik EVENT_SQUARE_WIDTH *= mScale; 6082fda24534978f55711526dbde747aa50d68dec40RoboErik EVENT_LINE_PADDING *= mScale; 609705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan } 610705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan } 611e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik HOURS_MARGIN = HOURS_LEFT_MARGIN + HOURS_RIGHT_MARGIN; 612e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik DAY_HEADER_HEIGHT = numDays == 1 ? ONE_DAY_HEADER_HEIGHT : MULTI_DAY_HEADER_HEIGHT; 613705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan 6143eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan mCurrentTimeLine = mResources.getDrawable(R.drawable.timeline_week_holo_light); 6153eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan mTodayHeaderDrawable = mResources.getDrawable(R.drawable.today_blue_week_holo_light); 616cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik mExpandAlldayDrawable = mResources.getDrawable(R.drawable.ic_allday_expand_holo_light); 617cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik mCollapseAlldayDrawable = mResources.getDrawable(R.drawable.ic_allday_collapse_holo_light); 618f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan mAcceptedOrTentativeEventBoxDrawable = mResources 619f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan .getDrawable(R.drawable.panel_month_event_holo_light); 62025996100d6ea61888ebe54d7708a9a371bb12a55RoboErik 62125996100d6ea61888ebe54d7708a9a371bb12a55RoboErik mDeclinedBgDrawable = new BitmapDrawable(mResources, BitmapFactory.decodeResource( 62225996100d6ea61888ebe54d7708a9a371bb12a55RoboErik mResources, R.drawable.event_bg_declined)); 62325996100d6ea61888ebe54d7708a9a371bb12a55RoboErik mDeclinedBgDrawable.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT); 62425996100d6ea61888ebe54d7708a9a371bb12a55RoboErik 625ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan mEventLoader = eventLoader; 626146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEventGeometry = new EventGeometry(); 627146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEventGeometry.setMinEventHeight(MIN_EVENT_HEIGHT); 628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEventGeometry.setHourGap(HOUR_GAP); 629e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mEventGeometry.setCellMargin(DAY_GAP); 630ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan mContext = context; 6318f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan mAllDayString = mContext.getString(R.string.edit_event_all_day_label); 632ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan mDeleteEventHelper = new DeleteEventHelper(context, null, false /* don't exit when done */); 633666fc5e8ddbac15c951aad738bd818ee307eae42Erik mLastPopupEventID = INVALID_EVENT_ID; 634ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan mController = controller; 635ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan mViewSwitcher = viewSwitcher; 636ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan mGestureDetector = new GestureDetector(context, new CalendarGestureListener()); 637d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mScaleGestureDetector = new ScaleGestureDetector(getContext(), this); 63875d9b567e1fd3b9c6945cd0afe28781f5a19c6c8Michael Chan mNumDays = numDays; 639d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan if (mCellHeight == 0) { 640d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mCellHeight = Utils.getSharedPreference(mContext, 641d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan GeneralPreferences.KEY_DEFAULT_CELL_HEIGHT, DEFAULT_CELL_HEIGHT); 642d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 6433f6328f579b05c02606572c777541b97aa04f9f3Michael Chan mScroller = new OverScroller(context); 6442c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan mHScrollInterpolator = new ScrollInterpolator(); 645ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan init(context); 646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 647146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 648146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void init(Context context) { 649146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project setFocusable(true); 650146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 651146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Allow focus in touch mode so that we can do keyboard shortcuts 652146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // even after we've entered touch mode. 653146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project setFocusableInTouchMode(true); 654146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project setClickable(true); 655146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project setOnCreateContextMenuListener(this); 656146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 657487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mFirstDayOfWeek = Utils.getFirstDayOfWeek(context); 658146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 659731f1cb808b7586b93615b408ab2636081fab0dcErik mCurrentTime = new Time(Utils.getTimeZone(context, mTZUpdater)); 660bd0e834aea317236d574f8738fe11a51fdc87968Erik long currentTime = System.currentTimeMillis(); 661bd0e834aea317236d574f8738fe11a51fdc87968Erik mCurrentTime.set(currentTime); 662bd0e834aea317236d574f8738fe11a51fdc87968Erik //The % makes it go off at the next increment of 5 minutes. 663bd0e834aea317236d574f8738fe11a51fdc87968Erik postDelayed(mUpdateCurrentTime, 664bd0e834aea317236d574f8738fe11a51fdc87968Erik UPDATE_CURRENT_TIME_DELAY - (currentTime % UPDATE_CURRENT_TIME_DELAY)); 665bd0e834aea317236d574f8738fe11a51fdc87968Erik mTodayJulianDay = Time.getJulianDay(currentTime, mCurrentTime.gmtoff); 666bd0e834aea317236d574f8738fe11a51fdc87968Erik 66764b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok mWeek_saturdayColor = mResources.getColor(R.color.week_saturday); 66864b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok mWeek_sundayColor = mResources.getColor(R.color.week_sunday); 669d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan mCalendarDateBannerTextColor = mResources.getColor(R.color.calendar_date_banner_text_color); 670e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mTodayBgColor = mResources.getColor(R.color.calendar_today_bg_color); 671e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mBgColor = mResources.getColor(R.color.calendar_hour_background); 672d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan mCalendarAmPmLabel = mResources.getColor(R.color.calendar_ampm_label); 673ba902466b19b11d587468e354edc58e542707747Michael Chan mCalendarGridAreaSelected = mResources.getColor(R.color.calendar_grid_area_selected); 674e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mCalendarGridLineInnerHorizontalColor = mResources 675e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik .getColor(R.color.calendar_grid_line_inner_horizontal_color); 676e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mCalendarGridLineInnerVerticalColor = mResources 677e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik .getColor(R.color.calendar_grid_line_inner_vertical_color); 6788f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan mCalendarHourLabelColor = mResources.getColor(R.color.calendar_hour_label); 679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPressedColor = mResources.getColor(R.color.pressed); 680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEventTextColor = mResources.getColor(R.color.calendar_event_text_color); 681e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mMoreEventsTextColor = mResources.getColor(R.color.month_event_other_color); 68211638ad4fb56b978770aebe75deac7a0e6ac60d2Erik 683146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEventTextPaint.setTextSize(EVENT_TEXT_FONT_SIZE); 684146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEventTextPaint.setTextAlign(Paint.Align.LEFT); 685146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEventTextPaint.setAntiAlias(true); 686146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 687146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int gridLineColor = mResources.getColor(R.color.calendar_grid_line_highlight_color); 688146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Paint p = mSelectionPaint; 689146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setColor(gridLineColor); 6903937a47bc5a1afb9701e1d0565fae31f5800590dErik p.setStyle(Style.FILL); 691146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setAntiAlias(false); 692146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 693146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p = mPaint; 694146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setAntiAlias(true); 695146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 696146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Allocate space for 2 weeks worth of weekday names so that we can 697146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // easily start the week display at any week day. 698146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mDayStrs = new String[14]; 699146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 700146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Also create an array of 2-letter abbreviations. 701146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mDayStrs2Letter = new String[14]; 702146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 703146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) { 704146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int index = i - Calendar.SUNDAY; 705146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // e.g. Tue for Tuesday 706e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mDayStrs[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_MEDIUM) 707e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik .toUpperCase(); 708146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mDayStrs[index + 7] = mDayStrs[index]; 709146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // e.g. Tu for Tuesday 710e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mDayStrs2Letter[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_SHORT) 711e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik .toUpperCase(); 71252b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer 71352b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer // If we don't have 2-letter day strings, fall back to 1-letter. 71452b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer if (mDayStrs2Letter[index].equals(mDayStrs[index])) { 71552b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer mDayStrs2Letter[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_SHORTEST); 71652b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer } 71752b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer 718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mDayStrs2Letter[index + 7] = mDayStrs2Letter[index]; 719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 720146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Figure out how much space we need for the 3-letter abbrev names 722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // in the worst case. 7233eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setTextSize(DATE_HEADER_FONT_SIZE); 724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setTypeface(mBold); 725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String[] dateStrs = {" 28", " 30"}; 726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mDateStrWidth = computeMaxStringWidth(0, dateStrs, p); 7273eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setTextSize(DAY_HEADER_FONT_SIZE); 728146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mDateStrWidth += computeMaxStringWidth(0, mDayStrs, p); 729146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 730e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextSize(HOURS_TEXT_SIZE); 731146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setTypeface(null); 73261a2e87e7412281d17e86ccff4352cbf32fe77e7Michael Chan handleOnResume(); 733146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 734e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mAmString = DateUtils.getAMPMString(Calendar.AM).toUpperCase(); 735e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mPmString = DateUtils.getAMPMString(Calendar.PM).toUpperCase(); 736146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String[] ampm = {mAmString, mPmString}; 737e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextSize(AMPM_TEXT_SIZE); 738e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mHoursWidth = Math.max(HOURS_MARGIN, computeMaxStringWidth(mHoursWidth, ampm, p) 739e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik + HOURS_RIGHT_MARGIN); 7408f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan mHoursWidth = Math.max(MIN_HOURS_WIDTH, mHoursWidth); 741146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 742146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project LayoutInflater inflater; 743146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 744146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopupView = inflater.inflate(R.layout.bubble_event, null); 745146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopupView.setLayoutParams(new ViewGroup.LayoutParams( 746df279e3f9d5b0f189f812c52aca78d18178e4445Romain Guy ViewGroup.LayoutParams.MATCH_PARENT, 747146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ViewGroup.LayoutParams.WRAP_CONTENT)); 748146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup = new PopupWindow(context); 749146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup.setContentView(mPopupView); 750146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Resources.Theme dialogTheme = getResources().newTheme(); 751146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project dialogTheme.applyStyle(android.R.style.Theme_Dialog, true); 752146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project TypedArray ta = dialogTheme.obtainStyledAttributes(new int[] { 753146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project android.R.attr.windowBackground }); 754146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup.setBackgroundDrawable(ta.getDrawable(0)); 755146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ta.recycle(); 756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Enable touching the popup window 758146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopupView.setOnClickListener(this); 759cd405a28e6821b116dcf3c531805d0c90b6cc08cErik // Catch long clicks for creating a new event 760cd405a28e6821b116dcf3c531805d0c90b6cc08cErik setOnLongClickListener(this); 761146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 762731f1cb808b7586b93615b408ab2636081fab0dcErik mBaseDate = new Time(Utils.getTimeZone(context, mTZUpdater)); 763146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long millis = System.currentTimeMillis(); 764146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mBaseDate.set(millis); 765146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 766146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEarliestStartHour = new int[mNumDays]; 767146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mHasAllDayEvent = new boolean[mNumDays]; 76802041687c35441e8a21cb763f1fc3a26525292efDavid Brown 76902041687c35441e8a21cb763f1fc3a26525292efDavid Brown // mLines is the array of points used with Canvas.drawLines() in 77002041687c35441e8a21cb763f1fc3a26525292efDavid Brown // drawGridBackground() and drawAllDayEvents(). Its size depends 77102041687c35441e8a21cb763f1fc3a26525292efDavid Brown // on the max number of lines that can ever be drawn by any single 77202041687c35441e8a21cb763f1fc3a26525292efDavid Brown // drawLines() call in either of those methods. 77302041687c35441e8a21cb763f1fc3a26525292efDavid Brown final int maxGridLines = (24 + 1) // max horizontal lines we might draw 774e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik + (mNumDays + 1); // max vertical lines we might draw 77502041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines = new float[maxGridLines * 4]; 776146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 777146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * This is called when the popup window is pressed. 780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 781146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void onClick(View v) { 782146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (v == mPopupView) { 783146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Pretend it was a trackball click because that will always 784146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // jump to the "View event" screen. 785146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project switchViews(true /* trackball */); 786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 787146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 788146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 78961a2e87e7412281d17e86ccff4352cbf32fe77e7Michael Chan public void handleOnResume() { 790ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan mIs24HourFormat = DateFormat.is24HourFormat(mContext); 79169ab334d6988eda70ba53618506d23ebf7d7b405Erik mHourStrs = mIs24HourFormat ? CalendarData.s24Hours : CalendarData.s12HoursNoAmPm; 79261a2e87e7412281d17e86ccff4352cbf32fe77e7Michael Chan mFirstDayOfWeek = Utils.getFirstDayOfWeek(mContext); 79369ab334d6988eda70ba53618506d23ebf7d7b405Erik } 79469ab334d6988eda70ba53618506d23ebf7d7b405Erik 795146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 796146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Returns the start of the selected time in milliseconds since the epoch. 797146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * @return selected time in UTC milliseconds since the epoch. 799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long getSelectedTimeInMillis() { 801146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Time time = new Time(mBaseDate); 802146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project time.setJulianDay(mSelectionDay); 803146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project time.hour = mSelectionHour; 804146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 805146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // We ignore the "isDst" field because we want normalize() to figure 806146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // out the correct DST value and not adjust the selected time based 807146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // on the current setting of DST. 808146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return time.normalize(true /* ignore isDst */); 809146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 810146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 811146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Time getSelectedTime() { 812146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Time time = new Time(mBaseDate); 813146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project time.setJulianDay(mSelectionDay); 814146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project time.hour = mSelectionHour; 815146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 816146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // We ignore the "isDst" field because we want normalize() to figure 817146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // out the correct DST value and not adjust the selected time based 818146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // on the current setting of DST. 819146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project time.normalize(true /* ignore isDst */); 820146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return time; 821146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 822146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 823146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 824146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Returns the start of the selected time in minutes since midnight, 825146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * local time. The derived class must ensure that this is consistent 826146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * with the return value from getSelectedTimeInMillis(). 827146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 828146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int getSelectedMinutesSinceMidnight() { 829146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return mSelectionHour * MINUTES_PER_HOUR; 830146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 831146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 83246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int getFirstVisibleHour() { 83346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return mFirstHour; 83446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 83546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 83646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan void setFirstVisibleHour(int firstHour) { 83746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mFirstHour = firstHour; 83846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mFirstHourOffset = 0; 83946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 84046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 84146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan public void setSelected(Time time, boolean ignoreTime) { 842146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mBaseDate.set(time); 843146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionHour = mBaseDate.hour; 844146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvent = null; 845146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevSelectedEvent = null; 846146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long millis = mBaseDate.toMillis(false /* use isDst */); 847146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionDay = Time.getJulianDay(millis, mBaseDate.gmtoff); 848146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvents.clear(); 849146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mComputeSelectedEvents = true; 850146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 85146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int gotoY = Integer.MIN_VALUE; 85246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 85346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (!ignoreTime && mGridAreaHeight != -1) { 85446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int lastHour = 0; 85546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 85646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mBaseDate.hour < mFirstHour) { 85746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // Above visible region 85846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan gotoY = mBaseDate.hour * (mCellHeight + HOUR_GAP); 85946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } else { 86046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan lastHour = (mGridAreaHeight - mFirstHourOffset) / (mCellHeight + HOUR_GAP) 86146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan + mFirstHour; 86246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 86346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mBaseDate.hour >= lastHour) { 86446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // Below visible region 86546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 86646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // target hour + 1 (to give it room to see the event) - 86746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // grid height (to get the y of the top of the visible 86846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // region) 86955a26d7062d5aa1a1b001b7271bb137276ab807eErik gotoY = (int) ((mBaseDate.hour + 1 + mBaseDate.minute / 60.0f) 87046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan * (mCellHeight + HOUR_GAP) - mGridAreaHeight); 87146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 87246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 87346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 87446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (DEBUG) { 87546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan Log.e(TAG, "Go " + gotoY + " 1st " + mFirstHour + ":" + mFirstHourOffset + "CH " 87646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan + (mCellHeight + HOUR_GAP) + " lh " + lastHour + " gh " + mGridAreaHeight 87746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan + " ymax " + mMaxViewStartY); 87846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 87946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 88046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (gotoY > mMaxViewStartY) { 88146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan gotoY = mMaxViewStartY; 88246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } else if (gotoY < 0 && gotoY != Integer.MIN_VALUE) { 88346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan gotoY = 0; 88446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 88546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 88646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 887146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project recalc(); 888146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 889ef2185bf0c7a80154a79788915db04d4f9e7ad4dMichael Chan // Don't draw the selection box if we are going to the "current" time 890ef2185bf0c7a80154a79788915db04d4f9e7ad4dMichael Chan long currMillis = System.currentTimeMillis(); 891ef2185bf0c7a80154a79788915db04d4f9e7ad4dMichael Chan boolean recent = (currMillis - 10000) < millis && millis < currMillis; 89246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mSelectionMode = (recent || ignoreTime) ? SELECTION_HIDDEN : SELECTION_SELECTED; 893146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mRemeasure = true; 894146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 89546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 89646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (gotoY != Integer.MIN_VALUE) { 89746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan TypeEvaluator evaluator = new TypeEvaluator() { 89846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan @Override 89946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan public Object evaluate(float fraction, Object startValue, Object endValue) { 90046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int start = (Integer) startValue; 90146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int end = (Integer) endValue; 90246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan final int newValue = (int) ((end - start) * fraction + start); 90346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan setViewStartY(newValue); 90446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return new Integer(newValue); 90546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 90646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan }; 90746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan ValueAnimator scrollAnim = ObjectAnimator.ofObject(evaluator, new Integer(mViewStartY), 90846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan new Integer(gotoY)); 90946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan// TODO The following line is supposed to replace the two statements above. 91046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan// Need to investigate why it's not working. 91146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 91246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan// ValueAnimator scrollAnim = ObjectAnimator.ofInt(this, "viewStartY", mViewStartY, gotoY); 91346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan scrollAnim.setDuration(200); 91446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan scrollAnim.setInterpolator(new AccelerateDecelerateInterpolator()); 91546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan scrollAnim.addListener(mAnimatorListener); 91646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan scrollAnim.start(); 91746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 91846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 91946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 92046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan public void setViewStartY(int viewStartY) { 92146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (viewStartY > mMaxViewStartY) { 92246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan viewStartY = mMaxViewStartY; 92346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 92446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 92546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mViewStartY = viewStartY; 92646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 92746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan computeFirstHour(); 92846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan invalidate(); 929146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 930146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 931146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public Time getSelectedDay() { 932146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Time time = new Time(mBaseDate); 933146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project time.setJulianDay(mSelectionDay); 934146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project time.hour = mSelectionHour; 935146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 936146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // We ignore the "isDst" field because we want normalize() to figure 937146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // out the correct DST value and not adjust the selected time based 938146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // on the current setting of DST. 939146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project time.normalize(true /* ignore isDst */); 940146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return time; 941146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 942146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 943eaafa2b48be7194a61754604ae37b3d62e9118d8Erik public void updateTitle() { 944eaafa2b48be7194a61754604ae37b3d62e9118d8Erik Time start = new Time(mBaseDate); 945eaafa2b48be7194a61754604ae37b3d62e9118d8Erik start.normalize(true); 946eaafa2b48be7194a61754604ae37b3d62e9118d8Erik Time end = new Time(start); 947eaafa2b48be7194a61754604ae37b3d62e9118d8Erik end.monthDay += mNumDays - 1; 948eaafa2b48be7194a61754604ae37b3d62e9118d8Erik // Move it forward one minute so the formatter doesn't lose a day 949eaafa2b48be7194a61754604ae37b3d62e9118d8Erik end.minute += 1; 950eaafa2b48be7194a61754604ae37b3d62e9118d8Erik end.normalize(true); 951eaafa2b48be7194a61754604ae37b3d62e9118d8Erik 9529e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan long formatFlags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR; 9539e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan if (mNumDays != 1) { 9549e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan // Don't show day of the month if for multi-day view 9559e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan formatFlags |= DateUtils.FORMAT_NO_MONTH_DAY; 9569e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan 9579e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan // Abbreviate the month if showing multiple months 9589e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan if (start.month != end.month) { 9599e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan formatFlags |= DateUtils.FORMAT_ABBREV_MONTH; 9609e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan } 9619e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan } 9629e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan 963f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan mController.sendEvent(this, EventType.UPDATE_TITLE, start, end, null, -1, ViewType.CURRENT, 9649e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan formatFlags, null, null); 965eaafa2b48be7194a61754604ae37b3d62e9118d8Erik } 966eaafa2b48be7194a61754604ae37b3d62e9118d8Erik 96783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan /** 968487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan * return a negative number if "time" is comes before the visible time 969487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan * range, a positive number if "time" is after the visible time range, and 0 970487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan * if it is in the visible time range. 97183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan */ 972487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan public int compareToVisibleTimeRange(Time time) { 973487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan 974487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan int savedHour = mBaseDate.hour; 975487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan int savedMinute = mBaseDate.minute; 976487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan int savedSec = mBaseDate.second; 977487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan 978487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mBaseDate.hour = 0; 979487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mBaseDate.minute = 0; 980487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mBaseDate.second = 0; 981487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan 982030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown if (DEBUG) { 983030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown Log.d(TAG, "Begin " + mBaseDate.toString()); 984030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown Log.d(TAG, "Diff " + time.toString()); 985030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown } 986487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan 98783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan // Compare beginning of range 98883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan int diff = Time.compare(time, mBaseDate); 989487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan if (diff > 0) { 990487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan // Compare end of range 991487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mBaseDate.monthDay += mNumDays; 992487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mBaseDate.normalize(true); 993487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan diff = Time.compare(time, mBaseDate); 994487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan 995030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown if (DEBUG) Log.d(TAG, "End " + mBaseDate.toString()); 996487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan 997487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mBaseDate.monthDay -= mNumDays; 998487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mBaseDate.normalize(true); 999487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan if (diff < 0) { 1000487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan // in visible time 1001487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan diff = 0; 1002487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan } else if (diff == 0) { 1003487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan // Midnight of following day 1004487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan diff = 1; 1005487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan } 100683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan } 100783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan 1008030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown if (DEBUG) Log.d(TAG, "Diff: " + diff); 100983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan 1010487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mBaseDate.hour = savedHour; 1011487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mBaseDate.minute = savedMinute; 1012487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mBaseDate.second = savedSec; 1013487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan return diff; 101483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan } 101583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan 1016146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void recalc() { 1017146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Set the base date to the beginning of the week if we are displaying 1018146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // 7 days at a time. 1019146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mNumDays == 7) { 10206d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan adjustToBeginningOfWeek(mBaseDate); 1021146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1022146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1023146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project final long start = mBaseDate.toMillis(false /* use isDst */); 1024146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mFirstJulianDay = Time.getJulianDay(start, mBaseDate.gmtoff); 1025146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mLastJulianDay = mFirstJulianDay + mNumDays - 1; 1026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mMonthLength = mBaseDate.getActualMaximum(Time.MONTH_DAY); 1028487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mFirstVisibleDate = mBaseDate.monthDay; 1029487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mFirstVisibleDayOfWeek = mBaseDate.weekDay; 1030146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1031146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 10326d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan private void adjustToBeginningOfWeek(Time time) { 10336d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan int dayOfWeek = time.weekDay; 10346d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan int diff = dayOfWeek - mFirstDayOfWeek; 10356d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan if (diff != 0) { 10366d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan if (diff < 0) { 10376d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan diff += 7; 10386d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 10396d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan time.monthDay -= diff; 10406d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan time.normalize(true /* ignore isDst */); 10416d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 10426d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 10436d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 1044146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project @Override 1045146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project protected void onSizeChanged(int width, int height, int oldw, int oldh) { 1046146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewWidth = width; 1047146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewHeight = height; 1048146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int gridAreaWidth = width - mHoursWidth; 1049146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mCellWidth = (gridAreaWidth - (mNumDays * DAY_GAP)) / mNumDays; 1050146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1051d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan // This would be about 1 day worth in a 7 day view 1052d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan mHorizontalSnapBackThreshold = width / 7; 1053d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan 1054146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Paint p = new Paint(); 1055e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextSize(HOURS_TEXT_SIZE); 1056146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mHoursTextHeight = (int) Math.abs(p.ascent()); 1057146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project remeasure(width, height); 1058146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1059146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 106046b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa /** 106146b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa * Measures the space needed for various parts of the view after 106246b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa * loading new events. This can change if there are all-day events. 106346b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa */ 1064146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void remeasure(int width, int height) { 10652fda24534978f55711526dbde747aa50d68dec40RoboErik // Shrink to fit available space but make sure we can display at least two events 10662fda24534978f55711526dbde747aa50d68dec40RoboErik MAX_UNEXPANDED_ALLDAY_HEIGHT = (int) (MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT * 4); 10672fda24534978f55711526dbde747aa50d68dec40RoboErik MAX_UNEXPANDED_ALLDAY_HEIGHT = Math.min(MAX_UNEXPANDED_ALLDAY_HEIGHT, height / 6); 10682fda24534978f55711526dbde747aa50d68dec40RoboErik MAX_UNEXPANDED_ALLDAY_HEIGHT = Math.max(MAX_UNEXPANDED_ALLDAY_HEIGHT, 10692fda24534978f55711526dbde747aa50d68dec40RoboErik (int) MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT * 2); 10702fda24534978f55711526dbde747aa50d68dec40RoboErik mMaxUnexpandedAlldayEventCount = 10712fda24534978f55711526dbde747aa50d68dec40RoboErik (int) (MAX_UNEXPANDED_ALLDAY_HEIGHT / MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT); 1072146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1073146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // First, clear the array of earliest start times, and the array 1074146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // indicating presence of an all-day event. 1075146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int day = 0; day < mNumDays; day++) { 1076146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEarliestStartHour[day] = 25; // some big number 1077146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mHasAllDayEvent[day] = false; 1078146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1079146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 10802fda24534978f55711526dbde747aa50d68dec40RoboErik int maxAllDayEvents = mMaxAlldayEvents; 1081c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa 10822fda24534978f55711526dbde747aa50d68dec40RoboErik // The min is where 24 hours cover the entire visible area 10837939fa59d64c1e6ac95f352e24d761dbacf67547RoboErik mMinCellHeight = Math.max((height - DAY_HEADER_HEIGHT) / 24, (int) MIN_EVENT_HEIGHT); 10842fda24534978f55711526dbde747aa50d68dec40RoboErik if (mCellHeight < mMinCellHeight) { 10852fda24534978f55711526dbde747aa50d68dec40RoboErik mCellHeight = mMinCellHeight; 1086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1087146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 10889c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan // Calculate mAllDayHeight 10893eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan mFirstCell = DAY_HEADER_HEIGHT; 1090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int allDayHeight = 0; 1091146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (maxAllDayEvents > 0) { 10922fda24534978f55711526dbde747aa50d68dec40RoboErik int maxAllAllDayHeight = height - DAY_HEADER_HEIGHT - MIN_HOURS_HEIGHT; 1093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If there is at most one all-day event per day, then use less 1094146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // space (but more than the space for a single event). 1095146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (maxAllDayEvents == 1) { 1096146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project allDayHeight = SINGLE_ALLDAY_HEIGHT; 10972fda24534978f55711526dbde747aa50d68dec40RoboErik } else if (maxAllDayEvents <= mMaxUnexpandedAlldayEventCount){ 1098146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Allow the all-day area to grow in height depending on the 1099146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // number of all-day events we need to show, up to a limit. 1100f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan allDayHeight = maxAllDayEvents * MAX_HEIGHT_OF_ONE_ALLDAY_EVENT; 11012fda24534978f55711526dbde747aa50d68dec40RoboErik if (allDayHeight > MAX_UNEXPANDED_ALLDAY_HEIGHT) { 11022fda24534978f55711526dbde747aa50d68dec40RoboErik allDayHeight = MAX_UNEXPANDED_ALLDAY_HEIGHT; 11032fda24534978f55711526dbde747aa50d68dec40RoboErik } 11042fda24534978f55711526dbde747aa50d68dec40RoboErik } else { 11052fda24534978f55711526dbde747aa50d68dec40RoboErik // if we have more than the magic number, check if we're animating 11062fda24534978f55711526dbde747aa50d68dec40RoboErik // and if not adjust the sizes appropriately 11072fda24534978f55711526dbde747aa50d68dec40RoboErik if (mAnimateDayHeight != 0) { 11082fda24534978f55711526dbde747aa50d68dec40RoboErik // Don't shrink the space past the final allDay space. The animation 11092fda24534978f55711526dbde747aa50d68dec40RoboErik // continues to hide the last event so the more events text can 11102fda24534978f55711526dbde747aa50d68dec40RoboErik // fade in. 11112fda24534978f55711526dbde747aa50d68dec40RoboErik allDayHeight = Math.max(mAnimateDayHeight, MAX_UNEXPANDED_ALLDAY_HEIGHT); 11122fda24534978f55711526dbde747aa50d68dec40RoboErik } else { 11132fda24534978f55711526dbde747aa50d68dec40RoboErik // Try to fit all the events in 11142fda24534978f55711526dbde747aa50d68dec40RoboErik allDayHeight = (int) (maxAllDayEvents * MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT); 11152fda24534978f55711526dbde747aa50d68dec40RoboErik // But clip the area depending on which mode we're in 11162fda24534978f55711526dbde747aa50d68dec40RoboErik if (!mShowAllAllDayEvents && allDayHeight > MAX_UNEXPANDED_ALLDAY_HEIGHT) { 1117e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik allDayHeight = (int) (mMaxUnexpandedAlldayEventCount * 1118e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT); 11192fda24534978f55711526dbde747aa50d68dec40RoboErik } else if (allDayHeight > maxAllAllDayHeight) { 11202fda24534978f55711526dbde747aa50d68dec40RoboErik allDayHeight = maxAllAllDayHeight; 11212fda24534978f55711526dbde747aa50d68dec40RoboErik } 1122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 11243eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan mFirstCell = DAY_HEADER_HEIGHT + allDayHeight + ALLDAY_TOP_MARGIN; 1125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 11262fda24534978f55711526dbde747aa50d68dec40RoboErik mSelectionAllday = false; 1127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 11282fda24534978f55711526dbde747aa50d68dec40RoboErik mAlldayHeight = allDayHeight; 1129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mGridAreaHeight = height - mFirstCell; 1131d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 11322fda24534978f55711526dbde747aa50d68dec40RoboErik // Set up the expand icon position 1133e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int allDayIconWidth = mExpandAlldayDrawable.getIntrinsicWidth(); 1134e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mExpandAllDayRect.left = Math.max((mHoursWidth - allDayIconWidth) / 2, 1135e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik EVENT_ALL_DAY_TEXT_LEFT_MARGIN); 1136e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mExpandAllDayRect.right = Math.min(mExpandAllDayRect.left + allDayIconWidth, mHoursWidth 1137e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik - EVENT_ALL_DAY_TEXT_RIGHT_MARGIN); 1138cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik mExpandAllDayRect.bottom = mFirstCell - EXPAND_ALL_DAY_BOTTOM_MARGIN; 1139e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mExpandAllDayRect.top = mExpandAllDayRect.bottom 1140e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik - mExpandAlldayDrawable.getIntrinsicHeight(); 1141e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 1142e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // Cause the allDay text to be relaid out on the next draw pass 1143e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mAllDayTextLayout = null; 1144e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 1145d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 114646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mNumHours = mGridAreaHeight / (mCellHeight + HOUR_GAP); 1147146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEventGeometry.setHourHeight(mCellHeight); 1148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 114927d671cdba3e8b50219def2c9e1118abe987f908Daisuke Miyakawa final long minimumDurationMillis = (long) 115027d671cdba3e8b50219def2c9e1118abe987f908Daisuke Miyakawa (MIN_EVENT_HEIGHT * DateUtils.MINUTE_IN_MILLIS / (mCellHeight / 60.0f)); 11512fda24534978f55711526dbde747aa50d68dec40RoboErik Event.computePositions(mEvents, minimumDurationMillis); 115246b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa 1153c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // Compute the top of our reachable view 1154c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik mMaxViewStartY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP) - mGridAreaHeight; 1155d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan if (DEBUG) { 1156d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan Log.e(TAG, "mViewStartY: " + mViewStartY); 1157d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan Log.e(TAG, "mMaxViewStartY: " + mMaxViewStartY); 1158d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 1159d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan if (mViewStartY > mMaxViewStartY) { 1160d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mViewStartY = mMaxViewStartY; 1161d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan computeFirstHour(); 1162d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 1163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mFirstHour == -1) { 1165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project initFirstHour(); 1166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mFirstHourOffset = 0; 1167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // When we change the base date, the number of all-day events may 1170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // change and that changes the cell height. When we switch dates, 1171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // we use the mFirstHourOffset from the previous view, but that may 1172146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // be too large for the new view if the cell height is smaller. 1173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mFirstHourOffset >= mCellHeight + HOUR_GAP) { 1174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mFirstHourOffset = mCellHeight + HOUR_GAP - 1; 1175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartY = mFirstHour * (mCellHeight + HOUR_GAP) - mFirstHourOffset; 1177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 117846b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa final int eventAreaWidth = mNumDays * (mCellWidth + DAY_GAP); 1179666fc5e8ddbac15c951aad738bd818ee307eae42Erik //When we get new events we don't want to dismiss the popup unless the event changes 1180666fc5e8ddbac15c951aad738bd818ee307eae42Erik if (mSelectedEvent != null && mLastPopupEventID != mSelectedEvent.id) { 1181666fc5e8ddbac15c951aad738bd818ee307eae42Erik mPopup.dismiss(); 1182666fc5e8ddbac15c951aad738bd818ee307eae42Erik } 1183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup.setWidth(eventAreaWidth - 20); 1184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup.setHeight(WindowManager.LayoutParams.WRAP_CONTENT); 1185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 1188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Initialize the state for another view. The given view is one that has 1189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * its own bitmap and will use an animation to replace the current view. 1190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * The current view and new view are either both Week views or both Day 1191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * views. They differ in their base date. 1192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 1193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * @param view the view to initialize. 1194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 1195d190418220467c02327dd9b3ae1eae238889720bMichael Chan private void initView(DayView view) { 1196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.mSelectionHour = mSelectionHour; 1197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.mSelectedEvents.clear(); 1198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.mComputeSelectedEvents = true; 1199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.mFirstHour = mFirstHour; 1200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.mFirstHourOffset = mFirstHourOffset; 1201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.remeasure(getWidth(), getHeight()); 12022fda24534978f55711526dbde747aa50d68dec40RoboErik view.initAllDayHeights(); 1203e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 1204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.mSelectedEvent = null; 1205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.mPrevSelectedEvent = null; 1206487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan view.mFirstDayOfWeek = mFirstDayOfWeek; 1207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (view.mEvents.size() > 0) { 12082fda24534978f55711526dbde747aa50d68dec40RoboErik view.mSelectionAllday = mSelectionAllday; 1209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 12102fda24534978f55711526dbde747aa50d68dec40RoboErik view.mSelectionAllday = false; 1211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Redraw the screen so that the selection box will be redrawn. We may 1214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // have scrolled to a different part of the day in some other view 1215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // so the selection box in this view may no longer be visible. 1216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.recalc(); 1217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 1220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Switch to another view based on what was selected (an event or a free 1221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * slot) and how it was selected (by touch or by trackball). 1222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 1223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * @param trackBallSelection true if the selection was made using the 1224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * trackball. 1225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 1226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void switchViews(boolean trackBallSelection) { 1227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event selectedEvent = mSelectedEvent; 1228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup.dismiss(); 1230666fc5e8ddbac15c951aad738bd818ee307eae42Erik mLastPopupEventID = INVALID_EVENT_ID; 1231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mNumDays > 1) { 1232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This is the Week view. 1233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // With touch, we always switch to Day/Agenda View 1234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // With track ball, if we selected a free slot, then create an event. 1235146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If we selected a specific event, switch to EventInfo view. 1236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (trackBallSelection) { 1237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (selectedEvent == null) { 1238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Switch to the EditEvent view 1239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long startMillis = getSelectedTimeInMillis(); 1240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS; 12419e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1, 124287f993ff96172f508d3f241f8a425f953c7eb739RoboErik startMillis, endMillis, 0, 0, -1); 1243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 1244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Switch to the EventInfo view 12459e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id, 124687f993ff96172f508d3f241f8a425f953c7eb739RoboErik selectedEvent.startMillis, selectedEvent.endMillis, 0, 0, 124787f993ff96172f508d3f241f8a425f953c7eb739RoboErik getSelectedTimeInMillis()); 1248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 1250146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This was a touch selection. If the touch selected a single 1251146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // unambiguous event, then view that event. Otherwise go to 1252146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Day/Agenda view. 1253146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectedEvents.size() == 1) { 12549e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id, 125587f993ff96172f508d3f241f8a425f953c7eb739RoboErik selectedEvent.startMillis, selectedEvent.endMillis, 0, 0, 125687f993ff96172f508d3f241f8a425f953c7eb739RoboErik getSelectedTimeInMillis()); 1257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 1260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This is the Day view. 1261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If we selected a free slot, then create an event. 1262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If we selected an event, then go to the EventInfo view. 1263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (selectedEvent == null) { 1264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Switch to the EditEvent view 1265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long startMillis = getSelectedTimeInMillis(); 1266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS; 12679e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan 12689e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1, startMillis, 126987f993ff96172f508d3f241f8a425f953c7eb739RoboErik endMillis, 0, 0, -1); 1270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 12719e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id, 127287f993ff96172f508d3f241f8a425f953c7eb739RoboErik selectedEvent.startMillis, selectedEvent.endMillis, 0, 0, 127387f993ff96172f508d3f241f8a425f953c7eb739RoboErik getSelectedTimeInMillis()); 1274146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project @Override 1279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public boolean onKeyUp(int keyCode, KeyEvent event) { 1280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mScrolling = false; 1281146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long duration = event.getEventTime() - event.getDownTime(); 1282146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1283146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project switch (keyCode) { 1284146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project case KeyEvent.KEYCODE_DPAD_CENTER: 1285146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionMode == SELECTION_HIDDEN) { 1286146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Don't do anything unless the selection is visible. 1287146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project break; 1288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1289146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionMode == SELECTION_PRESSED) { 1291146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This was the first press when there was nothing selected. 1292146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Change the selection from the "pressed" state to the 1293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // the "selected" state. We treat short-press and 1294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // long-press the same here because nothing was selected. 1295146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionMode = SELECTION_SELECTED; 1296146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 1297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project break; 1298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Check the duration to determine if this was a short press 1301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (duration < ViewConfiguration.getLongPressTimeout()) { 1302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project switchViews(true /* trackball */); 1303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 1304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionMode = SELECTION_LONGPRESS; 1305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 1306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project performLongClick(); 1307146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project break; 1309ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// case KeyEvent.KEYCODE_BACK: 1310ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// if (event.isTracking() && !event.isCanceled()) { 1311ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// mPopup.dismiss(); 1312ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// mContext.finish(); 1313ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// return true; 1314ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// } 1315ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// break; 1316146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1317146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return super.onKeyUp(keyCode, event); 1318146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project @Override 1321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public boolean onKeyDown(int keyCode, KeyEvent event) { 1322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionMode == SELECTION_HIDDEN) { 1323146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT 1324146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project || keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_UP 1325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { 1326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Display the selection box but don't move or select it 1327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // on this key press. 1328146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionMode = SELECTION_SELECTED; 1329146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 1330146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return true; 1331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { 1332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Display the selection box but don't select it 1333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // on this key press. 1334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionMode = SELECTION_PRESSED; 1335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 1336146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return true; 1337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionMode = SELECTION_SELECTED; 1341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mScrolling = false; 1342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project boolean redraw; 1343146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int selectionDay = mSelectionDay; 1344146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project switch (keyCode) { 134646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case KeyEvent.KEYCODE_DEL: 134746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // Delete the selected event, if any 134846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan Event selectedEvent = mSelectedEvent; 134946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (selectedEvent == null) { 135046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return false; 135146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 135246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mPopup.dismiss(); 135346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mLastPopupEventID = INVALID_EVENT_ID; 1354146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 135546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan long begin = selectedEvent.startMillis; 135646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan long end = selectedEvent.endMillis; 135746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan long id = selectedEvent.id; 135846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mDeleteEventHelper.delete(begin, end, id, -1); 1359b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan return true; 136046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case KeyEvent.KEYCODE_ENTER: 136146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan switchViews(true /* trackball or keyboard */); 136246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return true; 136346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case KeyEvent.KEYCODE_BACK: 136446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (event.getRepeatCount() == 0) { 136546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan event.startTracking(); 136646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return true; 136746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 136846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return super.onKeyDown(keyCode, event); 136946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case KeyEvent.KEYCODE_DPAD_LEFT: 137046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mSelectedEvent != null) { 137146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mSelectedEvent = mSelectedEvent.nextLeft; 137246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 137346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mSelectedEvent == null) { 137446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mLastPopupEventID = INVALID_EVENT_ID; 137546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan selectionDay -= 1; 137646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 137746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan redraw = true; 137846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan break; 1379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 138046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case KeyEvent.KEYCODE_DPAD_RIGHT: 138146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mSelectedEvent != null) { 138246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mSelectedEvent = mSelectedEvent.nextRight; 138346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 138446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mSelectedEvent == null) { 138546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mLastPopupEventID = INVALID_EVENT_ID; 138646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan selectionDay += 1; 138746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 138846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan redraw = true; 138946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan break; 1390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 139146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case KeyEvent.KEYCODE_DPAD_UP: 139246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mSelectedEvent != null) { 139346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mSelectedEvent = mSelectedEvent.nextUp; 1394146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 139546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mSelectedEvent == null) { 139646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mLastPopupEventID = INVALID_EVENT_ID; 13972fda24534978f55711526dbde747aa50d68dec40RoboErik if (!mSelectionAllday) { 139846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mSelectionHour -= 1; 139946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan adjustHourSelection(); 140046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mSelectedEvents.clear(); 140146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mComputeSelectedEvents = true; 140246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 140346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 140446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan redraw = true; 140546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan break; 1406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 140746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case KeyEvent.KEYCODE_DPAD_DOWN: 140846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mSelectedEvent != null) { 140946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mSelectedEvent = mSelectedEvent.nextDown; 1410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 141146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mSelectedEvent == null) { 141246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mLastPopupEventID = INVALID_EVENT_ID; 14132fda24534978f55711526dbde747aa50d68dec40RoboErik if (mSelectionAllday) { 14142fda24534978f55711526dbde747aa50d68dec40RoboErik mSelectionAllday = false; 141546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } else { 141646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mSelectionHour++; 141746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan adjustHourSelection(); 141846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mSelectedEvents.clear(); 141946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mComputeSelectedEvents = true; 142046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 142146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 142246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan redraw = true; 142346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan break; 1424146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 142546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan default: 142646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return super.onKeyDown(keyCode, event); 1427146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1428146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1429146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if ((selectionDay < mFirstJulianDay) || (selectionDay > mLastJulianDay)) { 1430d190418220467c02327dd9b3ae1eae238889720bMichael Chan DayView view = (DayView) mViewSwitcher.getNextView(); 1431146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Time date = view.mBaseDate; 1432146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project date.set(mBaseDate); 1433146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (selectionDay < mFirstJulianDay) { 1434146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project date.monthDay -= mNumDays; 1435146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 1436146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project date.monthDay += mNumDays; 1437146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1438146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project date.normalize(true /* ignore isDst */); 1439146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.mSelectionDay = selectionDay; 1440146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1441146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project initView(view); 144283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan 144383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan Time end = new Time(date); 144483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan end.monthDay += mNumDays - 1; 14453458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan mController.sendEvent(this, EventType.GO_TO, date, end, -1, ViewType.CURRENT); 1446146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return true; 1447146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 144804b288958078f8b29870dcbb2239df448c559610Erik if (mSelectionDay != selectionDay) { 144904b288958078f8b29870dcbb2239df448c559610Erik Time date = new Time(mBaseDate); 145004b288958078f8b29870dcbb2239df448c559610Erik date.setJulianDay(selectionDay); 145104b288958078f8b29870dcbb2239df448c559610Erik date.hour = mSelectionHour; 145204b288958078f8b29870dcbb2239df448c559610Erik mController.sendEvent(this, EventType.GO_TO, date, date, -1, ViewType.CURRENT); 145304b288958078f8b29870dcbb2239df448c559610Erik } 1454146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionDay = selectionDay; 1455146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvents.clear(); 1456146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mComputeSelectedEvents = true; 14578307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik mUpdateToast = true; 1458146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1459146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (redraw) { 1460146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 1461146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return true; 1462146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1463146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1464146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return super.onKeyDown(keyCode, event); 1465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1466146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1467259b8f9a21fffd3858218581e9daaf689b6b888fErik private class AccessibilityRunnable implements Runnable { 1468259b8f9a21fffd3858218581e9daaf689b6b888fErik int mEventType = AccessibilityEvent.TYPE_VIEW_SELECTED; 1469259b8f9a21fffd3858218581e9daaf689b6b888fErik @Override 1470259b8f9a21fffd3858218581e9daaf689b6b888fErik public void run() { 1471259b8f9a21fffd3858218581e9daaf689b6b888fErik sendAccessibilityEvent(mEventType); 1472259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1473259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1474259b8f9a21fffd3858218581e9daaf689b6b888fErik 1475259b8f9a21fffd3858218581e9daaf689b6b888fErik private AccessibilityRunnable mDispatchAccessibilityEventRunnable = new AccessibilityRunnable(); 1476259b8f9a21fffd3858218581e9daaf689b6b888fErik 1477259b8f9a21fffd3858218581e9daaf689b6b888fErik @Override 1478259b8f9a21fffd3858218581e9daaf689b6b888fErik public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 1479259b8f9a21fffd3858218581e9daaf689b6b888fErik if (event.getEventType() != AccessibilityEvent.TYPE_VIEW_SELECTED && 1480259b8f9a21fffd3858218581e9daaf689b6b888fErik event.getEventType() != AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) { 1481259b8f9a21fffd3858218581e9daaf689b6b888fErik return false; 1482259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1483259b8f9a21fffd3858218581e9daaf689b6b888fErik StringBuilder b = new StringBuilder(getSelectedTime() 1484259b8f9a21fffd3858218581e9daaf689b6b888fErik .format(mIs24HourFormat ? HOUR_FORMAT_24H : HOUR_FORMAT_12H)); 1485259b8f9a21fffd3858218581e9daaf689b6b888fErik b.append(PERIOD_SPACE); 1486259b8f9a21fffd3858218581e9daaf689b6b888fErik int numEvents = mSelectedEvents.size(); 1487259b8f9a21fffd3858218581e9daaf689b6b888fErik if (mEventCountTemplate == null) { 1488259b8f9a21fffd3858218581e9daaf689b6b888fErik mEventCountTemplate = mContext.getString(R.string.template_announce_item_index); 1489259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1490259b8f9a21fffd3858218581e9daaf689b6b888fErik switch (event.getEventType()) { 1491259b8f9a21fffd3858218581e9daaf689b6b888fErik // When a new hour is selected we sent this event 1492259b8f9a21fffd3858218581e9daaf689b6b888fErik case AccessibilityEvent.TYPE_VIEW_SELECTED: 1493259b8f9a21fffd3858218581e9daaf689b6b888fErik int i = 1; 1494259b8f9a21fffd3858218581e9daaf689b6b888fErik for (Event calEvent : mSelectedEvents) { 1495259b8f9a21fffd3858218581e9daaf689b6b888fErik if (numEvents > 1) { 1496259b8f9a21fffd3858218581e9daaf689b6b888fErik mStringBuilder.setLength(0); 1497259b8f9a21fffd3858218581e9daaf689b6b888fErik b.append(mFormatter.format(mEventCountTemplate, i++, numEvents)); 1498259b8f9a21fffd3858218581e9daaf689b6b888fErik b.append(" "); 1499259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1500259b8f9a21fffd3858218581e9daaf689b6b888fErik appendEventAccessibilityString(b, calEvent); 1501259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1502259b8f9a21fffd3858218581e9daaf689b6b888fErik break; 1503259b8f9a21fffd3858218581e9daaf689b6b888fErik // When a different event is selected we send this event 1504259b8f9a21fffd3858218581e9daaf689b6b888fErik case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: 1505259b8f9a21fffd3858218581e9daaf689b6b888fErik if (mSelectedEvent != null) { 1506259b8f9a21fffd3858218581e9daaf689b6b888fErik if (numEvents > 1) { 1507259b8f9a21fffd3858218581e9daaf689b6b888fErik mStringBuilder.setLength(0); 1508259b8f9a21fffd3858218581e9daaf689b6b888fErik b.append(mFormatter.format(mEventCountTemplate, 1509259b8f9a21fffd3858218581e9daaf689b6b888fErik mSelectedEvents.indexOf(mSelectedEvent) + 1, numEvents)); 1510259b8f9a21fffd3858218581e9daaf689b6b888fErik b.append(" "); 1511259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1512259b8f9a21fffd3858218581e9daaf689b6b888fErik appendEventAccessibilityString(b, mSelectedEvent); 1513259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1514259b8f9a21fffd3858218581e9daaf689b6b888fErik break; 1515259b8f9a21fffd3858218581e9daaf689b6b888fErik default: 1516259b8f9a21fffd3858218581e9daaf689b6b888fErik break; 1517259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1518259b8f9a21fffd3858218581e9daaf689b6b888fErik CharSequence msg = b.toString(); 1519259b8f9a21fffd3858218581e9daaf689b6b888fErik event.getText().add(msg); 1520259b8f9a21fffd3858218581e9daaf689b6b888fErik event.setAddedCount(msg.length()); 1521259b8f9a21fffd3858218581e9daaf689b6b888fErik return true; 1522259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1523259b8f9a21fffd3858218581e9daaf689b6b888fErik 1524259b8f9a21fffd3858218581e9daaf689b6b888fErik /** 1525259b8f9a21fffd3858218581e9daaf689b6b888fErik * @param b 1526259b8f9a21fffd3858218581e9daaf689b6b888fErik * @param calEvent 1527259b8f9a21fffd3858218581e9daaf689b6b888fErik */ 1528259b8f9a21fffd3858218581e9daaf689b6b888fErik private void appendEventAccessibilityString(StringBuilder b, Event calEvent) { 1529259b8f9a21fffd3858218581e9daaf689b6b888fErik b.append(calEvent.getTitleAndLocation()); 1530259b8f9a21fffd3858218581e9daaf689b6b888fErik b.append(PERIOD_SPACE); 1531259b8f9a21fffd3858218581e9daaf689b6b888fErik String when; 1532259b8f9a21fffd3858218581e9daaf689b6b888fErik int flags = DateUtils.FORMAT_SHOW_DATE; 1533259b8f9a21fffd3858218581e9daaf689b6b888fErik if (calEvent.allDay) { 1534259b8f9a21fffd3858218581e9daaf689b6b888fErik flags |= DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_WEEKDAY; 1535259b8f9a21fffd3858218581e9daaf689b6b888fErik } else { 1536259b8f9a21fffd3858218581e9daaf689b6b888fErik flags |= DateUtils.FORMAT_SHOW_TIME; 1537259b8f9a21fffd3858218581e9daaf689b6b888fErik if (DateFormat.is24HourFormat(mContext)) { 1538259b8f9a21fffd3858218581e9daaf689b6b888fErik flags |= DateUtils.FORMAT_24HOUR; 1539259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1540259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1541259b8f9a21fffd3858218581e9daaf689b6b888fErik when = Utils.formatDateRange(mContext, calEvent.startMillis, calEvent.endMillis, flags); 1542259b8f9a21fffd3858218581e9daaf689b6b888fErik b.append(when); 1543259b8f9a21fffd3858218581e9daaf689b6b888fErik b.append(PERIOD_SPACE); 1544259b8f9a21fffd3858218581e9daaf689b6b888fErik } 1545259b8f9a21fffd3858218581e9daaf689b6b888fErik 15466d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan private class GotoBroadcaster implements Animation.AnimationListener { 15476d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan private final int mCounter; 15486d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan private final Time mStart; 15496d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan private final Time mEnd; 15506d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 15516d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan public GotoBroadcaster(Time start, Time end) { 15526d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan mCounter = ++sCounter; 15536d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan mStart = start; 15546d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan mEnd = end; 15556d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 15566d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 15576d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan @Override 15586d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan public void onAnimationEnd(Animation animation) { 1559f9a2842a66fe858336144ba87c668efc2e18a9acMichael Chan DayView view = (DayView) mViewSwitcher.getCurrentView(); 1560f9a2842a66fe858336144ba87c668efc2e18a9acMichael Chan view.mViewStartX = 0; 1561f9a2842a66fe858336144ba87c668efc2e18a9acMichael Chan view = (DayView) mViewSwitcher.getNextView(); 1562f9a2842a66fe858336144ba87c668efc2e18a9acMichael Chan view.mViewStartX = 0; 1563f9a2842a66fe858336144ba87c668efc2e18a9acMichael Chan 15646d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan if (mCounter == sCounter) { 1565f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan mController.sendEvent(this, EventType.GO_TO, mStart, mEnd, null, -1, 1566f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan ViewType.CURRENT, CalendarController.EXTRA_GOTO_DATE, null, null); 15676d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 15686d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 15696d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 15706d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan @Override 15716d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan public void onAnimationRepeat(Animation animation) { 15726d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 15736d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 15746d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan @Override 15756d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan public void onAnimationStart(Animation animation) { 15766d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 15776d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 15786d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 15792c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan private View switchViews(boolean forward, float xOffSet, float width, float velocity) { 158095d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan mAnimationDistance = width - xOffSet; 158195d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan if (DEBUG) { 158295d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan Log.d(TAG, "switchViews(" + forward + ") O:" + xOffSet + " Dist:" + mAnimationDistance); 158395d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan } 158495d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan 1585ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan float progress = Math.abs(xOffSet) / width; 1586ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan if (progress > 1.0f) { 1587ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan progress = 1.0f; 1588ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan } 1589ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 1590ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan float inFromXValue, inToXValue; 1591ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan float outFromXValue, outToXValue; 1592ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan if (forward) { 1593ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan inFromXValue = 1.0f - progress; 1594ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan inToXValue = 0.0f; 1595ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan outFromXValue = -progress; 1596ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan outToXValue = -1.0f; 1597ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan } else { 1598ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan inFromXValue = progress - 1.0f; 1599ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan inToXValue = 0.0f; 1600ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan outFromXValue = progress; 1601ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan outToXValue = 1.0f; 1602ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan } 1603ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 16046d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan final Time start = new Time(mBaseDate.timezone); 16056d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan start.set(mController.getTime()); 16066d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan if (forward) { 16076d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan start.monthDay += mNumDays; 16086d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } else { 16096d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan start.monthDay -= mNumDays; 16106d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 1611f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan mController.setTime(start.normalize(true)); 1612f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan 1613f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan Time newSelected = start; 16146d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 16156d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan if (mNumDays == 7) { 1616f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan newSelected = new Time(start); 16176d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan adjustToBeginningOfWeek(start); 16186d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 16196d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 16206d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan final Time end = new Time(start); 16216d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan end.monthDay += mNumDays - 1; 16226d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 1623ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan // We have to allocate these animation objects each time we switch views 1624ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan // because that is the only way to set the animation parameters. 1625ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan TranslateAnimation inAnimation = new TranslateAnimation( 1626ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan Animation.RELATIVE_TO_SELF, inFromXValue, 1627ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan Animation.RELATIVE_TO_SELF, inToXValue, 1628ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan Animation.ABSOLUTE, 0.0f, 1629ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan Animation.ABSOLUTE, 0.0f); 1630ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 1631ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan TranslateAnimation outAnimation = new TranslateAnimation( 1632ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan Animation.RELATIVE_TO_SELF, outFromXValue, 1633ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan Animation.RELATIVE_TO_SELF, outToXValue, 1634ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan Animation.ABSOLUTE, 0.0f, 1635ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan Animation.ABSOLUTE, 0.0f); 1636ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 16372c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan long duration = calculateDuration(width - Math.abs(xOffSet), width, velocity); 1638ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan inAnimation.setDuration(duration); 16392c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan inAnimation.setInterpolator(mHScrollInterpolator); 16402c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan outAnimation.setInterpolator(mHScrollInterpolator); 1641ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan outAnimation.setDuration(duration); 16426d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan outAnimation.setAnimationListener(new GotoBroadcaster(start, end)); 1643ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan mViewSwitcher.setInAnimation(inAnimation); 1644ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan mViewSwitcher.setOutAnimation(outAnimation); 1645ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 1646d190418220467c02327dd9b3ae1eae238889720bMichael Chan DayView view = (DayView) mViewSwitcher.getCurrentView(); 1647ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan view.cleanup(); 1648ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan mViewSwitcher.showNext(); 1649d190418220467c02327dd9b3ae1eae238889720bMichael Chan view = (DayView) mViewSwitcher.getCurrentView(); 1650f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan view.setSelected(newSelected, true); 1651ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan view.requestFocus(); 1652ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan view.reloadEvents(); 1653eaafa2b48be7194a61754604ae37b3d62e9118d8Erik view.updateTitle(); 1654e98dd73c67205b01f5348271d9a7a630003ecf52David Brown 1655ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan return view; 1656ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan } 1657ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 1658146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This is called after scrolling stops to move the selected hour 1659146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // to the visible part of the screen. 1660146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void resetSelectedHour() { 1661146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionHour < mFirstHour + 1) { 1662146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionHour = mFirstHour + 1; 1663146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvent = null; 1664146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvents.clear(); 1665146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mComputeSelectedEvents = true; 1666146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (mSelectionHour > mFirstHour + mNumHours - 3) { 1667146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionHour = mFirstHour + mNumHours - 3; 1668146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvent = null; 1669146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvents.clear(); 1670146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mComputeSelectedEvents = true; 1671146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1672146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1673146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1674146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void initFirstHour() { 1675d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mFirstHour = mSelectionHour - mNumHours / 5; 1676146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mFirstHour < 0) { 1677146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mFirstHour = 0; 1678146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (mFirstHour + mNumHours > 24) { 1679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mFirstHour = 24 - mNumHours; 1680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1681146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1682146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1683146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 1684146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Recomputes the first full hour that is visible on screen after the 1685146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * screen is scrolled. 1686146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 1687146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void computeFirstHour() { 1688146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Compute the first full hour that is visible on screen 1689146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mFirstHour = (mViewStartY + mCellHeight + HOUR_GAP - 1) / (mCellHeight + HOUR_GAP); 1690146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mFirstHourOffset = mFirstHour * (mCellHeight + HOUR_GAP) - mViewStartY; 1691146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1692146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1693146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void adjustHourSelection() { 1694146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionHour < 0) { 1695146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionHour = 0; 16962fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMaxAlldayEvents > 0) { 1697146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevSelectedEvent = null; 16982fda24534978f55711526dbde747aa50d68dec40RoboErik mSelectionAllday = true; 1699146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1700146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1701146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1702146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionHour > 23) { 1703146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionHour = 23; 1704146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1705146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1706146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If the selected hour is at least 2 time slots from the top and 1707146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // bottom of the screen, then don't scroll the view. 1708146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionHour < mFirstHour + 1) { 1709146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If there are all-days events for the selected day but there 1710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // are no more normal events earlier in the day, then jump to 1711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // the all-day event area. 1712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Exception 1: allow the user to scroll to 8am with the trackball 1713146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // before jumping to the all-day event area. 1714146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Exception 2: if 12am is on screen, then allow the user to select 1715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // 12am before going up to the all-day event area. 1716146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int daynum = mSelectionDay - mFirstJulianDay; 17172fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMaxAlldayEvents > 0 && mEarliestStartHour[daynum] > mSelectionHour 1718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project && mFirstHour > 0 && mFirstHour < 8) { 1719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevSelectedEvent = null; 17202fda24534978f55711526dbde747aa50d68dec40RoboErik mSelectionAllday = true; 1721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionHour = mFirstHour + 1; 1722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 1723146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mFirstHour > 0) { 1726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mFirstHour -= 1; 1727146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartY -= (mCellHeight + HOUR_GAP); 1728146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mViewStartY < 0) { 1729146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartY = 0; 1730146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1731146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 1732146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1733146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1734146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1735146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionHour > mFirstHour + mNumHours - 3) { 1736146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mFirstHour < 24 - mNumHours) { 1737146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mFirstHour += 1; 1738146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartY += (mCellHeight + HOUR_GAP); 1739c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik if (mViewStartY > mMaxViewStartY) { 1740c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik mViewStartY = mMaxViewStartY; 1741146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1742146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 1743146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (mFirstHour == 24 - mNumHours && mFirstHourOffset > 0) { 1744c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik mViewStartY = mMaxViewStartY; 1745146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1746146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1747146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1748146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1749146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project void clearCachedEvents() { 1750146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mLastReloadMillis = 0; 1751146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1752146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1753146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Runnable mCancelCallback = new Runnable() { 1754146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void run() { 1755146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project clearCachedEvents(); 1756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project }; 1758146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 175946b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa /* package */ void reloadEvents() { 1760146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Protect against this being called before this view has been 1761146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // initialized. 1762ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// if (mContext == null) { 1763ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// return; 1764ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// } 1765146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1766731f1cb808b7586b93615b408ab2636081fab0dcErik // Make sure our time zones are up to date 1767731f1cb808b7586b93615b408ab2636081fab0dcErik mTZUpdater.run(); 1768731f1cb808b7586b93615b408ab2636081fab0dcErik 1769146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvent = null; 1770146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevSelectedEvent = null; 1771146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvents.clear(); 1772146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1773146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // The start date is the beginning of the week at 12am 1774731f1cb808b7586b93615b408ab2636081fab0dcErik Time weekStart = new Time(Utils.getTimeZone(mContext, mTZUpdater)); 1775146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project weekStart.set(mBaseDate); 1776146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project weekStart.hour = 0; 1777146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project weekStart.minute = 0; 1778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project weekStart.second = 0; 1779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long millis = weekStart.normalize(true /* ignore isDst */); 1780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1781146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Avoid reloading events unnecessarily. 1782146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (millis == mLastReloadMillis) { 1783146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 1784146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1785146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mLastReloadMillis = millis; 1786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1787146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // load events in the background 1788ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// mContext.startProgressSpinner(); 1789146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project final ArrayList<Event> events = new ArrayList<Event>(); 1790b5e3c17201b2c08ca9f3fd33f4585e1ec8fa71b1RoboErik mEventLoader.loadEventsInBackground(mNumDays, events, mFirstJulianDay, new Runnable() { 1791146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void run() { 1792146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mEvents = events; 179308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan if (mAllDayEvents == null) { 179408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan mAllDayEvents = new ArrayList<Event>(); 179508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan } else { 179608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan mAllDayEvents.clear(); 179708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan } 179808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan 179908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // Create a shorter array for all day events 180046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan for (Event e : events) { 180168655b5af2b7e5f872a103858ec58a19042123ceRoboErik if (e.drawAsAllday()) { 180208ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan mAllDayEvents.add(e); 180308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan } 180408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan } 180508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan 180608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // New events, new layouts 180708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan if (mLayouts == null || mLayouts.length < events.size()) { 180808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan mLayouts = new StaticLayout[events.size()]; 180908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan } else { 181008ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan Arrays.fill(mLayouts, null); 18113e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh } 181208ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan 181308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan if (mAllDayLayouts == null || mAllDayLayouts.length < mAllDayEvents.size()) { 181408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan mAllDayLayouts = new StaticLayout[events.size()]; 181508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan } else { 181608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan Arrays.fill(mAllDayLayouts, null); 181708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan } 181808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan 18192fda24534978f55711526dbde747aa50d68dec40RoboErik computeEventRelations(); 18202fda24534978f55711526dbde747aa50d68dec40RoboErik 1821146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mRemeasure = true; 1822146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mComputeSelectedEvents = true; 1823146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project recalc(); 1824ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// mContext.stopProgressSpinner(); 1825146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 1826146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1827146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project }, mCancelCallback); 1828146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1829146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 18302fda24534978f55711526dbde747aa50d68dec40RoboErik private void computeEventRelations() { 18312fda24534978f55711526dbde747aa50d68dec40RoboErik // Compute the layout relation between each event before measuring cell 18322fda24534978f55711526dbde747aa50d68dec40RoboErik // width, as the cell width should be adjusted along with the relation. 18332fda24534978f55711526dbde747aa50d68dec40RoboErik // 18342fda24534978f55711526dbde747aa50d68dec40RoboErik // Examples: A (1:00pm - 1:01pm), B (1:02pm - 2:00pm) 18352fda24534978f55711526dbde747aa50d68dec40RoboErik // We should mark them as "overwapped". Though they are not overwapped logically, but 18362fda24534978f55711526dbde747aa50d68dec40RoboErik // minimum cell height implicitly expands the cell height of A and it should look like 18372fda24534978f55711526dbde747aa50d68dec40RoboErik // (1:00pm - 1:15pm) after the cell height adjustment. 18382fda24534978f55711526dbde747aa50d68dec40RoboErik 18392fda24534978f55711526dbde747aa50d68dec40RoboErik // Compute the space needed for the all-day events, if any. 18402fda24534978f55711526dbde747aa50d68dec40RoboErik // Make a pass over all the events, and keep track of the maximum 18412fda24534978f55711526dbde747aa50d68dec40RoboErik // number of all-day events in any one day. Also, keep track of 18422fda24534978f55711526dbde747aa50d68dec40RoboErik // the earliest event in each day. 18432fda24534978f55711526dbde747aa50d68dec40RoboErik int maxAllDayEvents = 0; 18442fda24534978f55711526dbde747aa50d68dec40RoboErik final ArrayList<Event> events = mEvents; 18452fda24534978f55711526dbde747aa50d68dec40RoboErik final int len = events.size(); 18462fda24534978f55711526dbde747aa50d68dec40RoboErik // Num of all-day-events on each day. 18472fda24534978f55711526dbde747aa50d68dec40RoboErik final int eventsCount[] = new int[mLastJulianDay - mFirstJulianDay + 1]; 18482fda24534978f55711526dbde747aa50d68dec40RoboErik Arrays.fill(eventsCount, 0); 18492fda24534978f55711526dbde747aa50d68dec40RoboErik for (int ii = 0; ii < len; ii++) { 18502fda24534978f55711526dbde747aa50d68dec40RoboErik Event event = events.get(ii); 18512fda24534978f55711526dbde747aa50d68dec40RoboErik if (event.startDay > mLastJulianDay || event.endDay < mFirstJulianDay) { 18522fda24534978f55711526dbde747aa50d68dec40RoboErik continue; 18532fda24534978f55711526dbde747aa50d68dec40RoboErik } 18542fda24534978f55711526dbde747aa50d68dec40RoboErik if (event.drawAsAllday()) { 18552fda24534978f55711526dbde747aa50d68dec40RoboErik // Count all the events being drawn as allDay events 18562fda24534978f55711526dbde747aa50d68dec40RoboErik final int firstDay = Math.max(event.startDay, mFirstJulianDay); 18572fda24534978f55711526dbde747aa50d68dec40RoboErik final int lastDay = Math.min(event.endDay, mLastJulianDay); 18582fda24534978f55711526dbde747aa50d68dec40RoboErik for (int day = firstDay; day <= lastDay; day++) { 18592fda24534978f55711526dbde747aa50d68dec40RoboErik final int count = ++eventsCount[day - mFirstJulianDay]; 18602fda24534978f55711526dbde747aa50d68dec40RoboErik if (maxAllDayEvents < count) { 18612fda24534978f55711526dbde747aa50d68dec40RoboErik maxAllDayEvents = count; 18622fda24534978f55711526dbde747aa50d68dec40RoboErik } 18632fda24534978f55711526dbde747aa50d68dec40RoboErik } 18642fda24534978f55711526dbde747aa50d68dec40RoboErik 18652fda24534978f55711526dbde747aa50d68dec40RoboErik int daynum = event.startDay - mFirstJulianDay; 18662fda24534978f55711526dbde747aa50d68dec40RoboErik int durationDays = event.endDay - event.startDay + 1; 18672fda24534978f55711526dbde747aa50d68dec40RoboErik if (daynum < 0) { 18682fda24534978f55711526dbde747aa50d68dec40RoboErik durationDays += daynum; 18692fda24534978f55711526dbde747aa50d68dec40RoboErik daynum = 0; 18702fda24534978f55711526dbde747aa50d68dec40RoboErik } 18712fda24534978f55711526dbde747aa50d68dec40RoboErik if (daynum + durationDays > mNumDays) { 18722fda24534978f55711526dbde747aa50d68dec40RoboErik durationDays = mNumDays - daynum; 18732fda24534978f55711526dbde747aa50d68dec40RoboErik } 18742fda24534978f55711526dbde747aa50d68dec40RoboErik for (int day = daynum; durationDays > 0; day++, durationDays--) { 18752fda24534978f55711526dbde747aa50d68dec40RoboErik mHasAllDayEvent[day] = true; 18762fda24534978f55711526dbde747aa50d68dec40RoboErik } 18772fda24534978f55711526dbde747aa50d68dec40RoboErik } else { 18782fda24534978f55711526dbde747aa50d68dec40RoboErik int daynum = event.startDay - mFirstJulianDay; 18792fda24534978f55711526dbde747aa50d68dec40RoboErik int hour = event.startTime / 60; 18802fda24534978f55711526dbde747aa50d68dec40RoboErik if (daynum >= 0 && hour < mEarliestStartHour[daynum]) { 18812fda24534978f55711526dbde747aa50d68dec40RoboErik mEarliestStartHour[daynum] = hour; 18822fda24534978f55711526dbde747aa50d68dec40RoboErik } 18832fda24534978f55711526dbde747aa50d68dec40RoboErik 18842fda24534978f55711526dbde747aa50d68dec40RoboErik // Also check the end hour in case the event spans more than 18852fda24534978f55711526dbde747aa50d68dec40RoboErik // one day. 18862fda24534978f55711526dbde747aa50d68dec40RoboErik daynum = event.endDay - mFirstJulianDay; 18872fda24534978f55711526dbde747aa50d68dec40RoboErik hour = event.endTime / 60; 18882fda24534978f55711526dbde747aa50d68dec40RoboErik if (daynum < mNumDays && hour < mEarliestStartHour[daynum]) { 18892fda24534978f55711526dbde747aa50d68dec40RoboErik mEarliestStartHour[daynum] = hour; 18902fda24534978f55711526dbde747aa50d68dec40RoboErik } 18912fda24534978f55711526dbde747aa50d68dec40RoboErik } 18922fda24534978f55711526dbde747aa50d68dec40RoboErik } 18932fda24534978f55711526dbde747aa50d68dec40RoboErik mMaxAlldayEvents = maxAllDayEvents; 18942fda24534978f55711526dbde747aa50d68dec40RoboErik initAllDayHeights(); 18952fda24534978f55711526dbde747aa50d68dec40RoboErik } 18962fda24534978f55711526dbde747aa50d68dec40RoboErik 1897146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project @Override 1898146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project protected void onDraw(Canvas canvas) { 1899146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mRemeasure) { 1900146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project remeasure(getWidth(), getHeight()); 1901146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mRemeasure = false; 1902146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1903c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik canvas.save(); 1904146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 19052fda24534978f55711526dbde747aa50d68dec40RoboErik float yTranslate = -mViewStartY + DAY_HEADER_HEIGHT + mAlldayHeight; 1906c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // offset canvas by the current drag and header position 1907c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik canvas.translate(-mViewStartX, yTranslate); 1908c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // clip to everything below the allDay area 1909c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik Rect dest = mDestRect; 1910c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik dest.top = (int) (mFirstCell - yTranslate); 1911c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik dest.bottom = (int) (mViewHeight - yTranslate); 1912c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik dest.left = 0; 1913c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik dest.right = mViewWidth; 1914c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik canvas.save(); 1915c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik canvas.clipRect(dest); 1916c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // Draw the movable part of the view 1917c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik doDraw(canvas); 1918c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // restore to having no clip 1919c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik canvas.restore(); 1920146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1921146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) { 1922c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik float xTranslate; 1923146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mViewStartX > 0) { 1924c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik xTranslate = mViewWidth; 1925146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 1926c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik xTranslate = -mViewWidth; 1927146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1928c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // Move the canvas around to prep it for the next view 1929c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // specifically, shift it by a screen and undo the 1930c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // yTranslation which will be redone in the nextView's onDraw(). 1931c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik canvas.translate(xTranslate, -yTranslate); 1932d190418220467c02327dd9b3ae1eae238889720bMichael Chan DayView nextView = (DayView) mViewSwitcher.getNextView(); 1933146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1934146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Prevent infinite recursive calls to onDraw(). 1935146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project nextView.mTouchMode = TOUCH_MODE_INITIAL_STATE; 1936146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1937146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project nextView.onDraw(canvas); 1938c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // Move it back for this view 1939c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik canvas.translate(-xTranslate, 0); 1940c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik } else { 1941c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // If we drew another view we already translated it back 1942c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // If we didn't draw another view we should be at the edge of the 1943c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik // screen 1944c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik canvas.translate(mViewStartX, -yTranslate); 1945146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1946146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1947146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Draw the fixed areas (that don't scroll) directly to the canvas. 1948146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project drawAfterScroll(canvas); 19498307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik if (mComputeSelectedEvents && mUpdateToast) { 19508307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik updateEventDetails(); 19518307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik mUpdateToast = false; 19528307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik } 1953146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mComputeSelectedEvents = false; 1954146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project canvas.restore(); 1955146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1956146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1957146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void drawAfterScroll(Canvas canvas) { 1958146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Paint p = mPaint; 1959146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Rect r = mRect; 1960146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1961e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik drawAllDayHighlights(r, canvas, p); 19622fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMaxAlldayEvents != 0) { 19631ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan drawAllDayEvents(mFirstJulianDay, mNumDays, canvas, p); 19648f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan drawUpperLeftCorner(r, canvas, p); 1965146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1966146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1967c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik drawScrollLine(r, canvas, p); 19683eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan drawDayHeaderLoop(r, canvas, p); 1969146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 1970146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Draw the AM and PM indicators if we're in 12 hour mode 1971146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (!mIs24HourFormat) { 1972146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project drawAmPm(canvas, p); 1973146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1974146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 1975146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 197646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // This isn't really the upper-left corner. It's the square area just 1977146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // below the upper-left corner, above the hours and to the left of the 1978146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // all-day area. 19798f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan private void drawUpperLeftCorner(Rect r, Canvas canvas, Paint p) { 1980e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // StaticLayout is wonky and doesn't do multi-line center text 1981e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // correctly. In order to make it work set the paint to Align.CENTER and 1982e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // the Layout to Alignment.ALIGN_NORMAL. 1983e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextAlign(Align.CENTER); 1984e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextSize(ALLDAY_TEXT_SIZE); 1985e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setColor(mCalendarHourLabelColor); 1986e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int translateY = DAY_HEADER_HEIGHT + ALLDAY_TOP_MARGIN; 1987e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.left = -mHoursWidth / 2; 1988e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.right = mHoursWidth / 2; 1989e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.top = 0; 1990e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.bottom = mFirstCell - translateY; 1991e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.save(); 1992e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.translate(mHoursWidth / 2, translateY); 1993e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.clipRect(r); 1994e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik StaticLayout allDayLayout = getOrCreateAllDayTextLayout(p); 1995e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik allDayLayout.draw(canvas); 1996e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.restore(); 1997e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 19988f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan setupHourTextPaint(p); 19992fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMaxAlldayEvents > mMaxUnexpandedAlldayEventCount) { 2000cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik // Draw the allDay expand/collapse icon 2001cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik if (mUseExpandIcon) { 2002cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik mExpandAlldayDrawable.setBounds(mExpandAllDayRect); 2003cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik mExpandAlldayDrawable.draw(canvas); 2004cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik } else { 2005cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik mCollapseAlldayDrawable.setBounds(mExpandAllDayRect); 2006cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik mCollapseAlldayDrawable.draw(canvas); 2007cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik } 20082fda24534978f55711526dbde747aa50d68dec40RoboErik } 20098f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan } 2010146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2011c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik private void drawScrollLine(Rect r, Canvas canvas, Paint p) { 2012e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik final int right = computeDayLeftPosition(mNumDays + 1); 20138f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan final int y = mFirstCell - 1; 20148f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan 2015c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik p.setAntiAlias(false); 20168f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan p.setStyle(Style.FILL); 20178f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan 20188f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan p.setColor(mCalendarGridLineInnerHorizontalColor); 20198f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan p.setStrokeWidth(GRID_LINE_INNER_WIDTH); 20208f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan canvas.drawLine(GRID_LINE_LEFT_MARGIN, y, right, y, p); 2021c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik p.setAntiAlias(true); 2022c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik } 2023c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik 2024e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // Computes the x position for the left side of the given day 2025e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private int computeDayLeftPosition(int day) { 2026e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int effectiveWidth = mViewWidth - mHoursWidth; 2027e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik return day * effectiveWidth / mNumDays + mHoursWidth; 2028e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 2029e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 2030e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private void drawAllDayHighlights(Rect r, Canvas canvas, Paint p) { 2031e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // First, color the labels area light gray 2032e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.top = 0; 2033e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.bottom = DAY_HEADER_HEIGHT; 2034e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.left = 0; 2035e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.right = mViewWidth; 2036e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setColor(mBgColor); 2037e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setStyle(Style.FILL); 2038e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.drawRect(r, p); 2039e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // and the area that says All day 2040e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.top = DAY_HEADER_HEIGHT; 2041e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.bottom = mFirstCell - 1; 2042e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.left = 0; 2043e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.right = mHoursWidth; 2044e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.drawRect(r, p); 2045e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int todayIndex = mTodayJulianDay - mFirstJulianDay; 2046e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik if (mNumDays > 1 && todayIndex >= 0 && todayIndex < mNumDays) { 2047e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // Draw the today highlight 2048e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.top = 0; 2049e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.bottom = mFirstCell - 1; 2050e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.left = computeDayLeftPosition(todayIndex) + 1; 2051e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.right = computeDayLeftPosition(todayIndex + 1); 2052e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setColor(mTodayBgColor); 2053e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setStyle(Style.FILL); 2054e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.drawRect(r, p); 2055e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 2056e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik if (mSelectionAllday) { 2057e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // Draw the selection highlight on the selected all-day area 2058e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mRect.top = DAY_HEADER_HEIGHT + 1; 2059e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mRect.bottom = mRect.top + mAlldayHeight + ALLDAY_TOP_MARGIN - 2; 2060e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int daynum = mSelectionDay - mFirstJulianDay; 2061e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mRect.left = computeDayLeftPosition(daynum) + 1; 2062e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mRect.right = computeDayLeftPosition(daynum + 1); 2063e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setColor(mCalendarGridAreaSelected); 2064e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.drawRect(mRect, p); 2065e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 2066e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 2067e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 2068146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void drawDayHeaderLoop(Rect r, Canvas canvas, Paint p) { 2069146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Draw the horizontal day background banner 20703eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // p.setColor(mCalendarDateBannerBackground); 20713eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // r.top = 0; 20723eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // r.bottom = DAY_HEADER_HEIGHT; 20733eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // r.left = 0; 20743eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // r.right = mHoursWidth + mNumDays * (mCellWidth + DAY_GAP); 20753eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // canvas.drawRect(r, p); 20763eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // 2077146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Fill the extra space on the right side with the default background 20783eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // r.left = r.right; 20793eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // r.right = mViewWidth; 20803eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // p.setColor(mCalendarGridAreaBackground); 20813eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // canvas.drawRect(r, p); 2082e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik if (mNumDays == 1 && ONE_DAY_HEADER_HEIGHT == 0) { 2083e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik return; 2084146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2085e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int todayNum = mTodayJulianDay - mFirstJulianDay; 2086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 20873eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setTypeface(mBold); 20883eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setTextAlign(Paint.Align.RIGHT); 2089146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int deltaX = mCellWidth + DAY_GAP; 2090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int cell = mFirstJulianDay; 2091146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2092146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String[] dayNames; 2093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mDateStrWidth < mCellWidth) { 2094146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project dayNames = mDayStrs; 2095146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 2096146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project dayNames = mDayStrs2Letter; 2097146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2098146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2099d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan p.setAntiAlias(true); 2100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int day = 0; day < mNumDays; day++, cell++) { 21011f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan int dayOfWeek = day + mFirstVisibleDayOfWeek; 21021f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan if (dayOfWeek >= 14) { 21031f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan dayOfWeek -= 14; 2104487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan } 2105487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan 21063eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan int color = mCalendarDateBannerTextColor; 2107071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa if (mNumDays == 1) { 2108071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa if (dayOfWeek == Time.SATURDAY) { 2109071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa color = mWeek_saturdayColor; 2110071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa } else if (dayOfWeek == Time.SUNDAY) { 2111071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa color = mWeek_sundayColor; 2112071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa } 2113071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa } else { 2114071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa final int column = day % 7; 2115071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa if (Utils.isSaturday(column, mFirstDayOfWeek)) { 2116071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa color = mWeek_saturdayColor; 2117071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa } else if (Utils.isSunday(column, mFirstDayOfWeek)) { 2118071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa color = mWeek_sundayColor; 2119071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa } 21203eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan } 21213eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan 21223eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setColor(color); 2123e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik drawDayHeader(dayNames[dayOfWeek], day, cell, canvas, p); 2124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 21253eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setTypeface(null); 2126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2128146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void drawAmPm(Canvas canvas, Paint p) { 2129d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan p.setColor(mCalendarAmPmLabel); 2130e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextSize(AMPM_TEXT_SIZE); 2131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setTypeface(mBold); 2132146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setAntiAlias(true); 2133e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextAlign(Paint.Align.RIGHT); 2134146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String text = mAmString; 2135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mFirstHour >= 12) { 2136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project text = mPmString; 2137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int y = mFirstCell + mFirstHourOffset + 2 * mHoursTextHeight + HOUR_GAP; 21398f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan canvas.drawText(text, HOURS_LEFT_MARGIN, y, p); 2140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2141146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mFirstHour < 12 && mFirstHour + mNumHours > 12) { 2142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Also draw the "PM" 2143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project text = mPmString; 2144146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project y = mFirstCell + mFirstHourOffset + (12 - mFirstHour) * (mCellHeight + HOUR_GAP) 2145146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project + 2 * mHoursTextHeight + HOUR_GAP; 21468f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan canvas.drawText(text, HOURS_LEFT_MARGIN, y, p); 2147146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2150e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private void drawCurrentTimeLine(Rect r, final int day, final int top, Canvas canvas, 2151f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan Paint p) { 2152e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.left = computeDayLeftPosition(day) - CURRENT_TIME_LINE_SIDE_BUFFER + 1; 2153e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.right = computeDayLeftPosition(day + 1) + CURRENT_TIME_LINE_SIDE_BUFFER; 21543eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan 21553eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan r.top = top - mCurrentTimeLine.getIntrinsicHeight() / 2; 21563eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan r.bottom = r.top + mCurrentTimeLine.getIntrinsicHeight(); 2157bd0e834aea317236d574f8738fe11a51fdc87968Erik 21583eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan mCurrentTimeLine.setBounds(r); 21593eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan mCurrentTimeLine.draw(canvas); 2160bd0e834aea317236d574f8738fe11a51fdc87968Erik } 2161bd0e834aea317236d574f8738fe11a51fdc87968Erik 2162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void doDraw(Canvas canvas) { 2163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Paint p = mPaint; 2164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Rect r = mRect; 2165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2166e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik drawBgColors(r, canvas, p); 2167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project drawGridBackground(r, canvas, p); 2168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project drawHours(r, canvas, p); 2169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Draw each day 2171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int cell = mFirstJulianDay; 2172e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(false); 2173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int day = 0; day < mNumDays; day++, cell++) { 217408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // TODO Wow, this needs cleanup. drawEvents loop through all the 217508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // events on every call. 2176e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik drawEvents(cell, day, HOUR_GAP, canvas, p); 217746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // If this is today 217846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (cell == mTodayJulianDay) { 21791ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan int lineY = mCurrentTime.hour * (mCellHeight + HOUR_GAP) 21801ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan + ((mCurrentTime.minute * mCellHeight) / 60) + 1; 21811ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan 218246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // And the current time shows up somewhere on the screen 218346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (lineY >= mViewStartY && lineY < mViewStartY + mViewHeight - 2) { 2184e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik drawCurrentTimeLine(r, day, lineY, canvas, p); 2185bd0e834aea317236d574f8738fe11a51fdc87968Erik } 2186bd0e834aea317236d574f8738fe11a51fdc87968Erik } 2187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2188e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(true); 2189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void drawHours(Rect r, Canvas canvas, Paint p) { 21923eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // Comment out as the background will be a drawable 21933eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan 2194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Draw a highlight on the selected hour (if needed) 21952fda24534978f55711526dbde747aa50d68dec40RoboErik if (mSelectionMode != SELECTION_HIDDEN && !mSelectionAllday) { 2196ba902466b19b11d587468e354edc58e542707747Michael Chan // p.setColor(mCalendarHourSelected); 21973937a47bc5a1afb9701e1d0565fae31f5800590dErik int daynum = mSelectionDay - mFirstJulianDay; 2198ba902466b19b11d587468e354edc58e542707747Michael Chan r.top = mSelectionHour * (mCellHeight + HOUR_GAP); 21991ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.bottom = r.top + mCellHeight + HOUR_GAP; 2200e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.left = computeDayLeftPosition(daynum); 2201e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.right = computeDayLeftPosition(daynum + 1); 2202ba902466b19b11d587468e354edc58e542707747Michael Chan 2203ba902466b19b11d587468e354edc58e542707747Michael Chan // Draw a border around the highlighted grid hour. 22041ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan // drawEmptyRect(canvas, r, mSelectionPaint.getColor()); 2205ba902466b19b11d587468e354edc58e542707747Michael Chan saveSelectionPosition(r.left, r.top, r.right, r.bottom); 22063937a47bc5a1afb9701e1d0565fae31f5800590dErik 22073937a47bc5a1afb9701e1d0565fae31f5800590dErik // Also draw the highlight on the grid 22083937a47bc5a1afb9701e1d0565fae31f5800590dErik p.setColor(mCalendarGridAreaSelected); 22093937a47bc5a1afb9701e1d0565fae31f5800590dErik r.top += HOUR_GAP; 22103937a47bc5a1afb9701e1d0565fae31f5800590dErik r.right -= DAY_GAP; 2211e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(false); 22123937a47bc5a1afb9701e1d0565fae31f5800590dErik canvas.drawRect(r, p); 2213ba902466b19b11d587468e354edc58e542707747Michael Chan } 2214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 22158f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan setupHourTextPaint(p); 2216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 22178f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan int y = HOUR_GAP + mHoursTextHeight + HOURS_TOP_MARGIN; 2218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int i = 0; i < 24; i++) { 2220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String time = mHourStrs[i]; 22218f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan canvas.drawText(time, HOURS_LEFT_MARGIN, y, p); 2222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project y += mCellHeight + HOUR_GAP; 2223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 22268f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan private void setupHourTextPaint(Paint p) { 22278f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan p.setColor(mCalendarHourLabelColor); 2228e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextSize(HOURS_TEXT_SIZE); 2229f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan p.setTypeface(Typeface.DEFAULT); 2230e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextAlign(Paint.Align.RIGHT); 22318f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan p.setAntiAlias(true); 22328f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan } 22338f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan 2234e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private void drawDayHeader(String dayStr, int day, int cell, Canvas canvas, Paint p) { 2235487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan int dateNum = mFirstVisibleDate + day; 2236e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int x; 2237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (dateNum > mMonthLength) { 2238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project dateNum -= mMonthLength; 2239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2240e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(true); 2241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 22423eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // Draw day of the month 22433eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan String dateNumStr = String.valueOf(dateNum); 22443eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan if (mNumDays > 1) { 22453eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan float y = DAY_HEADER_HEIGHT - DAY_HEADER_BOTTOM_MARGIN; 22463eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan 22473eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // Draw day of the month 2248e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik x = computeDayLeftPosition(day + 1) - DAY_HEADER_RIGHT_MARGIN; 2249e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextAlign(Align.RIGHT); 22503eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setTextSize(DATE_HEADER_FONT_SIZE); 2251f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan p.setTypeface(mBold); 22523eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan canvas.drawText(dateNumStr, x, y, p); 22533eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan 22543eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // Draw day of the week 2255e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik x -= p.measureText(" " + dateNumStr); 22563eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setTextSize(DAY_HEADER_FONT_SIZE); 2257f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan p.setTypeface(Typeface.DEFAULT); 22583eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan canvas.drawText(dayStr, x, y, p); 2259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 2260e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik float y = ONE_DAY_HEADER_HEIGHT - DAY_HEADER_ONE_DAY_BOTTOM_MARGIN; 2261e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setTextAlign(Align.LEFT); 2262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2263f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan 22643eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // Draw day of the week 2265e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik x = computeDayLeftPosition(day) + DAY_HEADER_ONE_DAY_LEFT_MARGIN; 22663eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setTextSize(DAY_HEADER_FONT_SIZE); 2267f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan p.setTypeface(Typeface.DEFAULT); 22683eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan canvas.drawText(dayStr, x, y, p); 2269d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan 22703eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // Draw day of the month 22713eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan x += p.measureText(dayStr) + DAY_HEADER_ONE_DAY_RIGHT_MARGIN; 22723eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setTextSize(DATE_HEADER_FONT_SIZE); 2273f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan p.setTypeface(mBold); 22743eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan canvas.drawText(dateNumStr, x, y, p); 2275d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan } 2276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void drawGridBackground(Rect r, Canvas canvas, Paint p) { 2279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Paint.Style savedStyle = p.getStyle(); 2280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2281e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik final float stopX = computeDayLeftPosition(mNumDays + 1); 2282000ba1109e2f4e527e9227fe341598ceeb3fbca6Michael Chan float y = 0; 22833eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan final float deltaY = mCellHeight + HOUR_GAP; 228402041687c35441e8a21cb763f1fc3a26525292efDavid Brown int linesIndex = 0; 22853eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan final float startY = 0; 22863eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan final float stopY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP); 22871ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan float x = mHoursWidth; 2288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 22893eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // Draw the inner horizontal grid lines 22903eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setColor(mCalendarGridLineInnerHorizontalColor); 22913eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setStrokeWidth(GRID_LINE_INNER_WIDTH); 2292e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(false); 22933eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan y = 0; 229402041687c35441e8a21cb763f1fc3a26525292efDavid Brown linesIndex = 0; 22953eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan for (int hour = 0; hour <= 24; hour++) { 22968f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan mLines[linesIndex++] = GRID_LINE_LEFT_MARGIN; 229702041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = y; 229802041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = stopX; 229902041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = y; 23003eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan y += deltaY; 23013eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan } 230202041687c35441e8a21cb763f1fc3a26525292efDavid Brown if (mCalendarGridLineInnerVerticalColor != mCalendarGridLineInnerHorizontalColor) { 230302041687c35441e8a21cb763f1fc3a26525292efDavid Brown canvas.drawLines(mLines, 0, linesIndex, p); 230402041687c35441e8a21cb763f1fc3a26525292efDavid Brown linesIndex = 0; 230502041687c35441e8a21cb763f1fc3a26525292efDavid Brown p.setColor(mCalendarGridLineInnerVerticalColor); 230602041687c35441e8a21cb763f1fc3a26525292efDavid Brown } 23073eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan 23083eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // Draw the inner vertical grid lines 2309e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik for (int day = 0; day <= mNumDays; day++) { 2310e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik x = computeDayLeftPosition(day); 231102041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = x; 231202041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = startY; 231302041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = x; 231402041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = stopY; 23153eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan } 231602041687c35441e8a21cb763f1fc3a26525292efDavid Brown canvas.drawLines(mLines, 0, linesIndex, p); 23173eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan 2318146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Restore the saved style. 2319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setStyle(savedStyle); 2320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setAntiAlias(true); 2321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2323e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik /** 2324e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik * @param r 2325e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik * @param canvas 2326e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik * @param p 2327e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik */ 2328e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private void drawBgColors(Rect r, Canvas canvas, Paint p) { 2329e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int todayIndex = mTodayJulianDay - mFirstJulianDay; 2330e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // Draw the hours background color 2331e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.top = mDestRect.top; 2332e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.bottom = mDestRect.bottom; 2333e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.left = 0; 2334e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.right = mHoursWidth; 2335e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setColor(mBgColor); 2336e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setStyle(Style.FILL); 2337e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(false); 2338e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.drawRect(r, p); 2339e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik if (mNumDays == 1 && todayIndex == 0) { 2340e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik // Draw a white background for the time later than current time 2341e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int lineY = mCurrentTime.hour * (mCellHeight + HOUR_GAP) 2342e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik + ((mCurrentTime.minute * mCellHeight) / 60) + 1; 2343e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik if (lineY < mViewStartY + mViewHeight) { 2344e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik lineY = Math.max(lineY, mViewStartY); 2345e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.left = mHoursWidth; 2346e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.right = mViewWidth; 2347e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.top = lineY; 2348e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.bottom = mViewStartY + mViewHeight; 2349e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setColor(mTodayBgColor); 2350e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.drawRect(r, p); 2351e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 2352e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } else if (todayIndex >= 0 && todayIndex < mNumDays) { 2353e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.left = computeDayLeftPosition(todayIndex) + 1; 2354e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.right = computeDayLeftPosition(todayIndex + 1); 2355e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.top = mDestRect.top; 2356e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik r.bottom = mDestRect.bottom; 2357e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setColor(mTodayBgColor); 2358e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik canvas.drawRect(r, p); 2359e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 2360e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(true); 2361e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 2362e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 2363146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event getSelectedEvent() { 2364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectedEvent == null) { 2365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // There is no event at the selected hour, so create a new event. 2366146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return getNewEvent(mSelectionDay, getSelectedTimeInMillis(), 2367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project getSelectedMinutesSinceMidnight()); 2368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2369146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return mSelectedEvent; 2370146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2371146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2372146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project boolean isEventSelected() { 2373146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return (mSelectedEvent != null); 2374146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2376146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event getNewEvent() { 2377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return getNewEvent(mSelectionDay, getSelectedTimeInMillis(), 2378146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project getSelectedMinutesSinceMidnight()); 2379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2380146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2381146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project static Event getNewEvent(int julianDay, long utcMillis, 2382146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int minutesSinceMidnight) { 2383146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event event = Event.newInstance(); 2384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project event.startDay = julianDay; 2385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project event.endDay = julianDay; 2386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project event.startMillis = utcMillis; 2387146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project event.endMillis = event.startMillis + MILLIS_PER_HOUR; 2388146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project event.startTime = minutesSinceMidnight; 2389146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project event.endTime = event.startTime + MINUTES_PER_HOUR; 2390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return event; 2391146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2392146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2393146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private int computeMaxStringWidth(int currentMax, String[] strings, Paint p) { 2394146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project float maxWidthF = 0.0f; 2395146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int len = strings.length; 2397146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int i = 0; i < len; i++) { 2398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project float width = p.measureText(strings[i]); 2399146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project maxWidthF = Math.max(width, maxWidthF); 2400146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2401146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int maxWidth = (int) (maxWidthF + 0.5); 2402146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (maxWidth < currentMax) { 2403146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project maxWidth = currentMax; 2404146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return maxWidth; 2406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2407146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2408146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void saveSelectionPosition(float left, float top, float right, float bottom) { 2409146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevBox.left = (int) left; 2410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevBox.right = (int) right; 2411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevBox.top = (int) top; 2412146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevBox.bottom = (int) bottom; 2413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2414146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2415146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private Rect getCurrentSelectionPosition() { 2416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Rect box = new Rect(); 2417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project box.top = mSelectionHour * (mCellHeight + HOUR_GAP); 2418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project box.bottom = box.top + mCellHeight + HOUR_GAP; 2419146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int daynum = mSelectionDay - mFirstJulianDay; 2420e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik box.left = computeDayLeftPosition(daynum) + 1; 2421e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik box.right = computeDayLeftPosition(daynum + 1); 2422146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return box; 2423146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2424146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 24251ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private void setupTextRect(Rect r) { 24261ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan if (r.bottom <= r.top || r.right <= r.left) { 24271ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.bottom = r.top; 24281ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.right = r.left; 242936a4668f603c432d08ad156cd7c731f9838c0212Michael Chan return; 243036a4668f603c432d08ad156cd7c731f9838c0212Michael Chan } 243136a4668f603c432d08ad156cd7c731f9838c0212Michael Chan 24321ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan if (r.bottom - r.top > EVENT_TEXT_TOP_MARGIN + EVENT_TEXT_BOTTOM_MARGIN) { 24331ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.top += EVENT_TEXT_TOP_MARGIN; 24341ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.bottom -= EVENT_TEXT_BOTTOM_MARGIN; 243536a4668f603c432d08ad156cd7c731f9838c0212Michael Chan } 24361ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan if (r.right - r.left > EVENT_TEXT_LEFT_MARGIN + EVENT_TEXT_RIGHT_MARGIN) { 24371ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.left += EVENT_TEXT_LEFT_MARGIN; 24381ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.right -= EVENT_TEXT_RIGHT_MARGIN; 243936a4668f603c432d08ad156cd7c731f9838c0212Michael Chan } 24409c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan } 24419c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan 24421ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private void setupAllDayTextRect(Rect r) { 24431ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan if (r.bottom <= r.top || r.right <= r.left) { 24441ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.bottom = r.top; 24451ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.right = r.left; 244636a4668f603c432d08ad156cd7c731f9838c0212Michael Chan return; 244736a4668f603c432d08ad156cd7c731f9838c0212Michael Chan } 244836a4668f603c432d08ad156cd7c731f9838c0212Michael Chan 24491ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan if (r.bottom - r.top > EVENT_ALL_DAY_TEXT_TOP_MARGIN + EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN) { 24501ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.top += EVENT_ALL_DAY_TEXT_TOP_MARGIN; 24511ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.bottom -= EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN; 245236a4668f603c432d08ad156cd7c731f9838c0212Michael Chan } 24531ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan if (r.right - r.left > EVENT_ALL_DAY_TEXT_LEFT_MARGIN + EVENT_ALL_DAY_TEXT_RIGHT_MARGIN) { 24541ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.left += EVENT_ALL_DAY_TEXT_LEFT_MARGIN; 24551ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.right -= EVENT_ALL_DAY_TEXT_RIGHT_MARGIN; 245636a4668f603c432d08ad156cd7c731f9838c0212Michael Chan } 24579c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan } 24589c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan 2459e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private StaticLayout getOrCreateAllDayTextLayout(Paint p) { 2460e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 2461e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik if (mAllDayTextLayout == null) { 2462e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int allDayWidth = mHoursWidth - EVENT_ALL_DAY_TEXT_LEFT_MARGIN 2463e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik - EVENT_ALL_DAY_TEXT_RIGHT_MARGIN; 2464e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mAllDayTextLayout = new StaticLayout(mAllDayString, 0, mAllDayString.length(), 2465e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik new TextPaint(p), allDayWidth, Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true, null, 2466e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik allDayWidth); 2467e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 2468e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik return mAllDayTextLayout; 2469e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 2470e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 24713e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh /** 24723e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh * Return the layout for a numbered event. Create it if not already existing 24733e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh */ 247408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan private StaticLayout getEventLayout(StaticLayout[] layouts, int i, Event event, Paint paint, 247508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan Rect r) { 247608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan if (i < 0 || i >= layouts.length) { 24770a0f7f3b2ca79419d417626f11b119d5a8b92f45Michael Chan return null; 24780a0f7f3b2ca79419d417626f11b119d5a8b92f45Michael Chan } 24790a0f7f3b2ca79419d417626f11b119d5a8b92f45Michael Chan 248008ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan StaticLayout layout = layouts[i]; 2481f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan // Check if we have already initialized the StaticLayout and that 2482f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan // the width hasn't changed (due to vertical resizing which causes 2483f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan // re-layout of events at min height) 24841ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan if (layout == null || r.width() != layout.getWidth()) { 2485e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik SpannableStringBuilder bob = new SpannableStringBuilder(); 2486e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik if (event.title != null) { 2487e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik bob.append(drawTextSanitizer(event.title.toString(), MAX_EVENT_TEXT_LEN)); 2488e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik bob.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, bob.length(), 0); 2489e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik bob.append(' '); 2490e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 2491e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik if (event.location != null) { 2492e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik bob.append(drawTextSanitizer(event.location.toString(), 2493e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik MAX_EVENT_TEXT_LEN - bob.length())); 2494e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik } 24953e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh 249625996100d6ea61888ebe54d7708a9a371bb12a55RoboErik switch (event.selfAttendeeStatus) { 249725996100d6ea61888ebe54d7708a9a371bb12a55RoboErik case Attendees.ATTENDEE_STATUS_INVITED: 249825996100d6ea61888ebe54d7708a9a371bb12a55RoboErik paint.setColor(event.color); 249925996100d6ea61888ebe54d7708a9a371bb12a55RoboErik break; 250025996100d6ea61888ebe54d7708a9a371bb12a55RoboErik case Attendees.ATTENDEE_STATUS_DECLINED: 250125996100d6ea61888ebe54d7708a9a371bb12a55RoboErik case Attendees.ATTENDEE_STATUS_NONE: // Your own events 250225996100d6ea61888ebe54d7708a9a371bb12a55RoboErik case Attendees.ATTENDEE_STATUS_ACCEPTED: 250325996100d6ea61888ebe54d7708a9a371bb12a55RoboErik case Attendees.ATTENDEE_STATUS_TENTATIVE: 250425996100d6ea61888ebe54d7708a9a371bb12a55RoboErik default: 250525996100d6ea61888ebe54d7708a9a371bb12a55RoboErik paint.setColor(mEventTextColor); 250625996100d6ea61888ebe54d7708a9a371bb12a55RoboErik break; 2507f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan } 2508f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan 25093e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh // Leave a one pixel boundary on the left and right of the rectangle for the event 2510e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik layout = new StaticLayout(bob, 0, bob.length(), new TextPaint(paint), r.width(), 25111ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true, null, r.width()); 25123e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh 251308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan layouts[i] = layout; 25143e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh } 25153e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh 25163e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh return layout; 25173e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh } 25183e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh 25191ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private void drawAllDayEvents(int firstDay, int numDays, Canvas canvas, Paint p) { 25203e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh 2521146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setTextSize(NORMAL_FONT_SIZE); 2522146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setTextAlign(Paint.Align.LEFT); 2523146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Paint eventTextPaint = mEventTextPaint; 2524146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 25253eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan final float startY = DAY_HEADER_HEIGHT; 25262fda24534978f55711526dbde747aa50d68dec40RoboErik final float stopY = startY + mAlldayHeight + ALLDAY_TOP_MARGIN; 2527e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik float x = 0; 252802041687c35441e8a21cb763f1fc3a26525292efDavid Brown int linesIndex = 0; 25293eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan 25303eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // Draw the inner vertical grid lines 25313eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setColor(mCalendarGridLineInnerVerticalColor); 25321ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan x = mHoursWidth; 25333eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan p.setStrokeWidth(GRID_LINE_INNER_WIDTH); 25341ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan // Line bounding the top of the all day area 25358f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan mLines[linesIndex++] = GRID_LINE_LEFT_MARGIN; 25361ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = startY; 2537e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik mLines[linesIndex++] = computeDayLeftPosition(mNumDays + 1); 25381ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = startY; 25391ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan 2540e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik for (int day = 0; day <= mNumDays; day++) { 2541e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik x = computeDayLeftPosition(day); 254202041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = x; 254302041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = startY; 254402041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = x; 254502041687c35441e8a21cb763f1fc3a26525292efDavid Brown mLines[linesIndex++] = stopY; 25463eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan } 2547e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(false); 254802041687c35441e8a21cb763f1fc3a26525292efDavid Brown canvas.drawLines(mLines, 0, linesIndex, p); 2549146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project p.setStyle(Style.FILL); 2550146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 25513eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan int y = DAY_HEADER_HEIGHT + ALLDAY_TOP_MARGIN; 2552146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project float left = mHoursWidth; 2553146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int lastDay = firstDay + numDays - 1; 255408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan final ArrayList<Event> events = mAllDayEvents; 2555146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int numEvents = events.size(); 25562fda24534978f55711526dbde747aa50d68dec40RoboErik // Whether or not we should draw the more events text 25572fda24534978f55711526dbde747aa50d68dec40RoboErik boolean hasMoreEvents = false; 25582fda24534978f55711526dbde747aa50d68dec40RoboErik // size of the allDay area 25592fda24534978f55711526dbde747aa50d68dec40RoboErik float drawHeight = mAlldayHeight; 25602fda24534978f55711526dbde747aa50d68dec40RoboErik // max number of events being drawn in one day of the allday area 25612fda24534978f55711526dbde747aa50d68dec40RoboErik float numRectangles = mMaxAlldayEvents; 25622fda24534978f55711526dbde747aa50d68dec40RoboErik // Where to cut off drawn allday events 25632fda24534978f55711526dbde747aa50d68dec40RoboErik int allDayEventClip = DAY_HEADER_HEIGHT + mAlldayHeight + ALLDAY_TOP_MARGIN; 25642fda24534978f55711526dbde747aa50d68dec40RoboErik // The number of events that weren't drawn in each day 25652fda24534978f55711526dbde747aa50d68dec40RoboErik mSkippedAlldayEvents = new int[numDays]; 25662fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMaxAlldayEvents > mMaxUnexpandedAlldayEventCount && !mShowAllAllDayEvents && 25672fda24534978f55711526dbde747aa50d68dec40RoboErik mAnimateDayHeight == 0) { 25682fda24534978f55711526dbde747aa50d68dec40RoboErik // We draw one fewer event than will fit so that more events text 25692fda24534978f55711526dbde747aa50d68dec40RoboErik // can be drawn 25702fda24534978f55711526dbde747aa50d68dec40RoboErik numRectangles = mMaxUnexpandedAlldayEventCount - 1; 25712fda24534978f55711526dbde747aa50d68dec40RoboErik // We also clip the events above the more events text 25722fda24534978f55711526dbde747aa50d68dec40RoboErik allDayEventClip -= MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT; 25732fda24534978f55711526dbde747aa50d68dec40RoboErik hasMoreEvents = true; 25742fda24534978f55711526dbde747aa50d68dec40RoboErik } else if (mAnimateDayHeight != 0) { 25752fda24534978f55711526dbde747aa50d68dec40RoboErik // clip at the end of the animating space 25762fda24534978f55711526dbde747aa50d68dec40RoboErik allDayEventClip = DAY_HEADER_HEIGHT + mAnimateDayHeight + ALLDAY_TOP_MARGIN; 25772fda24534978f55711526dbde747aa50d68dec40RoboErik } 2578146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int i = 0; i < numEvents; i++) { 2579146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event event = events.get(i); 2580146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int startDay = event.startDay; 2581146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int endDay = event.endDay; 2582c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa if (startDay > lastDay || endDay < firstDay) { 2583146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project continue; 2584c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa } 2585c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa if (startDay < firstDay) { 2586146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project startDay = firstDay; 2587c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa } 2588c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa if (endDay > lastDay) { 2589146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project endDay = lastDay; 2590c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa } 2591146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int startIndex = startDay - firstDay; 2592146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int endIndex = endDay - firstDay; 25932fda24534978f55711526dbde747aa50d68dec40RoboErik float height = mMaxAlldayEvents > mMaxUnexpandedAlldayEventCount ? mAnimateDayEventHeight : 25942fda24534978f55711526dbde747aa50d68dec40RoboErik drawHeight / numRectangles; 2595146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2596146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Prevent a single event from getting too big 2597f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan if (height > MAX_HEIGHT_OF_ONE_ALLDAY_EVENT) { 2598f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan height = MAX_HEIGHT_OF_ONE_ALLDAY_EVENT; 2599146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2600146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2601146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Leave a one-pixel space between the vertical day lines and the 2602146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // event rectangle. 2603e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik event.left = computeDayLeftPosition(startIndex); 2604e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik event.right = computeDayLeftPosition(endIndex + 1) - DAY_GAP; 2605146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project event.top = y + height * event.getColumn(); 260625996100d6ea61888ebe54d7708a9a371bb12a55RoboErik event.bottom = event.top + height - ALL_DAY_EVENT_RECT_BOTTOM_MARGIN; 26072fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMaxAlldayEvents > mMaxUnexpandedAlldayEventCount) { 26082fda24534978f55711526dbde747aa50d68dec40RoboErik // check if we should skip this event. We skip if it starts 26092fda24534978f55711526dbde747aa50d68dec40RoboErik // after the clip bound or ends after the skip bound and we're 26102fda24534978f55711526dbde747aa50d68dec40RoboErik // not animating. 26112fda24534978f55711526dbde747aa50d68dec40RoboErik if (event.top >= allDayEventClip) { 26122fda24534978f55711526dbde747aa50d68dec40RoboErik incrementSkipCount(mSkippedAlldayEvents, startIndex, endIndex); 26132fda24534978f55711526dbde747aa50d68dec40RoboErik continue; 26142fda24534978f55711526dbde747aa50d68dec40RoboErik } else if (event.bottom > allDayEventClip) { 26152fda24534978f55711526dbde747aa50d68dec40RoboErik if (hasMoreEvents) { 26162fda24534978f55711526dbde747aa50d68dec40RoboErik incrementSkipCount(mSkippedAlldayEvents, startIndex, endIndex); 26172fda24534978f55711526dbde747aa50d68dec40RoboErik continue; 26182fda24534978f55711526dbde747aa50d68dec40RoboErik } 26192fda24534978f55711526dbde747aa50d68dec40RoboErik event.bottom = allDayEventClip; 26202fda24534978f55711526dbde747aa50d68dec40RoboErik } 26212fda24534978f55711526dbde747aa50d68dec40RoboErik } 262225996100d6ea61888ebe54d7708a9a371bb12a55RoboErik Rect r = drawEventRect(event, canvas, p, eventTextPaint, (int) event.top, 262325996100d6ea61888ebe54d7708a9a371bb12a55RoboErik (int) event.bottom); 26241ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan setupAllDayTextRect(r); 262508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan StaticLayout layout = getEventLayout(mAllDayLayouts, i, event, eventTextPaint, r); 262608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan drawEventText(layout, r, canvas, r.top, r.bottom); 2627146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Check if this all-day event intersects the selected day 26292fda24534978f55711526dbde747aa50d68dec40RoboErik if (mSelectionAllday && mComputeSelectedEvents) { 2630146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (startDay <= mSelectionDay && endDay >= mSelectionDay) { 2631146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvents.add(event); 2632146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2633146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2634146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 26352fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMoreAlldayEventsTextAlpha != 0 && mSkippedAlldayEvents != null) { 26362fda24534978f55711526dbde747aa50d68dec40RoboErik // If the more allday text should be visible, draw it. 26372fda24534978f55711526dbde747aa50d68dec40RoboErik p.setColor(mMoreAlldayEventsTextAlpha << 24 & mMoreEventsTextColor); 26382fda24534978f55711526dbde747aa50d68dec40RoboErik for (int i = 0; i < mSkippedAlldayEvents.length; i++) { 26392fda24534978f55711526dbde747aa50d68dec40RoboErik if (mSkippedAlldayEvents[i] > 0) { 26402fda24534978f55711526dbde747aa50d68dec40RoboErik drawMoreAlldayEvents(canvas, mSkippedAlldayEvents[i], i, p); 26412fda24534978f55711526dbde747aa50d68dec40RoboErik } 26422fda24534978f55711526dbde747aa50d68dec40RoboErik } 26432fda24534978f55711526dbde747aa50d68dec40RoboErik } 2644146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 26452fda24534978f55711526dbde747aa50d68dec40RoboErik if (mSelectionAllday) { 2646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Compute the neighbors for the list of all-day events that 2647146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // intersect the selected day. 2648146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project computeAllDayNeighbors(); 2649146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2650146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Set the selection position to zero so that when we move down 2651146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // to the normal event area, we will highlight the topmost event. 2652146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project saveSelectionPosition(0f, 0f, 0f, 0f); 2653146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2654146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2655146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 26562fda24534978f55711526dbde747aa50d68dec40RoboErik // Helper method for counting the number of allday events skipped on each day 26572fda24534978f55711526dbde747aa50d68dec40RoboErik private void incrementSkipCount(int[] counts, int startIndex, int endIndex) { 26582fda24534978f55711526dbde747aa50d68dec40RoboErik if (counts == null || startIndex < 0 || endIndex > counts.length) { 26592fda24534978f55711526dbde747aa50d68dec40RoboErik return; 26602fda24534978f55711526dbde747aa50d68dec40RoboErik } 26612fda24534978f55711526dbde747aa50d68dec40RoboErik for (int i = startIndex; i <= endIndex; i++) { 26622fda24534978f55711526dbde747aa50d68dec40RoboErik counts[i]++; 26632fda24534978f55711526dbde747aa50d68dec40RoboErik } 26642fda24534978f55711526dbde747aa50d68dec40RoboErik } 26652fda24534978f55711526dbde747aa50d68dec40RoboErik 26662fda24534978f55711526dbde747aa50d68dec40RoboErik // Draws the "box +n" text for hidden allday events 26672fda24534978f55711526dbde747aa50d68dec40RoboErik protected void drawMoreAlldayEvents(Canvas canvas, int remainingEvents, int day, Paint p) { 2668e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int x = computeDayLeftPosition(day) + EVENT_ALL_DAY_TEXT_LEFT_MARGIN; 2669e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int y = (int) (mAlldayHeight - .5f * MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT - .5f 2670e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik * EVENT_SQUARE_WIDTH + DAY_HEADER_HEIGHT + ALLDAY_TOP_MARGIN); 26712fda24534978f55711526dbde747aa50d68dec40RoboErik float[] lines = new float[4 * 4]; 26722fda24534978f55711526dbde747aa50d68dec40RoboErik addChipOutline(lines, 0, x, y); 2673e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setColor(mMoreEventsTextColor); 2674e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setStrokeWidth(EVENT_RECT_STROKE_WIDTH); 2675e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(false); 26762fda24534978f55711526dbde747aa50d68dec40RoboErik canvas.drawLines(lines, p); 2677e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(true); 26782fda24534978f55711526dbde747aa50d68dec40RoboErik String text = mResources.getQuantityString(R.plurals.month_more_events, remainingEvents); 26792fda24534978f55711526dbde747aa50d68dec40RoboErik y += EVENT_SQUARE_WIDTH; 26802fda24534978f55711526dbde747aa50d68dec40RoboErik x += EVENT_SQUARE_WIDTH + EVENT_LINE_PADDING; 26812fda24534978f55711526dbde747aa50d68dec40RoboErik canvas.drawText(String.format(text, remainingEvents), x, y, p); 26822fda24534978f55711526dbde747aa50d68dec40RoboErik } 26832fda24534978f55711526dbde747aa50d68dec40RoboErik 26842fda24534978f55711526dbde747aa50d68dec40RoboErik // helper method for drawing a box 26852fda24534978f55711526dbde747aa50d68dec40RoboErik protected int addChipOutline(float[] lines, int count, int x, int y) { 26862fda24534978f55711526dbde747aa50d68dec40RoboErik // top of box 2687e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik lines[count++] = x - 1; 26882fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = y; 2689e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik lines[count++] = x + EVENT_SQUARE_WIDTH + 1; 26902fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = y; 26912fda24534978f55711526dbde747aa50d68dec40RoboErik // right side of box 26922fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = x + EVENT_SQUARE_WIDTH; 26932fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = y; 26942fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = x + EVENT_SQUARE_WIDTH; 26952fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = y + EVENT_SQUARE_WIDTH; 26962fda24534978f55711526dbde747aa50d68dec40RoboErik // left side of box 26972fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = x; 26982fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = y; 26992fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = x; 27002fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = y + EVENT_SQUARE_WIDTH + 1; 27012fda24534978f55711526dbde747aa50d68dec40RoboErik // bottom of box 27022fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = x; 27032fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = y + EVENT_SQUARE_WIDTH; 27042fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = x + EVENT_SQUARE_WIDTH + 1; 27052fda24534978f55711526dbde747aa50d68dec40RoboErik lines[count++] = y + EVENT_SQUARE_WIDTH; 27062fda24534978f55711526dbde747aa50d68dec40RoboErik 27072fda24534978f55711526dbde747aa50d68dec40RoboErik return count; 27082fda24534978f55711526dbde747aa50d68dec40RoboErik } 27092fda24534978f55711526dbde747aa50d68dec40RoboErik 2710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void computeAllDayNeighbors() { 2711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int len = mSelectedEvents.size(); 2712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (len == 0 || mSelectedEvent != null) { 2713146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 2714146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2716146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // First, clear all the links 2717146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int ii = 0; ii < len; ii++) { 2718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event ev = mSelectedEvents.get(ii); 2719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextUp = null; 2720146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextDown = null; 2721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextLeft = null; 2722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextRight = null; 2723146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // For each event in the selected event list "mSelectedEvents", find 272646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // its neighbors in the up and down directions. This could be done 2727146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // more efficiently by sorting on the Event.getColumn() field, but 2728146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // the list is expected to be very small. 2729146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2730146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Find the event in the same row as the previously selected all-day 2731146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // event, if any. 2732146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int startPosition = -1; 273368655b5af2b7e5f872a103858ec58a19042123ceRoboErik if (mPrevSelectedEvent != null && mPrevSelectedEvent.drawAsAllday()) { 2734146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project startPosition = mPrevSelectedEvent.getColumn(); 2735146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2736146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int maxPosition = -1; 2737146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event startEvent = null; 2738146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event maxPositionEvent = null; 2739146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int ii = 0; ii < len; ii++) { 2740146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event ev = mSelectedEvents.get(ii); 2741146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int position = ev.getColumn(); 2742146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (position == startPosition) { 2743146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project startEvent = ev; 2744146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (position > maxPosition) { 2745146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project maxPositionEvent = ev; 2746146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project maxPosition = position; 2747146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2748146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int jj = 0; jj < len; jj++) { 2749146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (jj == ii) { 2750146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project continue; 2751146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2752146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event neighbor = mSelectedEvents.get(jj); 2753146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborPosition = neighbor.getColumn(); 2754146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborPosition == position - 1) { 2755146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextUp = neighbor; 2756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (neighborPosition == position + 1) { 2757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextDown = neighbor; 2758146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2759146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2760146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2761146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (startEvent != null) { 2762146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvent = startEvent; 2763146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 2764146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvent = maxPositionEvent; 2765146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2766146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2767146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2768e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik private void drawEvents(int date, int dayIndex, int top, Canvas canvas, Paint p) { 2769146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Paint eventTextPaint = mEventTextPaint; 2770e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int left = computeDayLeftPosition(dayIndex); 2771e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int cellWidth = computeDayLeftPosition(dayIndex + 1) - left; 2772146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int cellHeight = mCellHeight; 2773146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2774146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Use the selected hour as the selection region 2775259b8f9a21fffd3858218581e9daaf689b6b888fErik Rect selectionArea = mSelectionRect; 2776146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project selectionArea.top = top + mSelectionHour * (cellHeight + HOUR_GAP); 2777146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project selectionArea.bottom = selectionArea.top + cellHeight; 2778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project selectionArea.left = left; 2779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project selectionArea.right = selectionArea.left + cellWidth; 2780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 278108ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan final ArrayList<Event> events = mEvents; 2782146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int numEvents = events.size(); 2783146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project EventGeometry geometry = mEventGeometry; 2784146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 27852fda24534978f55711526dbde747aa50d68dec40RoboErik final int viewEndY = mViewStartY + mViewHeight - DAY_HEADER_HEIGHT - mAlldayHeight; 2786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int i = 0; i < numEvents; i++) { 2787146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event event = events.get(i); 2788146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (!geometry.computeEventRect(date, left, top, cellWidth, event)) { 2789146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project continue; 2790146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2791146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 279208ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // Don't draw it if it is not visible 279308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan if (event.bottom < mViewStartY || event.top > viewEndY) { 279408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan continue; 279508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan } 279608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan 27972fda24534978f55711526dbde747aa50d68dec40RoboErik if (date == mSelectionDay && !mSelectionAllday && mComputeSelectedEvents 2798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project && geometry.eventIntersectsSelection(event, selectionArea)) { 2799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvents.add(event); 2800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2801146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 280225996100d6ea61888ebe54d7708a9a371bb12a55RoboErik Rect r = drawEventRect(event, canvas, p, eventTextPaint, mViewStartY, viewEndY); 28031ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan setupTextRect(r); 280408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan 280508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // Don't draw text if it is not visible 280608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan if (r.top > viewEndY || r.bottom < mViewStartY) { 280708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan continue; 280808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan } 280908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan StaticLayout layout = getEventLayout(mLayouts, i, event, eventTextPaint, r); 281008ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // TODO: not sure why we are 4 pixels off 281146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan drawEventText(layout, r, canvas, mViewStartY + 4, mViewStartY + mViewHeight 28122fda24534978f55711526dbde747aa50d68dec40RoboErik - DAY_HEADER_HEIGHT - mAlldayHeight); 2813146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2814146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2815259b8f9a21fffd3858218581e9daaf689b6b888fErik 2816259b8f9a21fffd3858218581e9daaf689b6b888fErik if (mComputeSelectedEvents) { 2817259b8f9a21fffd3858218581e9daaf689b6b888fErik mDispatchAccessibilityEventRunnable.mEventType = mSelectedEvent == null ? 2818259b8f9a21fffd3858218581e9daaf689b6b888fErik AccessibilityEvent.TYPE_VIEW_SELECTED : 2819259b8f9a21fffd3858218581e9daaf689b6b888fErik AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED; 2820259b8f9a21fffd3858218581e9daaf689b6b888fErik post(mDispatchAccessibilityEventRunnable); 2821259b8f9a21fffd3858218581e9daaf689b6b888fErik } 2822259b8f9a21fffd3858218581e9daaf689b6b888fErik 28232fda24534978f55711526dbde747aa50d68dec40RoboErik if (date == mSelectionDay && !mSelectionAllday && isFocused() 2824146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project && mSelectionMode != SELECTION_HIDDEN) { 2825146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project computeNeighbors(); 2826146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2827146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2828146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2829146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Computes the "nearest" neighbor event in four directions (left, right, 2830146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // up, down) for each of the events in the mSelectedEvents array. 2831146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void computeNeighbors() { 2832146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int len = mSelectedEvents.size(); 2833146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (len == 0 || mSelectedEvent != null) { 2834146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 2835146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2836146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2837146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // First, clear all the links 2838146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int ii = 0; ii < len; ii++) { 2839146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event ev = mSelectedEvents.get(ii); 2840146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextUp = null; 2841146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextDown = null; 2842146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextLeft = null; 2843146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextRight = null; 2844146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2845146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2846146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event startEvent = mSelectedEvents.get(0); 284746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int startEventDistance1 = 100000; // any large number 284846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int startEventDistance2 = 100000; // any large number 2849146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int prevLocation = FROM_NONE; 2850146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int prevTop; 2851146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int prevBottom; 2852146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int prevLeft; 2853146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int prevRight; 2854146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int prevCenter = 0; 2855146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Rect box = getCurrentSelectionPosition(); 2856146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mPrevSelectedEvent != null) { 2857146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevTop = (int) mPrevSelectedEvent.top; 2858146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevBottom = (int) mPrevSelectedEvent.bottom; 2859146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevLeft = (int) mPrevSelectedEvent.left; 2860146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevRight = (int) mPrevSelectedEvent.right; 2861146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Check if the previously selected event intersects the previous 286246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // selection box. (The previously selected event may be from a 2863146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // much older selection box.) 2864146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (prevTop >= mPrevBox.bottom || prevBottom <= mPrevBox.top 2865146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project || prevRight <= mPrevBox.left || prevLeft >= mPrevBox.right) { 2866146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevSelectedEvent = null; 2867146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevTop = mPrevBox.top; 2868146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevBottom = mPrevBox.bottom; 2869146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevLeft = mPrevBox.left; 2870146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevRight = mPrevBox.right; 2871146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 2872146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Clip the top and bottom to the previous selection box. 2873146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (prevTop < mPrevBox.top) { 2874146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevTop = mPrevBox.top; 2875146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2876146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (prevBottom > mPrevBox.bottom) { 2877146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevBottom = mPrevBox.bottom; 2878146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2879146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2880146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 2881146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Just use the previously drawn selection box 2882146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevTop = mPrevBox.top; 2883146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevBottom = mPrevBox.bottom; 2884146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevLeft = mPrevBox.left; 2885146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevRight = mPrevBox.right; 2886146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2887146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2888146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Figure out where we came from and compute the center of that area. 2889146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (prevLeft >= box.right) { 2890146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // The previously selected event was to the right of us. 2891146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevLocation = FROM_RIGHT; 2892146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevCenter = (prevTop + prevBottom) / 2; 2893146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (prevRight <= box.left) { 2894146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // The previously selected event was to the left of us. 2895146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevLocation = FROM_LEFT; 2896146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevCenter = (prevTop + prevBottom) / 2; 2897146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (prevBottom <= box.top) { 2898146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // The previously selected event was above us. 2899146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevLocation = FROM_ABOVE; 2900146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevCenter = (prevLeft + prevRight) / 2; 2901146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (prevTop >= box.bottom) { 2902146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // The previously selected event was below us. 2903146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevLocation = FROM_BELOW; 2904146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prevCenter = (prevLeft + prevRight) / 2; 2905146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2906146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2907146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // For each event in the selected event list "mSelectedEvents", search 2908146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // all the other events in that list for the nearest neighbor in 4 2909146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // directions. 2910146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int ii = 0; ii < len; ii++) { 2911146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event ev = mSelectedEvents.get(ii); 2912146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2913146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int startTime = ev.startTime; 2914146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int endTime = ev.endTime; 2915146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int left = (int) ev.left; 2916146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int right = (int) ev.right; 2917146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int top = (int) ev.top; 2918146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (top < box.top) { 2919146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project top = box.top; 2920146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2921146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int bottom = (int) ev.bottom; 2922146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (bottom > box.bottom) { 2923146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project bottom = box.bottom; 2924146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2925146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (false) { 2926146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL 2927146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project | DateUtils.FORMAT_CAP_NOON_MIDNIGHT; 2928ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan if (DateFormat.is24HourFormat(mContext)) { 2929146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project flags |= DateUtils.FORMAT_24HOUR; 2930146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 293146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan String timeRange = DateUtils.formatDateRange(mContext, ev.startMillis, 293246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan ev.endMillis, flags); 293346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan Log.i("Cal", "left: " + left + " right: " + right + " top: " + top + " bottom: " 293446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan + bottom + " ev: " + timeRange + " " + ev.title); 293546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 293646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int upDistanceMin = 10000; // any large number 293746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int downDistanceMin = 10000; // any large number 293846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int leftDistanceMin = 10000; // any large number 293946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan int rightDistanceMin = 10000; // any large number 2940146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event upEvent = null; 2941146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event downEvent = null; 2942146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event leftEvent = null; 2943146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event rightEvent = null; 2944146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2945146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Pick the starting event closest to the previously selected event, 294646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // if any. distance1 takes precedence over distance2. 2947146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int distance1 = 0; 2948146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int distance2 = 0; 2949146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (prevLocation == FROM_ABOVE) { 2950146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (left >= prevCenter) { 2951146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance1 = left - prevCenter; 2952146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (right <= prevCenter) { 2953146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance1 = prevCenter - right; 2954146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2955146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance2 = top - prevBottom; 2956146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (prevLocation == FROM_BELOW) { 2957146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (left >= prevCenter) { 2958146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance1 = left - prevCenter; 2959146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (right <= prevCenter) { 2960146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance1 = prevCenter - right; 2961146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2962146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance2 = prevTop - bottom; 2963146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (prevLocation == FROM_LEFT) { 2964146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (bottom <= prevCenter) { 2965146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance1 = prevCenter - bottom; 2966146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (top >= prevCenter) { 2967146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance1 = top - prevCenter; 2968146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2969146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance2 = left - prevRight; 2970146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (prevLocation == FROM_RIGHT) { 2971146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (bottom <= prevCenter) { 2972146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance1 = prevCenter - bottom; 2973146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (top >= prevCenter) { 2974146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance1 = top - prevCenter; 2975146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2976146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance2 = prevLeft - right; 2977146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2978146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (distance1 < startEventDistance1 2979146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project || (distance1 == startEventDistance1 && distance2 < startEventDistance2)) { 2980146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project startEvent = ev; 2981146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project startEventDistance1 = distance1; 2982146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project startEventDistance2 = distance2; 2983146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2984146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 2985146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // For each neighbor, figure out if it is above or below or left 2986146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // or right of me and compute the distance. 2987146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int jj = 0; jj < len; jj++) { 2988146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (jj == ii) { 2989146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project continue; 2990146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 2991146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event neighbor = mSelectedEvents.get(jj); 2992146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborLeft = (int) neighbor.left; 2993146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborRight = (int) neighbor.right; 2994146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighbor.endTime <= startTime) { 2995146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This neighbor is entirely above me. 2996146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If we overlap the same column, then compute the distance. 2997146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborLeft < right && neighborRight > left) { 2998146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int distance = startTime - neighbor.endTime; 2999146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (distance < upDistanceMin) { 3000146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project upDistanceMin = distance; 3001146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project upEvent = neighbor; 3002146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (distance == upDistanceMin) { 3003146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int center = (left + right) / 2; 3004146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int currentDistance = 0; 3005146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int currentLeft = (int) upEvent.left; 3006146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int currentRight = (int) upEvent.right; 3007146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (currentRight <= center) { 3008146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project currentDistance = center - currentRight; 3009146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (currentLeft >= center) { 3010146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project currentDistance = currentLeft - center; 3011146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3012146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3013146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborDistance = 0; 3014146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborRight <= center) { 3015146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project neighborDistance = center - neighborRight; 3016146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (neighborLeft >= center) { 3017146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project neighborDistance = neighborLeft - center; 3018146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3019146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborDistance < currentDistance) { 3020146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project upDistanceMin = distance; 3021146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project upEvent = neighbor; 3022146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3023146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3024146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3025146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (neighbor.startTime >= endTime) { 3026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This neighbor is entirely below me. 3027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If we overlap the same column, then compute the distance. 3028146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborLeft < right && neighborRight > left) { 3029146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int distance = neighbor.startTime - endTime; 3030146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (distance < downDistanceMin) { 3031146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project downDistanceMin = distance; 3032146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project downEvent = neighbor; 3033146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (distance == downDistanceMin) { 3034146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int center = (left + right) / 2; 3035146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int currentDistance = 0; 3036146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int currentLeft = (int) downEvent.left; 3037146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int currentRight = (int) downEvent.right; 3038146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (currentRight <= center) { 3039146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project currentDistance = center - currentRight; 3040146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (currentLeft >= center) { 3041146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project currentDistance = currentLeft - center; 3042146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3043146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3044146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborDistance = 0; 3045146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborRight <= center) { 3046146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project neighborDistance = center - neighborRight; 3047146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (neighborLeft >= center) { 3048146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project neighborDistance = neighborLeft - center; 3049146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3050146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborDistance < currentDistance) { 3051146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project downDistanceMin = distance; 3052146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project downEvent = neighbor; 3053146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3054146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3055146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3056146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3057146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3058146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborLeft >= right) { 3059146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This neighbor is entirely to the right of me. 3060146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Take the closest neighbor in the y direction. 3061146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int center = (top + bottom) / 2; 3062146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int distance = 0; 3063146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborBottom = (int) neighbor.bottom; 3064146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborTop = (int) neighbor.top; 3065146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborBottom <= center) { 3066146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance = center - neighborBottom; 3067146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (neighborTop >= center) { 3068146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance = neighborTop - center; 3069146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3070146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (distance < rightDistanceMin) { 3071146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project rightDistanceMin = distance; 3072146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project rightEvent = neighbor; 3073146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (distance == rightDistanceMin) { 3074146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Pick the closest in the x direction 3075146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborDistance = neighborLeft - right; 3076146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int currentDistance = (int) rightEvent.left - right; 3077146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborDistance < currentDistance) { 3078146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project rightDistanceMin = distance; 3079146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project rightEvent = neighbor; 3080146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3081146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3082146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (neighborRight <= left) { 3083146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This neighbor is entirely to the left of me. 3084146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Take the closest neighbor in the y direction. 3085146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int center = (top + bottom) / 2; 3086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int distance = 0; 3087146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborBottom = (int) neighbor.bottom; 3088146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborTop = (int) neighbor.top; 3089146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborBottom <= center) { 3090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance = center - neighborBottom; 3091146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (neighborTop >= center) { 3092146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project distance = neighborTop - center; 3093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3094146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (distance < leftDistanceMin) { 3095146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project leftDistanceMin = distance; 3096146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project leftEvent = neighbor; 3097146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (distance == leftDistanceMin) { 3098146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Pick the closest in the x direction 3099146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int neighborDistance = left - neighborRight; 3100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int currentDistance = left - (int) leftEvent.right; 3101146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (neighborDistance < currentDistance) { 3102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project leftDistanceMin = distance; 3103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project leftEvent = neighbor; 3104146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3105146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextUp = upEvent; 3109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextDown = downEvent; 3110146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextLeft = leftEvent; 3111146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ev.nextRight = rightEvent; 3112146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3113146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvent = startEvent; 3114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3115146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 311625996100d6ea61888ebe54d7708a9a371bb12a55RoboErik private Rect drawEventRect(Event event, Canvas canvas, Paint p, Paint eventTextPaint, 311725996100d6ea61888ebe54d7708a9a371bb12a55RoboErik int visibleTop, int visibleBot) { 311811ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan // Draw the Event Rect 31191ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan Rect r = mRect; 312025996100d6ea61888ebe54d7708a9a371bb12a55RoboErik r.top = Math.max((int) event.top + EVENT_RECT_TOP_MARGIN, visibleTop); 312125996100d6ea61888ebe54d7708a9a371bb12a55RoboErik r.bottom = Math.min((int) event.bottom - EVENT_RECT_BOTTOM_MARGIN, visibleBot); 31221ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.left = (int) event.left + EVENT_RECT_LEFT_MARGIN; 312325996100d6ea61888ebe54d7708a9a371bb12a55RoboErik r.right = (int) event.right; 31241ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan 3125f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan Drawable eventBoxDrawable; 3126f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan switch (event.selfAttendeeStatus) { 3127f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan case Attendees.ATTENDEE_STATUS_INVITED: 312825996100d6ea61888ebe54d7708a9a371bb12a55RoboErik p.setStyle(Style.STROKE); 312925996100d6ea61888ebe54d7708a9a371bb12a55RoboErik break; 3130f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan case Attendees.ATTENDEE_STATUS_DECLINED: 313125996100d6ea61888ebe54d7708a9a371bb12a55RoboErik mDeclinedBgDrawable.setColorFilter((event.color & 0x00FFFFFF) | DECLINED_ALPHA, 313225996100d6ea61888ebe54d7708a9a371bb12a55RoboErik PorterDuff.Mode.OVERLAY); 3133f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan break; 3134f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan case Attendees.ATTENDEE_STATUS_NONE: // Your own events 3135f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan case Attendees.ATTENDEE_STATUS_ACCEPTED: 3136f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan case Attendees.ATTENDEE_STATUS_TENTATIVE: 3137f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan default: 313825996100d6ea61888ebe54d7708a9a371bb12a55RoboErik p.setStyle(Style.FILL_AND_STROKE); 313925996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // eventBoxDrawable = mAcceptedOrTentativeEventBoxDrawable; 3140f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan break; 3141f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan } 3142e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 3143e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(false); 3144e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 314525996100d6ea61888ebe54d7708a9a371bb12a55RoboErik if (event.selfAttendeeStatus == Attendees.ATTENDEE_STATUS_DECLINED) { 314625996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // Magic 314725996100d6ea61888ebe54d7708a9a371bb12a55RoboErik int oldTop = r.top; 314825996100d6ea61888ebe54d7708a9a371bb12a55RoboErik r.top = r.bottom; 314925996100d6ea61888ebe54d7708a9a371bb12a55RoboErik r.bottom = oldTop; 315025996100d6ea61888ebe54d7708a9a371bb12a55RoboErik mDeclinedBgDrawable.setBounds(r); 315125996100d6ea61888ebe54d7708a9a371bb12a55RoboErik mDeclinedBgDrawable.draw(canvas); 315225996100d6ea61888ebe54d7708a9a371bb12a55RoboErik } else { 315325996100d6ea61888ebe54d7708a9a371bb12a55RoboErik int halfStroke = EVENT_RECT_STROKE_WIDTH / 2; 315425996100d6ea61888ebe54d7708a9a371bb12a55RoboErik r.top = Math.max((int) event.top + EVENT_RECT_TOP_MARGIN + halfStroke, visibleTop); 315525996100d6ea61888ebe54d7708a9a371bb12a55RoboErik r.bottom = Math.min((int) event.bottom - EVENT_RECT_BOTTOM_MARGIN - halfStroke, 315625996100d6ea61888ebe54d7708a9a371bb12a55RoboErik visibleBot); 315725996100d6ea61888ebe54d7708a9a371bb12a55RoboErik r.left += EVENT_RECT_STROKE_WIDTH / 2; 315825996100d6ea61888ebe54d7708a9a371bb12a55RoboErik r.right -= EVENT_RECT_STROKE_WIDTH / 2; 315925996100d6ea61888ebe54d7708a9a371bb12a55RoboErik p.setStrokeWidth(EVENT_RECT_STROKE_WIDTH); 316025996100d6ea61888ebe54d7708a9a371bb12a55RoboErik p.setColor(event.color); 316125996100d6ea61888ebe54d7708a9a371bb12a55RoboErik canvas.drawRect(r, p); 316225996100d6ea61888ebe54d7708a9a371bb12a55RoboErik } 3163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 31641ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan p.setStyle(Style.FILL); 3165e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 3166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If this event is selected, then use the selection color 3167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectedEvent == event) { 31681ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan boolean paintIt = false; 31691ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan int color = 0; 3170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionMode == SELECTION_PRESSED) { 3171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Also, remember the last selected event that we drew 3172146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevSelectedEvent = event; 3173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // box = mBoxPressed; 317478f58c119af15ed85a727e16cddd793ced4c809dMichael Chan color = mPressedColor; 31751ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan paintIt = true; 3176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (mSelectionMode == SELECTION_SELECTED) { 3177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Also, remember the last selected event that we drew 3178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPrevSelectedEvent = event; 3179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // box = mBoxSelected; 318078f58c119af15ed85a727e16cddd793ced4c809dMichael Chan color = mPressedColor; 31811ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan paintIt = true; 3182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (mSelectionMode == SELECTION_LONGPRESS) { 3183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // box = mBoxLongPressed; 318478f58c119af15ed85a727e16cddd793ced4c809dMichael Chan color = mPressedColor; 31851ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan paintIt = true; 31861ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan } 31871ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan 31881ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan if (paintIt) { 31891ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan p.setColor(color); 31901ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan canvas.drawRect(r, p); 3191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3192e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik 3193e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik p.setAntiAlias(true); 3194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 319611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan // Draw cal color square border 319725996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // r.top = (int) event.top + CALENDAR_COLOR_SQUARE_V_OFFSET; 319825996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // r.left = (int) event.left + CALENDAR_COLOR_SQUARE_H_OFFSET; 319925996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // r.bottom = r.top + CALENDAR_COLOR_SQUARE_SIZE + 1; 320025996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // r.right = r.left + CALENDAR_COLOR_SQUARE_SIZE + 1; 320125996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // p.setColor(0xFFFFFFFF); 320225996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // canvas.drawRect(r, p); 32038af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project 320411ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan // Draw cal color 320525996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // r.top++; 320625996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // r.left++; 320725996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // r.bottom--; 320825996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // r.right--; 320925996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // p.setColor(event.color); 321025996100d6ea61888ebe54d7708a9a371bb12a55RoboErik // canvas.drawRect(r, p); 3211e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 32123eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan // Setup rect for drawEventText which follows 32131ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.top = (int) event.top + EVENT_RECT_TOP_MARGIN; 32141ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.bottom = (int) event.bottom - EVENT_RECT_BOTTOM_MARGIN; 32151ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.left = (int) event.left + EVENT_RECT_LEFT_MARGIN; 32161ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan r.right = (int) event.right - EVENT_RECT_RIGHT_MARGIN; 32171ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan return r; 3218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 32200d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan private Pattern drawTextSanitizerFilter = Pattern.compile("[\t\n],"); 32210d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan 32220d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan // Sanitize a string before passing it to drawText or else we get little 32230d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan // squares. For newlines and tabs before a comma, delete the character. 32240d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan // Otherwise, just replace them with a space. 3225f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan private String drawTextSanitizer(String string, int maxEventTextLen) { 32260d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan Matcher m = drawTextSanitizerFilter.matcher(string); 3227f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan string = m.replaceAll(","); 3228f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan 3229f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan int len = string.length(); 3230f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan if (len > maxEventTextLen) { 3231f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan string = string.substring(0, maxEventTextLen); 3232f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan len = maxEventTextLen; 3233f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan } 3234f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan 3235f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan return string.replace('\n', ' '); 32360d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan } 32370d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan 323808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan private void drawEventText(StaticLayout eventLayout, Rect rect, Canvas canvas, int top, 323908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan int bottom) { 32401ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan // drawEmptyRect(canvas, rect, 0xFFFF00FF); // for debugging 32411ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan 32421ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan int width = rect.right - rect.left; 32431ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan int height = rect.bottom - rect.top; 3244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3245146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If the rectangle is too small for text, then return 32460a0f7f3b2ca79419d417626f11b119d5a8b92f45Michael Chan if (eventLayout == null || width < MIN_CELL_WIDTH_FOR_TEXT) { 3247f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan return; 3248f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan } 3249f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan 325008ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan int totalLineHeight = 0; 3251f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan int lineCount = eventLayout.getLineCount(); 3252f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan for (int i = 0; i < lineCount; i++) { 3253f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan int lineBottom = eventLayout.getLineBottom(i); 3254f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan if (lineBottom <= height) { 325508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan totalLineHeight = lineBottom; 325608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan } else { 325708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan break; 3258f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan } 3259f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan } 3260f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan 326108ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan if (totalLineHeight == 0 || rect.top > bottom || rect.top + totalLineHeight < top) { 3262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 3263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 32653e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh // Use a StaticLayout to format the string. 32663e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh canvas.save(); 32671ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan canvas.translate(rect.left, rect.top); 32681ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan rect.left = 0; 32691ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan rect.right = width; 32701ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan rect.top = 0; 327108ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan rect.bottom = totalLineHeight; 327208ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan 327308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // There's a bug somewhere. If this rect is outside of a previous 327408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // cliprect, this becomes a no-op. What happens is that the text draw 327508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // past the event rect. The current fix is to not draw the staticLayout 327608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan // at all if it is completely out of bound. 32771ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan canvas.clipRect(rect); 32783e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh eventLayout.draw(canvas); 32793e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh canvas.restore(); 3280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3281146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 32821ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan // This is to replace p.setStyle(Style.STROKE); canvas.drawRect() since it 32831ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan // doesn't work well with hardware acceleration 32841ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan private void drawEmptyRect(Canvas canvas, Rect r, int color) { 32851ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan int linesIndex = 0; 32861ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.left; 32871ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.top; 32881ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.right; 32891ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.top; 32901ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan 32911ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.left; 32921ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.bottom; 32931ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.right; 32941ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.bottom; 32951ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan 32961ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.left; 32971ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.top; 32981ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.left; 32991ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.bottom; 33001ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan 33011ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.right; 33021ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.top; 33031ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.right; 33041ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mLines[linesIndex++] = r.bottom; 33051ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan mPaint.setColor(color); 33061ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan canvas.drawLines(mLines, 0, linesIndex, mPaint); 33071ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan } 33081ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan 3309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void updateEventDetails() { 3310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectedEvent == null || mSelectionMode == SELECTION_HIDDEN 3311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project || mSelectionMode == SELECTION_LONGPRESS) { 3312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup.dismiss(); 3313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 3314146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3315666fc5e8ddbac15c951aad738bd818ee307eae42Erik if (mLastPopupEventID == mSelectedEvent.id) { 3316666fc5e8ddbac15c951aad738bd818ee307eae42Erik return; 3317666fc5e8ddbac15c951aad738bd818ee307eae42Erik } 3318666fc5e8ddbac15c951aad738bd818ee307eae42Erik 3319666fc5e8ddbac15c951aad738bd818ee307eae42Erik mLastPopupEventID = mSelectedEvent.id; 3320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Remove any outstanding callbacks to dismiss the popup. 3322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project getHandler().removeCallbacks(mDismissPopup); 3323146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3324146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event event = mSelectedEvent; 3325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project TextView titleView = (TextView) mPopupView.findViewById(R.id.event_title); 3326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project titleView.setText(event.title); 3327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3328146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ImageView imageView = (ImageView) mPopupView.findViewById(R.id.reminder_icon); 3329146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project imageView.setVisibility(event.hasAlarm ? View.VISIBLE : View.GONE); 3330146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project imageView = (ImageView) mPopupView.findViewById(R.id.repeat_icon); 3332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project imageView.setVisibility(event.isRepeating ? View.VISIBLE : View.GONE); 3333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int flags; 3335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (event.allDay) { 333646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan flags = DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_DATE 333746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL; 3338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 3339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE 3340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL 3341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project | DateUtils.FORMAT_CAP_NOON_MIDNIGHT; 3342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3343ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan if (DateFormat.is24HourFormat(mContext)) { 3344146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project flags |= DateUtils.FORMAT_24HOUR; 3345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 334646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan String timeRange = Utils.formatDateRange(mContext, event.startMillis, event.endMillis, 334746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan flags); 3348146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project TextView timeView = (TextView) mPopupView.findViewById(R.id.time); 3349146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project timeView.setText(timeRange); 3350146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3351146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project TextView whereView = (TextView) mPopupView.findViewById(R.id.where); 3352146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project final boolean empty = TextUtils.isEmpty(event.location); 3353146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project whereView.setVisibility(empty ? View.GONE : View.VISIBLE); 3354146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (!empty) whereView.setText(event.location); 3355146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.LEFT, mHoursWidth, 5); 3357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project postDelayed(mDismissPopup, POPUP_DISMISS_DELAY); 3358146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3359146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // The following routines are called from the parent activity when certain 3361146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // touch events occur. 33624484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan private void doDown(MotionEvent ev) { 3363146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mTouchMode = TOUCH_MODE_DOWN; 3364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartX = 0; 3365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mOnFlingCalled = false; 3366146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project getHandler().removeCallbacks(mContinueScroll); 3367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 33692fda24534978f55711526dbde747aa50d68dec40RoboErik // Kicks off all the animations when the expand allday area is tapped 33702fda24534978f55711526dbde747aa50d68dec40RoboErik private void doExpandAllDayClick() { 33712fda24534978f55711526dbde747aa50d68dec40RoboErik mShowAllAllDayEvents = !mShowAllAllDayEvents; 33722fda24534978f55711526dbde747aa50d68dec40RoboErik 33732fda24534978f55711526dbde747aa50d68dec40RoboErik ObjectAnimator.setFrameDelay(0); 33742fda24534978f55711526dbde747aa50d68dec40RoboErik 33752fda24534978f55711526dbde747aa50d68dec40RoboErik // Determine the starting height 33762fda24534978f55711526dbde747aa50d68dec40RoboErik if (mAnimateDayHeight == 0) { 33772fda24534978f55711526dbde747aa50d68dec40RoboErik mAnimateDayHeight = mShowAllAllDayEvents ? 33782fda24534978f55711526dbde747aa50d68dec40RoboErik mAlldayHeight - (int) MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT : mAlldayHeight; 33792fda24534978f55711526dbde747aa50d68dec40RoboErik } 33802fda24534978f55711526dbde747aa50d68dec40RoboErik // Cancel current animations 33812fda24534978f55711526dbde747aa50d68dec40RoboErik mCancellingAnimations = true; 33822fda24534978f55711526dbde747aa50d68dec40RoboErik if (mAlldayAnimator != null) { 33832fda24534978f55711526dbde747aa50d68dec40RoboErik mAlldayAnimator.cancel(); 33842fda24534978f55711526dbde747aa50d68dec40RoboErik } 33852fda24534978f55711526dbde747aa50d68dec40RoboErik if (mAlldayEventAnimator != null) { 33862fda24534978f55711526dbde747aa50d68dec40RoboErik mAlldayEventAnimator.cancel(); 33872fda24534978f55711526dbde747aa50d68dec40RoboErik } 33882fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMoreAlldayEventsAnimator != null) { 33892fda24534978f55711526dbde747aa50d68dec40RoboErik mMoreAlldayEventsAnimator.cancel(); 33902fda24534978f55711526dbde747aa50d68dec40RoboErik } 33912fda24534978f55711526dbde747aa50d68dec40RoboErik mCancellingAnimations = false; 33922fda24534978f55711526dbde747aa50d68dec40RoboErik // get new animators 33932fda24534978f55711526dbde747aa50d68dec40RoboErik mAlldayAnimator = getAllDayAnimator(); 33942fda24534978f55711526dbde747aa50d68dec40RoboErik mAlldayEventAnimator = getAllDayEventAnimator(); 33952fda24534978f55711526dbde747aa50d68dec40RoboErik mMoreAlldayEventsAnimator = ObjectAnimator.ofInt(this, 33962fda24534978f55711526dbde747aa50d68dec40RoboErik "moreAllDayEventsTextAlpha", 33972fda24534978f55711526dbde747aa50d68dec40RoboErik mShowAllAllDayEvents ? MORE_EVENTS_MAX_ALPHA : 0, 33982fda24534978f55711526dbde747aa50d68dec40RoboErik mShowAllAllDayEvents ? 0 : MORE_EVENTS_MAX_ALPHA); 33992fda24534978f55711526dbde747aa50d68dec40RoboErik 34002fda24534978f55711526dbde747aa50d68dec40RoboErik // Set up delays and start the animators 34012fda24534978f55711526dbde747aa50d68dec40RoboErik mAlldayAnimator.setStartDelay(mShowAllAllDayEvents ? ANIMATION_SECONDARY_DURATION : 0); 34022fda24534978f55711526dbde747aa50d68dec40RoboErik mAlldayAnimator.start(); 34032fda24534978f55711526dbde747aa50d68dec40RoboErik mMoreAlldayEventsAnimator.setStartDelay(mShowAllAllDayEvents ? 0 : ANIMATION_DURATION); 34042fda24534978f55711526dbde747aa50d68dec40RoboErik mMoreAlldayEventsAnimator.setDuration(ANIMATION_SECONDARY_DURATION); 34052fda24534978f55711526dbde747aa50d68dec40RoboErik mMoreAlldayEventsAnimator.start(); 34062fda24534978f55711526dbde747aa50d68dec40RoboErik if (mAlldayEventAnimator != null) { 34072fda24534978f55711526dbde747aa50d68dec40RoboErik // This is the only animator that can return null, so check it 34082fda24534978f55711526dbde747aa50d68dec40RoboErik mAlldayEventAnimator 34092fda24534978f55711526dbde747aa50d68dec40RoboErik .setStartDelay(mShowAllAllDayEvents ? ANIMATION_SECONDARY_DURATION : 0); 34102fda24534978f55711526dbde747aa50d68dec40RoboErik mAlldayEventAnimator.start(); 34112fda24534978f55711526dbde747aa50d68dec40RoboErik } 34122fda24534978f55711526dbde747aa50d68dec40RoboErik } 34132fda24534978f55711526dbde747aa50d68dec40RoboErik 34142fda24534978f55711526dbde747aa50d68dec40RoboErik /** 34152fda24534978f55711526dbde747aa50d68dec40RoboErik * Figures out the initial heights for allDay events and space when 34162fda24534978f55711526dbde747aa50d68dec40RoboErik * a view is being set up. 34172fda24534978f55711526dbde747aa50d68dec40RoboErik */ 34182fda24534978f55711526dbde747aa50d68dec40RoboErik public void initAllDayHeights() { 34192fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMaxAlldayEvents <= mMaxUnexpandedAlldayEventCount) { 34202fda24534978f55711526dbde747aa50d68dec40RoboErik return; 34212fda24534978f55711526dbde747aa50d68dec40RoboErik } 34222fda24534978f55711526dbde747aa50d68dec40RoboErik if (mShowAllAllDayEvents) { 34232fda24534978f55711526dbde747aa50d68dec40RoboErik int maxADHeight = mViewHeight - DAY_HEADER_HEIGHT - MIN_HOURS_HEIGHT; 34242fda24534978f55711526dbde747aa50d68dec40RoboErik maxADHeight = Math.min(maxADHeight, 34252fda24534978f55711526dbde747aa50d68dec40RoboErik (int)(mMaxAlldayEvents * MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT)); 34262fda24534978f55711526dbde747aa50d68dec40RoboErik mAnimateDayEventHeight = maxADHeight / mMaxAlldayEvents; 34272fda24534978f55711526dbde747aa50d68dec40RoboErik } else { 34282fda24534978f55711526dbde747aa50d68dec40RoboErik mAnimateDayEventHeight = (int)MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT; 34292fda24534978f55711526dbde747aa50d68dec40RoboErik } 34302fda24534978f55711526dbde747aa50d68dec40RoboErik } 34312fda24534978f55711526dbde747aa50d68dec40RoboErik 34322fda24534978f55711526dbde747aa50d68dec40RoboErik // Sets up an animator for changing the height of allday events 34332fda24534978f55711526dbde747aa50d68dec40RoboErik private ObjectAnimator getAllDayEventAnimator() { 34342fda24534978f55711526dbde747aa50d68dec40RoboErik // First calculate the absolute max height 34352fda24534978f55711526dbde747aa50d68dec40RoboErik int maxADHeight = mViewHeight - DAY_HEADER_HEIGHT - MIN_HOURS_HEIGHT; 34362fda24534978f55711526dbde747aa50d68dec40RoboErik // Now expand to fit but not beyond the absolute max 34372fda24534978f55711526dbde747aa50d68dec40RoboErik maxADHeight = 34382fda24534978f55711526dbde747aa50d68dec40RoboErik Math.min(maxADHeight, (int)(mMaxAlldayEvents * MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT)); 34392fda24534978f55711526dbde747aa50d68dec40RoboErik // calculate the height of individual events in order to fit 34402fda24534978f55711526dbde747aa50d68dec40RoboErik int fitHeight = maxADHeight / mMaxAlldayEvents; 34412fda24534978f55711526dbde747aa50d68dec40RoboErik int currentHeight = mAnimateDayEventHeight; 34422fda24534978f55711526dbde747aa50d68dec40RoboErik int desiredHeight = 34432fda24534978f55711526dbde747aa50d68dec40RoboErik mShowAllAllDayEvents ? fitHeight : (int)MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT; 34442fda24534978f55711526dbde747aa50d68dec40RoboErik // if there's nothing to animate just return 34452fda24534978f55711526dbde747aa50d68dec40RoboErik if (currentHeight == desiredHeight) { 34462fda24534978f55711526dbde747aa50d68dec40RoboErik return null; 34472fda24534978f55711526dbde747aa50d68dec40RoboErik } 34482fda24534978f55711526dbde747aa50d68dec40RoboErik 34492fda24534978f55711526dbde747aa50d68dec40RoboErik // Set up the animator with the calculated values 34502fda24534978f55711526dbde747aa50d68dec40RoboErik ObjectAnimator animator = ObjectAnimator.ofInt(this, "animateDayEventHeight", 34512fda24534978f55711526dbde747aa50d68dec40RoboErik currentHeight, desiredHeight); 34522fda24534978f55711526dbde747aa50d68dec40RoboErik animator.setDuration(ANIMATION_DURATION); 34532fda24534978f55711526dbde747aa50d68dec40RoboErik return animator; 34542fda24534978f55711526dbde747aa50d68dec40RoboErik } 34552fda24534978f55711526dbde747aa50d68dec40RoboErik 34562fda24534978f55711526dbde747aa50d68dec40RoboErik // Sets up an animator for changing the height of the allday area 34572fda24534978f55711526dbde747aa50d68dec40RoboErik private ObjectAnimator getAllDayAnimator() { 34582fda24534978f55711526dbde747aa50d68dec40RoboErik // Calculate the absolute max height 34592fda24534978f55711526dbde747aa50d68dec40RoboErik int maxADHeight = mViewHeight - DAY_HEADER_HEIGHT - MIN_HOURS_HEIGHT; 34602fda24534978f55711526dbde747aa50d68dec40RoboErik // Find the desired height but don't exceed abs max 34612fda24534978f55711526dbde747aa50d68dec40RoboErik maxADHeight = 34622fda24534978f55711526dbde747aa50d68dec40RoboErik Math.min(maxADHeight, (int)(mMaxAlldayEvents * MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT)); 34632fda24534978f55711526dbde747aa50d68dec40RoboErik // calculate the current and desired heights 34642fda24534978f55711526dbde747aa50d68dec40RoboErik int currentHeight = mAnimateDayHeight != 0 ? mAnimateDayHeight : mAlldayHeight; 34652fda24534978f55711526dbde747aa50d68dec40RoboErik int desiredHeight = mShowAllAllDayEvents ? maxADHeight : 34662fda24534978f55711526dbde747aa50d68dec40RoboErik (int) (MAX_UNEXPANDED_ALLDAY_HEIGHT - MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT - 1); 34672fda24534978f55711526dbde747aa50d68dec40RoboErik 34682fda24534978f55711526dbde747aa50d68dec40RoboErik // Set up the animator with the calculated values 34692fda24534978f55711526dbde747aa50d68dec40RoboErik ObjectAnimator animator = ObjectAnimator.ofInt(this, "animateDayHeight", 34702fda24534978f55711526dbde747aa50d68dec40RoboErik currentHeight, desiredHeight); 34712fda24534978f55711526dbde747aa50d68dec40RoboErik animator.setDuration(ANIMATION_DURATION); 34722fda24534978f55711526dbde747aa50d68dec40RoboErik 34732fda24534978f55711526dbde747aa50d68dec40RoboErik animator.addListener(new AnimatorListenerAdapter() { 34742fda24534978f55711526dbde747aa50d68dec40RoboErik @Override 34752fda24534978f55711526dbde747aa50d68dec40RoboErik public void onAnimationEnd(Animator animation) { 34762fda24534978f55711526dbde747aa50d68dec40RoboErik if (!mCancellingAnimations) { 34772fda24534978f55711526dbde747aa50d68dec40RoboErik // when finished, set this to 0 to signify not animating 34782fda24534978f55711526dbde747aa50d68dec40RoboErik mAnimateDayHeight = 0; 3479cbc6ad106295bad0bef29cb51a2dfb56be9d6bcdRoboErik mUseExpandIcon = !mShowAllAllDayEvents; 34802fda24534978f55711526dbde747aa50d68dec40RoboErik } 34812fda24534978f55711526dbde747aa50d68dec40RoboErik mRemeasure = true; 34822fda24534978f55711526dbde747aa50d68dec40RoboErik invalidate(); 34832fda24534978f55711526dbde747aa50d68dec40RoboErik } 34842fda24534978f55711526dbde747aa50d68dec40RoboErik }); 34852fda24534978f55711526dbde747aa50d68dec40RoboErik return animator; 34862fda24534978f55711526dbde747aa50d68dec40RoboErik } 34872fda24534978f55711526dbde747aa50d68dec40RoboErik 34882fda24534978f55711526dbde747aa50d68dec40RoboErik // setter for the 'box +n' alpha text used by the animator 34892fda24534978f55711526dbde747aa50d68dec40RoboErik public void setMoreAllDayEventsTextAlpha(int alpha) { 34902fda24534978f55711526dbde747aa50d68dec40RoboErik mMoreAlldayEventsTextAlpha = alpha; 34912fda24534978f55711526dbde747aa50d68dec40RoboErik invalidate(); 34922fda24534978f55711526dbde747aa50d68dec40RoboErik } 34932fda24534978f55711526dbde747aa50d68dec40RoboErik 34942fda24534978f55711526dbde747aa50d68dec40RoboErik // setter for the height of the allday area used by the animator 34952fda24534978f55711526dbde747aa50d68dec40RoboErik public void setAnimateDayHeight(int height) { 34962fda24534978f55711526dbde747aa50d68dec40RoboErik mAnimateDayHeight = height; 34972fda24534978f55711526dbde747aa50d68dec40RoboErik mRemeasure = true; 34982fda24534978f55711526dbde747aa50d68dec40RoboErik invalidate(); 34992fda24534978f55711526dbde747aa50d68dec40RoboErik } 35002fda24534978f55711526dbde747aa50d68dec40RoboErik 35012fda24534978f55711526dbde747aa50d68dec40RoboErik // setter for the height of allday events used by the animator 35022fda24534978f55711526dbde747aa50d68dec40RoboErik public void setAnimateDayEventHeight(int height) { 35032fda24534978f55711526dbde747aa50d68dec40RoboErik mAnimateDayEventHeight = height; 35042fda24534978f55711526dbde747aa50d68dec40RoboErik mRemeasure = true; 35052fda24534978f55711526dbde747aa50d68dec40RoboErik invalidate(); 35062fda24534978f55711526dbde747aa50d68dec40RoboErik } 35072fda24534978f55711526dbde747aa50d68dec40RoboErik 35084484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan private void doSingleTapUp(MotionEvent ev) { 3509bbf2cbdb040108da50d763b699836e5f63fb7cceMichael Chan if (!mHandleActionUp || mScrolling) { 3510d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan return; 3511d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 3512d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3513146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int x = (int) ev.getX(); 3514146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int y = (int) ev.getY(); 3515146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int selectedDay = mSelectionDay; 3516146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int selectedHour = mSelectionHour; 3517146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 35182fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMaxAlldayEvents > mMaxUnexpandedAlldayEventCount) { 35192fda24534978f55711526dbde747aa50d68dec40RoboErik // check if the tap was in the allday expansion area 35202fda24534978f55711526dbde747aa50d68dec40RoboErik int bottom = MAX_UNEXPANDED_ALLDAY_HEIGHT + DAY_HEADER_HEIGHT + ALLDAY_TOP_MARGIN; 35212fda24534978f55711526dbde747aa50d68dec40RoboErik if((x < mHoursWidth && y > DAY_HEADER_HEIGHT && y < DAY_HEADER_HEIGHT + mAlldayHeight) 35222fda24534978f55711526dbde747aa50d68dec40RoboErik || (!mShowAllAllDayEvents && mAnimateDayHeight == 0 && y < bottom && 35232fda24534978f55711526dbde747aa50d68dec40RoboErik y >= bottom - MIN_UNEXPANDED_ALLDAY_EVENT_HEIGHT)) { 35242fda24534978f55711526dbde747aa50d68dec40RoboErik doExpandAllDayClick(); 35252fda24534978f55711526dbde747aa50d68dec40RoboErik return; 35262fda24534978f55711526dbde747aa50d68dec40RoboErik } 35272fda24534978f55711526dbde747aa50d68dec40RoboErik } 35282fda24534978f55711526dbde747aa50d68dec40RoboErik 3529146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project boolean validPosition = setSelectionFromPosition(x, y); 3530146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (!validPosition) { 3531360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan if (y < DAY_HEADER_HEIGHT) { 3532360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan Time selectedTime = new Time(mBaseDate); 3533360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan selectedTime.setJulianDay(mSelectionDay); 3534360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan selectedTime.hour = mSelectionHour; 3535360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan selectedTime.normalize(true /* ignore isDst */); 3536360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan mController.sendEvent(this, EventType.GO_TO, null, null, selectedTime, -1, 3537360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan ViewType.DAY, CalendarController.EXTRA_GOTO_DATE, null, null); 3538360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan } 3539146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 3540146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3541146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 354280bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan mSelectionMode = SELECTION_SELECTED; 3543146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 3544146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 354580bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan if (mSelectedEvent != null) { 354680bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan // If the tap is on an event, launch the "View event" view 3547344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, mSelectedEvent.id, 3548344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan mSelectedEvent.startMillis, mSelectedEvent.endMillis, (int) ev.getRawX(), 354987f993ff96172f508d3f241f8a425f953c7eb739RoboErik (int) ev.getRawY(), getSelectedTimeInMillis()); 3550344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan } else if (selectedDay == mSelectionDay && selectedHour == mSelectionHour) { 3551344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan // If the tap is on an already selected hour slot, then create a new 3552344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan // event 3553344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1, 355487f993ff96172f508d3f241f8a425f953c7eb739RoboErik getSelectedTimeInMillis(), 0, (int) ev.getRawX(), (int) ev.getRawY(), -1); 3555344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan } else { 3556344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan Time startTime = new Time(mBaseDate); 3557344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan startTime.setJulianDay(mSelectionDay); 3558344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan startTime.hour = mSelectionHour; 3559344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan startTime.normalize(true /* ignore isDst */); 356083b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan 356183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan Time endTime = new Time(startTime); 356283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan endTime.hour++; 356383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan 356446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mController.sendEvent(this, EventType.GO_TO, startTime, endTime, -1, ViewType.CURRENT, 356546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan CalendarController.EXTRA_GOTO_TIME, null, null); 3566146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3567146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3568146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 35694484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan private void doLongPress(MotionEvent ev) { 3570bbf2cbdb040108da50d763b699836e5f63fb7cceMichael Chan if (mScrolling) { 3571bbf2cbdb040108da50d763b699836e5f63fb7cceMichael Chan return; 3572bbf2cbdb040108da50d763b699836e5f63fb7cceMichael Chan } 3573bbf2cbdb040108da50d763b699836e5f63fb7cceMichael Chan 3574d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan // Scale gesture in progress 3575d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan if (mStartingSpanY != 0) { 3576d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan return; 3577d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 3578d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 357980bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan int x = (int) ev.getX(); 358080bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan int y = (int) ev.getY(); 358180bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan 358280bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan boolean validPosition = setSelectionFromPosition(x, y); 358380bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan if (!validPosition) { 358480bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan // return if the touch wasn't on an area of concern 358580bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan return; 358680bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan } 358780bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan 3588146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionMode = SELECTION_LONGPRESS; 3589146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 3590146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project performLongClick(); 3591146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3592146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 35934484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan private void doScroll(MotionEvent e1, MotionEvent e2, float deltaX, float deltaY) { 359495d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan cancelAnimation(); 35954f58287a1e02325337e39073a50bbb880094099fRoboErik if (mStartingScroll) { 35964f58287a1e02325337e39073a50bbb880094099fRoboErik mInitialScrollX = 0; 35974f58287a1e02325337e39073a50bbb880094099fRoboErik mInitialScrollY = 0; 35984f58287a1e02325337e39073a50bbb880094099fRoboErik mStartingScroll = false; 35994f58287a1e02325337e39073a50bbb880094099fRoboErik } 36006d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 36014f58287a1e02325337e39073a50bbb880094099fRoboErik mInitialScrollX += deltaX; 36024f58287a1e02325337e39073a50bbb880094099fRoboErik mInitialScrollY += deltaY; 36034f58287a1e02325337e39073a50bbb880094099fRoboErik int distanceX = (int) mInitialScrollX; 36044f58287a1e02325337e39073a50bbb880094099fRoboErik int distanceY = (int) mInitialScrollY; 3605146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3606146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If we haven't figured out the predominant scroll direction yet, 3607146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // then do it now. 3608146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mTouchMode == TOUCH_MODE_DOWN) { 3609146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int absDistanceX = Math.abs(distanceX); 3610146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int absDistanceY = Math.abs(distanceY); 3611146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mScrollStartY = mViewStartY; 3612146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPreviousDirection = 0; 3613146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3614f9a2842a66fe858336144ba87c668efc2e18a9acMichael Chan if (absDistanceX > absDistanceY) { 3615146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mTouchMode = TOUCH_MODE_HSCROLL; 3616146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartX = distanceX; 3617146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project initNextView(-mViewStartX); 3618146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 3619146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mTouchMode = TOUCH_MODE_VSCROLL; 3620146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3621146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) { 3622146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // We are already scrolling horizontally, so check if we 3623146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // changed the direction of scrolling so that the other week 3624146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // is now visible. 3625146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartX = distanceX; 3626146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (distanceX != 0) { 3627146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int direction = (distanceX > 0) ? 1 : -1; 3628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (direction != mPreviousDirection) { 3629146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // The user has switched the direction of scrolling 3630146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // so re-init the next view 3631146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project initNextView(-mViewStartX); 3632146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPreviousDirection = direction; 3633146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3634146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3635146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3636146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3637146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if ((mTouchMode & TOUCH_MODE_VSCROLL) != 0) { 3638146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartY = mScrollStartY + distanceY; 3639146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mViewStartY < 0) { 3640146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartY = 0; 3641146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (mViewStartY > mMaxViewStartY) { 3642146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartY = mMaxViewStartY; 3643146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3644146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project computeFirstHour(); 3645146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3647146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mScrolling = true; 3648146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3649d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan mSelectionMode = SELECTION_HIDDEN; 3650146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 3651146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3652146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3653f6c785f1dacb26523f229e1b06e3a4eb6fa4ff0dMichael Chan private void cancelAnimation() { 3654f6c785f1dacb26523f229e1b06e3a4eb6fa4ff0dMichael Chan Animation in = mViewSwitcher.getInAnimation(); 3655f6c785f1dacb26523f229e1b06e3a4eb6fa4ff0dMichael Chan if (in != null) { 365695d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan // cancel() doesn't terminate cleanly. 365795d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan in.scaleCurrentDuration(0); 36586d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan } 3659f6c785f1dacb26523f229e1b06e3a4eb6fa4ff0dMichael Chan Animation out = mViewSwitcher.getOutAnimation(); 3660f6c785f1dacb26523f229e1b06e3a4eb6fa4ff0dMichael Chan if (out != null) { 366195d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan // cancel() doesn't terminate cleanly. 366295d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan out.scaleCurrentDuration(0); 3663f6c785f1dacb26523f229e1b06e3a4eb6fa4ff0dMichael Chan } 3664f6c785f1dacb26523f229e1b06e3a4eb6fa4ff0dMichael Chan } 3665f6c785f1dacb26523f229e1b06e3a4eb6fa4ff0dMichael Chan 3666f6c785f1dacb26523f229e1b06e3a4eb6fa4ff0dMichael Chan private void doFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 3667f6c785f1dacb26523f229e1b06e3a4eb6fa4ff0dMichael Chan cancelAnimation(); 36686d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan 3669146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionMode = SELECTION_HIDDEN; 3670146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mOnFlingCalled = true; 367190a68379c01137781249156742cfc9ba21684b83Michael Chan 367290a68379c01137781249156742cfc9ba21684b83Michael Chan if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) { 3673030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown // Horizontal fling. 367411638ad4fb56b978770aebe75deac7a0e6ac60d2Erik // initNextView(deltaX); 367590a68379c01137781249156742cfc9ba21684b83Michael Chan mTouchMode = TOUCH_MODE_INITIAL_STATE; 367690a68379c01137781249156742cfc9ba21684b83Michael Chan if (DEBUG) Log.d(TAG, "doFling: velocityX " + velocityX); 367790a68379c01137781249156742cfc9ba21684b83Michael Chan int deltaX = (int) e2.getX() - (int) e1.getX(); 36782c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan switchViews(deltaX < 0, mViewStartX, mViewWidth, velocityX); 3679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartX = 0; 3680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 3681146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3682146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 368390a68379c01137781249156742cfc9ba21684b83Michael Chan if ((mTouchMode & TOUCH_MODE_VSCROLL) == 0) { 368490a68379c01137781249156742cfc9ba21684b83Michael Chan if (DEBUG) Log.d(TAG, "doFling: no fling"); 368590a68379c01137781249156742cfc9ba21684b83Michael Chan return; 368690a68379c01137781249156742cfc9ba21684b83Michael Chan } 368790a68379c01137781249156742cfc9ba21684b83Michael Chan 3688030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown // Vertical fling. 368990a68379c01137781249156742cfc9ba21684b83Michael Chan mTouchMode = TOUCH_MODE_INITIAL_STATE; 3690030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown mViewStartX = 0; 3691030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown 36923f6328f579b05c02606572c777541b97aa04f9f3Michael Chan if (DEBUG) { 36933f6328f579b05c02606572c777541b97aa04f9f3Michael Chan Log.d(TAG, "doFling: mViewStartY" + mViewStartY + " velocityY " + velocityY); 36943f6328f579b05c02606572c777541b97aa04f9f3Michael Chan } 36953f6328f579b05c02606572c777541b97aa04f9f3Michael Chan 3696146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Continue scrolling vertically 36973f6328f579b05c02606572c777541b97aa04f9f3Michael Chan mScrolling = true; 36983f6328f579b05c02606572c777541b97aa04f9f3Michael Chan mScroller.fling(0 /* startX */, mViewStartY /* startY */, 0 /* velocityX */, 36993f6328f579b05c02606572c777541b97aa04f9f3Michael Chan (int) -velocityY, 0 /* minX */, 0 /* maxX */, 0 /* minY */, mMaxViewStartY); 3700146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project post(mContinueScroll); 3701146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3702146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3703146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private boolean initNextView(int deltaX) { 3704146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Change the view to the previous day or week 3705d190418220467c02327dd9b3ae1eae238889720bMichael Chan DayView view = (DayView) mViewSwitcher.getNextView(); 3706146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Time date = view.mBaseDate; 3707146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project date.set(mBaseDate); 3708146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project boolean switchForward; 3709146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (deltaX > 0) { 3710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project date.monthDay -= mNumDays; 3711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.mSelectionDay = mSelectionDay - mNumDays; 3712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project switchForward = false; 3713146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 3714146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project date.monthDay += mNumDays; 3715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.mSelectionDay = mSelectionDay + mNumDays; 3716146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project switchForward = true; 3717146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project date.normalize(true /* ignore isDst */); 3719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project initView(view); 3720ad36a3c3cde7a2ec6d3a35d2529d46f03bd8d59dMichael Chan view.layout(getLeft(), getTop(), getRight(), getBottom()); 3721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project view.reloadEvents(); 3722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return switchForward; 3723146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3725d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan // ScaleGestureDetector.OnScaleGestureListener 3726d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan public boolean onScaleBegin(ScaleGestureDetector detector) { 3727d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mHandleActionUp = false; 37282fda24534978f55711526dbde747aa50d68dec40RoboErik float gestureCenterInPixels = detector.getFocusY() - DAY_HEADER_HEIGHT - mAlldayHeight; 3729d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mGestureCenterHour = (mViewStartY + gestureCenterInPixels) / (mCellHeight + DAY_GAP); 3730d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3731d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mStartingSpanY = Math.max(MIN_Y_SPAN, Math.abs(detector.getCurrentSpanY())); 3732d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mCellHeightBeforeScaleGesture = mCellHeight; 3733d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3734d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan if (DEBUG) { 3735d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan float ViewStartHour = mViewStartY / (float) (mCellHeight + DAY_GAP); 3736d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan Log.d(TAG, "mGestureCenterHour:" + mGestureCenterHour + "\tViewStartHour: " 3737d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan + ViewStartHour + "\tmViewStartY:" + mViewStartY + "\tmCellHeight:" 3738d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan + mCellHeight); 3739d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 3740d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3741d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan return true; 3742d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 3743d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3744d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan // ScaleGestureDetector.OnScaleGestureListener 3745d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan public boolean onScale(ScaleGestureDetector detector) { 3746d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan float spanY = Math.abs(detector.getCurrentSpanY()); 3747d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3748d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mCellHeight = (int) (mCellHeightBeforeScaleGesture * spanY / mStartingSpanY); 3749d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3750d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan if (mCellHeight < mMinCellHeight) { 3751d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan // If mStartingSpanY is too small, even a small increase in the 3752d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan // gesture can bump the mCellHeight beyond MAX_CELL_HEIGHT 3753d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mStartingSpanY = Math.max(MIN_Y_SPAN, spanY); 3754d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mCellHeight = mMinCellHeight; 3755d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mCellHeightBeforeScaleGesture = mMinCellHeight; 3756d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } else if (mCellHeight > MAX_CELL_HEIGHT) { 3757d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mStartingSpanY = spanY; 3758d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mCellHeight = MAX_CELL_HEIGHT; 3759d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mCellHeightBeforeScaleGesture = MAX_CELL_HEIGHT; 3760d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 3761d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 37622fda24534978f55711526dbde747aa50d68dec40RoboErik int gestureCenterInPixels = (int) detector.getFocusY() - DAY_HEADER_HEIGHT - mAlldayHeight; 3763d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mViewStartY = (int) (mGestureCenterHour * (mCellHeight + DAY_GAP)) - gestureCenterInPixels; 3764d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mMaxViewStartY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP) - mGridAreaHeight; 3765d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3766d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan if (DEBUG) { 3767d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan float ViewStartHour = mViewStartY / (float) (mCellHeight + DAY_GAP); 3768d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan Log.d(TAG, " mGestureCenterHour:" + mGestureCenterHour + "\tViewStartHour: " 3769d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan + ViewStartHour + "\tmViewStartY:" + mViewStartY + "\tmCellHeight:" 3770d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan + mCellHeight + " SpanY:" + detector.getCurrentSpanY()); 3771d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 3772d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3773d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan if (mViewStartY < 0) { 3774d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mViewStartY = 0; 3775d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mGestureCenterHour = (mViewStartY + gestureCenterInPixels) 3776d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan / (float) (mCellHeight + DAY_GAP); 3777d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } else if (mViewStartY > mMaxViewStartY) { 3778d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mViewStartY = mMaxViewStartY; 3779d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mGestureCenterHour = (mViewStartY + gestureCenterInPixels) 3780d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan / (float) (mCellHeight + DAY_GAP); 3781d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 3782d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan computeFirstHour(); 3783d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3784d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mRemeasure = true; 3785d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan invalidate(); 3786d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan return true; 3787d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 3788d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3789d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan // ScaleGestureDetector.OnScaleGestureListener 3790d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan public void onScaleEnd(ScaleGestureDetector detector) { 37914f58287a1e02325337e39073a50bbb880094099fRoboErik mScrollStartY = mViewStartY; 37924f58287a1e02325337e39073a50bbb880094099fRoboErik mInitialScrollY = 0; 37934f58287a1e02325337e39073a50bbb880094099fRoboErik mInitialScrollX = 0; 3794d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mStartingSpanY = 0; 3795d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 3796d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3797146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project @Override 3798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public boolean onTouchEvent(MotionEvent ev) { 3799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int action = ev.getAction(); 3800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 38011ba48526c2542484d91383c21d3d8e07db87df0fMichael Chan if ((mTouchMode & TOUCH_MODE_HSCROLL) == 0) { 38021ba48526c2542484d91383c21d3d8e07db87df0fMichael Chan mScaleGestureDetector.onTouchEvent(ev); 38031ba48526c2542484d91383c21d3d8e07db87df0fMichael Chan if (mScaleGestureDetector.isInProgress()) { 38041ba48526c2542484d91383c21d3d8e07db87df0fMichael Chan return true; 38051ba48526c2542484d91383c21d3d8e07db87df0fMichael Chan } 3806d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 3807d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 3808146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project switch (action) { 380946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case MotionEvent.ACTION_DOWN: 38104f58287a1e02325337e39073a50bbb880094099fRoboErik mStartingScroll = true; 381146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (DEBUG) Log.e(TAG, "ACTION_DOWN"); 38122fda24534978f55711526dbde747aa50d68dec40RoboErik int bottom = mAlldayHeight + DAY_HEADER_HEIGHT + ALLDAY_TOP_MARGIN; 38132fda24534978f55711526dbde747aa50d68dec40RoboErik if (ev.getY() < bottom) { 38142fda24534978f55711526dbde747aa50d68dec40RoboErik mTouchStartedInAlldayArea = true; 38152fda24534978f55711526dbde747aa50d68dec40RoboErik } else { 38162fda24534978f55711526dbde747aa50d68dec40RoboErik mTouchStartedInAlldayArea = false; 38172fda24534978f55711526dbde747aa50d68dec40RoboErik } 3818d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mHandleActionUp = true; 381946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mGestureDetector.onTouchEvent(ev); 3820d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan return true; 382146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 382246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case MotionEvent.ACTION_MOVE: 382346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (DEBUG) Log.e(TAG, "ACTION_MOVE"); 382446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mGestureDetector.onTouchEvent(ev); 3825146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return true; 382646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 382746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case MotionEvent.ACTION_UP: 382846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (DEBUG) Log.e(TAG, "ACTION_UP " + mHandleActionUp); 38294f58287a1e02325337e39073a50bbb880094099fRoboErik mStartingScroll = false; 383046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mGestureDetector.onTouchEvent(ev); 383146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (!mHandleActionUp) { 383246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mHandleActionUp = true; 38337abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project return true; 383446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 383546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mOnFlingCalled) { 383646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return true; 383746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 383846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) { 383946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mTouchMode = TOUCH_MODE_INITIAL_STATE; 384046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (Math.abs(mViewStartX) > mHorizontalSnapBackThreshold) { 384146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // The user has gone beyond the threshold so switch views 384246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (DEBUG) Log.d(TAG, "- horizontal scroll: switch views"); 38432c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan switchViews(mViewStartX > 0, mViewStartX, mViewWidth, 0); 384446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mViewStartX = 0; 384546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return true; 384646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } else { 384746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // Not beyond the threshold so invalidate which will cause 384846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // the view to snap back. Also call recalc() to ensure 384946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // that we have the correct starting date and title. 385046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (DEBUG) Log.d(TAG, "- horizontal scroll: snap back"); 385146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan recalc(); 385246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan invalidate(); 385346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mViewStartX = 0; 385446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 385546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 385646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 385746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // If we were scrolling, then reset the selected hour so that it 385846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // is visible. 385946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mScrolling) { 386046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mScrolling = false; 386146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan resetSelectedHour(); 3862146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 3863146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 386446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return true; 3865146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 386646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // This case isn't expected to happen. 386746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan case MotionEvent.ACTION_CANCEL: 386846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (DEBUG) Log.e(TAG, "ACTION_CANCEL"); 386946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mGestureDetector.onTouchEvent(ev); 3870146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mScrolling = false; 3871146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project resetSelectedHour(); 3872146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return true; 387346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 387446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan default: 38754f58287a1e02325337e39073a50bbb880094099fRoboErik if (DEBUG) Log.e(TAG, "Not MotionEvent " + action); 387646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (mGestureDetector.onTouchEvent(ev)) { 387746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return true; 387846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 387946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan return super.onTouchEvent(ev); 3880146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3881146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3882146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3883146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) { 3884146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project MenuItem item; 3885146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3886146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If the trackball is held down, then the context menu pops up and 388746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // we never get onKeyUp() for the long-press. So check for it here 3888146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // and change the selection to the long-press state. 3889146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionMode != SELECTION_LONGPRESS) { 3890146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionMode = SELECTION_LONGPRESS; 3891146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 3892146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3893146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3894e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan final long startMillis = getSelectedTimeInMillis(); 3895146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int flags = DateUtils.FORMAT_SHOW_TIME 3896146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project | DateUtils.FORMAT_CAP_NOON_MIDNIGHT 3897146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project | DateUtils.FORMAT_SHOW_WEEKDAY; 3898c5f92d7bdeb1950ace783cc022aa41a4b4f00cd6Erik final String title = Utils.formatDateRange(mContext, startMillis, startMillis, flags); 3899146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project menu.setHeaderTitle(title); 3900e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 3901146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int numSelectedEvents = mSelectedEvents.size(); 3902146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mNumDays == 1) { 3903146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Day view. 3904146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3905146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If there is a selected event, then allow it to be viewed and 3906146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // edited. 3907146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (numSelectedEvents >= 1) { 39084484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item = menu.add(0, MENU_EVENT_VIEW, 0, R.string.event_view); 3909146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setOnMenuItemClickListener(mContextMenuHandler); 3910146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setIcon(android.R.drawable.ic_menu_info_details); 3911146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3912ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan int accessLevel = getEventAccessLevel(mContext, mSelectedEvent); 3913a505627659f6bfba8869eac8089f7030f2d0d92cErik if (accessLevel == ACCESS_LEVEL_EDIT) { 39144484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item = menu.add(0, MENU_EVENT_EDIT, 0, R.string.event_edit); 3915146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setOnMenuItemClickListener(mContextMenuHandler); 3916146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setIcon(android.R.drawable.ic_menu_edit); 3917146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setAlphabeticShortcut('e'); 3918a505627659f6bfba8869eac8089f7030f2d0d92cErik } 3919146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3920a505627659f6bfba8869eac8089f7030f2d0d92cErik if (accessLevel >= ACCESS_LEVEL_DELETE) { 39214484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item = menu.add(0, MENU_EVENT_DELETE, 0, R.string.event_delete); 3922146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setOnMenuItemClickListener(mContextMenuHandler); 3923146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setIcon(android.R.drawable.ic_menu_delete); 3924146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3925146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 39264484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create); 3927146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setOnMenuItemClickListener(mContextMenuHandler); 3928146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setIcon(android.R.drawable.ic_menu_add); 3929146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setAlphabeticShortcut('n'); 3930146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 3931146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Otherwise, if the user long-pressed on a blank hour, allow 393246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // them to create an event. They can also do this by tapping. 39334484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create); 3934146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setOnMenuItemClickListener(mContextMenuHandler); 3935146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setIcon(android.R.drawable.ic_menu_add); 3936146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setAlphabeticShortcut('n'); 3937146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3938146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 3939146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Week view. 3940e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 3941146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If there is a selected event, then allow it to be viewed and 3942146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // edited. 3943146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (numSelectedEvents >= 1) { 39444484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item = menu.add(0, MENU_EVENT_VIEW, 0, R.string.event_view); 3945146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setOnMenuItemClickListener(mContextMenuHandler); 3946146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setIcon(android.R.drawable.ic_menu_info_details); 3947146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3948ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan int accessLevel = getEventAccessLevel(mContext, mSelectedEvent); 3949a505627659f6bfba8869eac8089f7030f2d0d92cErik if (accessLevel == ACCESS_LEVEL_EDIT) { 39504484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item = menu.add(0, MENU_EVENT_EDIT, 0, R.string.event_edit); 3951146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setOnMenuItemClickListener(mContextMenuHandler); 3952146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setIcon(android.R.drawable.ic_menu_edit); 3953146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setAlphabeticShortcut('e'); 3954a505627659f6bfba8869eac8089f7030f2d0d92cErik } 3955146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3956a505627659f6bfba8869eac8089f7030f2d0d92cErik if (accessLevel >= ACCESS_LEVEL_DELETE) { 39574484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item = menu.add(0, MENU_EVENT_DELETE, 0, R.string.event_delete); 3958146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setOnMenuItemClickListener(mContextMenuHandler); 3959146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project item.setIcon(android.R.drawable.ic_menu_delete); 3960146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 39614484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan } 3962146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 39634484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create); 39644484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item.setOnMenuItemClickListener(mContextMenuHandler); 39654484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item.setIcon(android.R.drawable.ic_menu_add); 39664484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item.setAlphabeticShortcut('n'); 3967146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 39684484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item = menu.add(0, MENU_DAY, 0, R.string.show_day_view); 39694484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item.setOnMenuItemClickListener(mContextMenuHandler); 39704484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item.setIcon(android.R.drawable.ic_menu_day); 39714484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan item.setAlphabeticShortcut('d'); 3972146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3973146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3974146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup.dismiss(); 3975146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3976146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3977146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private class ContextMenuHandler implements MenuItem.OnMenuItemClickListener { 3978146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public boolean onMenuItemClick(MenuItem item) { 3979146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project switch (item.getItemId()) { 39804484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan case MENU_EVENT_VIEW: { 3981146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectedEvent != null) { 3982a7694eead7cbb293990bc89c3906e17bad36194cErik mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT_DETAILS, 39839e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan mSelectedEvent.id, mSelectedEvent.startMillis, 398487f993ff96172f508d3f241f8a425f953c7eb739RoboErik mSelectedEvent.endMillis, 0, 0, -1); 3985146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3986146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project break; 3987146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 39884484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan case MENU_EVENT_EDIT: { 3989146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectedEvent != null) { 39909e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan mController.sendEventRelatedEvent(this, EventType.EDIT_EVENT, 39919e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan mSelectedEvent.id, mSelectedEvent.startMillis, 399287f993ff96172f508d3f241f8a425f953c7eb739RoboErik mSelectedEvent.endMillis, 0, 0, -1); 3993146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 3994146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project break; 3995146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 39964484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan case MENU_DAY: { 3997487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mController.sendEvent(this, EventType.GO_TO, getSelectedTime(), null, -1, 39989e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan ViewType.DAY); 3999146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project break; 4000146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 40014484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan case MENU_AGENDA: { 4002487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan mController.sendEvent(this, EventType.GO_TO, getSelectedTime(), null, -1, 40039e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan ViewType.AGENDA); 4004146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project break; 4005146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 40064484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan case MENU_EVENT_CREATE: { 4007146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long startMillis = getSelectedTimeInMillis(); 4008146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS; 40099e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1, 401087f993ff96172f508d3f241f8a425f953c7eb739RoboErik startMillis, endMillis, 0, 0, -1); 4011146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project break; 4012146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 40134484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan case MENU_EVENT_DELETE: { 4014146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectedEvent != null) { 4015146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event selectedEvent = mSelectedEvent; 4016146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long begin = selectedEvent.startMillis; 4017146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long end = selectedEvent.endMillis; 4018146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long id = selectedEvent.id; 40199e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan mController.sendEventRelatedEvent(this, EventType.DELETE_EVENT, id, begin, 402087f993ff96172f508d3f241f8a425f953c7eb739RoboErik end, 0, 0, -1); 4021146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4022146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project break; 4023146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4024146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project default: { 4025146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return false; 4026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4028146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return true; 4029146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4030146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4031146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4032a505627659f6bfba8869eac8089f7030f2d0d92cErik private static int getEventAccessLevel(Context context, Event e) { 4033146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ContentResolver cr = context.getContentResolver(); 4034146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4035ef2add9145f058ea103ade2870a8ba899b9ed1c9RoboErik int accessLevel = Calendars.CAL_ACCESS_NONE; 4036146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4037146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Get the calendar id for this event 4038146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Cursor cursor = cr.query(ContentUris.withAppendedId(Events.CONTENT_URI, e.id), 4039146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project new String[] { Events.CALENDAR_ID }, 4040146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project null /* selection */, 4041146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project null /* selectionArgs */, 4042146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project null /* sort */); 4043e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 4044e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan if (cursor == null) { 4045a505627659f6bfba8869eac8089f7030f2d0d92cErik return ACCESS_LEVEL_NONE; 4046146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4047e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 4048e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan if (cursor.getCount() == 0) { 4049e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan cursor.close(); 4050a505627659f6bfba8869eac8089f7030f2d0d92cErik return ACCESS_LEVEL_NONE; 4051e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan } 4052e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 4053146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cursor.moveToFirst(); 4054146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long calId = cursor.getLong(0); 4055697bd6a8cec36cc75c72603674e57e4c6fe42dbfKen Shirriff cursor.close(); 4056146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4057146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Uri uri = Calendars.CONTENT_URI; 4058146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String where = String.format(CALENDARS_WHERE, calId); 4059146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cursor = cr.query(uri, CALENDARS_PROJECTION, where, null, null); 4060146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 40616d34cec523930368976bc8d358d0a6de1da3462cMichael Chan String calendarOwnerAccount = null; 4062146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (cursor != null) { 4063146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cursor.moveToFirst(); 4064ced0eb67ef49c3203f72520c296e73d9cb4f654bMichael Chan accessLevel = cursor.getInt(CALENDARS_INDEX_ACCESS_LEVEL); 40656d34cec523930368976bc8d358d0a6de1da3462cMichael Chan calendarOwnerAccount = cursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT); 4066146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cursor.close(); 4067146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4068e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 4069ef2add9145f058ea103ade2870a8ba899b9ed1c9RoboErik if (accessLevel < Calendars.CAL_ACCESS_CONTRIBUTOR) { 4070a505627659f6bfba8869eac8089f7030f2d0d92cErik return ACCESS_LEVEL_NONE; 40716d34cec523930368976bc8d358d0a6de1da3462cMichael Chan } 4072146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 40736d34cec523930368976bc8d358d0a6de1da3462cMichael Chan if (e.guestsCanModify) { 4074a505627659f6bfba8869eac8089f7030f2d0d92cErik return ACCESS_LEVEL_EDIT; 4075a505627659f6bfba8869eac8089f7030f2d0d92cErik } 4076a505627659f6bfba8869eac8089f7030f2d0d92cErik 407746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (!TextUtils.isEmpty(calendarOwnerAccount) 407846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan && calendarOwnerAccount.equalsIgnoreCase(e.organizer)) { 4079a505627659f6bfba8869eac8089f7030f2d0d92cErik return ACCESS_LEVEL_EDIT; 4080146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4081146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4082a505627659f6bfba8869eac8089f7030f2d0d92cErik return ACCESS_LEVEL_DELETE; 4083146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4084146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4085146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 4086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Sets mSelectionDay and mSelectionHour based on the (x,y) touch position. 4087146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * If the touch position is not within the displayed grid, then this 4088146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * method returns false. 4089146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 4090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * @param x the x position of the touch 4091146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * @param y the y position of the touch 4092146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * @return true if the touch position is valid 4093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 4094360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan private boolean setSelectionFromPosition(int x, final int y) { 4095146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (x < mHoursWidth) { 4096360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan x = mHoursWidth; 4097146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4098146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4099146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int day = (x - mHoursWidth) / (mCellWidth + DAY_GAP); 4100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (day >= mNumDays) { 4101146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project day = mNumDays - 1; 4102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project day += mFirstJulianDay; 4104360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan mSelectionDay = day; 4105360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan 4106360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan if (y < DAY_HEADER_HEIGHT) { 4107360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan return false; 4108360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan } 410946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 411046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan mSelectionHour = mFirstHour; /* First fully visible hour */ 411146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 411246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan if (y < mFirstCell) { 41132fda24534978f55711526dbde747aa50d68dec40RoboErik mSelectionAllday = true; 4114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 411546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // y is now offset from top of the scrollable region 411655a26d7062d5aa1a1b001b7271bb137276ab807eErik int adjustedY = y - mFirstCell; 411746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 411855a26d7062d5aa1a1b001b7271bb137276ab807eErik if (adjustedY < mFirstHourOffset) { 411946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan --mSelectionHour; /* In the partially visible hour */ 412046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } else { 412155a26d7062d5aa1a1b001b7271bb137276ab807eErik mSelectionHour += (adjustedY - mFirstHourOffset) / (mCellHeight + HOUR_GAP); 412246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan } 412346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 41242fda24534978f55711526dbde747aa50d68dec40RoboErik mSelectionAllday = false; 4125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4126360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan 4127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project findSelectedEvent(x, y); 412846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan 412946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan// Log.i("Cal", "setSelectionFromPosition( " + x + ", " + y + " ) day: " + day + " hour: " 413046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan// + mSelectionHour + " mFirstCell: " + mFirstCell + " mFirstHourOffset: " 413146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan// + mFirstHourOffset); 4132146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project// if (mSelectedEvent != null) { 413346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan// Log.i("Cal", " num events: " + mSelectedEvents.size() + " event: " 413446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan// + mSelectedEvent.title); 4135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project// for (Event ev : mSelectedEvents) { 4136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project// int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL 4137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project// | DateUtils.FORMAT_CAP_NOON_MIDNIGHT; 413846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan// String timeRange = formatDateRange(mContext, ev.startMillis, ev.endMillis, flags); 4139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project// 4140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project// Log.i("Cal", " " + timeRange + " " + ev.title); 4141146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project// } 4142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project// } 4143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return true; 4144146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4145146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4146146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void findSelectedEvent(int x, int y) { 4147146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int date = mSelectionDay; 4148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int cellWidth = mCellWidth; 4149b5e3c17201b2c08ca9f3fd33f4585e1ec8fa71b1RoboErik ArrayList<Event> events = mEvents; 4150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int numEvents = events.size(); 4151e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik int left = computeDayLeftPosition(mSelectionDay - mFirstJulianDay); 4152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int top = 0; 4153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvent = null; 4154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvents.clear(); 41562fda24534978f55711526dbde747aa50d68dec40RoboErik if (mSelectionAllday) { 4157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project float yDistance; 415846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan float minYdistance = 10000.0f; // any large number 4159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event closestEvent = null; 41602fda24534978f55711526dbde747aa50d68dec40RoboErik float drawHeight = mAlldayHeight; 41613eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan int yOffset = DAY_HEADER_HEIGHT + ALLDAY_TOP_MARGIN; 41622fda24534978f55711526dbde747aa50d68dec40RoboErik int maxUnexpandedColumn = mMaxUnexpandedAlldayEventCount; 41632fda24534978f55711526dbde747aa50d68dec40RoboErik if (mMaxAlldayEvents > mMaxUnexpandedAlldayEventCount) { 41642fda24534978f55711526dbde747aa50d68dec40RoboErik // Leave a gap for the 'box +n' text 41652fda24534978f55711526dbde747aa50d68dec40RoboErik maxUnexpandedColumn--; 41662fda24534978f55711526dbde747aa50d68dec40RoboErik } 4167b5e3c17201b2c08ca9f3fd33f4585e1ec8fa71b1RoboErik events = mAllDayEvents; 4168b5e3c17201b2c08ca9f3fd33f4585e1ec8fa71b1RoboErik numEvents = events.size(); 4169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int i = 0; i < numEvents; i++) { 4170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event event = events.get(i); 41712fda24534978f55711526dbde747aa50d68dec40RoboErik if (!event.drawAsAllday() || 41722fda24534978f55711526dbde747aa50d68dec40RoboErik (!mShowAllAllDayEvents && event.getColumn() >= maxUnexpandedColumn)) { 41732fda24534978f55711526dbde747aa50d68dec40RoboErik // Don't check non-allday events or events that aren't shown 4174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project continue; 4175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (event.startDay <= mSelectionDay && event.endDay >= mSelectionDay) { 4178b5e3c17201b2c08ca9f3fd33f4585e1ec8fa71b1RoboErik float numRectangles = mShowAllAllDayEvents ? mMaxAlldayEvents 4179b5e3c17201b2c08ca9f3fd33f4585e1ec8fa71b1RoboErik : mMaxUnexpandedAlldayEventCount; 4180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project float height = drawHeight / numRectangles; 4181f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan if (height > MAX_HEIGHT_OF_ONE_ALLDAY_EVENT) { 4182f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan height = MAX_HEIGHT_OF_ONE_ALLDAY_EVENT; 4183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project float eventTop = yOffset + height * event.getColumn(); 4185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project float eventBottom = eventTop + height; 4186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (eventTop < y && eventBottom > y) { 4187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If the touch is inside the event rectangle, then 4188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // add the event. 4189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvents.add(event); 4190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project closestEvent = event; 4191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project break; 4192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 4193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Find the closest event 4194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (eventTop >= y) { 4195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project yDistance = eventTop - y; 4196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 4197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project yDistance = y - eventBottom; 4198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (yDistance < minYdistance) { 4200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project minYdistance = yDistance; 4201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project closestEvent = event; 4202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvent = closestEvent; 4207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 4208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4210146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Adjust y for the scrollable bitmap 4211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project y += mViewStartY - mFirstCell; 4212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Use a region around (x,y) for the selection region 4214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Rect region = mRect; 4215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project region.left = x - 10; 4216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project region.right = x + 10; 4217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project region.top = y - 10; 4218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project region.bottom = y + 10; 4219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project EventGeometry geometry = mEventGeometry; 4221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int i = 0; i < numEvents; i++) { 4223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event event = events.get(i); 4224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Compute the event rectangle. 4225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (!geometry.computeEventRect(date, left, top, cellWidth, event)) { 4226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project continue; 4227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If the event intersects the selection region, then add it to 4230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // mSelectedEvents. 4231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (geometry.eventIntersectsSelection(event, region)) { 4232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvents.add(event); 4233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4235146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If there are any events in the selected region, then assign the 4237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // closest one to mSelectedEvent. 4238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectedEvents.size() > 0) { 4239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int len = mSelectedEvents.size(); 4240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event closestEvent = null; 424146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan float minDist = mViewWidth + mViewHeight; // some large distance 4242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project for (int index = 0; index < len; index++) { 4243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Event ev = mSelectedEvents.get(index); 4244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project float dist = geometry.pointToEvent(x, y, ev); 4245146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (dist < minDist) { 4246146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project minDist = dist; 4247146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project closestEvent = ev; 4248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4250146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectedEvent = closestEvent; 4251146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4252146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Keep the selected hour and day consistent with the selected 425346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // event. They could be different if we touched on an empty hour 425446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // slot very close to an event in the previous hour slot. In 4255146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // that case we will select the nearby event. 4256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int startDay = mSelectedEvent.startDay; 4257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int endDay = mSelectedEvent.endDay; 4258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectionDay < startDay) { 4259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionDay = startDay; 4260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (mSelectionDay > endDay) { 4261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionDay = endDay; 4262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int startHour = mSelectedEvent.startTime / 60; 4265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int endHour; 4266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mSelectedEvent.startTime < mSelectedEvent.endTime) { 4267146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project endHour = (mSelectedEvent.endTime - 1) / 60; 4268146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 4269146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project endHour = mSelectedEvent.endTime / 60; 4270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4271146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4272349dd91e8475a72eb68a5eae4482ce7e82c01d16RoboErik if (mSelectionHour < startHour && mSelectionDay == startDay) { 4273146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionHour = startHour; 4274349dd91e8475a72eb68a5eae4482ce7e82c01d16RoboErik } else if (mSelectionHour > endHour && mSelectionDay == endDay) { 4275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mSelectionHour = endHour; 4276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Encapsulates the code to continue the scrolling after the 428146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan // finger is lifted. Instead of stopping the scroll immediately, 4282146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // the scroll continues to "free spin" and gradually slows down. 4283146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private class ContinueScroll implements Runnable { 4284146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void run() { 42853f6328f579b05c02606572c777541b97aa04f9f3Michael Chan mScrolling = mScrolling && mScroller.computeScrollOffset(); 42863f6328f579b05c02606572c777541b97aa04f9f3Michael Chan if (!mScrolling) { 42873f6328f579b05c02606572c777541b97aa04f9f3Michael Chan resetSelectedHour(); 42883f6328f579b05c02606572c777541b97aa04f9f3Michael Chan invalidate(); 42893f6328f579b05c02606572c777541b97aa04f9f3Michael Chan return; 4290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4291146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 42923f6328f579b05c02606572c777541b97aa04f9f3Michael Chan mViewStartY = mScroller.getCurrY(); 4293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mViewStartY < 0) { 4295146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartY = 0; 4296146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else if (mViewStartY > mMaxViewStartY) { 4297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mViewStartY = mMaxViewStartY; 4298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project computeFirstHour(); 43013f6328f579b05c02606572c777541b97aa04f9f3Michael Chan post(this); 4302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project invalidate(); 4303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 4307bd0e834aea317236d574f8738fe11a51fdc87968Erik * Cleanup the pop-up and timers. 4308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 4309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void cleanup() { 4310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Protect against null-pointer exceptions 4311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mPopup != null) { 4312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup.dismiss(); 4313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4314666fc5e8ddbac15c951aad738bd818ee307eae42Erik mLastPopupEventID = INVALID_EVENT_ID; 4315146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Handler handler = getHandler(); 4316146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (handler != null) { 4317146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project handler.removeCallbacks(mDismissPopup); 4318bd0e834aea317236d574f8738fe11a51fdc87968Erik handler.removeCallbacks(mUpdateCurrentTime); 4319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4320e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan 4321d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan Utils.setSharedPreference(mContext, GeneralPreferences.KEY_DEFAULT_CELL_HEIGHT, 4322d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan mCellHeight); 4323d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 43247abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project // Turn off redraw 43257abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project mRemeasure = false; 4326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4328bd0e834aea317236d574f8738fe11a51fdc87968Erik /** 4329bd0e834aea317236d574f8738fe11a51fdc87968Erik * Restart the update timer 4330bd0e834aea317236d574f8738fe11a51fdc87968Erik */ 4331bd0e834aea317236d574f8738fe11a51fdc87968Erik public void restartCurrentTimeUpdates() { 4332bd0e834aea317236d574f8738fe11a51fdc87968Erik post(mUpdateCurrentTime); 4333bd0e834aea317236d574f8738fe11a51fdc87968Erik } 4334bd0e834aea317236d574f8738fe11a51fdc87968Erik 433546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan @Override 433646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan protected void onDetachedFromWindow() { 4337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cleanup(); 4338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project super.onDetachedFromWindow(); 4339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 4341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project class DismissPopup implements Runnable { 4342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void run() { 4343146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Protect against null-pointer exceptions 4344146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (mPopup != null) { 4345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mPopup.dismiss(); 4346146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4348146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 4349bd0e834aea317236d574f8738fe11a51fdc87968Erik 4350bd0e834aea317236d574f8738fe11a51fdc87968Erik class UpdateCurrentTime implements Runnable { 4351bd0e834aea317236d574f8738fe11a51fdc87968Erik public void run() { 4352bd0e834aea317236d574f8738fe11a51fdc87968Erik long currentTime = System.currentTimeMillis(); 4353bd0e834aea317236d574f8738fe11a51fdc87968Erik mCurrentTime.set(currentTime); 4354bd0e834aea317236d574f8738fe11a51fdc87968Erik //% causes update to occur on 5 minute marks (11:10, 11:15, 11:20, etc.) 4355bd0e834aea317236d574f8738fe11a51fdc87968Erik postDelayed(mUpdateCurrentTime, 4356bd0e834aea317236d574f8738fe11a51fdc87968Erik UPDATE_CURRENT_TIME_DELAY - (currentTime % UPDATE_CURRENT_TIME_DELAY)); 4357bd0e834aea317236d574f8738fe11a51fdc87968Erik mTodayJulianDay = Time.getJulianDay(currentTime, mCurrentTime.gmtoff); 4358bd0e834aea317236d574f8738fe11a51fdc87968Erik invalidate(); 4359bd0e834aea317236d574f8738fe11a51fdc87968Erik } 4360bd0e834aea317236d574f8738fe11a51fdc87968Erik } 4361ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 4362ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener { 4363ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan @Override 4364ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan public boolean onSingleTapUp(MotionEvent ev) { 4365d190418220467c02327dd9b3ae1eae238889720bMichael Chan DayView.this.doSingleTapUp(ev); 4366ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan return true; 4367ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan } 4368ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 4369ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan @Override 4370ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan public void onLongPress(MotionEvent ev) { 4371d190418220467c02327dd9b3ae1eae238889720bMichael Chan DayView.this.doLongPress(ev); 4372ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan } 4373ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 4374ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan @Override 4375ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 43762fda24534978f55711526dbde747aa50d68dec40RoboErik if (mTouchStartedInAlldayArea) { 43770e9e8a522740e4083f944638a82d5bd7a6e89fa8Erik if (Math.abs(distanceX) < Math.abs(distanceY)) { 43780e9e8a522740e4083f944638a82d5bd7a6e89fa8Erik return false; 43790e9e8a522740e4083f944638a82d5bd7a6e89fa8Erik } 43800e9e8a522740e4083f944638a82d5bd7a6e89fa8Erik // don't scroll vertically if this started in the allday area 43810e9e8a522740e4083f944638a82d5bd7a6e89fa8Erik distanceY = 0; 43822fda24534978f55711526dbde747aa50d68dec40RoboErik } 4383d190418220467c02327dd9b3ae1eae238889720bMichael Chan DayView.this.doScroll(e1, e2, distanceX, distanceY); 4384ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan return true; 4385ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan } 4386ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 4387ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan @Override 4388ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 43892fda24534978f55711526dbde747aa50d68dec40RoboErik if (mTouchStartedInAlldayArea) { 43900e9e8a522740e4083f944638a82d5bd7a6e89fa8Erik if (Math.abs(velocityX) < Math.abs(velocityY)) { 43910e9e8a522740e4083f944638a82d5bd7a6e89fa8Erik return false; 43920e9e8a522740e4083f944638a82d5bd7a6e89fa8Erik } 43930e9e8a522740e4083f944638a82d5bd7a6e89fa8Erik // don't fling vertically if this started in the allday area 43940e9e8a522740e4083f944638a82d5bd7a6e89fa8Erik velocityY = 0; 43952fda24534978f55711526dbde747aa50d68dec40RoboErik } 4396d190418220467c02327dd9b3ae1eae238889720bMichael Chan DayView.this.doFling(e1, e2, velocityX, velocityY); 4397ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan return true; 4398ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan } 4399ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan 4400ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan @Override 4401ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan public boolean onDown(MotionEvent ev) { 4402d190418220467c02327dd9b3ae1eae238889720bMichael Chan DayView.this.doDown(ev); 4403ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan return true; 4404ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan } 4405ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan } 4406cd405a28e6821b116dcf3c531805d0c90b6cc08cErik 4407cd405a28e6821b116dcf3c531805d0c90b6cc08cErik @Override 4408cd405a28e6821b116dcf3c531805d0c90b6cc08cErik public boolean onLongClick(View v) { 4409cd405a28e6821b116dcf3c531805d0c90b6cc08cErik mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1, 441087f993ff96172f508d3f241f8a425f953c7eb739RoboErik getSelectedTimeInMillis(), 0, -1, -1, -1); 4411cd405a28e6821b116dcf3c531805d0c90b6cc08cErik return true; 4412cd405a28e6821b116dcf3c531805d0c90b6cc08cErik } 44132c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan 44142c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan // The rest of this file was borrowed from Launcher2 - PagedView.java 44152c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan private static final int MINIMUM_SNAP_VELOCITY = 2200; 44162c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan 441795d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan private class ScrollInterpolator implements Interpolator { 44182c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan public ScrollInterpolator() { 44192c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan } 44202c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan 44212c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan public float getInterpolation(float t) { 44222c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan t -= 1.0f; 442395d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan t = t * t * t * t * t + 1; 442495d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan 442595d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan if ((1 - t) * mAnimationDistance < 1) { 442695d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan cancelAnimation(); 442795d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan } 442895d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan 442995d9f9172802f19e28b1cabf39b371c4ac343dc2Michael Chan return t; 44302c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan } 44312c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan } 44322c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan 44332c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan private long calculateDuration(float delta, float width, float velocity) { 44342c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan /* 44352c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * Here we compute a "distance" that will be used in the computation of 44362c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * the overall snap duration. This is a function of the actual distance 44372c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * that needs to be traveled; we keep this value close to half screen 44382c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * size in order to reduce the variance in snap duration as a function 44392c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * of the distance the page needs to travel. 44402c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan */ 44412c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan final float halfScreenSize = width / 2; 44422c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan float distanceRatio = delta / width; 44432c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan float distanceInfluenceForSnapDuration = distanceInfluenceForSnapDuration(distanceRatio); 44442c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan float distance = halfScreenSize + halfScreenSize * distanceInfluenceForSnapDuration; 44452c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan 44462c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan velocity = Math.abs(velocity); 44472c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan velocity = Math.max(MINIMUM_SNAP_VELOCITY, velocity); 44482c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan 44492c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan /* 44502c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * we want the page's snap velocity to approximately match the velocity 44512c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * at which the user flings, so we scale the duration by a value near to 44522c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * the derivative of the scroll interpolator at zero, ie. 5. We use 6 to 44532c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * make it a little slower. 44542c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan */ 44552c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan long duration = 6 * Math.round(1000 * Math.abs(distance / velocity)); 44562c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan if (DEBUG) { 44572c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan Log.e(TAG, "halfScreenSize:" + halfScreenSize + " delta:" + delta + " distanceRatio:" 44582c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan + distanceRatio + " distance:" + distance + " velocity:" + velocity 44592c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan + " duration:" + duration + " distanceInfluenceForSnapDuration:" 44602c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan + distanceInfluenceForSnapDuration); 44612c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan } 44622c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan return duration; 44632c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan } 44642c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan 44652c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan /* 44662c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * We want the duration of the page snap animation to be influenced by the 44672c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * distance that the screen has to travel, however, we don't want this 44682c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * duration to be effected in a purely linear fashion. Instead, we use this 44692c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * method to moderate the effect that the distance of travel has on the 44702c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan * overall snap duration. 44712c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan */ 44722c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan private float distanceInfluenceForSnapDuration(float f) { 44732c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan f -= 0.5f; // center the values about 0. 44742c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan f *= 0.3f * Math.PI / 2.0f; 44752c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan return (float) Math.sin(f); 44762c0a3ca970425b0237cd9d99b943a9cd17529692Michael Chan } 4477146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project} 4478