DayView.java revision 87f993ff96172f508d3f241f8a425f953c7eb739
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;
33146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Canvas;
34146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Paint;
35dd95df57c8c5a58a85c4c0effad5652dec14f621Erikimport android.graphics.Paint.Style;
36146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Rect;
37146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Typeface;
38c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawaimport android.graphics.drawable.Drawable;
39146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.net.Uri;
40146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Handler;
41146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Attendees;
42146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Calendars;
43146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Events;
443e7015267340b09d142dfcd3ff8acda257711023Shachar Shemeshimport android.text.Layout.Alignment;
45f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chanimport android.text.StaticLayout;
463e7015267340b09d142dfcd3ff8acda257711023Shachar Shemeshimport android.text.TextPaint;
47f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chanimport android.text.TextUtils;
48146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.DateFormat;
49146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.DateUtils;
50146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.Time;
51146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.util.Log;
52146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ContextMenu;
53dd95df57c8c5a58a85c4c0effad5652dec14f621Erikimport android.view.ContextMenu.ContextMenuInfo;
54ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.GestureDetector;
55146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.Gravity;
56146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.KeyEvent;
57146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.LayoutInflater;
58146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.MenuItem;
59146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.MotionEvent;
60d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chanimport android.view.ScaleGestureDetector;
61146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.View;
62146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ViewConfiguration;
63146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ViewGroup;
64146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.WindowManager;
65259b8f9a21fffd3858218581e9daaf689b6b888fErikimport android.view.accessibility.AccessibilityEvent;
6646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chanimport android.view.animation.AccelerateDecelerateInterpolator;
67ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.animation.Animation;
68ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.animation.TranslateAnimation;
69146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.ImageView;
70146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.PopupWindow;
71146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.TextView;
72ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.widget.ViewSwitcher;
73146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
74146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport java.util.ArrayList;
75c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawaimport java.util.Arrays;
76146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport java.util.Calendar;
77259b8f9a21fffd3858218581e9daaf689b6b888fErikimport java.util.Formatter;
78259b8f9a21fffd3858218581e9daaf689b6b888fErikimport java.util.Locale;
790d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chanimport java.util.regex.Matcher;
800d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chanimport java.util.regex.Pattern;
81146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
82146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/**
83d190418220467c02327dd9b3ae1eae238889720bMichael Chan * View for multi-day view. So far only 1 and 7 day have been tested.
84d190418220467c02327dd9b3ae1eae238889720bMichael Chan */
85d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chanpublic class DayView extends View implements View.OnCreateContextMenuListener,
86cd405a28e6821b116dcf3c531805d0c90b6cc08cErik        ScaleGestureDetector.OnScaleGestureListener, View.OnClickListener, View.OnLongClickListener
87cd405a28e6821b116dcf3c531805d0c90b6cc08cErik        {
88d190418220467c02327dd9b3ae1eae238889720bMichael Chan    private static String TAG = "DayView";
89d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private static boolean DEBUG = false;
90259b8f9a21fffd3858218581e9daaf689b6b888fErik    private static final String HOUR_FORMAT_12H = "%A %I%p";
91259b8f9a21fffd3858218581e9daaf689b6b888fErik    private static final String HOUR_FORMAT_24H = "%A %H";
92259b8f9a21fffd3858218581e9daaf689b6b888fErik    private static final String PERIOD_SPACE = ". ";
93146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
94705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static float mScale = 0; // Used for supporting different screen densities
95666fc5e8ddbac15c951aad738bd818ee307eae42Erik    private static final long INVALID_EVENT_ID = -1; //This is used for remembering a null event
96ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private static final long ANIMATION_DURATION = 400;
97705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
984484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_AGENDA = 2;
994484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_DAY = 3;
1004484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_VIEW = 5;
1014484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_CREATE = 6;
1024484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_EDIT = 7;
1034484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_DELETE = 8;
1044484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan
10511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan    private static int DEFAULT_CELL_HEIGHT = 64;
106d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private static int MAX_CELL_HEIGHT = 150;
107d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private static int MIN_Y_SPAN = 100;
108d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mOnFlingCalled;
110666fc5e8ddbac15c951aad738bd818ee307eae42Erik    /**
111666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * ID of the last event which was displayed with the toast popup.
112666fc5e8ddbac15c951aad738bd818ee307eae42Erik     *
113666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * This is used to prevent popping up multiple quick views for the same event, especially
114666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * during calendar syncs. This becomes valid when an event is selected, either by default
115666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * on starting calendar or by scrolling to an event. It becomes invalid when the user
116666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * explicitly scrolls to an empty time slot, changes views, or deletes the event.
117666fc5e8ddbac15c951aad738bd818ee307eae42Erik     */
118666fc5e8ddbac15c951aad738bd818ee307eae42Erik    private long mLastPopupEventID;
119146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
120ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    protected Context mContext;
121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String[] CALENDARS_PROJECTION = new String[] {
123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Calendars._ID,          // 0
124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Calendars.ACCESS_LEVEL, // 1
1256d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        Calendars.OWNER_ACCOUNT, // 2
126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int CALENDARS_INDEX_ACCESS_LEVEL = 1;
1286d34cec523930368976bc8d358d0a6de1da3462cMichael Chan    private static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2;
129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String CALENDARS_WHERE = Calendars._ID + "=%d";
130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String[] ATTENDEES_PROJECTION = new String[] {
132146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Attendees._ID,                      // 0
133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Attendees.ATTENDEE_RELATIONSHIP,    // 1
134146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ATTENDEES_INDEX_RELATIONSHIP = 1;
136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=%d";
137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_NONE = 0;
139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_ABOVE = 1;
140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_BELOW = 2;
141146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_LEFT = 4;
142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_RIGHT = 8;
143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
144a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static final int ACCESS_LEVEL_NONE = 0;
145a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static final int ACCESS_LEVEL_DELETE = 1;
146a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static final int ACCESS_LEVEL_EDIT = 2;
147a505627659f6bfba8869eac8089f7030f2d0d92cErik
148d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan    private static int mHorizontalSnapBackThreshold = 128;
149d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan    private static int HORIZONTAL_FLING_THRESHOLD = 75;
150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ContinueScroll mContinueScroll = new ContinueScroll();
152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Make this visible within the package for more informative debugging
154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Time mBaseDate;
155bd0e834aea317236d574f8738fe11a51fdc87968Erik    private Time mCurrentTime;
156bd0e834aea317236d574f8738fe11a51fdc87968Erik    //Update the current time line every five minutes if the window is left open that long
157bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static final int UPDATE_CURRENT_TIME_DELAY = 300000;
158bd0e834aea317236d574f8738fe11a51fdc87968Erik    private UpdateCurrentTime mUpdateCurrentTime = new UpdateCurrentTime();
159bd0e834aea317236d574f8738fe11a51fdc87968Erik    private int mTodayJulianDay;
160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Typeface mBold = Typeface.DEFAULT_BOLD;
162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstJulianDay;
163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mLastJulianDay;
164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mMonthLength;
166487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    private int mFirstVisibleDate;
167487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    private int mFirstVisibleDayOfWeek;
168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int[] mEarliestStartHour;    // indexed by the week day offset
169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean[] mHasAllDayEvent;   // indexed by the week day offset
1708f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private String mAllDayString;
171259b8f9a21fffd3858218581e9daaf689b6b888fErik    private String mEventCountTemplate;
172259b8f9a21fffd3858218581e9daaf689b6b888fErik
173259b8f9a21fffd3858218581e9daaf689b6b888fErik    protected static StringBuilder mStringBuilder = new StringBuilder(50);
174259b8f9a21fffd3858218581e9daaf689b6b888fErik    // TODO recreate formatter when locale changes
175259b8f9a21fffd3858218581e9daaf689b6b888fErik    protected static Formatter mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
177731f1cb808b7586b93615b408ab2636081fab0dcErik    private Runnable mTZUpdater = new Runnable() {
178731f1cb808b7586b93615b408ab2636081fab0dcErik        @Override
179731f1cb808b7586b93615b408ab2636081fab0dcErik        public void run() {
180731f1cb808b7586b93615b408ab2636081fab0dcErik            String tz = Utils.getTimeZone(mContext, this);
181731f1cb808b7586b93615b408ab2636081fab0dcErik            mBaseDate.timezone = tz;
182731f1cb808b7586b93615b408ab2636081fab0dcErik            mBaseDate.normalize(true);
183731f1cb808b7586b93615b408ab2636081fab0dcErik            mCurrentTime.switchTimezone(tz);
184731f1cb808b7586b93615b408ab2636081fab0dcErik            invalidate();
185731f1cb808b7586b93615b408ab2636081fab0dcErik        }
186731f1cb808b7586b93615b408ab2636081fab0dcErik    };
187731f1cb808b7586b93615b408ab2636081fab0dcErik
18846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
18946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        @Override
19046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        public void onAnimationStart(Animator animation) {
19146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            mScrolling = true;
19246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        }
19346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
19446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        @Override
19546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        public void onAnimationCancel(Animator animation) {
19646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            mScrolling = false;
19746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        }
19846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
19946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        @Override
20046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        public void onAnimationEnd(Animator animation) {
20146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            mScrolling = false;
20246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            resetSelectedHour();
20346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            invalidate();
20446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        }
20546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    };
20646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * This variable helps to avoid unnecessarily reloading events by keeping
209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * track of the start millis parameter used for the most recent loading
210146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * of events.  If the next reload matches this, then the events are not
211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * reloaded.  To force a reload, set this to zero (this is set to zero
212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * in the method clearCachedEvents()).
213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private long mLastReloadMillis;
215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ArrayList<Event> mEvents = new ArrayList<Event>();
21708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan    private ArrayList<Event> mAllDayEvents = new ArrayList<Event>();
21808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan    private StaticLayout[] mLayouts = null;
21908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan    private StaticLayout[] mAllDayLayouts = null;
220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mSelectionDay;        // Julian day
221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mSelectionHour;
222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    boolean mSelectionAllDay;
224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2253eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    /** Width of a day or non-conflicting event */
226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mCellWidth;
227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Pre-allocate these objects and re-use them
229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect mRect = new Rect();
230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect mDestRect = new Rect();
231259b8f9a21fffd3858218581e9daaf689b6b888fErik    private Rect mSelectionRect = new Rect();
232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Paint mPaint = new Paint();
233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Paint mEventTextPaint = new Paint();
234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Paint mSelectionPaint = new Paint();
23502041687c35441e8a21cb763f1fc3a26525292efDavid Brown    private float[] mLines;
236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
237487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    private int mFirstDayOfWeek; // First day of the week
238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private PopupWindow mPopup;
240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private View mPopupView;
241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // The number of milliseconds to show the popup window
243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int POPUP_DISMISS_DELAY = 3000;
244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private DismissPopup mDismissPopup = new DismissPopup();
245146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
246146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mRemeasure = true;
247146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private final EventLoader mEventLoader;
249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected final EventGeometry mEventGeometry;
250146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2518f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private static float GRID_LINE_LEFT_MARGIN = 16;
252000ba1109e2f4e527e9227fe341598ceeb3fbca6Michael Chan    private static final float GRID_LINE_INNER_WIDTH = 1;
253000ba1109e2f4e527e9227fe341598ceeb3fbca6Michael Chan    private static final float GRID_LINE_WIDTH = 5;
2543eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
255146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int DAY_GAP = 1;
256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int HOUR_GAP = 1;
2579c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    private static int SINGLE_ALLDAY_HEIGHT = 34;
2581ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int MAX_ALLDAY_HEIGHT = 105;
259705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int ALLDAY_TOP_MARGIN = 3;
260f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan    private static int MAX_HEIGHT_OF_ONE_ALLDAY_EVENT = 34;
261e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2628f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private static int HOURS_TOP_MARGIN = 2;
2638f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private static int HOURS_LEFT_MARGIN = 30;
2648f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private static int HOURS_RIGHT_MARGIN = 4;
2658f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private static int HOURS_MARGIN = HOURS_LEFT_MARGIN + HOURS_RIGHT_MARGIN;
266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
267bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int CURRENT_TIME_LINE_HEIGHT = 2;
268bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int CURRENT_TIME_LINE_BORDER_WIDTH = 1;
2691ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static final int CURRENT_TIME_LINE_SIDE_BUFFER = 2;
270bd0e834aea317236d574f8738fe11a51fdc87968Erik
271146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MINUTES_PER_HOUR = 60;
272146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * 24;
273146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MILLIS_PER_MINUTE = 60 * 1000;
274146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MILLIS_PER_HOUR = (3600 * 1000);
275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MILLIS_PER_DAY = MILLIS_PER_HOUR * 24;
276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
277bf4aa400663a072813c87cf9c8aaee2d07abc945Erik    private static final int DAY_HEADER_ALPHA = 0x80000000;
278f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan    private static final int DATE_HEADER_ALPHA = 0x26000000;
279f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan    private static final int DATE_HEADER_TODAY_ALPHA = 0x99000000;
2809dd340d393575ba9740ef259e62ee7a17fc76ed1Michael Chan    private static float DAY_HEADER_ONE_DAY_LEFT_MARGIN = 0;
2813eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_ONE_DAY_RIGHT_MARGIN = 5;
2823eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_ONE_DAY_BOTTOM_MARGIN = 6;
2833eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_LEFT_MARGIN = 5;
2843eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_RIGHT_MARGIN = 7;
2853eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_BOTTOM_MARGIN = 3;
2863eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_FONT_SIZE = 14;
2878f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private static float DATE_HEADER_FONT_SIZE = 32;
2883eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float NORMAL_FONT_SIZE = 12;
2893eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float EVENT_TEXT_FONT_SIZE = 12;
2903eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float HOURS_FONT_SIZE = 12;
2913eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float AMPM_FONT_SIZE = 9;
2928f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private static int MIN_HOURS_WIDTH = 96;
293705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int MIN_CELL_WIDTH_FOR_TEXT = 27;
294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int MAX_EVENT_TEXT_LEN = 500;
295705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static float MIN_EVENT_HEIGHT = 15.0F;  // in pixels
2961ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int CALENDAR_COLOR_SQUARE_SIZE = 10;
2971ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int CALENDAR_COLOR_SQUARE_V_OFFSET = -1;
2981ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int CALENDAR_COLOR_SQUARE_H_OFFSET = -3;
2991ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_RECT_TOP_MARGIN = -1;
3001ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_RECT_BOTTOM_MARGIN = -1;
3011ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_RECT_LEFT_MARGIN = -1;
3021ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_RECT_RIGHT_MARGIN = -1;
3031ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_TEXT_TOP_MARGIN = 2;
3041ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_TEXT_BOTTOM_MARGIN = 3;
3051ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_TEXT_LEFT_MARGIN = 11;
3061ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_TEXT_RIGHT_MARGIN = 4;
3071ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_ALL_DAY_TEXT_TOP_MARGIN = EVENT_TEXT_TOP_MARGIN;
3081ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN = EVENT_TEXT_BOTTOM_MARGIN;
3091ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_ALL_DAY_TEXT_LEFT_MARGIN = EVENT_TEXT_LEFT_MARGIN;
3101ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private static int EVENT_ALL_DAY_TEXT_RIGHT_MARGIN = EVENT_TEXT_RIGHT_MARGIN;
311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static int mPressedColor;
313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static int mEventTextColor;
314f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan    private static int mDeclinedEventTextColor;
315f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan
31664b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok    private static int mWeek_saturdayColor;
31764b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok    private static int mWeek_sundayColor;
318d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarDateBannerTextColor;
3193eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//    private static int mCalendarAllDayBackground;
320d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarAmPmLabel;
3213eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//    private static int mCalendarDateBannerBackground;
32211ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan//    private static int mCalendarDateSelected;
3233eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//    private static int mCalendarGridAreaBackground;
324ba902466b19b11d587468e354edc58e542707747Michael Chan    private static int mCalendarGridAreaSelected;
325d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarGridLineHorizontalColor;
326d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarGridLineVerticalColor;
3273eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static int mCalendarGridLineInnerHorizontalColor;
3283eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static int mCalendarGridLineInnerVerticalColor;
3293eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//    private static int mCalendarHourBackground;
3308f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private static int mCalendarHourLabelColor;
33111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan//    private static int mCalendarHourSelected;
332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewStartX;
334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewStartY;
335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mMaxViewStartY;
336146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewHeight;
337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewWidth;
33846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    private int mGridAreaHeight = -1;
339d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private static int mCellHeight = 0; // shared among all DayViews
340d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private static int mMinCellHeight = 32;
341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mScrollStartY;
342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mPreviousDirection;
343146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
344d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    /**
345d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     * Vertical distance or span between the two touch points at the start of a
346d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     * scaling gesture
347d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     */
348d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private float mStartingSpanY = 0;
349d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    /** Height of 1 hour in pixels at the start of a scaling gesture */
350d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private int mCellHeightBeforeScaleGesture;
351d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    /** The hour at the center two touch points */
352d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private float mGestureCenterHour = 0;
353d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    /**
354d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     * Flag to decide whether to handle the up event. Cases where up events
355d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     * should be ignored are 1) right after a scale gesture and 2) finger was
356d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     * down before app launch
357d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     */
358d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private boolean mHandleActionUp = true;
359d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mHoursTextHeight;
361146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mAllDayHeight;
3623eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static int DAY_HEADER_HEIGHT = 45;
363f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan    /**
364f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan     * Max of all day events in a given day in this view.
365f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan     */
366146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mMaxAllDayEvents;
367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected int mNumDays = 7;
369146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mNumHours = 10;
3703eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
3713eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    /** Width of the time line (list of hours) to the left. */
372146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mHoursWidth;
373146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mDateStrWidth;
37446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    /** Top of the scrollable region i.e. below date labels and all day events */
375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstCell;
37646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    /** First fully visibile hour */
377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstHour = -1;
37846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    /** Distance between the mFirstCell and the top of first fully visible hour. */
379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstHourOffset;
380146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String[] mHourStrs;
381146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String[] mDayStrs;
382146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String[] mDayStrs2Letter;
383146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mIs24HourFormat;
384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ArrayList<Event> mSelectedEvents = new ArrayList<Event>();
386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mComputeSelectedEvents;
3878307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik    private boolean mUpdateToast;
388146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Event mSelectedEvent;
389146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Event mPrevSelectedEvent;
390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect mPrevBox = new Rect();
391146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected final Resources mResources;
3923eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    protected final Drawable mCurrentTimeLine;
3933eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    protected final Drawable mTodayHeaderDrawable;
394f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan    protected Drawable mAcceptedOrTentativeEventBoxDrawable;
395f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan    protected Drawable mUnconfirmedOrDeclinedEventBoxDrawable;
396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String mAmString;
397146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String mPmString;
398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private DeleteEventHelper mDeleteEventHelper;
3996d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan    private static int sCounter = 0;
400146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
401146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ContextMenuHandler mContextMenuHandler = new ContextMenuHandler();
402146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
403d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    ScaleGestureDetector mScaleGestureDetector;
404d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * The initial state of the touch mode when we enter this view.
407146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
408146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_INITIAL_STATE = 0;
409146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Indicates we just received the touch event and we are waiting to see if
412146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * it is a tap or a scroll gesture.
413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
414146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_DOWN = 1;
415146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Indicates the touch gesture is a vertical scroll
418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
419146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_VSCROLL = 0x20;
420146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
421146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
422146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Indicates the touch gesture is a horizontal scroll
423146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
424146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_HSCROLL = 0x40;
425146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
426146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mTouchMode = TOUCH_MODE_INITIAL_STATE;
427146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
428146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
429146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * The selection modes are HIDDEN, PRESSED, SELECTED, and LONGPRESS.
430146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
431146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_HIDDEN = 0;
432ef2185bf0c7a80154a79788915db04d4f9e7ad4dMichael Chan    private static final int SELECTION_PRESSED = 1; // D-pad down but not up yet
433146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_SELECTED = 2;
434146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_LONGPRESS = 3;
435146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
436146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mSelectionMode = SELECTION_HIDDEN;
437146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
438146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mScrolling = false;
439146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
440ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private CalendarController mController;
441ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private ViewSwitcher mViewSwitcher;
442ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private GestureDetector mGestureDetector;
443705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
444d190418220467c02327dd9b3ae1eae238889720bMichael Chan    public DayView(Context context, CalendarController controller,
44575d9b567e1fd3b9c6945cd0afe28781f5a19c6c8Michael Chan            ViewSwitcher viewSwitcher, EventLoader eventLoader, int numDays) {
446ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        super(context);
447705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan        if (mScale == 0) {
448705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan            mScale = getContext().getResources().getDisplayMetrics().density;
449705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan            if (mScale != 1) {
450705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                SINGLE_ALLDAY_HEIGHT *= mScale;
451705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                ALLDAY_TOP_MARGIN *= mScale;
452f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                MAX_HEIGHT_OF_ONE_ALLDAY_EVENT *= mScale;
453705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
454705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                NORMAL_FONT_SIZE *= mScale;
455705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                EVENT_TEXT_FONT_SIZE *= mScale;
4568f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan                GRID_LINE_LEFT_MARGIN *= mScale;
457705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                HOURS_FONT_SIZE *= mScale;
4588f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan                HOURS_TOP_MARGIN *= mScale;
4598f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan                HOURS_LEFT_MARGIN *= mScale;
4608f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan                HOURS_RIGHT_MARGIN *= mScale;
4618f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan                HOURS_MARGIN = HOURS_LEFT_MARGIN + HOURS_RIGHT_MARGIN;
462705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                AMPM_FONT_SIZE *= mScale;
4638f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan                MIN_HOURS_WIDTH *= mScale;
464705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                MIN_CELL_WIDTH_FOR_TEXT *= mScale;
465705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                MIN_EVENT_HEIGHT *= mScale;
466705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
467d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan                HORIZONTAL_FLING_THRESHOLD *= mScale;
468e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
469bd0e834aea317236d574f8738fe11a51fdc87968Erik                CURRENT_TIME_LINE_HEIGHT *= mScale;
470bd0e834aea317236d574f8738fe11a51fdc87968Erik                CURRENT_TIME_LINE_BORDER_WIDTH *= mScale;
471bd0e834aea317236d574f8738fe11a51fdc87968Erik
472d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                MIN_Y_SPAN *= mScale;
473d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                MAX_CELL_HEIGHT *= mScale;
474697157470a6f0d8e7b806af9b4fb7fbe0bccae87Erik                DEFAULT_CELL_HEIGHT *= mScale;
4753eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_HEIGHT *= mScale;
4763eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_LEFT_MARGIN *= mScale;
4773eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_RIGHT_MARGIN *= mScale;
4783eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_BOTTOM_MARGIN *= mScale;
4793eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_ONE_DAY_LEFT_MARGIN *= mScale;
4803eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_ONE_DAY_RIGHT_MARGIN *= mScale;
4813eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_ONE_DAY_BOTTOM_MARGIN *= mScale;
4823eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_FONT_SIZE *= mScale;
4833eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DATE_HEADER_FONT_SIZE *= mScale;
4843eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                CALENDAR_COLOR_SQUARE_SIZE *= mScale;
4853eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                EVENT_TEXT_TOP_MARGIN *= mScale;
4863eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                EVENT_TEXT_BOTTOM_MARGIN *= mScale;
4873eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                EVENT_TEXT_LEFT_MARGIN *= mScale;
4883eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                EVENT_TEXT_RIGHT_MARGIN *= mScale;
4899c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                EVENT_ALL_DAY_TEXT_TOP_MARGIN *= mScale;
4909c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN *= mScale;
4919c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                EVENT_ALL_DAY_TEXT_LEFT_MARGIN *= mScale;
4929c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                EVENT_ALL_DAY_TEXT_RIGHT_MARGIN *= mScale;
49311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                EVENT_RECT_TOP_MARGIN *= mScale;
49411ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                EVENT_RECT_BOTTOM_MARGIN *= mScale;
49511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                EVENT_RECT_LEFT_MARGIN *= mScale;
49611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                EVENT_RECT_RIGHT_MARGIN *= mScale;
497705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan            }
498705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan        }
499705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
500ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mResources = context.getResources();
5013eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mCurrentTimeLine = mResources.getDrawable(R.drawable.timeline_week_holo_light);
5023eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mTodayHeaderDrawable = mResources.getDrawable(R.drawable.today_blue_week_holo_light);
503f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan        mAcceptedOrTentativeEventBoxDrawable = mResources
504f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan                .getDrawable(R.drawable.panel_month_event_holo_light);
505f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan        mUnconfirmedOrDeclinedEventBoxDrawable = mResources
506f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan                .getDrawable(R.drawable.week_event_bg_decline_holo_light);
507ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mEventLoader = eventLoader;
508146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry = new EventGeometry();
509146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry.setMinEventHeight(MIN_EVENT_HEIGHT);
510146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry.setHourGap(HOUR_GAP);
511ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mContext = context;
5128f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        mAllDayString = mContext.getString(R.string.edit_event_all_day_label);
513ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mDeleteEventHelper = new DeleteEventHelper(context, null, false /* don't exit when done */);
514666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = INVALID_EVENT_ID;
515ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mController = controller;
516ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher = viewSwitcher;
517ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mGestureDetector = new GestureDetector(context, new CalendarGestureListener());
518d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mScaleGestureDetector = new ScaleGestureDetector(getContext(), this);
51975d9b567e1fd3b9c6945cd0afe28781f5a19c6c8Michael Chan        mNumDays = numDays;
520d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mCellHeight == 0) {
521d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeight = Utils.getSharedPreference(mContext,
522d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    GeneralPreferences.KEY_DEFAULT_CELL_HEIGHT, DEFAULT_CELL_HEIGHT);
523d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
524146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
525ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        init(context);
526146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
527146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
528146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void init(Context context) {
529146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setFocusable(true);
530146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
531146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Allow focus in touch mode so that we can do keyboard shortcuts
532146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // even after we've entered touch mode.
533146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setFocusableInTouchMode(true);
534146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setClickable(true);
535146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setOnCreateContextMenuListener(this);
536146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
537487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mFirstDayOfWeek = Utils.getFirstDayOfWeek(context);
538146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
539731f1cb808b7586b93615b408ab2636081fab0dcErik        mCurrentTime = new Time(Utils.getTimeZone(context, mTZUpdater));
540bd0e834aea317236d574f8738fe11a51fdc87968Erik        long currentTime = System.currentTimeMillis();
541bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTime.set(currentTime);
542bd0e834aea317236d574f8738fe11a51fdc87968Erik        //The % makes it go off at the next increment of 5 minutes.
543bd0e834aea317236d574f8738fe11a51fdc87968Erik        postDelayed(mUpdateCurrentTime,
544bd0e834aea317236d574f8738fe11a51fdc87968Erik                UPDATE_CURRENT_TIME_DELAY - (currentTime % UPDATE_CURRENT_TIME_DELAY));
545bd0e834aea317236d574f8738fe11a51fdc87968Erik        mTodayJulianDay = Time.getJulianDay(currentTime, mCurrentTime.gmtoff);
546bd0e834aea317236d574f8738fe11a51fdc87968Erik
54764b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok        mWeek_saturdayColor = mResources.getColor(R.color.week_saturday);
54864b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok        mWeek_sundayColor = mResources.getColor(R.color.week_sunday);
549d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarDateBannerTextColor = mResources.getColor(R.color.calendar_date_banner_text_color);
5503eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        mCalendarAllDayBackground = mResources.getColor(R.color.calendar_all_day_background);
551d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarAmPmLabel = mResources.getColor(R.color.calendar_ampm_label);
5523eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        mCalendarDateBannerBackground = mResources.getColor(R.color.calendar_date_banner_background);
55311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan//        mCalendarDateSelected = mResources.getColor(R.color.calendar_date_selected);
5543eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        mCalendarGridAreaBackground = mResources.getColor(R.color.calendar_grid_area_background);
555ba902466b19b11d587468e354edc58e542707747Michael Chan        mCalendarGridAreaSelected = mResources.getColor(R.color.calendar_grid_area_selected);
556d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarGridLineHorizontalColor = mResources.getColor(R.color.calendar_grid_line_horizontal_color);
557d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarGridLineVerticalColor = mResources.getColor(R.color.calendar_grid_line_vertical_color);
5583eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mCalendarGridLineInnerHorizontalColor = mResources.getColor(R.color.calendar_grid_line_inner_horizontal_color);
5593eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mCalendarGridLineInnerVerticalColor = mResources.getColor(R.color.calendar_grid_line_inner_vertical_color);
5603eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        mCalendarHourBackground = mResources.getColor(R.color.calendar_hour_background);
5618f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        mCalendarHourLabelColor = mResources.getColor(R.color.calendar_hour_label);
56211ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan//        mCalendarHourSelected = mResources.getColor(R.color.calendar_hour_selected);
563146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPressedColor = mResources.getColor(R.color.pressed);
564146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextColor = mResources.getColor(R.color.calendar_event_text_color);
565f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan        mDeclinedEventTextColor = mResources.getColor(R.color.calendar_declined_event_text_color);
56611638ad4fb56b978770aebe75deac7a0e6ac60d2Erik
567146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setTextSize(EVENT_TEXT_FONT_SIZE);
568146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setTextAlign(Paint.Align.LEFT);
569146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setAntiAlias(true);
570146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
571146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int gridLineColor = mResources.getColor(R.color.calendar_grid_line_highlight_color);
572146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = mSelectionPaint;
573146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setColor(gridLineColor);
5743937a47bc5a1afb9701e1d0565fae31f5800590dErik        p.setStyle(Style.FILL);
575146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(false);
576146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
577146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p = mPaint;
578146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
579146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
580146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Allocate space for 2 weeks worth of weekday names so that we can
581146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // easily start the week display at any week day.
582146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDayStrs = new String[14];
583146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
584146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Also create an array of 2-letter abbreviations.
585146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDayStrs2Letter = new String[14];
586146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
587146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
588146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int index = i - Calendar.SUNDAY;
589146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // e.g. Tue for Tuesday
590146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_MEDIUM);
591146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs[index + 7] = mDayStrs[index];
592146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // e.g. Tu for Tuesday
593146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs2Letter[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_SHORT);
59452b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer
59552b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer            // If we don't have 2-letter day strings, fall back to 1-letter.
59652b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer            if (mDayStrs2Letter[index].equals(mDayStrs[index])) {
59752b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer                mDayStrs2Letter[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_SHORTEST);
59852b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer            }
59952b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer
600146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs2Letter[index + 7] = mDayStrs2Letter[index];
601146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
602146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
603146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Figure out how much space we need for the 3-letter abbrev names
604146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // in the worst case.
6053eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setTextSize(DATE_HEADER_FONT_SIZE);
606146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(mBold);
607146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String[] dateStrs = {" 28", " 30"};
608146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDateStrWidth = computeMaxStringWidth(0, dateStrs, p);
6093eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setTextSize(DAY_HEADER_FONT_SIZE);
610146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDateStrWidth += computeMaxStringWidth(0, mDayStrs, p);
611146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
612146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(HOURS_FONT_SIZE);
613146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(null);
61461a2e87e7412281d17e86ccff4352cbf32fe77e7Michael Chan        handleOnResume();
615146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
616146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mAmString = DateUtils.getAMPMString(Calendar.AM);
617146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPmString = DateUtils.getAMPMString(Calendar.PM);
618146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String[] ampm = {mAmString, mPmString};
619146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(AMPM_FONT_SIZE);
6208f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        mHoursWidth = computeMaxStringWidth(mHoursWidth, ampm, p) + HOURS_MARGIN;
6218f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        mHoursWidth = Math.max(MIN_HOURS_WIDTH, mHoursWidth);
622146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
623146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        LayoutInflater inflater;
624146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
625146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopupView = inflater.inflate(R.layout.bubble_event, null);
626146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopupView.setLayoutParams(new ViewGroup.LayoutParams(
627df279e3f9d5b0f189f812c52aca78d18178e4445Romain Guy                ViewGroup.LayoutParams.MATCH_PARENT,
628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                ViewGroup.LayoutParams.WRAP_CONTENT));
629146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup = new PopupWindow(context);
630146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setContentView(mPopupView);
631146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Resources.Theme dialogTheme = getResources().newTheme();
632146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        dialogTheme.applyStyle(android.R.style.Theme_Dialog, true);
633146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TypedArray ta = dialogTheme.obtainStyledAttributes(new int[] {
634146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            android.R.attr.windowBackground });
635146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setBackgroundDrawable(ta.getDrawable(0));
636146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ta.recycle();
637146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
638146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Enable touching the popup window
639146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopupView.setOnClickListener(this);
640cd405a28e6821b116dcf3c531805d0c90b6cc08cErik        // Catch long clicks for creating a new event
641cd405a28e6821b116dcf3c531805d0c90b6cc08cErik        setOnLongClickListener(this);
642146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
643731f1cb808b7586b93615b408ab2636081fab0dcErik        mBaseDate = new Time(Utils.getTimeZone(context, mTZUpdater));
644146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = System.currentTimeMillis();
645146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mBaseDate.set(millis);
646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
647146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEarliestStartHour = new int[mNumDays];
648146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mHasAllDayEvent = new boolean[mNumDays];
64902041687c35441e8a21cb763f1fc3a26525292efDavid Brown
65002041687c35441e8a21cb763f1fc3a26525292efDavid Brown        // mLines is the array of points used with Canvas.drawLines() in
65102041687c35441e8a21cb763f1fc3a26525292efDavid Brown        // drawGridBackground() and drawAllDayEvents().  Its size depends
65202041687c35441e8a21cb763f1fc3a26525292efDavid Brown        // on the max number of lines that can ever be drawn by any single
65302041687c35441e8a21cb763f1fc3a26525292efDavid Brown        // drawLines() call in either of those methods.
65402041687c35441e8a21cb763f1fc3a26525292efDavid Brown        final int maxGridLines = (24 + 1)  // max horizontal lines we might draw
65502041687c35441e8a21cb763f1fc3a26525292efDavid Brown                + (mNumDays + 1);  // max vertical lines we might draw
65602041687c35441e8a21cb763f1fc3a26525292efDavid Brown        mLines = new float[maxGridLines * 4];
657146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
658146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
659146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
660146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * This is called when the popup window is pressed.
661146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
662146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void onClick(View v) {
663146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (v == mPopupView) {
664146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Pretend it was a trackball click because that will always
665146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // jump to the "View event" screen.
666146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchViews(true /* trackball */);
667146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
668146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
669146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
67061a2e87e7412281d17e86ccff4352cbf32fe77e7Michael Chan    public void handleOnResume() {
671ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mIs24HourFormat = DateFormat.is24HourFormat(mContext);
67269ab334d6988eda70ba53618506d23ebf7d7b405Erik        mHourStrs = mIs24HourFormat ? CalendarData.s24Hours : CalendarData.s12HoursNoAmPm;
67361a2e87e7412281d17e86ccff4352cbf32fe77e7Michael Chan        mFirstDayOfWeek = Utils.getFirstDayOfWeek(mContext);
67469ab334d6988eda70ba53618506d23ebf7d7b405Erik    }
67569ab334d6988eda70ba53618506d23ebf7d7b405Erik
676146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
677146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Returns the start of the selected time in milliseconds since the epoch.
678146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @return selected time in UTC milliseconds since the epoch.
680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
681146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    long getSelectedTimeInMillis() {
682146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time time = new Time(mBaseDate);
683146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.setJulianDay(mSelectionDay);
684146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.hour = mSelectionHour;
685146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
686146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // We ignore the "isDst" field because we want normalize() to figure
687146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // out the correct DST value and not adjust the selected time based
688146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // on the current setting of DST.
689146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return time.normalize(true /* ignore isDst */);
690146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
691146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
692146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Time getSelectedTime() {
693146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time time = new Time(mBaseDate);
694146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.setJulianDay(mSelectionDay);
695146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.hour = mSelectionHour;
696146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
697146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // We ignore the "isDst" field because we want normalize() to figure
698146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // out the correct DST value and not adjust the selected time based
699146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // on the current setting of DST.
700146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.normalize(true /* ignore isDst */);
701146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return time;
702146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
703146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
704146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
705146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Returns the start of the selected time in minutes since midnight,
706146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * local time.  The derived class must ensure that this is consistent
707146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * with the return value from getSelectedTimeInMillis().
708146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
709146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    int getSelectedMinutesSinceMidnight() {
710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return mSelectionHour * MINUTES_PER_HOUR;
711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
71346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    int getFirstVisibleHour() {
71446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        return mFirstHour;
71546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    }
71646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
71746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    void setFirstVisibleHour(int firstHour) {
71846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        mFirstHour = firstHour;
71946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        mFirstHourOffset = 0;
72046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    }
72146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
72246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    public void setSelected(Time time, boolean ignoreTime) {
723146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mBaseDate.set(time);
724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionHour = mBaseDate.hour;
725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = null;
726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevSelectedEvent = null;
727146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = mBaseDate.toMillis(false /* use isDst */);
728146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionDay = Time.getJulianDay(millis, mBaseDate.gmtoff);
729146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
730146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mComputeSelectedEvents = true;
731146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
73246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        int gotoY = Integer.MIN_VALUE;
73346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
73446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        if (!ignoreTime && mGridAreaHeight != -1) {
73546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            int lastHour = 0;
73646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
73746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            if (mBaseDate.hour < mFirstHour) {
73846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                // Above visible region
73946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                gotoY = mBaseDate.hour * (mCellHeight + HOUR_GAP);
74046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            } else {
74146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                lastHour = (mGridAreaHeight - mFirstHourOffset) / (mCellHeight + HOUR_GAP)
74246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        + mFirstHour;
74346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
74446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mBaseDate.hour >= lastHour) {
74546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    // Below visible region
74646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
74746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    // target hour + 1 (to give it room to see the event) -
74846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    // grid height (to get the y of the top of the visible
74946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    // region)
75055a26d7062d5aa1a1b001b7271bb137276ab807eErik                    gotoY = (int) ((mBaseDate.hour + 1 + mBaseDate.minute / 60.0f)
75146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                            * (mCellHeight + HOUR_GAP) - mGridAreaHeight);
75246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
75346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            }
75446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
75546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            if (DEBUG) {
75646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                Log.e(TAG, "Go " + gotoY + " 1st " + mFirstHour + ":" + mFirstHourOffset + "CH "
75746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        + (mCellHeight + HOUR_GAP) + " lh " + lastHour + " gh " + mGridAreaHeight
75846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        + " ymax " + mMaxViewStartY);
75946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            }
76046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
76146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            if (gotoY > mMaxViewStartY) {
76246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                gotoY = mMaxViewStartY;
76346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            } else if (gotoY < 0 && gotoY != Integer.MIN_VALUE) {
76446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                gotoY = 0;
76546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            }
76646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        }
76746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
768146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        recalc();
769146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
770ef2185bf0c7a80154a79788915db04d4f9e7ad4dMichael Chan        // Don't draw the selection box if we are going to the "current" time
771ef2185bf0c7a80154a79788915db04d4f9e7ad4dMichael Chan        long currMillis = System.currentTimeMillis();
772ef2185bf0c7a80154a79788915db04d4f9e7ad4dMichael Chan        boolean recent = (currMillis - 10000) < millis && millis < currMillis;
77346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        mSelectionMode = (recent || ignoreTime) ? SELECTION_HIDDEN : SELECTION_SELECTED;
774146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mRemeasure = true;
775146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
77646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
77746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        if (gotoY != Integer.MIN_VALUE) {
77846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            TypeEvaluator evaluator = new TypeEvaluator() {
77946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                @Override
78046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                public Object evaluate(float fraction, Object startValue, Object endValue) {
78146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    int start = (Integer) startValue;
78246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    int end = (Integer) endValue;
78346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    final int newValue = (int) ((end - start) * fraction + start);
78446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    setViewStartY(newValue);
78546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    return new Integer(newValue);
78646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
78746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            };
78846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            ValueAnimator scrollAnim = ObjectAnimator.ofObject(evaluator, new Integer(mViewStartY),
78946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    new Integer(gotoY));
79046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan//          TODO The following line is supposed to replace the two statements above.
79146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan//          Need to investigate why it's not working.
79246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
79346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan//          ValueAnimator scrollAnim = ObjectAnimator.ofInt(this, "viewStartY", mViewStartY, gotoY);
79446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            scrollAnim.setDuration(200);
79546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            scrollAnim.setInterpolator(new AccelerateDecelerateInterpolator());
79646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            scrollAnim.addListener(mAnimatorListener);
79746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            scrollAnim.start();
79846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        }
79946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    }
80046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
80146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    public void setViewStartY(int viewStartY) {
80246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        if (viewStartY > mMaxViewStartY) {
80346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            viewStartY = mMaxViewStartY;
80446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        }
80546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
80646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        mViewStartY = viewStartY;
80746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
80846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        computeFirstHour();
80946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        invalidate();
810146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
811146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
812146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public Time getSelectedDay() {
813146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time time = new Time(mBaseDate);
814146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.setJulianDay(mSelectionDay);
815146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.hour = mSelectionHour;
816146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
817146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // We ignore the "isDst" field because we want normalize() to figure
818146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // out the correct DST value and not adjust the selected time based
819146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // on the current setting of DST.
820146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.normalize(true /* ignore isDst */);
821146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return time;
822146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
823146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
824eaafa2b48be7194a61754604ae37b3d62e9118d8Erik    public void updateTitle() {
825eaafa2b48be7194a61754604ae37b3d62e9118d8Erik        Time start = new Time(mBaseDate);
826eaafa2b48be7194a61754604ae37b3d62e9118d8Erik        start.normalize(true);
827eaafa2b48be7194a61754604ae37b3d62e9118d8Erik        Time end = new Time(start);
828eaafa2b48be7194a61754604ae37b3d62e9118d8Erik        end.monthDay += mNumDays - 1;
829eaafa2b48be7194a61754604ae37b3d62e9118d8Erik        // Move it forward one minute so the formatter doesn't lose a day
830eaafa2b48be7194a61754604ae37b3d62e9118d8Erik        end.minute += 1;
831eaafa2b48be7194a61754604ae37b3d62e9118d8Erik        end.normalize(true);
832eaafa2b48be7194a61754604ae37b3d62e9118d8Erik
8339e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan        long formatFlags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
8349e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan        if (mNumDays != 1) {
8359e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan            // Don't show day of the month if for multi-day view
8369e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan            formatFlags |= DateUtils.FORMAT_NO_MONTH_DAY;
8379e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan
8389e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan            // Abbreviate the month if showing multiple months
8399e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan            if (start.month != end.month) {
8409e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan                formatFlags |= DateUtils.FORMAT_ABBREV_MONTH;
8419e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan            }
8429e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan        }
8439e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan
844f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        mController.sendEvent(this, EventType.UPDATE_TITLE, start, end, null, -1, ViewType.CURRENT,
8459e9e0678fe1969659dede3909c2cab6d2c3e5c8bMichael Chan                formatFlags, null, null);
846eaafa2b48be7194a61754604ae37b3d62e9118d8Erik    }
847eaafa2b48be7194a61754604ae37b3d62e9118d8Erik
84883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    /**
849487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan     * return a negative number if "time" is comes before the visible time
850487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan     * range, a positive number if "time" is after the visible time range, and 0
851487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan     * if it is in the visible time range.
85283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     */
853487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    public int compareToVisibleTimeRange(Time time) {
854487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
855487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int savedHour = mBaseDate.hour;
856487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int savedMinute = mBaseDate.minute;
857487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int savedSec = mBaseDate.second;
858487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
859487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.hour = 0;
860487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.minute = 0;
861487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.second = 0;
862487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
863030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown        if (DEBUG) {
864030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown            Log.d(TAG, "Begin " + mBaseDate.toString());
865030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown            Log.d(TAG, "Diff  " + time.toString());
866030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown        }
867487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
86883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        // Compare beginning of range
86983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        int diff = Time.compare(time, mBaseDate);
870487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        if (diff > 0) {
871487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            // Compare end of range
872487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.monthDay += mNumDays;
873487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.normalize(true);
874487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            diff = Time.compare(time, mBaseDate);
875487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
876030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown            if (DEBUG) Log.d(TAG, "End   " + mBaseDate.toString());
877487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
878487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.monthDay -= mNumDays;
879487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.normalize(true);
880487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            if (diff < 0) {
881487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                // in visible time
882487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                diff = 0;
883487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            } else if (diff == 0) {
884487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                // Midnight of following day
885487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                diff = 1;
886487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            }
88783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        }
88883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
889030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown        if (DEBUG) Log.d(TAG, "Diff: " + diff);
89083b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
891487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.hour = savedHour;
892487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.minute = savedMinute;
893487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.second = savedSec;
894487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        return diff;
89583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
89683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
897146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void recalc() {
898146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Set the base date to the beginning of the week if we are displaying
899146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // 7 days at a time.
900146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays == 7) {
9016d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            adjustToBeginningOfWeek(mBaseDate);
902146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
903146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
904146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        final long start = mBaseDate.toMillis(false /* use isDst */);
905146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstJulianDay = Time.getJulianDay(start, mBaseDate.gmtoff);
906146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mLastJulianDay = mFirstJulianDay + mNumDays - 1;
907146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
908146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mMonthLength = mBaseDate.getActualMaximum(Time.MONTH_DAY);
909487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mFirstVisibleDate = mBaseDate.monthDay;
910487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mFirstVisibleDayOfWeek = mBaseDate.weekDay;
911146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
912146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
9136d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan    private void adjustToBeginningOfWeek(Time time) {
9146d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        int dayOfWeek = time.weekDay;
9156d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        int diff = dayOfWeek - mFirstDayOfWeek;
9166d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        if (diff != 0) {
9176d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            if (diff < 0) {
9186d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan                diff += 7;
9196d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            }
9206d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            time.monthDay -= diff;
9216d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            time.normalize(true /* ignore isDst */);
9226d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
9236d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan    }
9246d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
925146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
926146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected void onSizeChanged(int width, int height, int oldw, int oldh) {
927146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewWidth = width;
928146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewHeight = height;
929146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int gridAreaWidth = width - mHoursWidth;
930146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mCellWidth = (gridAreaWidth - (mNumDays * DAY_GAP)) / mNumDays;
931146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
932d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan        // This would be about 1 day worth in a 7 day view
933d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan        mHorizontalSnapBackThreshold = width / 7;
934d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan
935146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = new Paint();
936146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(HOURS_FONT_SIZE);
937146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mHoursTextHeight = (int) Math.abs(p.ascent());
938146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        remeasure(width, height);
939146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
940146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
94146b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa    /**
94246b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa     * Measures the space needed for various parts of the view after
94346b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa     * loading new events.  This can change if there are all-day events.
94446b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa     */
945146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void remeasure(int width, int height) {
946146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
947146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // First, clear the array of earliest start times, and the array
948146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // indicating presence of an all-day event.
949146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++) {
950146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mEarliestStartHour[day] = 25;  // some big number
951146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mHasAllDayEvent[day] = false;
952146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
953146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
954d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        // Compute the layout relation between each event before measuring cell
955d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        // width, as the cell width should be adjusted along with the relation.
95646b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        //
95746b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // Examples: A (1:00pm - 1:01pm), B (1:02pm - 2:00pm)
95846b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // We should mark them as "overwapped". Though they are not overwapped logically, but
95946b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // minimum cell height implicitly expands the cell height of A and it should look like
96046b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // (1:00pm - 1:15pm) after the cell height adjustment.
96146b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa
962146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Compute the space needed for the all-day events, if any.
963146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Make a pass over all the events, and keep track of the maximum
964146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // number of all-day events in any one day.  Also, keep track of
965146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // the earliest event in each day.
966146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int maxAllDayEvents = 0;
96746b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        final ArrayList<Event> events = mEvents;
96846b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        final int len = events.size();
969c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa        // Num of all-day-events on each day.
970c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa        final int eventsCount[] = new int[mLastJulianDay - mFirstJulianDay + 1];
971c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa        Arrays.fill(eventsCount, 0);
972146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
973146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(ii);
974c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            if (event.startDay > mLastJulianDay || event.endDay < mFirstJulianDay) {
975146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
976c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            }
977d031419da7900dab91ac9f512374d7e59bb74dceErik            if (event.drawAsAllDay()) {
978c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                final int firstDay = Math.max(event.startDay, mFirstJulianDay);
979c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                final int lastDay = Math.min(event.endDay, mLastJulianDay);
980c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                for (int day = firstDay; day <= lastDay; day++) {
981c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                    final int count = ++eventsCount[day - mFirstJulianDay];
982c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                    if (maxAllDayEvents < count) {
983c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                        maxAllDayEvents = count;
984c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                    }
985146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
986c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa
987146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int daynum = event.startDay - mFirstJulianDay;
988146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int durationDays = event.endDay - event.startDay + 1;
989146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum < 0) {
990146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    durationDays += daynum;
991146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    daynum = 0;
992146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
993146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum + durationDays > mNumDays) {
994146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    durationDays = mNumDays - daynum;
995146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
996146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                for (int day = daynum; durationDays > 0; day++, durationDays--) {
997146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mHasAllDayEvent[day] = true;
998146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
999146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
1000146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int daynum = event.startDay - mFirstJulianDay;
1001146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int hour = event.startTime / 60;
1002146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum >= 0 && hour < mEarliestStartHour[daynum]) {
1003146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mEarliestStartHour[daynum] = hour;
1004146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1005146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1006146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Also check the end hour in case the event spans more than
1007146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // one day.
1008146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                daynum = event.endDay - mFirstJulianDay;
1009146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                hour = event.endTime / 60;
1010146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum < mNumDays && hour < mEarliestStartHour[daynum]) {
1011146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mEarliestStartHour[daynum] = hour;
1012146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1013146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1014146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1015146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mMaxAllDayEvents = maxAllDayEvents;
1016146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
10179c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        // Calculate mAllDayHeight
10183eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mFirstCell = DAY_HEADER_HEIGHT;
1019146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int allDayHeight = 0;
1020146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (maxAllDayEvents > 0) {
1021146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there is at most one all-day event per day, then use less
1022146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // space (but more than the space for a single event).
1023146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (maxAllDayEvents == 1) {
1024146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                allDayHeight = SINGLE_ALLDAY_HEIGHT;
1025146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
1026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Allow the all-day area to grow in height depending on the
1027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // number of all-day events we need to show, up to a limit.
1028f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                allDayHeight = maxAllDayEvents * MAX_HEIGHT_OF_ONE_ALLDAY_EVENT;
1029146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (allDayHeight > MAX_ALLDAY_HEIGHT) {
1030146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    allDayHeight = MAX_ALLDAY_HEIGHT;
1031146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1032146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
10333eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            mFirstCell = DAY_HEADER_HEIGHT + allDayHeight + ALLDAY_TOP_MARGIN;
1034146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
1035146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionAllDay = false;
1036146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1037146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mAllDayHeight = allDayHeight;
1038146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1039146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mGridAreaHeight = height - mFirstCell;
1040d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
1041d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        // The min is where 24 hours cover the entire visible area
104246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        mMinCellHeight = (height - DAY_HEADER_HEIGHT) / 24;
1043d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mCellHeight < mMinCellHeight) {
1044d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeight = mMinCellHeight;
1045d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
1046d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
104746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        mNumHours = mGridAreaHeight / (mCellHeight + HOUR_GAP);
1048146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry.setHourHeight(mCellHeight);
1049146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
105027d671cdba3e8b50219def2c9e1118abe987f908Daisuke Miyakawa        final long minimumDurationMillis = (long)
105127d671cdba3e8b50219def2c9e1118abe987f908Daisuke Miyakawa                (MIN_EVENT_HEIGHT * DateUtils.MINUTE_IN_MILLIS / (mCellHeight / 60.0f));
105246b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        Event.computePositions(events, minimumDurationMillis);
105346b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa
1054c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        // Compute the top of our reachable view
1055c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        mMaxViewStartY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP) - mGridAreaHeight;
1056d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (DEBUG) {
1057d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            Log.e(TAG, "mViewStartY: " + mViewStartY);
1058d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            Log.e(TAG, "mMaxViewStartY: " + mMaxViewStartY);
1059d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
1060d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mViewStartY > mMaxViewStartY) {
1061d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mViewStartY = mMaxViewStartY;
1062d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            computeFirstHour();
1063d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
1064146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1065146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour == -1) {
1066146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            initFirstHour();
1067146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHourOffset = 0;
1068146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1069146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1070146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // When we change the base date, the number of all-day events may
1071146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // change and that changes the cell height.  When we switch dates,
1072146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // we use the mFirstHourOffset from the previous view, but that may
1073146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // be too large for the new view if the cell height is smaller.
1074146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHourOffset >= mCellHeight + HOUR_GAP) {
1075146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHourOffset = mCellHeight + HOUR_GAP - 1;
1076146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1077146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewStartY = mFirstHour * (mCellHeight + HOUR_GAP) - mFirstHourOffset;
1078146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
107946b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        final int eventAreaWidth = mNumDays * (mCellWidth + DAY_GAP);
1080666fc5e8ddbac15c951aad738bd818ee307eae42Erik        //When we get new events we don't want to dismiss the popup unless the event changes
1081666fc5e8ddbac15c951aad738bd818ee307eae42Erik        if (mSelectedEvent != null && mLastPopupEventID != mSelectedEvent.id) {
1082666fc5e8ddbac15c951aad738bd818ee307eae42Erik            mPopup.dismiss();
1083666fc5e8ddbac15c951aad738bd818ee307eae42Erik        }
1084146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setWidth(eventAreaWidth - 20);
1085146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
1086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1087146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1088146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
1089146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Initialize the state for another view.  The given view is one that has
1090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * its own bitmap and will use an animation to replace the current view.
1091146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * The current view and new view are either both Week views or both Day
1092146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * views.  They differ in their base date.
1093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
1094146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param view the view to initialize.
1095146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
1096d190418220467c02327dd9b3ae1eae238889720bMichael Chan    private void initView(DayView view) {
1097146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mSelectionHour = mSelectionHour;
1098146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mSelectedEvents.clear();
1099146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mComputeSelectedEvents = true;
1100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mFirstHour = mFirstHour;
1101146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mFirstHourOffset = mFirstHourOffset;
1102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.remeasure(getWidth(), getHeight());
1103e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
1104146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mSelectedEvent = null;
1105146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mPrevSelectedEvent = null;
1106487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        view.mFirstDayOfWeek = mFirstDayOfWeek;
1107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (view.mEvents.size() > 0) {
1108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionAllDay = mSelectionAllDay;
1109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
1110146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionAllDay = false;
1111146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1112146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1113146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Redraw the screen so that the selection box will be redrawn.  We may
1114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // have scrolled to a different part of the day in some other view
1115146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // so the selection box in this view may no longer be visible.
1116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.recalc();
1117146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1118146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1119146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
1120146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Switch to another view based on what was selected (an event or a free
1121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * slot) and how it was selected (by touch or by trackball).
1122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
1123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param trackBallSelection true if the selection was made using the
1124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * trackball.
1125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
1126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void switchViews(boolean trackBallSelection) {
1127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event selectedEvent = mSelectedEvent;
1128146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.dismiss();
1130666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = INVALID_EVENT_ID;
1131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays > 1) {
1132146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // This is the Week view.
1133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // With touch, we always switch to Day/Agenda View
1134146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // With track ball, if we selected a free slot, then create an event.
1135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we selected a specific event, switch to EventInfo view.
1136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (trackBallSelection) {
1137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (selectedEvent == null) {
1138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Switch to the EditEvent view
1139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long startMillis = getSelectedTimeInMillis();
1140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
11419e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
114287f993ff96172f508d3f241f8a425f953c7eb739RoboErik                            startMillis, endMillis, 0, 0, -1);
1143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
1144146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Switch to the EventInfo view
11459e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
114687f993ff96172f508d3f241f8a425f953c7eb739RoboErik                            selectedEvent.startMillis, selectedEvent.endMillis, 0, 0,
114787f993ff96172f508d3f241f8a425f953c7eb739RoboErik                            getSelectedTimeInMillis());
1148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
1150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // This was a touch selection.  If the touch selected a single
1151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // unambiguous event, then view that event.  Otherwise go to
1152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Day/Agenda view.
1153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectedEvents.size() == 1) {
11549e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
115587f993ff96172f508d3f241f8a425f953c7eb739RoboErik                            selectedEvent.startMillis, selectedEvent.endMillis, 0, 0,
115687f993ff96172f508d3f241f8a425f953c7eb739RoboErik                            getSelectedTimeInMillis());
1157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1158146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
1160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // This is the Day view.
1161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we selected a free slot, then create an event.
1162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we selected an event, then go to the EventInfo view.
1163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (selectedEvent == null) {
1164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Switch to the EditEvent view
1165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                long startMillis = getSelectedTimeInMillis();
1166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
11679e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan
11689e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1, startMillis,
116987f993ff96172f508d3f241f8a425f953c7eb739RoboErik                        endMillis, 0, 0, -1);
1170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
11719e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
117287f993ff96172f508d3f241f8a425f953c7eb739RoboErik                        selectedEvent.startMillis, selectedEvent.endMillis, 0, 0,
117387f993ff96172f508d3f241f8a425f953c7eb739RoboErik                        getSelectedTimeInMillis());
1174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
1179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
1180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mScrolling = false;
1181146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long duration = event.getEventTime() - event.getDownTime();
1182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        switch (keyCode) {
1184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            case KeyEvent.KEYCODE_DPAD_CENTER:
1185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectionMode == SELECTION_HIDDEN) {
1186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Don't do anything unless the selection is visible.
1187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
1188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectionMode == SELECTION_PRESSED) {
1191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This was the first press when there was nothing selected.
1192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Change the selection from the "pressed" state to the
1193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // the "selected" state.  We treat short-press and
1194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // long-press the same here because nothing was selected.
1195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionMode = SELECTION_SELECTED;
1196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    invalidate();
1197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
1198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Check the duration to determine if this was a short press
1201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (duration < ViewConfiguration.getLongPressTimeout()) {
1202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    switchViews(true /* trackball */);
1203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
1204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionMode = SELECTION_LONGPRESS;
1205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    invalidate();
1206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    performLongClick();
1207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                break;
1209ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//            case KeyEvent.KEYCODE_BACK:
1210ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                if (event.isTracking() && !event.isCanceled()) {
1211ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                    mPopup.dismiss();
1212ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                    mContext.finish();
1213ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                    return true;
1214ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                }
1215ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                break;
1216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return super.onKeyUp(keyCode, event);
1218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
1221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
1222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionMode == SELECTION_HIDDEN) {
1223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
1224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_UP
1225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
1226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Display the selection box but don't move or select it
1227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // on this key press.
1228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionMode = SELECTION_SELECTED;
1229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
1230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
1231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
1232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Display the selection box but don't select it
1233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // on this key press.
1234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionMode = SELECTION_PRESSED;
1235146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
1236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
1237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_SELECTED;
1241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mScrolling = false;
1242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        boolean redraw;
1243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int selectionDay = mSelectionDay;
1244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1245146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        switch (keyCode) {
124646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case KeyEvent.KEYCODE_DEL:
124746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                // Delete the selected event, if any
124846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                Event selectedEvent = mSelectedEvent;
124946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (selectedEvent == null) {
125046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    return false;
125146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
125246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                mPopup.dismiss();
125346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                mLastPopupEventID = INVALID_EVENT_ID;
1254146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
125546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                long begin = selectedEvent.startMillis;
125646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                long end = selectedEvent.endMillis;
125746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                long id = selectedEvent.id;
125846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                mDeleteEventHelper.delete(begin, end, id, -1);
1259b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan                return true;
126046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case KeyEvent.KEYCODE_ENTER:
126146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                switchViews(true /* trackball or keyboard */);
126246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                return true;
126346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case KeyEvent.KEYCODE_BACK:
126446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (event.getRepeatCount() == 0) {
126546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    event.startTracking();
126646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    return true;
126746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
126846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                return super.onKeyDown(keyCode, event);
126946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case KeyEvent.KEYCODE_DPAD_LEFT:
127046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mSelectedEvent != null) {
127146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mSelectedEvent = mSelectedEvent.nextLeft;
127246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
127346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mSelectedEvent == null) {
127446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mLastPopupEventID = INVALID_EVENT_ID;
127546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    selectionDay -= 1;
127646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
127746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                redraw = true;
127846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                break;
1279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
128046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case KeyEvent.KEYCODE_DPAD_RIGHT:
128146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mSelectedEvent != null) {
128246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mSelectedEvent = mSelectedEvent.nextRight;
128346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
128446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mSelectedEvent == null) {
128546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mLastPopupEventID = INVALID_EVENT_ID;
128646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    selectionDay += 1;
128746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
128846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                redraw = true;
128946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                break;
1290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
129146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case KeyEvent.KEYCODE_DPAD_UP:
129246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mSelectedEvent != null) {
129346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mSelectedEvent = mSelectedEvent.nextUp;
1294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
129546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mSelectedEvent == null) {
129646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mLastPopupEventID = INVALID_EVENT_ID;
129746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    if (!mSelectionAllDay) {
129846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        mSelectionHour -= 1;
129946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        adjustHourSelection();
130046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        mSelectedEvents.clear();
130146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        mComputeSelectedEvents = true;
130246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    }
130346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
130446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                redraw = true;
130546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                break;
1306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
130746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case KeyEvent.KEYCODE_DPAD_DOWN:
130846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mSelectedEvent != null) {
130946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mSelectedEvent = mSelectedEvent.nextDown;
1310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
131146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mSelectedEvent == null) {
131246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mLastPopupEventID = INVALID_EVENT_ID;
131346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    if (mSelectionAllDay) {
131446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        mSelectionAllDay = false;
131546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    } else {
131646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        mSelectionHour++;
131746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        adjustHourSelection();
131846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        mSelectedEvents.clear();
131946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        mComputeSelectedEvents = true;
132046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    }
132146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
132246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                redraw = true;
132346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                break;
1324146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
132546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            default:
132646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                return super.onKeyDown(keyCode, event);
1327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1328146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1329146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((selectionDay < mFirstJulianDay) || (selectionDay > mLastJulianDay)) {
1330d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView view = (DayView) mViewSwitcher.getNextView();
1331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Time date = view.mBaseDate;
1332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.set(mBaseDate);
1333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (selectionDay < mFirstJulianDay) {
1334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                date.monthDay -= mNumDays;
1335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
1336146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                date.monthDay += mNumDays;
1337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.normalize(true /* ignore isDst */);
1339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionDay = selectionDay;
1340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            initView(view);
134283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
134383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Time end = new Time(date);
134483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            end.monthDay += mNumDays - 1;
134583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Log.d(TAG, "onKeyDown");
13463458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            mController.sendEvent(this, EventType.GO_TO, date, end, -1, ViewType.CURRENT);
1347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
1348146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
134904b288958078f8b29870dcbb2239df448c559610Erik        if (mSelectionDay != selectionDay) {
135004b288958078f8b29870dcbb2239df448c559610Erik            Time date = new Time(mBaseDate);
135104b288958078f8b29870dcbb2239df448c559610Erik            date.setJulianDay(selectionDay);
135204b288958078f8b29870dcbb2239df448c559610Erik            date.hour = mSelectionHour;
135304b288958078f8b29870dcbb2239df448c559610Erik            mController.sendEvent(this, EventType.GO_TO, date, date, -1, ViewType.CURRENT);
135404b288958078f8b29870dcbb2239df448c559610Erik        }
1355146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionDay = selectionDay;
1356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
1357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mComputeSelectedEvents = true;
13588307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik        mUpdateToast = true;
1359146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (redraw) {
1361146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            invalidate();
1362146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
1363146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return super.onKeyDown(keyCode, event);
1366146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1368259b8f9a21fffd3858218581e9daaf689b6b888fErik    private class AccessibilityRunnable implements Runnable {
1369259b8f9a21fffd3858218581e9daaf689b6b888fErik        int mEventType = AccessibilityEvent.TYPE_VIEW_SELECTED;
1370259b8f9a21fffd3858218581e9daaf689b6b888fErik        @Override
1371259b8f9a21fffd3858218581e9daaf689b6b888fErik        public void run() {
1372259b8f9a21fffd3858218581e9daaf689b6b888fErik            sendAccessibilityEvent(mEventType);
1373259b8f9a21fffd3858218581e9daaf689b6b888fErik        }
1374259b8f9a21fffd3858218581e9daaf689b6b888fErik    }
1375259b8f9a21fffd3858218581e9daaf689b6b888fErik
1376259b8f9a21fffd3858218581e9daaf689b6b888fErik    private AccessibilityRunnable mDispatchAccessibilityEventRunnable = new AccessibilityRunnable();
1377259b8f9a21fffd3858218581e9daaf689b6b888fErik
1378259b8f9a21fffd3858218581e9daaf689b6b888fErik    @Override
1379259b8f9a21fffd3858218581e9daaf689b6b888fErik    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1380259b8f9a21fffd3858218581e9daaf689b6b888fErik        if (event.getEventType() != AccessibilityEvent.TYPE_VIEW_SELECTED &&
1381259b8f9a21fffd3858218581e9daaf689b6b888fErik                event.getEventType() != AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
1382259b8f9a21fffd3858218581e9daaf689b6b888fErik            return false;
1383259b8f9a21fffd3858218581e9daaf689b6b888fErik        }
1384259b8f9a21fffd3858218581e9daaf689b6b888fErik        StringBuilder b = new StringBuilder(getSelectedTime()
1385259b8f9a21fffd3858218581e9daaf689b6b888fErik                .format(mIs24HourFormat ? HOUR_FORMAT_24H : HOUR_FORMAT_12H));
1386259b8f9a21fffd3858218581e9daaf689b6b888fErik        b.append(PERIOD_SPACE);
1387259b8f9a21fffd3858218581e9daaf689b6b888fErik        int numEvents = mSelectedEvents.size();
1388259b8f9a21fffd3858218581e9daaf689b6b888fErik        if (mEventCountTemplate == null) {
1389259b8f9a21fffd3858218581e9daaf689b6b888fErik            mEventCountTemplate = mContext.getString(R.string.template_announce_item_index);
1390259b8f9a21fffd3858218581e9daaf689b6b888fErik        }
1391259b8f9a21fffd3858218581e9daaf689b6b888fErik        switch (event.getEventType()) {
1392259b8f9a21fffd3858218581e9daaf689b6b888fErik            // When a new hour is selected we sent this event
1393259b8f9a21fffd3858218581e9daaf689b6b888fErik            case AccessibilityEvent.TYPE_VIEW_SELECTED:
1394259b8f9a21fffd3858218581e9daaf689b6b888fErik                int i = 1;
1395259b8f9a21fffd3858218581e9daaf689b6b888fErik                for (Event calEvent : mSelectedEvents) {
1396259b8f9a21fffd3858218581e9daaf689b6b888fErik                    if (numEvents > 1) {
1397259b8f9a21fffd3858218581e9daaf689b6b888fErik                        mStringBuilder.setLength(0);
1398259b8f9a21fffd3858218581e9daaf689b6b888fErik                        b.append(mFormatter.format(mEventCountTemplate, i++, numEvents));
1399259b8f9a21fffd3858218581e9daaf689b6b888fErik                        b.append(" ");
1400259b8f9a21fffd3858218581e9daaf689b6b888fErik                    }
1401259b8f9a21fffd3858218581e9daaf689b6b888fErik                    appendEventAccessibilityString(b, calEvent);
1402259b8f9a21fffd3858218581e9daaf689b6b888fErik                }
1403259b8f9a21fffd3858218581e9daaf689b6b888fErik                break;
1404259b8f9a21fffd3858218581e9daaf689b6b888fErik            // When a different event is selected we send this event
1405259b8f9a21fffd3858218581e9daaf689b6b888fErik            case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
1406259b8f9a21fffd3858218581e9daaf689b6b888fErik                if (mSelectedEvent != null) {
1407259b8f9a21fffd3858218581e9daaf689b6b888fErik                    if (numEvents > 1) {
1408259b8f9a21fffd3858218581e9daaf689b6b888fErik                        mStringBuilder.setLength(0);
1409259b8f9a21fffd3858218581e9daaf689b6b888fErik                        b.append(mFormatter.format(mEventCountTemplate,
1410259b8f9a21fffd3858218581e9daaf689b6b888fErik                                mSelectedEvents.indexOf(mSelectedEvent) + 1, numEvents));
1411259b8f9a21fffd3858218581e9daaf689b6b888fErik                        b.append(" ");
1412259b8f9a21fffd3858218581e9daaf689b6b888fErik                    }
1413259b8f9a21fffd3858218581e9daaf689b6b888fErik                    appendEventAccessibilityString(b, mSelectedEvent);
1414259b8f9a21fffd3858218581e9daaf689b6b888fErik                }
1415259b8f9a21fffd3858218581e9daaf689b6b888fErik                break;
1416259b8f9a21fffd3858218581e9daaf689b6b888fErik            default:
1417259b8f9a21fffd3858218581e9daaf689b6b888fErik                break;
1418259b8f9a21fffd3858218581e9daaf689b6b888fErik        }
1419259b8f9a21fffd3858218581e9daaf689b6b888fErik        CharSequence msg = b.toString();
1420259b8f9a21fffd3858218581e9daaf689b6b888fErik        event.getText().add(msg);
1421259b8f9a21fffd3858218581e9daaf689b6b888fErik        event.setAddedCount(msg.length());
1422259b8f9a21fffd3858218581e9daaf689b6b888fErik        return true;
1423259b8f9a21fffd3858218581e9daaf689b6b888fErik    }
1424259b8f9a21fffd3858218581e9daaf689b6b888fErik
1425259b8f9a21fffd3858218581e9daaf689b6b888fErik    /**
1426259b8f9a21fffd3858218581e9daaf689b6b888fErik     * @param b
1427259b8f9a21fffd3858218581e9daaf689b6b888fErik     * @param calEvent
1428259b8f9a21fffd3858218581e9daaf689b6b888fErik     */
1429259b8f9a21fffd3858218581e9daaf689b6b888fErik    private void appendEventAccessibilityString(StringBuilder b, Event calEvent) {
1430259b8f9a21fffd3858218581e9daaf689b6b888fErik        b.append(calEvent.getTitleAndLocation());
1431259b8f9a21fffd3858218581e9daaf689b6b888fErik        b.append(PERIOD_SPACE);
1432259b8f9a21fffd3858218581e9daaf689b6b888fErik        String when;
1433259b8f9a21fffd3858218581e9daaf689b6b888fErik        int flags = DateUtils.FORMAT_SHOW_DATE;
1434259b8f9a21fffd3858218581e9daaf689b6b888fErik        if (calEvent.allDay) {
1435259b8f9a21fffd3858218581e9daaf689b6b888fErik            flags |= DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_WEEKDAY;
1436259b8f9a21fffd3858218581e9daaf689b6b888fErik        } else {
1437259b8f9a21fffd3858218581e9daaf689b6b888fErik            flags |= DateUtils.FORMAT_SHOW_TIME;
1438259b8f9a21fffd3858218581e9daaf689b6b888fErik            if (DateFormat.is24HourFormat(mContext)) {
1439259b8f9a21fffd3858218581e9daaf689b6b888fErik                flags |= DateUtils.FORMAT_24HOUR;
1440259b8f9a21fffd3858218581e9daaf689b6b888fErik            }
1441259b8f9a21fffd3858218581e9daaf689b6b888fErik        }
1442259b8f9a21fffd3858218581e9daaf689b6b888fErik        when = Utils.formatDateRange(mContext, calEvent.startMillis, calEvent.endMillis, flags);
1443259b8f9a21fffd3858218581e9daaf689b6b888fErik        b.append(when);
1444259b8f9a21fffd3858218581e9daaf689b6b888fErik        b.append(PERIOD_SPACE);
1445259b8f9a21fffd3858218581e9daaf689b6b888fErik    }
1446259b8f9a21fffd3858218581e9daaf689b6b888fErik
14476d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan    private class GotoBroadcaster implements Animation.AnimationListener {
14486d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        private final int mCounter;
14496d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        private final Time mStart;
14506d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        private final Time mEnd;
14516d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
14526d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        public GotoBroadcaster(Time start, Time end) {
14536d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            mCounter = ++sCounter;
14546d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            mStart = start;
14556d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            mEnd = end;
14566d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
14576d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
14586d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        @Override
14596d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        public void onAnimationEnd(Animation animation) {
14606d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            if (mCounter == sCounter) {
1461f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                mController.sendEvent(this, EventType.GO_TO, mStart, mEnd, null, -1,
1462f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                        ViewType.CURRENT, CalendarController.EXTRA_GOTO_DATE, null, null);
14636d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            }
14646d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
14656d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
14666d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        @Override
14676d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        public void onAnimationRepeat(Animation animation) {
14686d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
14696d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
14706d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        @Override
14716d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        public void onAnimationStart(Animation animation) {
14726d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
14736d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan    }
14746d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
1475ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private View switchViews(boolean forward, float xOffSet, float width) {
1476030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown        if (DEBUG) Log.d(TAG, "switchViews(" + forward + ")...");
1477ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        float progress = Math.abs(xOffSet) / width;
1478ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        if (progress > 1.0f) {
1479ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            progress = 1.0f;
1480ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
1481ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1482ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        float inFromXValue, inToXValue;
1483ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        float outFromXValue, outToXValue;
1484ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        if (forward) {
1485ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inFromXValue = 1.0f - progress;
1486ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inToXValue = 0.0f;
1487ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outFromXValue = -progress;
1488ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outToXValue = -1.0f;
1489ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        } else {
1490ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inFromXValue = progress - 1.0f;
1491ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inToXValue = 0.0f;
1492ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outFromXValue = progress;
1493ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outToXValue = 1.0f;
1494ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
1495ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
14966d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        final Time start = new Time(mBaseDate.timezone);
14976d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        start.set(mController.getTime());
14986d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        if (forward) {
14996d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            start.monthDay += mNumDays;
15006d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        } else {
15016d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            start.monthDay -= mNumDays;
15026d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
1503f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        mController.setTime(start.normalize(true));
1504f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan
1505f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        Time newSelected = start;
15066d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
15076d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        if (mNumDays == 7) {
1508f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            newSelected = new Time(start);
15096d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            adjustToBeginningOfWeek(start);
15106d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
15116d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
15126d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        final Time end = new Time(start);
15136d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        end.monthDay += mNumDays - 1;
15146d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
1515ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        // We have to allocate these animation objects each time we switch views
1516ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        // because that is the only way to set the animation parameters.
1517ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        TranslateAnimation inAnimation = new TranslateAnimation(
1518ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, inFromXValue,
1519ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, inToXValue,
1520ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f,
1521ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f);
1522ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1523ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        TranslateAnimation outAnimation = new TranslateAnimation(
1524ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, outFromXValue,
1525ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, outToXValue,
1526ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f,
1527ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f);
1528ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1529ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        // Reduce the animation duration based on how far we have already swiped.
1530ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        long duration = (long) (ANIMATION_DURATION * (1.0f - progress));
1531ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        inAnimation.setDuration(duration);
1532ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        outAnimation.setDuration(duration);
15336d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        outAnimation.setAnimationListener(new GotoBroadcaster(start, end));
1534ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher.setInAnimation(inAnimation);
1535ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher.setOutAnimation(outAnimation);
1536ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1537d190418220467c02327dd9b3ae1eae238889720bMichael Chan        DayView view = (DayView) mViewSwitcher.getCurrentView();
1538ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        view.cleanup();
1539ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher.showNext();
1540d190418220467c02327dd9b3ae1eae238889720bMichael Chan        view = (DayView) mViewSwitcher.getCurrentView();
1541f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        view.setSelected(newSelected, true);
1542ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        view.requestFocus();
1543ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        view.reloadEvents();
1544eaafa2b48be7194a61754604ae37b3d62e9118d8Erik        view.updateTitle();
1545e98dd73c67205b01f5348271d9a7a630003ecf52David Brown
1546ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        return view;
1547ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    }
1548ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1549146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // This is called after scrolling stops to move the selected hour
1550146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // to the visible part of the screen.
1551146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void resetSelectedHour() {
1552146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour < mFirstHour + 1) {
1553146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = mFirstHour + 1;
1554146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = null;
1555146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvents.clear();
1556146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mComputeSelectedEvents = true;
1557146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (mSelectionHour > mFirstHour + mNumHours - 3) {
1558146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = mFirstHour + mNumHours - 3;
1559146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = null;
1560146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvents.clear();
1561146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mComputeSelectedEvents = true;
1562146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1563146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1564146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1565146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void initFirstHour() {
1566d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mFirstHour = mSelectionHour - mNumHours / 5;
1567146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour < 0) {
1568146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHour = 0;
1569146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (mFirstHour + mNumHours > 24) {
1570146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHour = 24 - mNumHours;
1571146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1572146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1573146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1574146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
1575146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Recomputes the first full hour that is visible on screen after the
1576146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * screen is scrolled.
1577146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
1578146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void computeFirstHour() {
1579146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Compute the first full hour that is visible on screen
1580146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstHour = (mViewStartY + mCellHeight + HOUR_GAP - 1) / (mCellHeight + HOUR_GAP);
1581146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstHourOffset = mFirstHour * (mCellHeight + HOUR_GAP) - mViewStartY;
1582146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1583146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1584146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void adjustHourSelection() {
1585146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour < 0) {
1586146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = 0;
1587146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mMaxAllDayEvents > 0) {
1588146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = null;
1589146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionAllDay = true;
1590146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1591146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1592146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1593146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour > 23) {
1594146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = 23;
1595146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1596146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1597146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If the selected hour is at least 2 time slots from the top and
1598146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // bottom of the screen, then don't scroll the view.
1599146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour < mFirstHour + 1) {
1600146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there are all-days events for the selected day but there
1601146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // are no more normal events earlier in the day, then jump to
1602146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // the all-day event area.
1603146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Exception 1: allow the user to scroll to 8am with the trackball
1604146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // before jumping to the all-day event area.
1605146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Exception 2: if 12am is on screen, then allow the user to select
1606146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // 12am before going up to the all-day event area.
1607146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int daynum = mSelectionDay - mFirstJulianDay;
1608146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mMaxAllDayEvents > 0 && mEarliestStartHour[daynum] > mSelectionHour
1609146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    && mFirstHour > 0 && mFirstHour < 8) {
1610146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = null;
1611146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionAllDay = true;
1612146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionHour = mFirstHour + 1;
1613146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return;
1614146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1615146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1616146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mFirstHour > 0) {
1617146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mFirstHour -= 1;
1618146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY -= (mCellHeight + HOUR_GAP);
1619146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mViewStartY < 0) {
1620146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mViewStartY = 0;
1621146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1622146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return;
1623146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1624146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1625146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1626146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour > mFirstHour + mNumHours - 3) {
1627146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mFirstHour < 24 - mNumHours) {
1628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mFirstHour += 1;
1629146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY += (mCellHeight + HOUR_GAP);
1630c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik                if (mViewStartY > mMaxViewStartY) {
1631c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik                    mViewStartY = mMaxViewStartY;
1632146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1633146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return;
1634146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mFirstHour == 24 - mNumHours && mFirstHourOffset > 0) {
1635c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik                mViewStartY = mMaxViewStartY;
1636146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1637146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1638146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1639146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1640146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    void clearCachedEvents() {
1641146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mLastReloadMillis = 0;
1642146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1643146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1644146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Runnable mCancelCallback = new Runnable() {
1645146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void run() {
1646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            clearCachedEvents();
1647146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1648146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
1649146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
165046b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa    /* package */ void reloadEvents() {
1651146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Protect against this being called before this view has been
1652146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // initialized.
1653ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//        if (mContext == null) {
1654ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//            return;
1655ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//        }
1656146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1657731f1cb808b7586b93615b408ab2636081fab0dcErik        // Make sure our time zones are up to date
1658731f1cb808b7586b93615b408ab2636081fab0dcErik        mTZUpdater.run();
1659731f1cb808b7586b93615b408ab2636081fab0dcErik
1660146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = null;
1661146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevSelectedEvent = null;
1662146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
1663146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1664146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // The start date is the beginning of the week at 12am
1665731f1cb808b7586b93615b408ab2636081fab0dcErik        Time weekStart = new Time(Utils.getTimeZone(mContext, mTZUpdater));
1666146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.set(mBaseDate);
1667146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.hour = 0;
1668146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.minute = 0;
1669146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.second = 0;
1670146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = weekStart.normalize(true /* ignore isDst */);
1671146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1672146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Avoid reloading events unnecessarily.
1673146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (millis == mLastReloadMillis) {
1674146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
1675146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1676146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mLastReloadMillis = millis;
1677146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1678146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // load events in the background
1679ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//        mContext.startProgressSpinner();
1680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        final ArrayList<Event> events = new ArrayList<Event>();
1681146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventLoader.loadEventsInBackground(mNumDays, events, millis, new Runnable() {
1682146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            public void run() {
1683146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mEvents = events;
168408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                if (mAllDayEvents == null) {
168508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                    mAllDayEvents = new ArrayList<Event>();
168608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                } else {
168708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                    mAllDayEvents.clear();
168808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                }
168908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan
169008ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                // Create a shorter array for all day events
169146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                for (Event e : events) {
1692d031419da7900dab91ac9f512374d7e59bb74dceErik                    if (e.drawAsAllDay()) {
169308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                        mAllDayEvents.add(e);
169408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                    }
169508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                }
169608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan
169708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                // New events, new layouts
169808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                if (mLayouts == null || mLayouts.length < events.size()) {
169908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                    mLayouts = new StaticLayout[events.size()];
170008ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                } else {
170108ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                    Arrays.fill(mLayouts, null);
17023e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                }
170308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan
170408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                if (mAllDayLayouts == null || mAllDayLayouts.length < mAllDayEvents.size()) {
170508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                    mAllDayLayouts = new StaticLayout[events.size()];
170608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                } else {
170708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                    Arrays.fill(mAllDayLayouts, null);
170808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                }
170908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan
1710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mRemeasure = true;
1711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mComputeSelectedEvents = true;
1712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                recalc();
1713ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                mContext.stopProgressSpinner();
1714146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
1715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1716146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }, mCancelCallback);
1717146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
1720146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected void onDraw(Canvas canvas) {
1721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mRemeasure) {
1722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            remeasure(getWidth(), getHeight());
1723146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mRemeasure = false;
1724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1725c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.save();
1726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1727c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        float yTranslate = -mViewStartY + DAY_HEADER_HEIGHT + mAllDayHeight;
1728c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        // offset canvas by the current drag and header position
1729c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.translate(-mViewStartX, yTranslate);
1730c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        // clip to everything below the allDay area
1731c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        Rect dest = mDestRect;
1732c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        dest.top = (int) (mFirstCell - yTranslate);
1733c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        dest.bottom = (int) (mViewHeight - yTranslate);
1734c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        dest.left = 0;
1735c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        dest.right = mViewWidth;
1736c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.save();
1737c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.clipRect(dest);
1738c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        // Draw the movable part of the view
1739c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        doDraw(canvas);
1740c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        // restore to having no clip
1741c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.restore();
1742146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1743146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
1744c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            float xTranslate;
1745146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mViewStartX > 0) {
1746c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik                xTranslate = mViewWidth;
1747146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
1748c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik                xTranslate = -mViewWidth;
1749146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1750c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // Move the canvas around to prep it for the next view
1751c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // specifically, shift it by a screen and undo the
1752c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // yTranslation which will be redone in the nextView's onDraw().
1753c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            canvas.translate(xTranslate, -yTranslate);
1754d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView nextView = (DayView) mViewSwitcher.getNextView();
1755146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Prevent infinite recursive calls to onDraw().
1757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            nextView.mTouchMode = TOUCH_MODE_INITIAL_STATE;
1758146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1759146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            nextView.onDraw(canvas);
1760c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // Move it back for this view
1761c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            canvas.translate(-xTranslate, 0);
1762c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        } else {
1763c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // If we drew another view we already translated it back
1764c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // If we didn't draw another view we should be at the edge of the
1765c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // screen
1766c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            canvas.translate(mViewStartX, -yTranslate);
1767146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1768146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1769146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the fixed areas (that don't scroll) directly to the canvas.
1770146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        drawAfterScroll(canvas);
17718307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik        if (mComputeSelectedEvents && mUpdateToast) {
17728307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik            updateEventDetails();
17738307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik            mUpdateToast = false;
17748307109ac75b748ae707f4d4cb9a9d28c2dbaae6Erik        }
1775146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mComputeSelectedEvents = false;
1776146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.restore();
1777146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawAfterScroll(Canvas canvas) {
1780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = mPaint;
1781146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect r = mRect;
1782146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1783146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mMaxAllDayEvents != 0) {
17841ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            drawAllDayEvents(mFirstJulianDay, mNumDays, canvas, p);
17858f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan            drawUpperLeftCorner(r, canvas, p);
1786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1787146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1788c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        drawScrollLine(r, canvas, p);
1789c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik
17903eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        drawDayHeaderLoop(r, canvas, p);
1791146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1792146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the AM and PM indicators if we're in 12 hour mode
1793146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!mIs24HourFormat) {
1794146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawAmPm(canvas, p);
1795146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1796146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1797146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
179846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    // This isn't really the upper-left corner. It's the square area just
1799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // below the upper-left corner, above the hours and to the left of the
1800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // all-day area.
18018f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private void drawUpperLeftCorner(Rect r, Canvas canvas, Paint p) {
18028f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        setupHourTextPaint(p);
18038f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        canvas.drawText(mAllDayString, HOURS_LEFT_MARGIN, DAY_HEADER_HEIGHT + HOURS_TOP_MARGIN
18048f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan                + HOUR_GAP + mHoursTextHeight, p);
18058f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    }
1806146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1807c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik    private void drawScrollLine(Rect r, Canvas canvas, Paint p) {
18088f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        final int right = mHoursWidth + (mCellWidth + DAY_GAP) * mNumDays;
18098f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        final int y = mFirstCell - 1;
18108f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan
1811c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        p.setAntiAlias(false);
18128f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        p.setStyle(Style.FILL);
18138f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan
18148f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        p.setColor(mCalendarGridLineHorizontalColor);
18158f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        p.setStrokeWidth(GRID_LINE_WIDTH);
18168f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        canvas.drawLine(GRID_LINE_LEFT_MARGIN, y, right, y, p);
18171ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
18188f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        p.setColor(mCalendarGridLineInnerHorizontalColor);
18198f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        p.setStrokeWidth(GRID_LINE_INNER_WIDTH);
18208f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        canvas.drawLine(GRID_LINE_LEFT_MARGIN, y, right, y, p);
1821c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        p.setAntiAlias(true);
1822c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik    }
1823c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik
1824146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawDayHeaderLoop(Rect r, Canvas canvas, Paint p) {
1825146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the horizontal day background banner
18263eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarDateBannerBackground);
18273eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.top = 0;
18283eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.bottom = DAY_HEADER_HEIGHT;
18293eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.left = 0;
18303eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.right = mHoursWidth + mNumDays * (mCellWidth + DAY_GAP);
18313eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
18323eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        //
1833146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Fill the extra space on the right side with the default background
18343eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.left = r.right;
18353eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.right = mViewWidth;
18363eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarGridAreaBackground);
18373eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
1838146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
18393eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        int todayNum = mTodayJulianDay - mFirstJulianDay;
18403eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        if (mNumDays > 1) {
18413eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            r.top = 0;
18423eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            r.bottom = DAY_HEADER_HEIGHT;
18433eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
18443eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Highlight today
18453eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            if (mFirstJulianDay <= mTodayJulianDay
18463eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                    && mTodayJulianDay < (mFirstJulianDay + mNumDays)) {
18478f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan                r.left = mHoursWidth + todayNum * (mCellWidth + DAY_GAP) - DAY_GAP;
18483eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                r.right = r.left + mCellWidth;
18493eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                mTodayHeaderDrawable.setBounds(r);
18503eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                mTodayHeaderDrawable.draw(canvas);
18513eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            }
18523eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
18533eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Draw a highlight on the selected day (if any), but only if we are
18543eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // displaying more than one day.
185511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            //
185611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // int selectedDayNum = mSelectionDay - mFirstJulianDay;
185711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // if (mSelectionMode != SELECTION_HIDDEN && selectedDayNum >= 0
185811ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // && selectedDayNum < mNumDays) {
185911ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // p.setColor(mCalendarDateSelected);
186011ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // r.left = mHoursWidth + selectedDayNum * (mCellWidth + DAY_GAP);
186111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // r.right = r.left + mCellWidth;
186211ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // canvas.drawRect(r, p);
186311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // }
1864146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1865146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
18663eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setTypeface(mBold);
18673eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setTextAlign(Paint.Align.RIGHT);
1868146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaX = mCellWidth + DAY_GAP;
1869146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cell = mFirstJulianDay;
18709dd340d393575ba9740ef259e62ee7a17fc76ed1Michael Chan        float x = mHoursWidth;
18719dd340d393575ba9740ef259e62ee7a17fc76ed1Michael Chan        if (mNumDays == 1) {
18729dd340d393575ba9740ef259e62ee7a17fc76ed1Michael Chan            x = HOURS_LEFT_MARGIN;
18739dd340d393575ba9740ef259e62ee7a17fc76ed1Michael Chan        }
1874146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1875146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String[] dayNames;
1876146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mDateStrWidth < mCellWidth) {
1877146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            dayNames = mDayStrs;
1878146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
1879146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            dayNames = mDayStrs2Letter;
1880146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1881146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1882d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setAntiAlias(true);
1883146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++, cell++) {
18841f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan            int dayOfWeek = day + mFirstVisibleDayOfWeek;
18851f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan            if (dayOfWeek >= 14) {
18861f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan                dayOfWeek -= 14;
1887487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            }
1888487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
18893eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            int color = mCalendarDateBannerTextColor;
1890071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa            if (mNumDays == 1) {
1891071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                if (dayOfWeek == Time.SATURDAY) {
1892071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                    color = mWeek_saturdayColor;
1893071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                } else if (dayOfWeek == Time.SUNDAY) {
1894071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                    color = mWeek_sundayColor;
1895071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                }
1896071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa            } else {
1897071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                final int column = day % 7;
1898071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                if (Utils.isSaturday(column, mFirstDayOfWeek)) {
1899071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                    color = mWeek_saturdayColor;
1900071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                } else if (Utils.isSunday(column, mFirstDayOfWeek)) {
1901071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                    color = mWeek_sundayColor;
1902071d56d859b0c9f9c7f002e2bee98bc1bd0fc95fDaisuke Miyakawa                }
19033eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            }
19043eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
19053eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            color &= 0x00FFFFFF;
19063eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            if (todayNum == day) {
1907f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan                color |= DATE_HEADER_TODAY_ALPHA;
1908487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            } else {
1909f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan                color |= DATE_HEADER_ALPHA;
1910487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            }
1911487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
19123eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            p.setColor(color);
1913487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            drawDayHeader(dayNames[dayOfWeek], day, cell, x, canvas, p);
1914146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            x += deltaX;
1915146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
19163eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setTypeface(null);
1917146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1918146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1919146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawAmPm(Canvas canvas, Paint p) {
1920d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarAmPmLabel);
1921146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(AMPM_FONT_SIZE);
1922146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(mBold);
1923146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
19248f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        mPaint.setTextAlign(Paint.Align.LEFT);
1925146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String text = mAmString;
1926146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour >= 12) {
1927146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            text = mPmString;
1928146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1929146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int y = mFirstCell + mFirstHourOffset + 2 * mHoursTextHeight + HOUR_GAP;
19308f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        canvas.drawText(text, HOURS_LEFT_MARGIN, y, p);
1931146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1932146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour < 12 && mFirstHour + mNumHours > 12) {
1933146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Also draw the "PM"
1934146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            text = mPmString;
1935146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            y = mFirstCell + mFirstHourOffset + (12 - mFirstHour) * (mCellHeight + HOUR_GAP)
1936146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    + 2 * mHoursTextHeight + HOUR_GAP;
19378f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan            canvas.drawText(text, HOURS_LEFT_MARGIN, y, p);
1938146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1939146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1940146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1941f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan    private void drawCurrentTimeLine(Rect r, final int left, final int top, Canvas canvas,
1942f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan            Paint p) {
19433eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        r.left = left - CURRENT_TIME_LINE_SIDE_BUFFER;
19441ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.right = left + mCellWidth + DAY_GAP + CURRENT_TIME_LINE_SIDE_BUFFER;
19453eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
19463eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        r.top = top - mCurrentTimeLine.getIntrinsicHeight() / 2;
19473eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        r.bottom = r.top + mCurrentTimeLine.getIntrinsicHeight();
1948bd0e834aea317236d574f8738fe11a51fdc87968Erik
19493eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mCurrentTimeLine.setBounds(r);
19503eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mCurrentTimeLine.draw(canvas);
1951bd0e834aea317236d574f8738fe11a51fdc87968Erik    }
1952bd0e834aea317236d574f8738fe11a51fdc87968Erik
1953146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void doDraw(Canvas canvas) {
1954146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = mPaint;
1955146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect r = mRect;
1956146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1957146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        drawGridBackground(r, canvas, p);
1958146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        drawHours(r, canvas, p);
1959146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1960146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw each day
1961146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int x = mHoursWidth;
1962146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaX = mCellWidth + DAY_GAP;
1963146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cell = mFirstJulianDay;
1964146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++, cell++) {
196508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            // TODO Wow, this needs cleanup. drawEvents loop through all the
196608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            // events on every call.
1967146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawEvents(cell, x, HOUR_GAP, canvas, p);
196846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            // If this is today
196946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            if (cell == mTodayJulianDay) {
19701ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan                int lineY = mCurrentTime.hour * (mCellHeight + HOUR_GAP)
19711ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan                        + ((mCurrentTime.minute * mCellHeight) / 60) + 1;
19721ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
197346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                // And the current time shows up somewhere on the screen
197446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (lineY >= mViewStartY && lineY < mViewStartY + mViewHeight - 2) {
1975bd0e834aea317236d574f8738fe11a51fdc87968Erik                    drawCurrentTimeLine(r, x, lineY, canvas, p);
1976bd0e834aea317236d574f8738fe11a51fdc87968Erik                }
1977bd0e834aea317236d574f8738fe11a51fdc87968Erik            }
1978146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            x += deltaX;
1979146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1980146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1981146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1982146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawHours(Rect r, Canvas canvas, Paint p) {
19833eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Comment out as the background will be a drawable
19843eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
1985146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the background for the hour labels
19863eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarHourBackground);
19873eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.top = 0;
19883eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.bottom = 24 * (mCellHeight + HOUR_GAP) + HOUR_GAP;
19893eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.left = 0;
19903eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.right = mHoursWidth;
19913eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
1992146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1993146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Fill the bottom left corner with the default grid background
19943eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.top = r.bottom;
19953eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.bottom = mBitmapHeight;
19963eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarGridAreaBackground);
19973eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
1998146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1999146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw a highlight on the selected hour (if needed)
2000ba902466b19b11d587468e354edc58e542707747Michael Chan        if (mSelectionMode != SELECTION_HIDDEN && !mSelectionAllDay) {
2001ba902466b19b11d587468e354edc58e542707747Michael Chan            // p.setColor(mCalendarHourSelected);
20023937a47bc5a1afb9701e1d0565fae31f5800590dErik            int daynum = mSelectionDay - mFirstJulianDay;
2003ba902466b19b11d587468e354edc58e542707747Michael Chan            r.top = mSelectionHour * (mCellHeight + HOUR_GAP);
20041ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.bottom = r.top + mCellHeight + HOUR_GAP;
200546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            r.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP) + DAY_GAP;
20063937a47bc5a1afb9701e1d0565fae31f5800590dErik            r.right = r.left + mCellWidth + DAY_GAP;
2007ba902466b19b11d587468e354edc58e542707747Michael Chan
2008ba902466b19b11d587468e354edc58e542707747Michael Chan            // Draw a border around the highlighted grid hour.
20091ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            // drawEmptyRect(canvas, r, mSelectionPaint.getColor());
2010ba902466b19b11d587468e354edc58e542707747Michael Chan            saveSelectionPosition(r.left, r.top, r.right, r.bottom);
20113937a47bc5a1afb9701e1d0565fae31f5800590dErik
20123937a47bc5a1afb9701e1d0565fae31f5800590dErik            // Also draw the highlight on the grid
20133937a47bc5a1afb9701e1d0565fae31f5800590dErik            p.setColor(mCalendarGridAreaSelected);
20143937a47bc5a1afb9701e1d0565fae31f5800590dErik            r.top += HOUR_GAP;
20153937a47bc5a1afb9701e1d0565fae31f5800590dErik            r.right -= DAY_GAP;
20163937a47bc5a1afb9701e1d0565fae31f5800590dErik            canvas.drawRect(r, p);
2017ba902466b19b11d587468e354edc58e542707747Michael Chan        }
2018146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
20198f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        setupHourTextPaint(p);
2020146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
20218f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        int y = HOUR_GAP + mHoursTextHeight + HOURS_TOP_MARGIN;
2022146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2023146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < 24; i++) {
2024146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            String time = mHourStrs[i];
20258f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan            canvas.drawText(time, HOURS_LEFT_MARGIN, y, p);
2026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            y += mCellHeight + HOUR_GAP;
2027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2028146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2029146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
20308f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    private void setupHourTextPaint(Paint p) {
20318f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        p.setColor(mCalendarHourLabelColor);
20328f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        p.setTextSize(HOURS_FONT_SIZE);
2033f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan        p.setTypeface(Typeface.DEFAULT);
20348f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        p.setTextAlign(Paint.Align.LEFT);
20358f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        p.setAntiAlias(true);
20368f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan    }
20378f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan
20383eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private void drawDayHeader(String dayStr, int day, int cell, float x, Canvas canvas, Paint p) {
2039487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int dateNum = mFirstVisibleDate + day;
2040146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (dateNum > mMonthLength) {
2041146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            dateNum -= mMonthLength;
2042146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2043146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
20443eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw day of the month
20453eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        String dateNumStr = String.valueOf(dateNum);
20463eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        if (mNumDays > 1) {
20473eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            float y = DAY_HEADER_HEIGHT - DAY_HEADER_BOTTOM_MARGIN;
20483eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
20493eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Draw day of the month
20503eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            x += mCellWidth - DAY_HEADER_RIGHT_MARGIN;
20513eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            p.setTextSize(DATE_HEADER_FONT_SIZE);
2052f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan            p.setTypeface(mBold);
20533eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            canvas.drawText(dateNumStr, x, y, p);
20543eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
20553eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Draw day of the week
20563eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            x -= p.measureText(dateNumStr) + DAY_HEADER_LEFT_MARGIN;
2057f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan            p.setColor((p.getColor() & 0x00FFFFFF) | DAY_HEADER_ALPHA);
20583eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            p.setTextSize(DAY_HEADER_FONT_SIZE);
2059f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan            p.setTypeface(Typeface.DEFAULT);
20603eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            canvas.drawText(dayStr, x, y, p);
2061146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
20623eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            float y = DAY_HEADER_HEIGHT - DAY_HEADER_ONE_DAY_BOTTOM_MARGIN;
206311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            p.setTextAlign(Paint.Align.LEFT);
2064146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2065f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan            int dateColor = p.getColor();
2066f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan
20673eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Draw day of the week
20683eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            x += DAY_HEADER_ONE_DAY_LEFT_MARGIN;
2069f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan            p.setColor((dateColor & 0x00FFFFFF) | DAY_HEADER_ALPHA);
20703eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            p.setTextSize(DAY_HEADER_FONT_SIZE);
2071f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan            p.setTypeface(Typeface.DEFAULT);
20723eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            canvas.drawText(dayStr, x, y, p);
2073d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan
20743eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Draw day of the month
20753eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            x += p.measureText(dayStr) + DAY_HEADER_ONE_DAY_RIGHT_MARGIN;
2076f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan            p.setColor(dateColor);
20773eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            p.setTextSize(DATE_HEADER_FONT_SIZE);
2078f1495b68983082cb7d1cd625abefcd87dd58cf5fMichael Chan            p.setTypeface(mBold);
20793eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            canvas.drawText(dateNumStr, x, y, p);
2080d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        }
2081146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2082146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2083146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawGridBackground(Rect r, Canvas canvas, Paint p) {
2084146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint.Style savedStyle = p.getStyle();
2085146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
20863eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the outer horizontal grid lines
2087d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridLineHorizontalColor);
20889c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        p.setStyle(Style.FILL);
20893937a47bc5a1afb9701e1d0565fae31f5800590dErik
2090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(false);
20913eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float stopX = mHoursWidth + (mCellWidth + DAY_GAP) * mNumDays;
2092000ba1109e2f4e527e9227fe341598ceeb3fbca6Michael Chan        float y = 0;
20933eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float deltaY = mCellHeight + HOUR_GAP;
20943937a47bc5a1afb9701e1d0565fae31f5800590dErik        p.setStrokeWidth(GRID_LINE_WIDTH);
209502041687c35441e8a21cb763f1fc3a26525292efDavid Brown        int linesIndex = 0;
2096146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int hour = 0; hour <= 24; hour++) {
20978f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan            mLines[linesIndex++] = GRID_LINE_LEFT_MARGIN;
209802041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = y;
209902041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopX;
210002041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = y;
2101146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            y += deltaY;
2102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
210302041687c35441e8a21cb763f1fc3a26525292efDavid Brown        if (mCalendarGridLineVerticalColor != mCalendarGridLineHorizontalColor) {
210402041687c35441e8a21cb763f1fc3a26525292efDavid Brown            canvas.drawLines(mLines, 0, linesIndex, p);
210502041687c35441e8a21cb763f1fc3a26525292efDavid Brown            linesIndex = 0;
210602041687c35441e8a21cb763f1fc3a26525292efDavid Brown            p.setColor(mCalendarGridLineVerticalColor);
210702041687c35441e8a21cb763f1fc3a26525292efDavid Brown        }
2108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
21093eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the outer vertical grid lines
21103eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float startY = 0;
21113eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float stopY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP);
21123eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float deltaX = mCellWidth + DAY_GAP;
21131ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        float x = mHoursWidth;
2114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++) {
21151ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            x += deltaX;
211602041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
211702041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = startY;
211802041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
211902041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopY;
2120146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
212102041687c35441e8a21cb763f1fc3a26525292efDavid Brown        canvas.drawLines(mLines, 0, linesIndex, p);
2122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
21233eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the inner horizontal grid lines
21243eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setColor(mCalendarGridLineInnerHorizontalColor);
21253eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setStrokeWidth(GRID_LINE_INNER_WIDTH);
21263eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        y = 0;
212702041687c35441e8a21cb763f1fc3a26525292efDavid Brown        linesIndex = 0;
21283eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        for (int hour = 0; hour <= 24; hour++) {
21298f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan            mLines[linesIndex++] = GRID_LINE_LEFT_MARGIN;
213002041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = y;
213102041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopX;
213202041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = y;
21333eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            y += deltaY;
21343eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        }
213502041687c35441e8a21cb763f1fc3a26525292efDavid Brown        if (mCalendarGridLineInnerVerticalColor != mCalendarGridLineInnerHorizontalColor) {
213602041687c35441e8a21cb763f1fc3a26525292efDavid Brown            canvas.drawLines(mLines, 0, linesIndex, p);
213702041687c35441e8a21cb763f1fc3a26525292efDavid Brown            linesIndex = 0;
213802041687c35441e8a21cb763f1fc3a26525292efDavid Brown            p.setColor(mCalendarGridLineInnerVerticalColor);
213902041687c35441e8a21cb763f1fc3a26525292efDavid Brown        }
21403eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
21413eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the inner vertical grid lines
21421ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        x = mHoursWidth;
21433eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        for (int day = 0; day < mNumDays; day++) {
21441ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            x += deltaX;
214502041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
214602041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = startY;
214702041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
214802041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopY;
21493eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        }
215002041687c35441e8a21cb763f1fc3a26525292efDavid Brown        canvas.drawLines(mLines, 0, linesIndex, p);
21513eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
2152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Restore the saved style.
2153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStyle(savedStyle);
2154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
2155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2156146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Event getSelectedEvent() {
2158146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == null) {
2159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // There is no event at the selected hour, so create a new event.
2160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return getNewEvent(mSelectionDay, getSelectedTimeInMillis(),
2161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    getSelectedMinutesSinceMidnight());
2162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return mSelectedEvent;
2164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    boolean isEventSelected() {
2167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return (mSelectedEvent != null);
2168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Event getNewEvent() {
2171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return getNewEvent(mSelectionDay, getSelectedTimeInMillis(),
2172146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                getSelectedMinutesSinceMidnight());
2173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    static Event getNewEvent(int julianDay, long utcMillis,
2176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int minutesSinceMidnight) {
2177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event event = Event.newInstance();
2178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.startDay = julianDay;
2179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.endDay = julianDay;
2180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.startMillis = utcMillis;
2181146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.endMillis = event.startMillis + MILLIS_PER_HOUR;
2182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.startTime = minutesSinceMidnight;
2183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.endTime = event.startTime + MINUTES_PER_HOUR;
2184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return event;
2185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int computeMaxStringWidth(int currentMax, String[] strings, Paint p) {
2188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float maxWidthF = 0.0f;
2189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int len = strings.length;
2191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < len; i++) {
2192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float width = p.measureText(strings[i]);
2193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            maxWidthF = Math.max(width, maxWidthF);
2194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int maxWidth = (int) (maxWidthF + 0.5);
2196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (maxWidth < currentMax) {
2197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            maxWidth = currentMax;
2198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return maxWidth;
2200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void saveSelectionPosition(float left, float top, float right, float bottom) {
2203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.left = (int) left;
2204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.right = (int) right;
2205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.top = (int) top;
2206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.bottom = (int) bottom;
2207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect getCurrentSelectionPosition() {
2210146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect box = new Rect();
2211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.top = mSelectionHour * (mCellHeight + HOUR_GAP);
2212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.bottom = box.top + mCellHeight + HOUR_GAP;
2213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int daynum = mSelectionDay - mFirstJulianDay;
2214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP);
2215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.right = box.left + mCellWidth + DAY_GAP;
2216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return box;
2217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
22191ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private void setupTextRect(Rect r) {
22201ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        if (r.bottom <= r.top || r.right <= r.left) {
22211ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.bottom = r.top;
22221ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.right = r.left;
222336a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            return;
222436a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
222536a4668f603c432d08ad156cd7c731f9838c0212Michael Chan
22261ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        if (r.bottom - r.top > EVENT_TEXT_TOP_MARGIN + EVENT_TEXT_BOTTOM_MARGIN) {
22271ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.top += EVENT_TEXT_TOP_MARGIN;
22281ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.bottom -= EVENT_TEXT_BOTTOM_MARGIN;
222936a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
22301ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        if (r.right - r.left > EVENT_TEXT_LEFT_MARGIN + EVENT_TEXT_RIGHT_MARGIN) {
22311ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.left += EVENT_TEXT_LEFT_MARGIN;
22321ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.right -= EVENT_TEXT_RIGHT_MARGIN;
223336a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
22349c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    }
22359c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan
22361ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private void setupAllDayTextRect(Rect r) {
22371ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        if (r.bottom <= r.top || r.right <= r.left) {
22381ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.bottom = r.top;
22391ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.right = r.left;
224036a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            return;
224136a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
224236a4668f603c432d08ad156cd7c731f9838c0212Michael Chan
22431ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        if (r.bottom - r.top > EVENT_ALL_DAY_TEXT_TOP_MARGIN + EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN) {
22441ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.top += EVENT_ALL_DAY_TEXT_TOP_MARGIN;
22451ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.bottom -= EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN;
224636a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
22471ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        if (r.right - r.left > EVENT_ALL_DAY_TEXT_LEFT_MARGIN + EVENT_ALL_DAY_TEXT_RIGHT_MARGIN) {
22481ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.left += EVENT_ALL_DAY_TEXT_LEFT_MARGIN;
22491ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            r.right -= EVENT_ALL_DAY_TEXT_RIGHT_MARGIN;
225036a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
22519c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    }
22529c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan
22533e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    /**
22543e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh     * Return the layout for a numbered event. Create it if not already existing
22553e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh     */
225608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan    private StaticLayout getEventLayout(StaticLayout[] layouts, int i, Event event, Paint paint,
225708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            Rect r) {
225808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        if (i < 0 || i >= layouts.length) {
22590a0f7f3b2ca79419d417626f11b119d5a8b92f45Michael Chan            return null;
22600a0f7f3b2ca79419d417626f11b119d5a8b92f45Michael Chan        }
22610a0f7f3b2ca79419d417626f11b119d5a8b92f45Michael Chan
226208ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        StaticLayout layout = layouts[i];
2263f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        // Check if we have already initialized the StaticLayout and that
2264f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        // the width hasn't changed (due to vertical resizing which causes
2265f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        // re-layout of events at min height)
22661ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        if (layout == null || r.width() != layout.getWidth()) {
2267f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan            String text = drawTextSanitizer(event.getTitleAndLocation(), MAX_EVENT_TEXT_LEN);
22683e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
2269f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan            if (event.selfAttendeeStatus == Attendees.ATTENDEE_STATUS_DECLINED) {
2270f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan                paint.setColor(mDeclinedEventTextColor);
2271f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan            } else {
2272f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan                paint.setColor(mEventTextColor);
2273f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan            }
2274f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan
22753e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            // Leave a one pixel boundary on the left and right of the rectangle for the event
22761ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            layout = new StaticLayout(text, 0, text.length(), new TextPaint(paint), r.width(),
22771ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan                    Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true, null, r.width());
22783e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
227908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            layouts[i] = layout;
22803e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        }
22813e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
22823e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        return layout;
22833e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    }
22843e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
22851ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private void drawAllDayEvents(int firstDay, int numDays, Canvas canvas, Paint p) {
22861ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        if (mSelectionAllDay) {
22871ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            // Draw the highlight on the selected all-day area
22881ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            mRect.top = DAY_HEADER_HEIGHT + 1;
22891ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            mRect.bottom = mRect.top + mAllDayHeight + ALLDAY_TOP_MARGIN - 2;
22901ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            int daynum = mSelectionDay - mFirstJulianDay;
22911ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            mRect.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP);
22921ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            mRect.right = mRect.left + mCellWidth + DAY_GAP - 1;
22931ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            p.setColor(mCalendarGridAreaSelected);
22941ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            canvas.drawRect(mRect, p);
22953e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        }
22963e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
2297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(NORMAL_FONT_SIZE);
2298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextAlign(Paint.Align.LEFT);
2299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint eventTextPaint = mEventTextPaint;
2300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the background for the all-day events area
23023eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.top = DAY_HEADER_HEIGHT;
23033eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.bottom = r.top + mAllDayHeight + ALLDAY_TOP_MARGIN;
23043eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.left = mHoursWidth;
23053eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.right = r.left + mNumDays * (mCellWidth + DAY_GAP);
23063eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarAllDayBackground);
23073eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
2308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Fill the extra space on the right side with the default background
23103eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.left = r.right;
23113eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.right = mViewWidth;
23123eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarGridAreaBackground);
23133eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
2314146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
23153eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the outer vertical grid lines
2316d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridLineVerticalColor);
23179c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        p.setStyle(Style.FILL);
23183eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setStrokeWidth(GRID_LINE_WIDTH);
2319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(false);
23203eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float startY = DAY_HEADER_HEIGHT;
23213eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float stopY = startY + mAllDayHeight + ALLDAY_TOP_MARGIN;
23223eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float deltaX = mCellWidth + DAY_GAP;
23231ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        float x = mHoursWidth;
232402041687c35441e8a21cb763f1fc3a26525292efDavid Brown        int linesIndex = 0;
23251ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        // Line bounding the top of the all day area
23268f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        mLines[linesIndex++] = GRID_LINE_LEFT_MARGIN;
23271ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = startY;
23281ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = mHoursWidth + deltaX * mNumDays;
23291ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = startY;
23301ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
23313eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        for (int day = 0; day < mNumDays; day++) {
23321ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            x += deltaX;
233302041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
233402041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = startY;
233502041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
233602041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopY;
2337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
233802041687c35441e8a21cb763f1fc3a26525292efDavid Brown        canvas.drawLines(mLines, 0, linesIndex, p);
23393eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
23403eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the inner vertical grid lines
23413eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setColor(mCalendarGridLineInnerVerticalColor);
23421ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        x = mHoursWidth;
23433eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setStrokeWidth(GRID_LINE_INNER_WIDTH);
234402041687c35441e8a21cb763f1fc3a26525292efDavid Brown        linesIndex = 0;
23451ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        // Line bounding the top of the all day area
23468f7a2b2fb82029bc23fce357d14f4484e80c13fdMichael Chan        mLines[linesIndex++] = GRID_LINE_LEFT_MARGIN;
23471ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = startY;
23481ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = mHoursWidth + (deltaX) * mNumDays;
23491ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = startY;
23501ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
23513eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        for (int day = 0; day < mNumDays; day++) {
23521ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            x += deltaX;
235302041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
235402041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = startY;
235502041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
235602041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopY;
23573eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        }
235802041687c35441e8a21cb763f1fc3a26525292efDavid Brown        canvas.drawLines(mLines, 0, linesIndex, p);
23593eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
2360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
2361146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStyle(Style.FILL);
2362146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
23633eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        int y = DAY_HEADER_HEIGHT + ALLDAY_TOP_MARGIN;
2364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float left = mHoursWidth;
2365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int lastDay = firstDay + numDays - 1;
236608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        final ArrayList<Event> events = mAllDayEvents;
2367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numEvents = events.size();
2368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float drawHeight = mAllDayHeight;
2369146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float numRectangles = mMaxAllDayEvents;
2370146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < numEvents; i++) {
2371146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(i);
2372146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startDay = event.startDay;
2373146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endDay = event.endDay;
2374c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            if (startDay > lastDay || endDay < firstDay) {
2375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
2376c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            }
2377c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            if (startDay < firstDay) {
2378146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startDay = firstDay;
2379c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            }
2380c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            if (endDay > lastDay) {
2381146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                endDay = lastDay;
2382c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            }
2383146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startIndex = startDay - firstDay;
2384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endIndex = endDay - firstDay;
2385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float height = drawHeight / numRectangles;
2386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2387146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Prevent a single event from getting too big
2388f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan            if (height > MAX_HEIGHT_OF_ONE_ALLDAY_EVENT) {
2389f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                height = MAX_HEIGHT_OF_ONE_ALLDAY_EVENT;
2390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2391146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2392146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Leave a one-pixel space between the vertical day lines and the
2393146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // event rectangle.
23949c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan            event.left = left + startIndex * (mCellWidth + DAY_GAP);
23959c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan            event.right = left + endIndex * (mCellWidth + DAY_GAP) + mCellWidth;
2396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            event.top = y + height * event.getColumn();
23979c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan            event.bottom = event.top + height;
2398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
23991ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            Rect r = drawEventRect(event, canvas, p, eventTextPaint);
24001ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            setupAllDayTextRect(r);
240108ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            StaticLayout layout = getEventLayout(mAllDayLayouts, i, event, eventTextPaint, r);
240208ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            drawEventText(layout, r, canvas, r.top, r.bottom);
2403146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2404146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Check if this all-day event intersects the selected day
2405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionAllDay && mComputeSelectedEvents) {
2406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (startDay <= mSelectionDay && endDay >= mSelectionDay) {
2407146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectedEvents.add(event);
2408146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2409146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2412146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionAllDay) {
2413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Compute the neighbors for the list of all-day events that
2414146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // intersect the selected day.
2415146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeAllDayNeighbors();
2416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Set the selection position to zero so that when we move down
2418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // to the normal event area, we will highlight the topmost event.
2419146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            saveSelectionPosition(0f, 0f, 0f, 0f);
2420146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2421146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2422146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2423146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void computeAllDayNeighbors() {
2424146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int len = mSelectedEvents.size();
2425146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (len == 0 || mSelectedEvent != null) {
2426146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2427146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2428146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2429146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // First, clear all the links
2430146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
2431146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
2432146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextUp = null;
2433146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextDown = null;
2434146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextLeft = null;
2435146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextRight = null;
2436146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2437146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2438146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // For each event in the selected event list "mSelectedEvents", find
243946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        // its neighbors in the up and down directions. This could be done
2440146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // more efficiently by sorting on the Event.getColumn() field, but
2441146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // the list is expected to be very small.
2442146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2443146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Find the event in the same row as the previously selected all-day
2444146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // event, if any.
2445146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int startPosition = -1;
2446d031419da7900dab91ac9f512374d7e59bb74dceErik        if (mPrevSelectedEvent != null && mPrevSelectedEvent.drawAsAllDay()) {
2447146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            startPosition = mPrevSelectedEvent.getColumn();
2448146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2449146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int maxPosition = -1;
2450146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event startEvent = null;
2451146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event maxPositionEvent = null;
2452146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
2453146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
2454146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int position = ev.getColumn();
2455146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (position == startPosition) {
2456146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEvent = ev;
2457146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (position > maxPosition) {
2458146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                maxPositionEvent = ev;
2459146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                maxPosition = position;
2460146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2461146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int jj = 0; jj < len; jj++) {
2462146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (jj == ii) {
2463146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    continue;
2464146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event neighbor = mSelectedEvents.get(jj);
2466146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int neighborPosition = neighbor.getColumn();
2467146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (neighborPosition == position - 1) {
2468146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    ev.nextUp = neighbor;
2469146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (neighborPosition == position + 1) {
2470146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    ev.nextDown = neighbor;
2471146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2472146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2473146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2474146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (startEvent != null) {
2475146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = startEvent;
2476146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2477146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = maxPositionEvent;
2478146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2479146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2480146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2481146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawEvents(int date, int left, int top, Canvas canvas, Paint p) {
2482146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint eventTextPaint = mEventTextPaint;
2483146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cellWidth = mCellWidth;
2484146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cellHeight = mCellHeight;
2485146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2486146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Use the selected hour as the selection region
2487259b8f9a21fffd3858218581e9daaf689b6b888fErik        Rect selectionArea = mSelectionRect;
2488146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.top = top + mSelectionHour * (cellHeight + HOUR_GAP);
2489146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.bottom = selectionArea.top + cellHeight;
2490146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.left = left;
2491146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.right = selectionArea.left + cellWidth;
2492146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
249308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        final ArrayList<Event> events = mEvents;
2494146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numEvents = events.size();
2495146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        EventGeometry geometry = mEventGeometry;
2496146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
249708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        final int viewEndY = mViewStartY + mViewHeight - DAY_HEADER_HEIGHT - mAllDayHeight;
2498146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < numEvents; i++) {
2499146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(i);
2500146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (!geometry.computeEventRect(date, left, top, cellWidth, event)) {
2501146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
2502146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2503146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
250408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            // Don't draw it if it is not visible
250508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            if (event.bottom < mViewStartY || event.top > viewEndY) {
250608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                continue;
250708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            }
250808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan
2509146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (date == mSelectionDay && !mSelectionAllDay && mComputeSelectedEvents
2510146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    && geometry.eventIntersectsSelection(event, selectionArea)) {
2511146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvents.add(event);
2512146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2513146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
25141ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            Rect r = drawEventRect(event, canvas, p, eventTextPaint);
25151ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            setupTextRect(r);
251608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan
251708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            // Don't draw text if it is not visible
251808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            if (r.top > viewEndY || r.bottom < mViewStartY) {
251908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                continue;
252008ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            }
252108ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            StaticLayout layout = getEventLayout(mLayouts, i, event, eventTextPaint, r);
252208ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            // TODO: not sure why we are 4 pixels off
252346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            drawEventText(layout, r, canvas, mViewStartY + 4, mViewStartY + mViewHeight
252446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    - DAY_HEADER_HEIGHT - mAllDayHeight);
2525146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2526146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2527259b8f9a21fffd3858218581e9daaf689b6b888fErik
2528259b8f9a21fffd3858218581e9daaf689b6b888fErik        if (mComputeSelectedEvents) {
2529259b8f9a21fffd3858218581e9daaf689b6b888fErik            mDispatchAccessibilityEventRunnable.mEventType = mSelectedEvent == null ?
2530259b8f9a21fffd3858218581e9daaf689b6b888fErik                    AccessibilityEvent.TYPE_VIEW_SELECTED :
2531259b8f9a21fffd3858218581e9daaf689b6b888fErik                    AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
2532259b8f9a21fffd3858218581e9daaf689b6b888fErik            post(mDispatchAccessibilityEventRunnable);
2533259b8f9a21fffd3858218581e9daaf689b6b888fErik        }
2534259b8f9a21fffd3858218581e9daaf689b6b888fErik
2535146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (date == mSelectionDay && !mSelectionAllDay && isFocused()
2536146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                && mSelectionMode != SELECTION_HIDDEN) {
2537146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeNeighbors();
2538146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2539146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2540146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2541146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Computes the "nearest" neighbor event in four directions (left, right,
2542146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // up, down) for each of the events in the mSelectedEvents array.
2543146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void computeNeighbors() {
2544146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int len = mSelectedEvents.size();
2545146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (len == 0 || mSelectedEvent != null) {
2546146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2547146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2548146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2549146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // First, clear all the links
2550146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
2551146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
2552146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextUp = null;
2553146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextDown = null;
2554146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextLeft = null;
2555146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextRight = null;
2556146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2557146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2558146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event startEvent = mSelectedEvents.get(0);
255946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        int startEventDistance1 = 100000; // any large number
256046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        int startEventDistance2 = 100000; // any large number
2561146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevLocation = FROM_NONE;
2562146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevTop;
2563146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevBottom;
2564146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevLeft;
2565146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevRight;
2566146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevCenter = 0;
2567146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect box = getCurrentSelectionPosition();
2568146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mPrevSelectedEvent != null) {
2569146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevTop = (int) mPrevSelectedEvent.top;
2570146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevBottom = (int) mPrevSelectedEvent.bottom;
2571146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLeft = (int) mPrevSelectedEvent.left;
2572146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevRight = (int) mPrevSelectedEvent.right;
2573146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Check if the previously selected event intersects the previous
257446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            // selection box. (The previously selected event may be from a
2575146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // much older selection box.)
2576146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (prevTop >= mPrevBox.bottom || prevBottom <= mPrevBox.top
2577146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || prevRight <= mPrevBox.left || prevLeft >= mPrevBox.right) {
2578146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = null;
2579146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevTop = mPrevBox.top;
2580146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevBottom = mPrevBox.bottom;
2581146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevLeft = mPrevBox.left;
2582146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevRight = mPrevBox.right;
2583146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
2584146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Clip the top and bottom to the previous selection box.
2585146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (prevTop < mPrevBox.top) {
2586146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    prevTop = mPrevBox.top;
2587146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2588146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (prevBottom > mPrevBox.bottom) {
2589146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    prevBottom = mPrevBox.bottom;
2590146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2591146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2592146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2593146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Just use the previously drawn selection box
2594146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevTop = mPrevBox.top;
2595146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevBottom = mPrevBox.bottom;
2596146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLeft = mPrevBox.left;
2597146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevRight = mPrevBox.right;
2598146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2599146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2600146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Figure out where we came from and compute the center of that area.
2601146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (prevLeft >= box.right) {
2602146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was to the right of us.
2603146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_RIGHT;
2604146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevTop + prevBottom) / 2;
2605146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (prevRight <= box.left) {
2606146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was to the left of us.
2607146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_LEFT;
2608146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevTop + prevBottom) / 2;
2609146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (prevBottom <= box.top) {
2610146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was above us.
2611146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_ABOVE;
2612146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevLeft + prevRight) / 2;
2613146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (prevTop >= box.bottom) {
2614146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was below us.
2615146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_BELOW;
2616146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevLeft + prevRight) / 2;
2617146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2618146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2619146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // For each event in the selected event list "mSelectedEvents", search
2620146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // all the other events in that list for the nearest neighbor in 4
2621146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // directions.
2622146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
2623146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
2624146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2625146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startTime = ev.startTime;
2626146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endTime = ev.endTime;
2627146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int left = (int) ev.left;
2628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int right = (int) ev.right;
2629146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int top = (int) ev.top;
2630146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (top < box.top) {
2631146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                top = box.top;
2632146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2633146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int bottom = (int) ev.bottom;
2634146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (bottom > box.bottom) {
2635146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                bottom = box.bottom;
2636146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2637146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (false) {
2638146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL
2639146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
2640ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                if (DateFormat.is24HourFormat(mContext)) {
2641146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    flags |= DateUtils.FORMAT_24HOUR;
2642146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
264346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                String timeRange = DateUtils.formatDateRange(mContext, ev.startMillis,
264446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        ev.endMillis, flags);
264546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                Log.i("Cal", "left: " + left + " right: " + right + " top: " + top + " bottom: "
264646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        + bottom + " ev: " + timeRange + " " + ev.title);
264746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            }
264846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            int upDistanceMin = 10000; // any large number
264946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            int downDistanceMin = 10000; // any large number
265046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            int leftDistanceMin = 10000; // any large number
265146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            int rightDistanceMin = 10000; // any large number
2652146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event upEvent = null;
2653146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event downEvent = null;
2654146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event leftEvent = null;
2655146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event rightEvent = null;
2656146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2657146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Pick the starting event closest to the previously selected event,
265846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            // if any. distance1 takes precedence over distance2.
2659146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int distance1 = 0;
2660146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int distance2 = 0;
2661146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (prevLocation == FROM_ABOVE) {
2662146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (left >= prevCenter) {
2663146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = left - prevCenter;
2664146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (right <= prevCenter) {
2665146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - right;
2666146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2667146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = top - prevBottom;
2668146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (prevLocation == FROM_BELOW) {
2669146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (left >= prevCenter) {
2670146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = left - prevCenter;
2671146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (right <= prevCenter) {
2672146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - right;
2673146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2674146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = prevTop - bottom;
2675146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (prevLocation == FROM_LEFT) {
2676146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (bottom <= prevCenter) {
2677146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - bottom;
2678146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (top >= prevCenter) {
2679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = top - prevCenter;
2680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2681146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = left - prevRight;
2682146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (prevLocation == FROM_RIGHT) {
2683146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (bottom <= prevCenter) {
2684146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - bottom;
2685146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (top >= prevCenter) {
2686146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = top - prevCenter;
2687146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2688146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = prevLeft - right;
2689146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2690146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (distance1 < startEventDistance1
2691146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || (distance1 == startEventDistance1 && distance2 < startEventDistance2)) {
2692146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEvent = ev;
2693146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEventDistance1 = distance1;
2694146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEventDistance2 = distance2;
2695146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2696146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2697146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // For each neighbor, figure out if it is above or below or left
2698146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // or right of me and compute the distance.
2699146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int jj = 0; jj < len; jj++) {
2700146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (jj == ii) {
2701146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    continue;
2702146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2703146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event neighbor = mSelectedEvents.get(jj);
2704146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int neighborLeft = (int) neighbor.left;
2705146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int neighborRight = (int) neighbor.right;
2706146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (neighbor.endTime <= startTime) {
2707146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely above me.
2708146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // If we overlap the same column, then compute the distance.
2709146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborLeft < right && neighborRight > left) {
2710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int distance = startTime - neighbor.endTime;
2711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (distance < upDistanceMin) {
2712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            upDistanceMin = distance;
2713146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            upEvent = neighbor;
2714146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        } else if (distance == upDistanceMin) {
2715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int center = (left + right) / 2;
2716146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentDistance = 0;
2717146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentLeft = (int) upEvent.left;
2718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentRight = (int) upEvent.right;
2719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (currentRight <= center) {
2720146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = center - currentRight;
2721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (currentLeft >= center) {
2722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = currentLeft - center;
2723146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int neighborDistance = 0;
2726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborRight <= center) {
2727146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = center - neighborRight;
2728146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (neighborLeft >= center) {
2729146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = neighborLeft - center;
2730146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2731146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborDistance < currentDistance) {
2732146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                upDistanceMin = distance;
2733146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                upEvent = neighbor;
2734146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2735146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2736146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2737146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (neighbor.startTime >= endTime) {
2738146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely below me.
2739146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // If we overlap the same column, then compute the distance.
2740146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborLeft < right && neighborRight > left) {
2741146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int distance = neighbor.startTime - endTime;
2742146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (distance < downDistanceMin) {
2743146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            downDistanceMin = distance;
2744146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            downEvent = neighbor;
2745146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        } else if (distance == downDistanceMin) {
2746146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int center = (left + right) / 2;
2747146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentDistance = 0;
2748146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentLeft = (int) downEvent.left;
2749146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentRight = (int) downEvent.right;
2750146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (currentRight <= center) {
2751146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = center - currentRight;
2752146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (currentLeft >= center) {
2753146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = currentLeft - center;
2754146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2755146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int neighborDistance = 0;
2757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborRight <= center) {
2758146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = center - neighborRight;
2759146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (neighborLeft >= center) {
2760146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = neighborLeft - center;
2761146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2762146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborDistance < currentDistance) {
2763146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                downDistanceMin = distance;
2764146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                downEvent = neighbor;
2765146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2766146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2767146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2768146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2769146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2770146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (neighborLeft >= right) {
2771146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely to the right of me.
2772146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Take the closest neighbor in the y direction.
2773146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int center = (top + bottom) / 2;
2774146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int distance = 0;
2775146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborBottom = (int) neighbor.bottom;
2776146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborTop = (int) neighbor.top;
2777146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborBottom <= center) {
2778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = center - neighborBottom;
2779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (neighborTop >= center) {
2780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = neighborTop - center;
2781146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2782146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (distance < rightDistanceMin) {
2783146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        rightDistanceMin = distance;
2784146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        rightEvent = neighbor;
2785146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (distance == rightDistanceMin) {
2786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // Pick the closest in the x direction
2787146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int neighborDistance = neighborLeft - right;
2788146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int currentDistance = (int) rightEvent.left - right;
2789146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (neighborDistance < currentDistance) {
2790146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            rightDistanceMin = distance;
2791146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            rightEvent = neighbor;
2792146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2793146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2794146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (neighborRight <= left) {
2795146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely to the left of me.
2796146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Take the closest neighbor in the y direction.
2797146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int center = (top + bottom) / 2;
2798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int distance = 0;
2799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborBottom = (int) neighbor.bottom;
2800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborTop = (int) neighbor.top;
2801146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborBottom <= center) {
2802146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = center - neighborBottom;
2803146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (neighborTop >= center) {
2804146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = neighborTop - center;
2805146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2806146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (distance < leftDistanceMin) {
2807146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        leftDistanceMin = distance;
2808146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        leftEvent = neighbor;
2809146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (distance == leftDistanceMin) {
2810146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // Pick the closest in the x direction
2811146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int neighborDistance = left - neighborRight;
2812146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int currentDistance = left - (int) leftEvent.right;
2813146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (neighborDistance < currentDistance) {
2814146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            leftDistanceMin = distance;
2815146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            leftEvent = neighbor;
2816146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2817146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2818146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2819146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2820146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextUp = upEvent;
2821146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextDown = downEvent;
2822146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextLeft = leftEvent;
2823146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextRight = rightEvent;
2824146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2825146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = startEvent;
2826146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2827146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
28281ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private Rect drawEventRect(Event event, Canvas canvas, Paint p, Paint eventTextPaint) {
282911ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        // Draw the Event Rect
28301ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        Rect r = mRect;
28311ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.top = (int) event.top + EVENT_RECT_TOP_MARGIN;
28321ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.bottom = (int) event.bottom - EVENT_RECT_BOTTOM_MARGIN;
28331ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.left = (int) event.left + EVENT_RECT_LEFT_MARGIN;
28341ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.right = (int) event.right - EVENT_RECT_RIGHT_MARGIN;
28351ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
2836f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan        Drawable eventBoxDrawable;
2837f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan        switch (event.selfAttendeeStatus) {
2838f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan            case Attendees.ATTENDEE_STATUS_INVITED:
2839f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan            case Attendees.ATTENDEE_STATUS_DECLINED:
2840f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan                eventBoxDrawable = mUnconfirmedOrDeclinedEventBoxDrawable;
2841f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan                break;
2842f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan            case Attendees.ATTENDEE_STATUS_NONE: // Your own events
2843f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan            case Attendees.ATTENDEE_STATUS_ACCEPTED:
2844f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan            case Attendees.ATTENDEE_STATUS_TENTATIVE:
2845f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan            default:
2846f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan                eventBoxDrawable = mAcceptedOrTentativeEventBoxDrawable;
2847f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan                break;
2848f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan        }
2849f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan        eventBoxDrawable.setBounds(r);
2850f2ca00946a543a19467d5dbfa3427ecf221186d4Michael Chan        eventBoxDrawable.draw(canvas);
2851146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
28521ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        p.setStyle(Style.FILL);
2853e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2854146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If this event is selected, then use the selection color
2855146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == event) {
28561ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            boolean paintIt = false;
28571ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            int color = 0;
2858146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionMode == SELECTION_PRESSED) {
2859146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Also, remember the last selected event that we drew
2860146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = event;
2861146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // box = mBoxPressed;
286278f58c119af15ed85a727e16cddd793ced4c809dMichael Chan                color = mPressedColor;
28631ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan                paintIt = true;
2864146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionMode == SELECTION_SELECTED) {
2865146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Also, remember the last selected event that we drew
2866146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = event;
2867146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // box = mBoxSelected;
286878f58c119af15ed85a727e16cddd793ced4c809dMichael Chan                color = mPressedColor;
28691ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan                paintIt = true;
2870146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionMode == SELECTION_LONGPRESS) {
2871146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // box = mBoxLongPressed;
287278f58c119af15ed85a727e16cddd793ced4c809dMichael Chan                color = mPressedColor;
28731ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan                paintIt = true;
28741ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            }
28751ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
28761ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan            if (paintIt) {
28771ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan                p.setColor(color);
28781ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan                canvas.drawRect(r, p);
2879146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2880146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2881146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
288211ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        // Draw cal color square border
28831ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.top = (int) event.top + CALENDAR_COLOR_SQUARE_V_OFFSET;
28841ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.left = (int) event.left + CALENDAR_COLOR_SQUARE_H_OFFSET;
28851ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.bottom = r.top + CALENDAR_COLOR_SQUARE_SIZE + 1;
28861ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.right = r.left + CALENDAR_COLOR_SQUARE_SIZE + 1;
288711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        p.setColor(0xFFFFFFFF);
28881ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        canvas.drawRect(r, p);
28898af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project
289011ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        // Draw cal color
28911ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.top++;
28921ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.left++;
28931ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.bottom--;
28941ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.right--;
289511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        p.setColor(event.color);
28961ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        canvas.drawRect(r, p);
2897e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
28983eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Setup rect for drawEventText which follows
28991ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.top = (int) event.top + EVENT_RECT_TOP_MARGIN;
29001ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.bottom = (int) event.bottom - EVENT_RECT_BOTTOM_MARGIN;
29011ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.left = (int) event.left + EVENT_RECT_LEFT_MARGIN;
29021ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        r.right = (int) event.right - EVENT_RECT_RIGHT_MARGIN;
29031ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        return r;
2904146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2905146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
29060d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    private Pattern drawTextSanitizerFilter = Pattern.compile("[\t\n],");
29070d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan
29080d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    // Sanitize a string before passing it to drawText or else we get little
29090d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    // squares. For newlines and tabs before a comma, delete the character.
29100d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    // Otherwise, just replace them with a space.
2911f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan    private String drawTextSanitizer(String string, int maxEventTextLen) {
29120d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan        Matcher m = drawTextSanitizerFilter.matcher(string);
2913f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        string = m.replaceAll(",");
2914f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan
2915f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        int len = string.length();
2916f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        if (len > maxEventTextLen) {
2917f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan            string = string.substring(0, maxEventTextLen);
2918f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan            len = maxEventTextLen;
2919f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        }
2920f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan
2921f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        return string.replace('\n', ' ');
29220d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    }
29230d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan
292408ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan    private void drawEventText(StaticLayout eventLayout, Rect rect, Canvas canvas, int top,
292508ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            int bottom) {
29261ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        // drawEmptyRect(canvas, rect, 0xFFFF00FF); // for debugging
29271ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
29281ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        int width = rect.right - rect.left;
29291ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        int height = rect.bottom - rect.top;
2930146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2931146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If the rectangle is too small for text, then return
29320a0f7f3b2ca79419d417626f11b119d5a8b92f45Michael Chan        if (eventLayout == null || width < MIN_CELL_WIDTH_FOR_TEXT) {
2933f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan            return;
2934f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        }
2935f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan
293608ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        int totalLineHeight = 0;
2937f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        int lineCount = eventLayout.getLineCount();
2938f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        for (int i = 0; i < lineCount; i++) {
2939f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan            int lineBottom = eventLayout.getLineBottom(i);
2940f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan            if (lineBottom <= height) {
294108ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                totalLineHeight = lineBottom;
294208ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan            } else {
294308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan                break;
2944f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan            }
2945f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        }
2946f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan
294708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        if (totalLineHeight == 0 || rect.top > bottom || rect.top + totalLineHeight < top) {
2948146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2949146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2950146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
29513e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        // Use a StaticLayout to format the string.
29523e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        canvas.save();
29531ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        canvas.translate(rect.left, rect.top);
29541ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        rect.left = 0;
29551ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        rect.right = width;
29561ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        rect.top = 0;
295708ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        rect.bottom = totalLineHeight;
295808ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan
295908ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        // There's a bug somewhere. If this rect is outside of a previous
296008ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        // cliprect, this becomes a no-op. What happens is that the text draw
296108ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        // past the event rect. The current fix is to not draw the staticLayout
296208ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        // at all if it is completely out of bound.
29631ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        canvas.clipRect(rect);
29643e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        eventLayout.draw(canvas);
29653e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        canvas.restore();
2966146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2967146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
29681ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    // This is to replace p.setStyle(Style.STROKE); canvas.drawRect() since it
29691ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    // doesn't work well with hardware acceleration
29701ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    private void drawEmptyRect(Canvas canvas, Rect r, int color) {
29711ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        int linesIndex = 0;
29721ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.left;
29731ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.top;
29741ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.right;
29751ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.top;
29761ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
29771ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.left;
29781ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.bottom;
29791ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.right;
29801ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.bottom;
29811ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
29821ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.left;
29831ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.top;
29841ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.left;
29851ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.bottom;
29861ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
29871ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.right;
29881ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.top;
29891ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.right;
29901ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mLines[linesIndex++] = r.bottom;
29911ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        mPaint.setColor(color);
29921ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan        canvas.drawLines(mLines, 0, linesIndex, mPaint);
29931ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan    }
29941ec87639bd05857bcb2c4a0acc189c0ff413a287Michael Chan
2995146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void updateEventDetails() {
2996146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == null || mSelectionMode == SELECTION_HIDDEN
2997146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                || mSelectionMode == SELECTION_LONGPRESS) {
2998146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPopup.dismiss();
2999146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
3000146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3001666fc5e8ddbac15c951aad738bd818ee307eae42Erik        if (mLastPopupEventID == mSelectedEvent.id) {
3002666fc5e8ddbac15c951aad738bd818ee307eae42Erik            return;
3003666fc5e8ddbac15c951aad738bd818ee307eae42Erik        }
3004666fc5e8ddbac15c951aad738bd818ee307eae42Erik
3005666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = mSelectedEvent.id;
3006146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3007146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Remove any outstanding callbacks to dismiss the popup.
3008146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        getHandler().removeCallbacks(mDismissPopup);
3009146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3010146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event event = mSelectedEvent;
3011146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TextView titleView = (TextView) mPopupView.findViewById(R.id.event_title);
3012146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        titleView.setText(event.title);
3013146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3014146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ImageView imageView = (ImageView) mPopupView.findViewById(R.id.reminder_icon);
3015146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        imageView.setVisibility(event.hasAlarm ? View.VISIBLE : View.GONE);
3016146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3017146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        imageView = (ImageView) mPopupView.findViewById(R.id.repeat_icon);
3018146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        imageView.setVisibility(event.isRepeating ? View.VISIBLE : View.GONE);
3019146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3020146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int flags;
3021146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (event.allDay) {
302246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            flags = DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_DATE
302346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL;
3024146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
3025146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE
3026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL
3027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
3028146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3029ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        if (DateFormat.is24HourFormat(mContext)) {
3030146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags |= DateUtils.FORMAT_24HOUR;
3031146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
303246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        String timeRange = Utils.formatDateRange(mContext, event.startMillis, event.endMillis,
303346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                flags);
3034146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TextView timeView = (TextView) mPopupView.findViewById(R.id.time);
3035146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        timeView.setText(timeRange);
3036146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3037146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TextView whereView = (TextView) mPopupView.findViewById(R.id.where);
3038146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        final boolean empty = TextUtils.isEmpty(event.location);
3039146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        whereView.setVisibility(empty ? View.GONE : View.VISIBLE);
3040146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!empty) whereView.setText(event.location);
3041146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3042146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.LEFT, mHoursWidth, 5);
3043146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        postDelayed(mDismissPopup, POPUP_DISMISS_DELAY);
3044146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3045146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3046146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // The following routines are called from the parent activity when certain
3047146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // touch events occur.
30484484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doDown(MotionEvent ev) {
3049146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mTouchMode = TOUCH_MODE_DOWN;
3050146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewStartX = 0;
3051146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mOnFlingCalled = false;
3052146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        getHandler().removeCallbacks(mContinueScroll);
3053146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3054146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
30554484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doSingleTapUp(MotionEvent ev) {
3056d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (!mHandleActionUp) {
3057d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            return;
3058d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
3059d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3060146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int x = (int) ev.getX();
3061146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int y = (int) ev.getY();
3062146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int selectedDay = mSelectionDay;
3063146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int selectedHour = mSelectionHour;
3064146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3065146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        boolean validPosition = setSelectionFromPosition(x, y);
3066146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!validPosition) {
3067360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan            if (y < DAY_HEADER_HEIGHT) {
3068360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan                Time selectedTime = new Time(mBaseDate);
3069360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan                selectedTime.setJulianDay(mSelectionDay);
3070360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan                selectedTime.hour = mSelectionHour;
3071360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan                selectedTime.normalize(true /* ignore isDst */);
3072360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan                mController.sendEvent(this, EventType.GO_TO, null, null, selectedTime, -1,
3073360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan                        ViewType.DAY, CalendarController.EXTRA_GOTO_DATE, null, null);
3074360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan            }
3075146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
3076146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3077146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
307880bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        mSelectionMode = SELECTION_SELECTED;
3079146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
3080146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
308180bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        if (mSelectedEvent != null) {
308280bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            // If the tap is on an event, launch the "View event" view
3083344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, mSelectedEvent.id,
3084344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan                    mSelectedEvent.startMillis, mSelectedEvent.endMillis, (int) ev.getRawX(),
308587f993ff96172f508d3f241f8a425f953c7eb739RoboErik                    (int) ev.getRawY(), getSelectedTimeInMillis());
3086344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan        } else if (selectedDay == mSelectionDay && selectedHour == mSelectionHour) {
3087344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            // If the tap is on an already selected hour slot, then create a new
3088344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            // event
3089344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
309087f993ff96172f508d3f241f8a425f953c7eb739RoboErik                    getSelectedTimeInMillis(), 0, (int) ev.getRawX(), (int) ev.getRawY(), -1);
3091344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan        } else {
3092344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            Time startTime = new Time(mBaseDate);
3093344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            startTime.setJulianDay(mSelectionDay);
3094344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            startTime.hour = mSelectionHour;
3095344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            startTime.normalize(true /* ignore isDst */);
309683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
309783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Time endTime = new Time(startTime);
309883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            endTime.hour++;
309983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
310046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            mController.sendEvent(this, EventType.GO_TO, startTime, endTime, -1, ViewType.CURRENT,
310146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    CalendarController.EXTRA_GOTO_TIME, null, null);
3102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3104146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
31054484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doLongPress(MotionEvent ev) {
3106d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        // Scale gesture in progress
3107d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mStartingSpanY != 0) {
3108d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            return;
3109d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
3110d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
311180bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        int x = (int) ev.getX();
311280bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        int y = (int) ev.getY();
311380bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan
311480bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        boolean validPosition = setSelectionFromPosition(x, y);
311580bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        if (!validPosition) {
311680bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            // return if the touch wasn't on an area of concern
311780bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            return;
311880bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        }
311980bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan
3120146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_LONGPRESS;
3121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
3122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        performLongClick();
3123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
31254484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doScroll(MotionEvent e1, MotionEvent e2, float deltaX, float deltaY) {
31266d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        if (isAnimating()) {
31276d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            return;
31286d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
31296d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
3130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Use the distance from the current point to the initial touch instead
3131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // of deltaX and deltaY to avoid accumulating floating-point rounding
313246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        // errors. Also, we don't need floats, we can use ints.
3133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceX = (int) e1.getX() - (int) e2.getX();
3134146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceY = (int) e1.getY() - (int) e2.getY();
3135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If we haven't figured out the predominant scroll direction yet,
3137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // then do it now.
3138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mTouchMode == TOUCH_MODE_DOWN) {
3139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int absDistanceX = Math.abs(distanceX);
3140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int absDistanceY = Math.abs(distanceY);
3141146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mScrollStartY = mViewStartY;
3142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPreviousDirection = 0;
3143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3144146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If the x distance is at least twice the y distance, then lock
314546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            // the scroll horizontally. Otherwise scroll vertically.
3146146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (absDistanceX >= 2 * absDistanceY) {
3147146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mTouchMode = TOUCH_MODE_HSCROLL;
3148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartX = distanceX;
3149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                initNextView(-mViewStartX);
3150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mTouchMode = TOUCH_MODE_VSCROLL;
3152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
3154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // We are already scrolling horizontally, so check if we
3155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // changed the direction of scrolling so that the other week
3156146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // is now visible.
3157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mViewStartX = distanceX;
3158146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (distanceX != 0) {
3159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int direction = (distanceX > 0) ? 1 : -1;
3160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (direction != mPreviousDirection) {
3161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // The user has switched the direction of scrolling
3162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // so re-init the next view
3163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    initNextView(-mViewStartX);
3164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mPreviousDirection = direction;
3165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((mTouchMode & TOUCH_MODE_VSCROLL) != 0) {
3170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mViewStartY = mScrollStartY + distanceY;
3171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mViewStartY < 0) {
3172146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = 0;
3173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mViewStartY > mMaxViewStartY) {
3174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = mMaxViewStartY;
3175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeFirstHour();
3177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mScrolling = true;
3180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3181d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan        mSelectionMode = SELECTION_HIDDEN;
3182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
3183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
31856d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan    private boolean isAnimating() {
31866d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        Animation in = mViewSwitcher.getInAnimation();
31876d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        if (in != null && in.hasStarted() && !in.hasEnded()) {
31886d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            return true;
31896d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
31906d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        Animation out = mViewSwitcher.getOutAnimation();
31916d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        if (out != null && out.hasStarted() && !out.hasEnded()) {
31926d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            return true;
31936d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
31946d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        return false;
31956d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan    }
31966d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
31974484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
31986d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        if (isAnimating()) {
31996d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            return;
32006d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        }
32016d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan
3202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mTouchMode = TOUCH_MODE_INITIAL_STATE;
3203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_HIDDEN;
3204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mOnFlingCalled = true;
3205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaX = (int) e2.getX() - (int) e1.getX();
3206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceX = Math.abs(deltaX);
3207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaY = (int) e2.getY() - (int) e1.getY();
3208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceY = Math.abs(deltaY);
32096d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        if (DEBUG) Log.d(TAG, "doFling: deltaX " + deltaX
3210d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan                         + ", HORIZONTAL_FLING_THRESHOLD " + HORIZONTAL_FLING_THRESHOLD);
3211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3212d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan        if ((distanceX >= HORIZONTAL_FLING_THRESHOLD) && (distanceX > distanceY)) {
3213030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown            // Horizontal fling.
321411638ad4fb56b978770aebe75deac7a0e6ac60d2Erik            // initNextView(deltaX);
3215d9dbab823d56bf596eedaecd0935037bd39d02c1Michael Chan            switchViews(deltaX < 0, mViewStartX, mViewWidth);
3216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mViewStartX = 0;
3217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
3218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3220030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown        // Vertical fling.
3221030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown        mViewStartX = 0;
3222030803e32522be52a1ddeb436edbd024942d7c4fDavid Brown
3223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Continue scrolling vertically
3224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mContinueScroll.init((int) velocityY / 20);
3225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        post(mContinueScroll);
3226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean initNextView(int deltaX) {
3229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Change the view to the previous day or week
3230d190418220467c02327dd9b3ae1eae238889720bMichael Chan        DayView view = (DayView) mViewSwitcher.getNextView();
3231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time date = view.mBaseDate;
3232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        date.set(mBaseDate);
3233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        boolean switchForward;
3234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (deltaX > 0) {
3235146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.monthDay -= mNumDays;
3236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionDay = mSelectionDay - mNumDays;
3237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchForward = false;
3238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
3239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.monthDay += mNumDays;
3240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionDay = mSelectionDay + mNumDays;
3241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchForward = true;
3242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        date.normalize(true /* ignore isDst */);
3244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        initView(view);
3245ad36a3c3cde7a2ec6d3a35d2529d46f03bd8d59dMichael Chan        view.layout(getLeft(), getTop(), getRight(), getBottom());
3246146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.reloadEvents();
3247146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return switchForward;
3248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3250d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    // ScaleGestureDetector.OnScaleGestureListener
3251d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    public boolean onScaleBegin(ScaleGestureDetector detector) {
3252d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mHandleActionUp = false;
3253d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        float gestureCenterInPixels = detector.getFocusY() - DAY_HEADER_HEIGHT - mAllDayHeight;
3254d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mGestureCenterHour = (mViewStartY + gestureCenterInPixels) / (mCellHeight + DAY_GAP);
3255d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3256d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mStartingSpanY = Math.max(MIN_Y_SPAN, Math.abs(detector.getCurrentSpanY()));
3257d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mCellHeightBeforeScaleGesture = mCellHeight;
3258d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3259d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (DEBUG) {
3260d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            float ViewStartHour = mViewStartY / (float) (mCellHeight + DAY_GAP);
3261d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            Log.d(TAG, "mGestureCenterHour:" + mGestureCenterHour + "\tViewStartHour: "
3262d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    + ViewStartHour + "\tmViewStartY:" + mViewStartY + "\tmCellHeight:"
3263d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    + mCellHeight);
3264d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
3265d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3266d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        return true;
3267d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    }
3268d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3269d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    // ScaleGestureDetector.OnScaleGestureListener
3270d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    public boolean onScale(ScaleGestureDetector detector) {
3271d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        float spanY = Math.abs(detector.getCurrentSpanY());
3272d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3273d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mCellHeight = (int) (mCellHeightBeforeScaleGesture * spanY / mStartingSpanY);
3274d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3275d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mCellHeight < mMinCellHeight) {
3276d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            // If mStartingSpanY is too small, even a small increase in the
3277d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            // gesture can bump the mCellHeight beyond MAX_CELL_HEIGHT
3278d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mStartingSpanY = Math.max(MIN_Y_SPAN, spanY);
3279d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeight = mMinCellHeight;
3280d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeightBeforeScaleGesture = mMinCellHeight;
3281d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        } else if (mCellHeight > MAX_CELL_HEIGHT) {
3282d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mStartingSpanY = spanY;
3283d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeight = MAX_CELL_HEIGHT;
3284d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeightBeforeScaleGesture = MAX_CELL_HEIGHT;
3285d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
3286d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3287d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        int gestureCenterInPixels = (int) detector.getFocusY() - DAY_HEADER_HEIGHT - mAllDayHeight;
3288d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mViewStartY = (int) (mGestureCenterHour * (mCellHeight + DAY_GAP)) - gestureCenterInPixels;
3289d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mMaxViewStartY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP) - mGridAreaHeight;
3290d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3291d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (DEBUG) {
3292d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            float ViewStartHour = mViewStartY / (float) (mCellHeight + DAY_GAP);
3293d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            Log.d(TAG, " mGestureCenterHour:" + mGestureCenterHour + "\tViewStartHour: "
3294d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    + ViewStartHour + "\tmViewStartY:" + mViewStartY + "\tmCellHeight:"
3295d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    + mCellHeight + " SpanY:" + detector.getCurrentSpanY());
3296d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
3297d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3298d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mViewStartY < 0) {
3299d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mViewStartY = 0;
3300d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mGestureCenterHour = (mViewStartY + gestureCenterInPixels)
3301d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    / (float) (mCellHeight + DAY_GAP);
3302d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        } else if (mViewStartY > mMaxViewStartY) {
3303d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mViewStartY = mMaxViewStartY;
3304d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mGestureCenterHour = (mViewStartY + gestureCenterInPixels)
3305d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    / (float) (mCellHeight + DAY_GAP);
3306d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
3307d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        computeFirstHour();
3308d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3309d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mRemeasure = true;
3310d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        invalidate();
3311d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        return true;
3312d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    }
3313d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3314d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    // ScaleGestureDetector.OnScaleGestureListener
3315d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    public void onScaleEnd(ScaleGestureDetector detector) {
3316d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mStartingSpanY = 0;
3317d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    }
3318d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
3320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
3321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int action = ev.getAction();
3322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
33231ba48526c2542484d91383c21d3d8e07db87df0fMichael Chan        if ((mTouchMode & TOUCH_MODE_HSCROLL) == 0) {
33241ba48526c2542484d91383c21d3d8e07db87df0fMichael Chan            mScaleGestureDetector.onTouchEvent(ev);
33251ba48526c2542484d91383c21d3d8e07db87df0fMichael Chan            if (mScaleGestureDetector.isInProgress()) {
33261ba48526c2542484d91383c21d3d8e07db87df0fMichael Chan                return true;
33271ba48526c2542484d91383c21d3d8e07db87df0fMichael Chan            }
3328d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
3329d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
3330146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        switch (action) {
333146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case MotionEvent.ACTION_DOWN:
333246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (DEBUG) Log.e(TAG, "ACTION_DOWN");
3333d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                mHandleActionUp = true;
333446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                mGestureDetector.onTouchEvent(ev);
3335d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                return true;
333646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
333746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case MotionEvent.ACTION_MOVE:
333846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (DEBUG) Log.e(TAG, "ACTION_MOVE");
333946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                mGestureDetector.onTouchEvent(ev);
3340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
334146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
334246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case MotionEvent.ACTION_UP:
334346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (DEBUG) Log.e(TAG, "ACTION_UP " + mHandleActionUp);
334446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                mGestureDetector.onTouchEvent(ev);
334546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (!mHandleActionUp) {
334646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mHandleActionUp = true;
33477abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project                    return true;
334846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
334946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mOnFlingCalled) {
335046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    return true;
335146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
335246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
335346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mTouchMode = TOUCH_MODE_INITIAL_STATE;
335446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    if (Math.abs(mViewStartX) > mHorizontalSnapBackThreshold) {
335546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        // The user has gone beyond the threshold so switch views
335646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        if (DEBUG) Log.d(TAG, "- horizontal scroll: switch views");
335746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        switchViews(mViewStartX > 0, mViewStartX, mViewWidth);
335846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        mViewStartX = 0;
335946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        return true;
336046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    } else {
336146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        // Not beyond the threshold so invalidate which will cause
336246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        // the view to snap back. Also call recalc() to ensure
336346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        // that we have the correct starting date and title.
336446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        if (DEBUG) Log.d(TAG, "- horizontal scroll: snap back");
336546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        recalc();
336646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        invalidate();
336746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                        mViewStartX = 0;
336846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    }
336946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
337046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
337146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                // If we were scrolling, then reset the selected hour so that it
337246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                // is visible.
337346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mScrolling) {
337446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    mScrolling = false;
337546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    resetSelectedHour();
3376146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    invalidate();
3377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
337846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                return true;
3379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
338046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                // This case isn't expected to happen.
338146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            case MotionEvent.ACTION_CANCEL:
338246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (DEBUG) Log.e(TAG, "ACTION_CANCEL");
338346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                mGestureDetector.onTouchEvent(ev);
3384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mScrolling = false;
3385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                resetSelectedHour();
3386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
338746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
338846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            default:
338946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (DEBUG) Log.e(TAG, "Not MotionEvent");
339046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                if (mGestureDetector.onTouchEvent(ev)) {
339146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                    return true;
339246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                }
339346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                return super.onTouchEvent(ev);
3394146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3395146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3397146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
3398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        MenuItem item;
3399146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3400146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If the trackball is held down, then the context menu pops up and
340146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        // we never get onKeyUp() for the long-press. So check for it here
3402146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // and change the selection to the long-press state.
3403146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionMode != SELECTION_LONGPRESS) {
3404146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionMode = SELECTION_LONGPRESS;
3405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            invalidate();
3406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3407146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3408e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        final long startMillis = getSelectedTimeInMillis();
3409146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int flags = DateUtils.FORMAT_SHOW_TIME
3410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                | DateUtils.FORMAT_CAP_NOON_MIDNIGHT
3411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                | DateUtils.FORMAT_SHOW_WEEKDAY;
3412c5f92d7bdeb1950ace783cc022aa41a4b4f00cd6Erik        final String title = Utils.formatDateRange(mContext, startMillis, startMillis, flags);
3413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        menu.setHeaderTitle(title);
3414e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3415146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numSelectedEvents = mSelectedEvents.size();
3416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays == 1) {
3417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Day view.
3418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3419146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there is a selected event, then allow it to be viewed and
3420146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // edited.
3421146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (numSelectedEvents >= 1) {
34224484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_VIEW, 0, R.string.event_view);
3423146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
3424146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_info_details);
3425146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3426ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                int accessLevel = getEventAccessLevel(mContext, mSelectedEvent);
3427a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel == ACCESS_LEVEL_EDIT) {
34284484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_EDIT, 0, R.string.event_edit);
3429146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
3430146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_edit);
3431146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setAlphabeticShortcut('e');
3432a505627659f6bfba8869eac8089f7030f2d0d92cErik                }
3433146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3434a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel >= ACCESS_LEVEL_DELETE) {
34354484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_DELETE, 0, R.string.event_delete);
3436146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
3437146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_delete);
3438146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3439146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
34404484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
3441146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
3442146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_add);
3443146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setAlphabeticShortcut('n');
3444146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3445146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Otherwise, if the user long-pressed on a blank hour, allow
344646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                // them to create an event. They can also do this by tapping.
34474484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
3448146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
3449146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_add);
3450146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setAlphabeticShortcut('n');
3451146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3452146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
3453146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Week view.
3454e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3455146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there is a selected event, then allow it to be viewed and
3456146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // edited.
3457146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (numSelectedEvents >= 1) {
34584484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_VIEW, 0, R.string.event_view);
3459146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
3460146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_info_details);
3461146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3462ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                int accessLevel = getEventAccessLevel(mContext, mSelectedEvent);
3463a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel == ACCESS_LEVEL_EDIT) {
34644484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_EDIT, 0, R.string.event_edit);
3465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
3466146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_edit);
3467146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setAlphabeticShortcut('e');
3468a505627659f6bfba8869eac8089f7030f2d0d92cErik                }
3469146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3470a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel >= ACCESS_LEVEL_DELETE) {
34714484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_DELETE, 0, R.string.event_delete);
3472146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
3473146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_delete);
3474146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
34754484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            }
3476146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
34774484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
34784484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setOnMenuItemClickListener(mContextMenuHandler);
34794484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setIcon(android.R.drawable.ic_menu_add);
34804484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setAlphabeticShortcut('n');
3481146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
34824484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item = menu.add(0, MENU_DAY, 0, R.string.show_day_view);
34834484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setOnMenuItemClickListener(mContextMenuHandler);
34844484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setIcon(android.R.drawable.ic_menu_day);
34854484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setAlphabeticShortcut('d');
3486146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3487146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3488146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.dismiss();
3489146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3490146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3491146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private class ContextMenuHandler implements MenuItem.OnMenuItemClickListener {
3492146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public boolean onMenuItemClick(MenuItem item) {
3493146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switch (item.getItemId()) {
34944484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_VIEW: {
3495146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (mSelectedEvent != null) {
3496a7694eead7cbb293990bc89c3906e17bad36194cErik                        mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT_DETAILS,
34979e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                mSelectedEvent.id, mSelectedEvent.startMillis,
349887f993ff96172f508d3f241f8a425f953c7eb739RoboErik                                mSelectedEvent.endMillis, 0, 0, -1);
3499146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3500146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3501146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
35024484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_EDIT: {
3503146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (mSelectedEvent != null) {
35049e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        mController.sendEventRelatedEvent(this, EventType.EDIT_EVENT,
35059e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                mSelectedEvent.id, mSelectedEvent.startMillis,
350687f993ff96172f508d3f241f8a425f953c7eb739RoboErik                                mSelectedEvent.endMillis, 0, 0, -1);
3507146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3508146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3509146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
35104484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_DAY: {
3511487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                    mController.sendEvent(this, EventType.GO_TO, getSelectedTime(), null, -1,
35129e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            ViewType.DAY);
3513146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3514146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
35154484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_AGENDA: {
3516487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                    mController.sendEvent(this, EventType.GO_TO, getSelectedTime(), null, -1,
35179e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            ViewType.AGENDA);
3518146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3519146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
35204484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_CREATE: {
3521146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long startMillis = getSelectedTimeInMillis();
3522146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
35239e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
352487f993ff96172f508d3f241f8a425f953c7eb739RoboErik                            startMillis, endMillis, 0, 0, -1);
3525146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3526146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
35274484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_DELETE: {
3528146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (mSelectedEvent != null) {
3529146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        Event selectedEvent = mSelectedEvent;
3530146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        long begin = selectedEvent.startMillis;
3531146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        long end = selectedEvent.endMillis;
3532146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        long id = selectedEvent.id;
35339e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        mController.sendEventRelatedEvent(this, EventType.DELETE_EVENT, id, begin,
353487f993ff96172f508d3f241f8a425f953c7eb739RoboErik                                end, 0, 0, -1);
3535146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3536146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3537146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3538146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                default: {
3539146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    return false;
3540146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3541146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3542146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
3543146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3544146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3545146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3546a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static int getEventAccessLevel(Context context, Event e) {
3547146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ContentResolver cr = context.getContentResolver();
3548146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3549146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int visibility = Calendars.NO_ACCESS;
3550146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3551146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Get the calendar id for this event
3552146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Cursor cursor = cr.query(ContentUris.withAppendedId(Events.CONTENT_URI, e.id),
3553146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                new String[] { Events.CALENDAR_ID },
3554146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                null /* selection */,
3555146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                null /* selectionArgs */,
3556146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                null /* sort */);
3557e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3558e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (cursor == null) {
3559a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_NONE;
3560146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3561e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3562e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (cursor.getCount() == 0) {
3563e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            cursor.close();
3564a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_NONE;
3565e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        }
3566e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3567146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        cursor.moveToFirst();
3568146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long calId = cursor.getLong(0);
3569697bd6a8cec36cc75c72603674e57e4c6fe42dbfKen Shirriff        cursor.close();
3570146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3571146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Uri uri = Calendars.CONTENT_URI;
3572146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String where = String.format(CALENDARS_WHERE, calId);
3573146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        cursor = cr.query(uri, CALENDARS_PROJECTION, where, null, null);
3574146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
35756d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        String calendarOwnerAccount = null;
3576146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (cursor != null) {
3577146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            cursor.moveToFirst();
3578146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            visibility = cursor.getInt(CALENDARS_INDEX_ACCESS_LEVEL);
35796d34cec523930368976bc8d358d0a6de1da3462cMichael Chan            calendarOwnerAccount = cursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
3580146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            cursor.close();
3581146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3582e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
35836d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        if (visibility < Calendars.CONTRIBUTOR_ACCESS) {
3584a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_NONE;
35856d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        }
3586146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
35876d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        if (e.guestsCanModify) {
3588a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_EDIT;
3589a505627659f6bfba8869eac8089f7030f2d0d92cErik        }
3590a505627659f6bfba8869eac8089f7030f2d0d92cErik
359146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        if (!TextUtils.isEmpty(calendarOwnerAccount)
359246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                && calendarOwnerAccount.equalsIgnoreCase(e.organizer)) {
3593a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_EDIT;
3594146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3595146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3596a505627659f6bfba8869eac8089f7030f2d0d92cErik        return ACCESS_LEVEL_DELETE;
3597146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3598146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3599146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
3600146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Sets mSelectionDay and mSelectionHour based on the (x,y) touch position.
3601146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * If the touch position is not within the displayed grid, then this
3602146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * method returns false.
3603146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
3604146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param x the x position of the touch
3605146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param y the y position of the touch
3606146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @return true if the touch position is valid
3607146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
3608360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan    private boolean setSelectionFromPosition(int x, final int y) {
3609146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (x < mHoursWidth) {
3610360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan            x = mHoursWidth;
3611146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3612146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3613146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int day = (x - mHoursWidth) / (mCellWidth + DAY_GAP);
3614146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (day >= mNumDays) {
3615146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            day = mNumDays - 1;
3616146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3617146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        day += mFirstJulianDay;
3618360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan        mSelectionDay = day;
3619360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan
3620360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan        if (y < DAY_HEADER_HEIGHT) {
3621360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan            return false;
3622360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan        }
362346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
362446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        mSelectionHour = mFirstHour; /* First fully visible hour */
362546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
362646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        if (y < mFirstCell) {
3627146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionAllDay = true;
3628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
362946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            // y is now offset from top of the scrollable region
363055a26d7062d5aa1a1b001b7271bb137276ab807eErik            int adjustedY = y - mFirstCell;
363146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
363255a26d7062d5aa1a1b001b7271bb137276ab807eErik            if (adjustedY < mFirstHourOffset) {
363346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan                --mSelectionHour; /* In the partially visible hour */
363446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            } else {
363555a26d7062d5aa1a1b001b7271bb137276ab807eErik                mSelectionHour += (adjustedY - mFirstHourOffset) / (mCellHeight + HOUR_GAP);
363646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            }
363746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
3638146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionAllDay = false;
3639146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3640360c67c9227c3e75cb4ea9b7350e3ed44b504f03Michael Chan
3641146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        findSelectedEvent(x, y);
364246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
364346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan//        Log.i("Cal", "setSelectionFromPosition( " + x + ", " + y + " ) day: " + day + " hour: "
364446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan//                + mSelectionHour + " mFirstCell: " + mFirstCell + " mFirstHourOffset: "
364546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan//                + mFirstHourOffset);
3646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//        if (mSelectedEvent != null) {
364746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan//            Log.i("Cal", "  num events: " + mSelectedEvents.size() + " event: "
364846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan//                    + mSelectedEvent.title);
3649146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            for (Event ev : mSelectedEvents) {
3650146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL
3651146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                        | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
365246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan//                String timeRange = formatDateRange(mContext, ev.startMillis, ev.endMillis, flags);
3653146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//
3654146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                Log.i("Cal", "  " + timeRange + " " + ev.title);
3655146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            }
3656146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//        }
3657146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return true;
3658146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3659146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3660146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void findSelectedEvent(int x, int y) {
3661146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int date = mSelectionDay;
3662146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cellWidth = mCellWidth;
366308ec68f143b718d300eb451047d3ba36dfae2e03Michael Chan        final ArrayList<Event> events = mEvents;
3664146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numEvents = events.size();
3665146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int left = mHoursWidth + (mSelectionDay - mFirstJulianDay) * (cellWidth + DAY_GAP);
3666146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int top = 0;
3667146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = null;
3668146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3669146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
3670146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionAllDay) {
3671146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float yDistance;
367246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            float minYdistance = 10000.0f; // any large number
3673146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event closestEvent = null;
3674146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float drawHeight = mAllDayHeight;
36753eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            int yOffset = DAY_HEADER_HEIGHT + ALLDAY_TOP_MARGIN;
3676146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int i = 0; i < numEvents; i++) {
3677146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event event = events.get(i);
3678d031419da7900dab91ac9f512374d7e59bb74dceErik                if (!event.drawAsAllDay()) {
3679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    continue;
3680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3681146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3682146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (event.startDay <= mSelectionDay && event.endDay >= mSelectionDay) {
3683146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float numRectangles = event.getMaxColumns();
3684146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float height = drawHeight / numRectangles;
3685f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                    if (height > MAX_HEIGHT_OF_ONE_ALLDAY_EVENT) {
3686f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                        height = MAX_HEIGHT_OF_ONE_ALLDAY_EVENT;
3687146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3688146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float eventTop = yOffset + height * event.getColumn();
3689146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float eventBottom = eventTop + height;
3690146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (eventTop < y && eventBottom > y) {
3691146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // If the touch is inside the event rectangle, then
3692146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // add the event.
3693146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        mSelectedEvents.add(event);
3694146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        closestEvent = event;
3695146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        break;
3696146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else {
3697146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // Find the closest event
3698146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (eventTop >= y) {
3699146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            yDistance = eventTop - y;
3700146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        } else {
3701146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            yDistance = y - eventBottom;
3702146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
3703146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (yDistance < minYdistance) {
3704146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            minYdistance = yDistance;
3705146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            closestEvent = event;
3706146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
3707146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3708146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3709146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = closestEvent;
3711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
3712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3713146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3714146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Adjust y for the scrollable bitmap
3715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        y += mViewStartY - mFirstCell;
3716146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3717146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Use a region around (x,y) for the selection region
3718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect region = mRect;
3719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.left = x - 10;
3720146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.right = x + 10;
3721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.top = y - 10;
3722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.bottom = y + 10;
3723146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        EventGeometry geometry = mEventGeometry;
3725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < numEvents; i++) {
3727146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(i);
3728146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Compute the event rectangle.
3729146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (!geometry.computeEventRect(date, left, top, cellWidth, event)) {
3730146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
3731146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3732146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3733146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If the event intersects the selection region, then add it to
3734146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // mSelectedEvents.
3735146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (geometry.eventIntersectsSelection(event, region)) {
3736146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvents.add(event);
3737146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3738146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3739146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3740146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If there are any events in the selected region, then assign the
3741146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // closest one to mSelectedEvent.
3742146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvents.size() > 0) {
3743146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int len = mSelectedEvents.size();
3744146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event closestEvent = null;
374546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            float minDist = mViewWidth + mViewHeight; // some large distance
3746146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int index = 0; index < len; index++) {
3747146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event ev = mSelectedEvents.get(index);
3748146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                float dist = geometry.pointToEvent(x, y, ev);
3749146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (dist < minDist) {
3750146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    minDist = dist;
3751146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    closestEvent = ev;
3752146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3753146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3754146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = closestEvent;
3755146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Keep the selected hour and day consistent with the selected
375746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            // event. They could be different if we touched on an empty hour
375846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            // slot very close to an event in the previous hour slot. In
3759146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // that case we will select the nearby event.
3760146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startDay = mSelectedEvent.startDay;
3761146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endDay = mSelectedEvent.endDay;
3762146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionDay < startDay) {
3763146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionDay = startDay;
3764146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionDay > endDay) {
3765146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionDay = endDay;
3766146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3767146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3768146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startHour = mSelectedEvent.startTime / 60;
3769146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endHour;
3770146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent.startTime < mSelectedEvent.endTime) {
3771146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                endHour = (mSelectedEvent.endTime - 1) / 60;
3772146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3773146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                endHour = mSelectedEvent.endTime / 60;
3774146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3775146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3776146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionHour < startHour) {
3777146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionHour = startHour;
3778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionHour > endHour) {
3779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionHour = endHour;
3780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3781146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3782146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3783146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3784146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Encapsulates the code to continue the scrolling after the
378546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    // finger is lifted. Instead of stopping the scroll immediately,
3786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // the scroll continues to "free spin" and gradually slows down.
3787146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private class ContinueScroll implements Runnable {
3788146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int mSignDeltaY;
3789146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int mAbsDeltaY;
3790146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float mFloatDeltaY;
3791146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long mFreeSpinTime;
3792146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final float FRICTION_COEF = 0.7F;
3793146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final long FREE_SPIN_MILLIS = 180;
3794146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final int MAX_DELTA = 60;
3795146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final int SCROLL_REPEAT_INTERVAL = 30;
3796146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3797146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void init(int deltaY) {
3798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSignDeltaY = 0;
3799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (deltaY > 0) {
3800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSignDeltaY = 1;
3801146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (deltaY < 0) {
3802146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSignDeltaY = -1;
3803146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3804146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mAbsDeltaY = Math.abs(deltaY);
3805146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3806146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Limit the maximum speed
3807146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mAbsDeltaY > MAX_DELTA) {
3808146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mAbsDeltaY = MAX_DELTA;
3809146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3810146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFloatDeltaY = mAbsDeltaY;
3811146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFreeSpinTime = System.currentTimeMillis() + FREE_SPIN_MILLIS;
3812146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            Log.i("Cal", "init scroll: mAbsDeltaY: " + mAbsDeltaY
3813146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                    + " mViewStartY: " + mViewStartY);
3814146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3815146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3816146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void run() {
3817146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            long time = System.currentTimeMillis();
3818146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3819146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Start out with a frictionless "free spin"
3820146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (time > mFreeSpinTime) {
3821146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // If the delta is small, then apply a fixed deceleration.
3822146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Otherwise
3823146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mAbsDeltaY <= 10) {
3824146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mAbsDeltaY -= 2;
3825146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
3826146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mFloatDeltaY *= FRICTION_COEF;
3827146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mAbsDeltaY = (int) mFloatDeltaY;
3828146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3829146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3830146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mAbsDeltaY < 0) {
3831146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mAbsDeltaY = 0;
3832146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3833146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3834146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3835146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSignDeltaY == 1) {
3836146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY -= mAbsDeltaY;
3837146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3838146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY += mAbsDeltaY;
3839146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3840146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            Log.i("Cal", "  scroll: mAbsDeltaY: " + mAbsDeltaY
3841146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                    + " mViewStartY: " + mViewStartY);
3842146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3843146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mViewStartY < 0) {
3844146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = 0;
3845146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mAbsDeltaY = 0;
3846146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mViewStartY > mMaxViewStartY) {
3847146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = mMaxViewStartY;
3848146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mAbsDeltaY = 0;
3849146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3850146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3851146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeFirstHour();
3852146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3853146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mAbsDeltaY > 0) {
3854146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                postDelayed(this, SCROLL_REPEAT_INTERVAL);
3855146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3856146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Done scrolling.
3857146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mScrolling = false;
3858146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                resetSelectedHour();
3859146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3860146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3861146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            invalidate();
3862146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3863146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3864146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3865146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
3866bd0e834aea317236d574f8738fe11a51fdc87968Erik     * Cleanup the pop-up and timers.
3867146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
3868146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void cleanup() {
3869146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Protect against null-pointer exceptions
3870146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mPopup != null) {
3871146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPopup.dismiss();
3872146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3873666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = INVALID_EVENT_ID;
3874146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Handler handler = getHandler();
3875146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (handler != null) {
3876146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            handler.removeCallbacks(mDismissPopup);
3877bd0e834aea317236d574f8738fe11a51fdc87968Erik            handler.removeCallbacks(mUpdateCurrentTime);
3878146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3879e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3880d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        Utils.setSharedPreference(mContext, GeneralPreferences.KEY_DEFAULT_CELL_HEIGHT,
3881d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeight);
3882d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
38837abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project        // Turn off redraw
38847abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project        mRemeasure = false;
3885146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3886146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3887bd0e834aea317236d574f8738fe11a51fdc87968Erik    /**
3888bd0e834aea317236d574f8738fe11a51fdc87968Erik     * Restart the update timer
3889bd0e834aea317236d574f8738fe11a51fdc87968Erik     */
3890bd0e834aea317236d574f8738fe11a51fdc87968Erik    public void restartCurrentTimeUpdates() {
3891bd0e834aea317236d574f8738fe11a51fdc87968Erik        post(mUpdateCurrentTime);
3892bd0e834aea317236d574f8738fe11a51fdc87968Erik    }
3893bd0e834aea317236d574f8738fe11a51fdc87968Erik
389446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    @Override
389546a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    protected void onDetachedFromWindow() {
3896146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        cleanup();
3897146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        super.onDetachedFromWindow();
3898146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3899146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3900146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    class DismissPopup implements Runnable {
3901146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void run() {
3902146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Protect against null-pointer exceptions
3903146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mPopup != null) {
3904146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPopup.dismiss();
3905146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3906146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3907146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3908bd0e834aea317236d574f8738fe11a51fdc87968Erik
3909bd0e834aea317236d574f8738fe11a51fdc87968Erik    class UpdateCurrentTime implements Runnable {
3910bd0e834aea317236d574f8738fe11a51fdc87968Erik        public void run() {
3911bd0e834aea317236d574f8738fe11a51fdc87968Erik            long currentTime = System.currentTimeMillis();
3912bd0e834aea317236d574f8738fe11a51fdc87968Erik            mCurrentTime.set(currentTime);
3913bd0e834aea317236d574f8738fe11a51fdc87968Erik            //% causes update to occur on 5 minute marks (11:10, 11:15, 11:20, etc.)
3914bd0e834aea317236d574f8738fe11a51fdc87968Erik            postDelayed(mUpdateCurrentTime,
3915bd0e834aea317236d574f8738fe11a51fdc87968Erik                    UPDATE_CURRENT_TIME_DELAY - (currentTime % UPDATE_CURRENT_TIME_DELAY));
3916bd0e834aea317236d574f8738fe11a51fdc87968Erik            mTodayJulianDay = Time.getJulianDay(currentTime, mCurrentTime.gmtoff);
3917bd0e834aea317236d574f8738fe11a51fdc87968Erik            invalidate();
3918bd0e834aea317236d574f8738fe11a51fdc87968Erik        }
3919bd0e834aea317236d574f8738fe11a51fdc87968Erik    }
3920ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3921ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener {
3922ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3923ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onSingleTapUp(MotionEvent ev) {
3924d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doSingleTapUp(ev);
3925ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3926ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3927ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3928ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3929ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public void onLongPress(MotionEvent ev) {
3930d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doLongPress(ev);
3931ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3932ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3933ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3934ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
3935d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doScroll(e1, e2, distanceX, distanceY);
3936ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3937ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3938ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3939ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3940ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
3941d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doFling(e1, e2, velocityX, velocityY);
3942ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3943ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3944ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3945ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3946ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onDown(MotionEvent ev) {
3947d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doDown(ev);
3948ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3949ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3950ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    }
3951cd405a28e6821b116dcf3c531805d0c90b6cc08cErik
3952cd405a28e6821b116dcf3c531805d0c90b6cc08cErik    @Override
3953cd405a28e6821b116dcf3c531805d0c90b6cc08cErik    public boolean onLongClick(View v) {
3954cd405a28e6821b116dcf3c531805d0c90b6cc08cErik        mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
395587f993ff96172f508d3f241f8a425f953c7eb739RoboErik                getSelectedTimeInMillis(), 0, -1, -1, -1);
3956cd405a28e6821b116dcf3c531805d0c90b6cc08cErik        return true;
3957cd405a28e6821b116dcf3c531805d0c90b6cc08cErik    }
3958146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project}
3959