DayView.java revision c5f92d7bdeb1950ace783cc022aa41a4b4f00cd6
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
22146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.ContentResolver;
23146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.ContentUris;
24146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Context;
25146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.res.Resources;
26146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.res.TypedArray;
27146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.database.Cursor;
28146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Canvas;
29146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Paint;
30dd95df57c8c5a58a85c4c0effad5652dec14f621Erikimport android.graphics.Paint.Style;
31146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Path;
32dd95df57c8c5a58a85c4c0effad5652dec14f621Erikimport android.graphics.Path.Direction;
33146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Rect;
34146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.RectF;
35146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Typeface;
36c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawaimport android.graphics.drawable.Drawable;
37146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.net.Uri;
38146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Handler;
39146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Attendees;
40146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Calendars;
41146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Events;
423e7015267340b09d142dfcd3ff8acda257711023Shachar Shemeshimport android.text.Layout.Alignment;
43f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chanimport android.text.StaticLayout;
443e7015267340b09d142dfcd3ff8acda257711023Shachar Shemeshimport android.text.TextPaint;
45f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chanimport android.text.TextUtils;
46146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.DateFormat;
47146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.DateUtils;
48146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.Time;
49146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.util.Log;
50146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ContextMenu;
51dd95df57c8c5a58a85c4c0effad5652dec14f621Erikimport android.view.ContextMenu.ContextMenuInfo;
52ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.GestureDetector;
53146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.Gravity;
54146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.KeyEvent;
55146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.LayoutInflater;
56146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.MenuItem;
57146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.MotionEvent;
58d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chanimport android.view.ScaleGestureDetector;
59146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.View;
60146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ViewConfiguration;
61146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ViewGroup;
62146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.WindowManager;
63ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.animation.Animation;
64ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.animation.TranslateAnimation;
65146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.ImageView;
66146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.PopupWindow;
67146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.TextView;
68ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.widget.ViewSwitcher;
69146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
70146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport java.util.ArrayList;
71c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawaimport java.util.Arrays;
72146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport java.util.Calendar;
730d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chanimport java.util.regex.Matcher;
740d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chanimport java.util.regex.Pattern;
75146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
76146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/**
77d190418220467c02327dd9b3ae1eae238889720bMichael Chan * View for multi-day view. So far only 1 and 7 day have been tested.
78d190418220467c02327dd9b3ae1eae238889720bMichael Chan */
79d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chanpublic class DayView extends View implements View.OnCreateContextMenuListener,
80d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        ScaleGestureDetector.OnScaleGestureListener, View.OnClickListener {
81d190418220467c02327dd9b3ae1eae238889720bMichael Chan    private static String TAG = "DayView";
82d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private static boolean DEBUG = false;
83146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
84705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static float mScale = 0; // Used for supporting different screen densities
85666fc5e8ddbac15c951aad738bd818ee307eae42Erik    private static final long INVALID_EVENT_ID = -1; //This is used for remembering a null event
86ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private static final long ANIMATION_DURATION = 400;
87705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
884484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_AGENDA = 2;
894484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_DAY = 3;
904484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_VIEW = 5;
914484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_CREATE = 6;
924484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_EDIT = 7;
934484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_DELETE = 8;
944484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan
9511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan    private static int DEFAULT_CELL_HEIGHT = 64;
96d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private static int MAX_CELL_HEIGHT = 150;
97d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private static int MIN_Y_SPAN = 100;
98d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
99146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mOnFlingCalled;
100666fc5e8ddbac15c951aad738bd818ee307eae42Erik    /**
101666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * ID of the last event which was displayed with the toast popup.
102666fc5e8ddbac15c951aad738bd818ee307eae42Erik     *
103666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * This is used to prevent popping up multiple quick views for the same event, especially
104666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * during calendar syncs. This becomes valid when an event is selected, either by default
105666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * on starting calendar or by scrolling to an event. It becomes invalid when the user
106666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * explicitly scrolls to an empty time slot, changes views, or deletes the event.
107666fc5e8ddbac15c951aad738bd818ee307eae42Erik     */
108666fc5e8ddbac15c951aad738bd818ee307eae42Erik    private long mLastPopupEventID;
109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
110ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    protected Context mContext;
111146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
112146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String[] CALENDARS_PROJECTION = new String[] {
113146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Calendars._ID,          // 0
114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Calendars.ACCESS_LEVEL, // 1
1156d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        Calendars.OWNER_ACCOUNT, // 2
116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
117146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int CALENDARS_INDEX_ACCESS_LEVEL = 1;
1186d34cec523930368976bc8d358d0a6de1da3462cMichael Chan    private static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2;
119146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String CALENDARS_WHERE = Calendars._ID + "=%d";
120146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String[] ATTENDEES_PROJECTION = new String[] {
122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Attendees._ID,                      // 0
123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Attendees.ATTENDEE_RELATIONSHIP,    // 1
124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ATTENDEES_INDEX_RELATIONSHIP = 1;
126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=%d";
127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
128146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_NONE = 0;
129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_ABOVE = 1;
130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_BELOW = 2;
131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_LEFT = 4;
132146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_RIGHT = 8;
133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
134a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static final int ACCESS_LEVEL_NONE = 0;
135a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static final int ACCESS_LEVEL_DELETE = 1;
136a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static final int ACCESS_LEVEL_EDIT = 2;
137a505627659f6bfba8869eac8089f7030f2d0d92cErik
138705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int HORIZONTAL_SCROLL_THRESHOLD = 50;
139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ContinueScroll mContinueScroll = new ContinueScroll();
141146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Make this visible within the package for more informative debugging
143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Time mBaseDate;
144bd0e834aea317236d574f8738fe11a51fdc87968Erik    private Time mCurrentTime;
145bd0e834aea317236d574f8738fe11a51fdc87968Erik    //Update the current time line every five minutes if the window is left open that long
146bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static final int UPDATE_CURRENT_TIME_DELAY = 300000;
147bd0e834aea317236d574f8738fe11a51fdc87968Erik    private UpdateCurrentTime mUpdateCurrentTime = new UpdateCurrentTime();
148bd0e834aea317236d574f8738fe11a51fdc87968Erik    private int mTodayJulianDay;
149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Typeface mBold = Typeface.DEFAULT_BOLD;
151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstJulianDay;
152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mLastJulianDay;
153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mMonthLength;
155487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    private int mFirstVisibleDate;
156487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    private int mFirstVisibleDayOfWeek;
157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int[] mEarliestStartHour;    // indexed by the week day offset
158146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean[] mHasAllDayEvent;   // indexed by the week day offset
159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
160731f1cb808b7586b93615b408ab2636081fab0dcErik    private Runnable mTZUpdater = new Runnable() {
161731f1cb808b7586b93615b408ab2636081fab0dcErik        @Override
162731f1cb808b7586b93615b408ab2636081fab0dcErik        public void run() {
163731f1cb808b7586b93615b408ab2636081fab0dcErik            String tz = Utils.getTimeZone(mContext, this);
164731f1cb808b7586b93615b408ab2636081fab0dcErik            mBaseDate.timezone = tz;
165731f1cb808b7586b93615b408ab2636081fab0dcErik            mBaseDate.normalize(true);
166731f1cb808b7586b93615b408ab2636081fab0dcErik            mCurrentTime.switchTimezone(tz);
167731f1cb808b7586b93615b408ab2636081fab0dcErik            invalidate();
168731f1cb808b7586b93615b408ab2636081fab0dcErik        }
169731f1cb808b7586b93615b408ab2636081fab0dcErik    };
170731f1cb808b7586b93615b408ab2636081fab0dcErik
171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
172146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * This variable helps to avoid unnecessarily reloading events by keeping
173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * track of the start millis parameter used for the most recent loading
174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * of events.  If the next reload matches this, then the events are not
175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * reloaded.  To force a reload, set this to zero (this is set to zero
176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * in the method clearCachedEvents()).
177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private long mLastReloadMillis;
179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ArrayList<Event> mEvents = new ArrayList<Event>();
1813e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    private ArrayList<StaticLayout> mLayouts = new ArrayList<StaticLayout>();
182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mSelectionDay;        // Julian day
183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mSelectionHour;
184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    boolean mSelectionAllDay;
186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1873eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    /** Width of a day or non-conflicting event */
188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mCellWidth;
189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Pre-allocate these objects and re-use them
191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect mRect = new Rect();
192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private RectF mRectF = new RectF();
193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect mDestRect = new Rect();
194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Paint mPaint = new Paint();
195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Paint mEventTextPaint = new Paint();
196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Paint mSelectionPaint = new Paint();
197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Path mPath = new Path();
19802041687c35441e8a21cb763f1fc3a26525292efDavid Brown    private float[] mLines;
199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
200487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    private int mFirstDayOfWeek; // First day of the week
201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private PopupWindow mPopup;
203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private View mPopupView;
204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // The number of milliseconds to show the popup window
206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int POPUP_DISMISS_DELAY = 3000;
207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private DismissPopup mDismissPopup = new DismissPopup();
208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mRemeasure = true;
210146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private final EventLoader mEventLoader;
212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected final EventGeometry mEventGeometry;
213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2143eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static final int GRID_LINE_INNER_WIDTH = 1;
2153eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static final int GRID_LINE_WIDTH = 5;
2163eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int DAY_GAP = 1;
218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int HOUR_GAP = 1;
2199c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    private static int SINGLE_ALLDAY_HEIGHT = 34;
2209c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    private static int MAX_ALLDAY_HEIGHT = 100;
221705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int ALLDAY_TOP_MARGIN = 3;
222f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan    private static int MAX_HEIGHT_OF_ONE_ALLDAY_EVENT = 34;
223e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* The extra space to leave above the text in all-day events */
225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALL_DAY_TEXT_TOP_MARGIN = 0;
226e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* The extra space to leave above the text in normal events */
228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int NORMAL_TEXT_TOP_MARGIN = 2;
229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int HOURS_LEFT_MARGIN = 2;
231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int HOURS_RIGHT_MARGIN = 4;
232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int HOURS_MARGIN = HOURS_LEFT_MARGIN + HOURS_RIGHT_MARGIN;
233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
234bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int CURRENT_TIME_LINE_HEIGHT = 2;
235bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int CURRENT_TIME_LINE_BORDER_WIDTH = 1;
2363eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static final int CURRENT_TIME_LINE_SIDE_BUFFER = 3;
237bd0e834aea317236d574f8738fe11a51fdc87968Erik
238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MINUTES_PER_HOUR = 60;
239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * 24;
240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MILLIS_PER_MINUTE = 60 * 1000;
241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MILLIS_PER_HOUR = (3600 * 1000);
242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MILLIS_PER_DAY = MILLIS_PER_HOUR * 24;
243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2443eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static final int DAY_HEADER_ALPHA = 0x26000000;
2453eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static final int DAY_HEADER_TODAY_ALPHA = 0x99000000;
246c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik    // TODO replace event draws with assets
247c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik    private static final int EVENT_OUTLINE_COLOR = 0x33333333;
24811ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan    private static float DAY_HEADER_ONE_DAY_LEFT_MARGIN = -12;
2493eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_ONE_DAY_RIGHT_MARGIN = 5;
2503eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_ONE_DAY_BOTTOM_MARGIN = 6;
2513eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_LEFT_MARGIN = 5;
2523eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_RIGHT_MARGIN = 7;
2533eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_BOTTOM_MARGIN = 3;
2543eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DAY_HEADER_FONT_SIZE = 14;
2553eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float DATE_HEADER_FONT_SIZE = 24;
2563eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float NORMAL_FONT_SIZE = 12;
2573eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float EVENT_TEXT_FONT_SIZE = 12;
2583eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float HOURS_FONT_SIZE = 12;
2593eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float AMPM_FONT_SIZE = 9;
260705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int MIN_CELL_WIDTH_FOR_TEXT = 27;
261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int MAX_EVENT_TEXT_LEN = 500;
262705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static float MIN_EVENT_HEIGHT = 15.0F;  // in pixels
2633eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static float CALENDAR_COLOR_SQUARE_SIZE = 11;
264c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik    private static float EVENT_RECT_TOP_MARGIN = 1;
26511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan    private static float EVENT_RECT_BOTTOM_MARGIN = 1;
266c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik    private static float EVENT_RECT_LEFT_MARGIN = 1;
26711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan    private static float EVENT_RECT_RIGHT_MARGIN = 1;
26811ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan    private static float EVENT_TEXT_TOP_MARGIN = 8;
26911ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan    private static float EVENT_TEXT_BOTTOM_MARGIN = 5;
27011ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan    private static float EVENT_TEXT_LEFT_MARGIN = 8;
27111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan    private static float EVENT_TEXT_RIGHT_MARGIN = 7;
2729c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    private static float EVENT_ALL_DAY_TEXT_TOP_MARGIN = 4;
2739c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    private static float EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN = 2;
2749c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    private static float EVENT_ALL_DAY_TEXT_LEFT_MARGIN = EVENT_TEXT_LEFT_MARGIN;
2759c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    private static float EVENT_ALL_DAY_TEXT_RIGHT_MARGIN = EVENT_TEXT_RIGHT_MARGIN;
276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static int mSelectionColor;
278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static int mPressedColor;
279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static int mSelectedEventTextColor;
280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static int mEventTextColor;
28164b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok    private static int mWeek_saturdayColor;
28264b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok    private static int mWeek_sundayColor;
283d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarDateBannerTextColor;
2843eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//    private static int mCalendarAllDayBackground;
285d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarAmPmLabel;
2863eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//    private static int mCalendarDateBannerBackground;
28711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan//    private static int mCalendarDateSelected;
2883eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//    private static int mCalendarGridAreaBackground;
289ba902466b19b11d587468e354edc58e542707747Michael Chan    private static int mCalendarGridAreaSelected;
290d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarGridLineHorizontalColor;
291d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarGridLineVerticalColor;
2923eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static int mCalendarGridLineInnerHorizontalColor;
2933eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static int mCalendarGridLineInnerVerticalColor;
2943eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//    private static int mCalendarHourBackground;
295d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarHourLabel;
29611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan//    private static int mCalendarHourSelected;
297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewStartX;
299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewStartY;
300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mMaxViewStartY;
301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewHeight;
302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewWidth;
303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mGridAreaHeight;
304d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private static int mCellHeight = 0; // shared among all DayViews
305d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private static int mMinCellHeight = 32;
306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mScrollStartY;
307146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mPreviousDirection;
308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
309d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    /**
310d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     * Vertical distance or span between the two touch points at the start of a
311d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     * scaling gesture
312d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     */
313d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private float mStartingSpanY = 0;
314d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    /** Height of 1 hour in pixels at the start of a scaling gesture */
315d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private int mCellHeightBeforeScaleGesture;
316d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    /** The hour at the center two touch points */
317d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private float mGestureCenterHour = 0;
318d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    /**
319d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     * Flag to decide whether to handle the up event. Cases where up events
320d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     * should be ignored are 1) right after a scale gesture and 2) finger was
321d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     * down before app launch
322d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan     */
323d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    private boolean mHandleActionUp = true;
324d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mHoursTextHeight;
326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mAllDayHeight;
3273eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private static int DAY_HEADER_HEIGHT = 45;
328f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan    /**
329f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan     * Max of all day events in a given day in this view.
330f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan     */
331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mMaxAllDayEvents;
332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected int mNumDays = 7;
334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mNumHours = 10;
3353eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
3363eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    /** Width of the time line (list of hours) to the left. */
337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mHoursWidth;
338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mDateStrWidth;
339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstCell;
340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstHour = -1;
341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstHourOffset;
342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String[] mHourStrs;
343146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String[] mDayStrs;
344146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String[] mDayStrs2Letter;
345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mIs24HourFormat;
346146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ArrayList<Event> mSelectedEvents = new ArrayList<Event>();
348146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mComputeSelectedEvents;
349146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Event mSelectedEvent;
350146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Event mPrevSelectedEvent;
3513e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    /*
3523e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh     * Cache of mSelectedEvent's corresponding StaticLayout. Set this to null whenever you change
3533e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh     * mSelectedEvent.
3543e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh     */
3553e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    private StaticLayout mSelectedLayout;
356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect mPrevBox = new Rect();
357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected final Resources mResources;
3583eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    protected final Drawable mCurrentTimeLine;
3593eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    protected final Drawable mTodayHeaderDrawable;
36011638ad4fb56b978770aebe75deac7a0e6ac60d2Erik    // TODO change back to using background image when we can make it fast enough
36111638ad4fb56b978770aebe75deac7a0e6ac60d2Erik    // protected final Drawable mBackgroundDrawable;
36211638ad4fb56b978770aebe75deac7a0e6ac60d2Erik    protected int mBackgroundColor;
363146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String mAmString;
364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String mPmString;
365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private DeleteEventHelper mDeleteEventHelper;
366146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ContextMenuHandler mContextMenuHandler = new ContextMenuHandler();
368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
369d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    ScaleGestureDetector mScaleGestureDetector;
370d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
371146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
372146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * The initial state of the touch mode when we enter this view.
373146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
374146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_INITIAL_STATE = 0;
375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
376146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Indicates we just received the touch event and we are waiting to see if
378146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * it is a tap or a scroll gesture.
379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
380146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_DOWN = 1;
381146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
382146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
383146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Indicates the touch gesture is a vertical scroll
384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_VSCROLL = 0x20;
386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
387146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
388146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Indicates the touch gesture is a horizontal scroll
389146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_HSCROLL = 0x40;
391146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
392146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mTouchMode = TOUCH_MODE_INITIAL_STATE;
393146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
394146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
395146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * The selection modes are HIDDEN, PRESSED, SELECTED, and LONGPRESS.
396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
397146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_HIDDEN = 0;
398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_PRESSED = 1;
399146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_SELECTED = 2;
400146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_LONGPRESS = 3;
401146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
402146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mSelectionMode = SELECTION_HIDDEN;
403146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
404146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mScrolling = false;
405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
406ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private CalendarController mController;
407ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private ViewSwitcher mViewSwitcher;
408ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private GestureDetector mGestureDetector;
409705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
410d190418220467c02327dd9b3ae1eae238889720bMichael Chan    public DayView(Context context, CalendarController controller,
41175d9b567e1fd3b9c6945cd0afe28781f5a19c6c8Michael Chan            ViewSwitcher viewSwitcher, EventLoader eventLoader, int numDays) {
412ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        super(context);
413705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan        if (mScale == 0) {
414705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan            mScale = getContext().getResources().getDisplayMetrics().density;
415705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan            if (mScale != 1) {
416705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                SINGLE_ALLDAY_HEIGHT *= mScale;
417705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                ALLDAY_TOP_MARGIN *= mScale;
418f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                MAX_HEIGHT_OF_ONE_ALLDAY_EVENT *= mScale;
419705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
420705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                NORMAL_FONT_SIZE *= mScale;
421705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                EVENT_TEXT_FONT_SIZE *= mScale;
422705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                HOURS_FONT_SIZE *= mScale;
423705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                AMPM_FONT_SIZE *= mScale;
424705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                MIN_CELL_WIDTH_FOR_TEXT *= mScale;
425705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                MIN_EVENT_HEIGHT *= mScale;
426705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
427705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                HORIZONTAL_SCROLL_THRESHOLD *= mScale;
428e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
429bd0e834aea317236d574f8738fe11a51fdc87968Erik                CURRENT_TIME_LINE_HEIGHT *= mScale;
430bd0e834aea317236d574f8738fe11a51fdc87968Erik                CURRENT_TIME_LINE_BORDER_WIDTH *= mScale;
431bd0e834aea317236d574f8738fe11a51fdc87968Erik
432d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                MIN_Y_SPAN *= mScale;
433d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                MAX_CELL_HEIGHT *= mScale;
434697157470a6f0d8e7b806af9b4fb7fbe0bccae87Erik                DEFAULT_CELL_HEIGHT *= mScale;
4353eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_HEIGHT *= mScale;
4363eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_LEFT_MARGIN *= mScale;
4373eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_RIGHT_MARGIN *= mScale;
4383eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_BOTTOM_MARGIN *= mScale;
4393eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_ONE_DAY_LEFT_MARGIN *= mScale;
4403eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_ONE_DAY_RIGHT_MARGIN *= mScale;
4413eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_ONE_DAY_BOTTOM_MARGIN *= mScale;
4423eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DAY_HEADER_FONT_SIZE *= mScale;
4433eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                DATE_HEADER_FONT_SIZE *= mScale;
4443eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                CALENDAR_COLOR_SQUARE_SIZE *= mScale;
4453eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                EVENT_TEXT_TOP_MARGIN *= mScale;
4463eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                EVENT_TEXT_BOTTOM_MARGIN *= mScale;
4473eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                EVENT_TEXT_LEFT_MARGIN *= mScale;
4483eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                EVENT_TEXT_RIGHT_MARGIN *= mScale;
4499c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                EVENT_ALL_DAY_TEXT_TOP_MARGIN *= mScale;
4509c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN *= mScale;
4519c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                EVENT_ALL_DAY_TEXT_LEFT_MARGIN *= mScale;
4529c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                EVENT_ALL_DAY_TEXT_RIGHT_MARGIN *= mScale;
45311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                EVENT_RECT_TOP_MARGIN *= mScale;
45411ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                EVENT_RECT_BOTTOM_MARGIN *= mScale;
45511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                EVENT_RECT_LEFT_MARGIN *= mScale;
45611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                EVENT_RECT_RIGHT_MARGIN *= mScale;
457705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan            }
458705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan        }
459705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
460ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mResources = context.getResources();
4613eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mCurrentTimeLine = mResources.getDrawable(R.drawable.timeline_week_holo_light);
4623eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mTodayHeaderDrawable = mResources.getDrawable(R.drawable.today_blue_week_holo_light);
46311638ad4fb56b978770aebe75deac7a0e6ac60d2Erik        // mBackgroundDrawable = mResources.getDrawable(R.drawable.calendar_background_holo_light);
464ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mEventLoader = eventLoader;
465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry = new EventGeometry();
466146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry.setMinEventHeight(MIN_EVENT_HEIGHT);
467146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry.setHourGap(HOUR_GAP);
468ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mContext = context;
469ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mDeleteEventHelper = new DeleteEventHelper(context, null, false /* don't exit when done */);
470666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = INVALID_EVENT_ID;
471ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mController = controller;
472ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher = viewSwitcher;
473ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mGestureDetector = new GestureDetector(context, new CalendarGestureListener());
474d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mScaleGestureDetector = new ScaleGestureDetector(getContext(), this);
47575d9b567e1fd3b9c6945cd0afe28781f5a19c6c8Michael Chan        mNumDays = numDays;
476d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mCellHeight == 0) {
477d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeight = Utils.getSharedPreference(mContext,
478d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    GeneralPreferences.KEY_DEFAULT_CELL_HEIGHT, DEFAULT_CELL_HEIGHT);
479d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
480146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
481ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        init(context);
482146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
483146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
484146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void init(Context context) {
485146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setFocusable(true);
486146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
487146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Allow focus in touch mode so that we can do keyboard shortcuts
488146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // even after we've entered touch mode.
489146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setFocusableInTouchMode(true);
490146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setClickable(true);
491146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setOnCreateContextMenuListener(this);
492146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
493487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mFirstDayOfWeek = Utils.getFirstDayOfWeek(context);
494146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
495731f1cb808b7586b93615b408ab2636081fab0dcErik        mCurrentTime = new Time(Utils.getTimeZone(context, mTZUpdater));
496bd0e834aea317236d574f8738fe11a51fdc87968Erik        long currentTime = System.currentTimeMillis();
497bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTime.set(currentTime);
498bd0e834aea317236d574f8738fe11a51fdc87968Erik        //The % makes it go off at the next increment of 5 minutes.
499bd0e834aea317236d574f8738fe11a51fdc87968Erik        postDelayed(mUpdateCurrentTime,
500bd0e834aea317236d574f8738fe11a51fdc87968Erik                UPDATE_CURRENT_TIME_DELAY - (currentTime % UPDATE_CURRENT_TIME_DELAY));
501bd0e834aea317236d574f8738fe11a51fdc87968Erik        mTodayJulianDay = Time.getJulianDay(currentTime, mCurrentTime.gmtoff);
502bd0e834aea317236d574f8738fe11a51fdc87968Erik
50364b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok        mWeek_saturdayColor = mResources.getColor(R.color.week_saturday);
50464b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok        mWeek_sundayColor = mResources.getColor(R.color.week_sunday);
505d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarDateBannerTextColor = mResources.getColor(R.color.calendar_date_banner_text_color);
5063eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        mCalendarAllDayBackground = mResources.getColor(R.color.calendar_all_day_background);
507d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarAmPmLabel = mResources.getColor(R.color.calendar_ampm_label);
5083eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        mCalendarDateBannerBackground = mResources.getColor(R.color.calendar_date_banner_background);
50911ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan//        mCalendarDateSelected = mResources.getColor(R.color.calendar_date_selected);
5103eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        mCalendarGridAreaBackground = mResources.getColor(R.color.calendar_grid_area_background);
511ba902466b19b11d587468e354edc58e542707747Michael Chan        mCalendarGridAreaSelected = mResources.getColor(R.color.calendar_grid_area_selected);
512d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarGridLineHorizontalColor = mResources.getColor(R.color.calendar_grid_line_horizontal_color);
513d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarGridLineVerticalColor = mResources.getColor(R.color.calendar_grid_line_vertical_color);
5143eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mCalendarGridLineInnerHorizontalColor = mResources.getColor(R.color.calendar_grid_line_inner_horizontal_color);
5153eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mCalendarGridLineInnerVerticalColor = mResources.getColor(R.color.calendar_grid_line_inner_vertical_color);
5163eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        mCalendarHourBackground = mResources.getColor(R.color.calendar_hour_background);
517d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarHourLabel = mResources.getColor(R.color.calendar_hour_label);
51811ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan//        mCalendarHourSelected = mResources.getColor(R.color.calendar_hour_selected);
519146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionColor = mResources.getColor(R.color.selection);
520146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPressedColor = mResources.getColor(R.color.pressed);
521146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEventTextColor = mResources.getColor(R.color.calendar_event_selected_text_color);
522146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextColor = mResources.getColor(R.color.calendar_event_text_color);
52311638ad4fb56b978770aebe75deac7a0e6ac60d2Erik
52411638ad4fb56b978770aebe75deac7a0e6ac60d2Erik        // TODO remove this
52511638ad4fb56b978770aebe75deac7a0e6ac60d2Erik        mBackgroundColor = mResources.getColor(R.color.month_bgcolor);
52611638ad4fb56b978770aebe75deac7a0e6ac60d2Erik
527146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setColor(mEventTextColor);
528146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setTextSize(EVENT_TEXT_FONT_SIZE);
529146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setTextAlign(Paint.Align.LEFT);
530146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setAntiAlias(true);
531146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
532146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int gridLineColor = mResources.getColor(R.color.calendar_grid_line_highlight_color);
533146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = mSelectionPaint;
534146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setColor(gridLineColor);
5353937a47bc5a1afb9701e1d0565fae31f5800590dErik        p.setStyle(Style.FILL);
536146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(false);
537146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
538146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p = mPaint;
539146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
540146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
541146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Allocate space for 2 weeks worth of weekday names so that we can
542146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // easily start the week display at any week day.
543146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDayStrs = new String[14];
544146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
545146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Also create an array of 2-letter abbreviations.
546146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDayStrs2Letter = new String[14];
547146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
548146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
549146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int index = i - Calendar.SUNDAY;
550146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // e.g. Tue for Tuesday
551146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_MEDIUM);
552146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs[index + 7] = mDayStrs[index];
553146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // e.g. Tu for Tuesday
554146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs2Letter[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_SHORT);
55552b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer
55652b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer            // If we don't have 2-letter day strings, fall back to 1-letter.
55752b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer            if (mDayStrs2Letter[index].equals(mDayStrs[index])) {
55852b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer                mDayStrs2Letter[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_SHORTEST);
55952b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer            }
56052b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer
561146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs2Letter[index + 7] = mDayStrs2Letter[index];
562146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
563146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
564146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Figure out how much space we need for the 3-letter abbrev names
565146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // in the worst case.
5663eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setTextSize(DATE_HEADER_FONT_SIZE);
567146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(mBold);
568146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String[] dateStrs = {" 28", " 30"};
569146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDateStrWidth = computeMaxStringWidth(0, dateStrs, p);
5703eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setTextSize(DAY_HEADER_FONT_SIZE);
571146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDateStrWidth += computeMaxStringWidth(0, mDayStrs, p);
572146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
573146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(HOURS_FONT_SIZE);
574146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(null);
57569ab334d6988eda70ba53618506d23ebf7d7b405Erik        updateIs24HourFormat();
576146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
577146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mAmString = DateUtils.getAMPMString(Calendar.AM);
578146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPmString = DateUtils.getAMPMString(Calendar.PM);
579146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String[] ampm = {mAmString, mPmString};
580146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(AMPM_FONT_SIZE);
581146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mHoursWidth = computeMaxStringWidth(mHoursWidth, ampm, p);
582146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mHoursWidth += HOURS_MARGIN;
583146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
584146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        LayoutInflater inflater;
585146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
586146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopupView = inflater.inflate(R.layout.bubble_event, null);
587146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopupView.setLayoutParams(new ViewGroup.LayoutParams(
588df279e3f9d5b0f189f812c52aca78d18178e4445Romain Guy                ViewGroup.LayoutParams.MATCH_PARENT,
589146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                ViewGroup.LayoutParams.WRAP_CONTENT));
590146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup = new PopupWindow(context);
591146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setContentView(mPopupView);
592146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Resources.Theme dialogTheme = getResources().newTheme();
593146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        dialogTheme.applyStyle(android.R.style.Theme_Dialog, true);
594146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TypedArray ta = dialogTheme.obtainStyledAttributes(new int[] {
595146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            android.R.attr.windowBackground });
596146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setBackgroundDrawable(ta.getDrawable(0));
597146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ta.recycle();
598146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
599146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Enable touching the popup window
600146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopupView.setOnClickListener(this);
601146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
602731f1cb808b7586b93615b408ab2636081fab0dcErik        mBaseDate = new Time(Utils.getTimeZone(context, mTZUpdater));
603146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = System.currentTimeMillis();
604146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mBaseDate.set(millis);
605146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
606146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEarliestStartHour = new int[mNumDays];
607146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mHasAllDayEvent = new boolean[mNumDays];
60802041687c35441e8a21cb763f1fc3a26525292efDavid Brown
60902041687c35441e8a21cb763f1fc3a26525292efDavid Brown        // mLines is the array of points used with Canvas.drawLines() in
61002041687c35441e8a21cb763f1fc3a26525292efDavid Brown        // drawGridBackground() and drawAllDayEvents().  Its size depends
61102041687c35441e8a21cb763f1fc3a26525292efDavid Brown        // on the max number of lines that can ever be drawn by any single
61202041687c35441e8a21cb763f1fc3a26525292efDavid Brown        // drawLines() call in either of those methods.
61302041687c35441e8a21cb763f1fc3a26525292efDavid Brown        final int maxGridLines = (24 + 1)  // max horizontal lines we might draw
61402041687c35441e8a21cb763f1fc3a26525292efDavid Brown                + (mNumDays + 1);  // max vertical lines we might draw
61502041687c35441e8a21cb763f1fc3a26525292efDavid Brown        mLines = new float[maxGridLines * 4];
616146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
617146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
618146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
619146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * This is called when the popup window is pressed.
620146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
621146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void onClick(View v) {
622146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (v == mPopupView) {
623146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Pretend it was a trackball click because that will always
624146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // jump to the "View event" screen.
625146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchViews(true /* trackball */);
626146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
627146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
62969ab334d6988eda70ba53618506d23ebf7d7b405Erik    public void updateIs24HourFormat() {
630ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mIs24HourFormat = DateFormat.is24HourFormat(mContext);
63169ab334d6988eda70ba53618506d23ebf7d7b405Erik        mHourStrs = mIs24HourFormat ? CalendarData.s24Hours : CalendarData.s12HoursNoAmPm;
63269ab334d6988eda70ba53618506d23ebf7d7b405Erik    }
63369ab334d6988eda70ba53618506d23ebf7d7b405Erik
634146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
635146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Returns the start of the selected time in milliseconds since the epoch.
636146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
637146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @return selected time in UTC milliseconds since the epoch.
638146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
639146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    long getSelectedTimeInMillis() {
640146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time time = new Time(mBaseDate);
641146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.setJulianDay(mSelectionDay);
642146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.hour = mSelectionHour;
643146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
644146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // We ignore the "isDst" field because we want normalize() to figure
645146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // out the correct DST value and not adjust the selected time based
646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // on the current setting of DST.
647146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return time.normalize(true /* ignore isDst */);
648146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
649146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
650146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Time getSelectedTime() {
651146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time time = new Time(mBaseDate);
652146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.setJulianDay(mSelectionDay);
653146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.hour = mSelectionHour;
654146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
655146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // We ignore the "isDst" field because we want normalize() to figure
656146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // out the correct DST value and not adjust the selected time based
657146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // on the current setting of DST.
658146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.normalize(true /* ignore isDst */);
659146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return time;
660146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
661146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
662146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
663146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Returns the start of the selected time in minutes since midnight,
664146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * local time.  The derived class must ensure that this is consistent
665146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * with the return value from getSelectedTimeInMillis().
666146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
667146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    int getSelectedMinutesSinceMidnight() {
668146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return mSelectionHour * MINUTES_PER_HOUR;
669146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
670146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
671146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void setSelectedDay(Time time) {
672146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mBaseDate.set(time);
673146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionHour = mBaseDate.hour;
674146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = null;
6753e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        mSelectedLayout = null;
676146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevSelectedEvent = null;
677146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = mBaseDate.toMillis(false /* use isDst */);
678146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionDay = Time.getJulianDay(millis, mBaseDate.gmtoff);
679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mComputeSelectedEvents = true;
681146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
682146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Force a recalculation of the first visible hour
683146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstHour = -1;
684146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        recalc();
685146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
686146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Force a redraw of the selection box.
687146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_SELECTED;
688146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mRemeasure = true;
689146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
690146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
691146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
692146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public Time getSelectedDay() {
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
70483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    /**
705487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan     * return a negative number if "time" is comes before the visible time
706487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan     * range, a positive number if "time" is after the visible time range, and 0
707487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan     * if it is in the visible time range.
70883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     */
709487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    public int compareToVisibleTimeRange(Time time) {
710487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
711487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int savedHour = mBaseDate.hour;
712487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int savedMinute = mBaseDate.minute;
713487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int savedSec = mBaseDate.second;
714487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
715487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.hour = 0;
716487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.minute = 0;
717487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.second = 0;
718487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
719487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        Log.d(TAG, "Begin " + mBaseDate.toString());
720487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        Log.d(TAG, "Diff  " + time.toString());
721487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
72283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        // Compare beginning of range
72383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        int diff = Time.compare(time, mBaseDate);
724487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        if (diff > 0) {
725487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            // Compare end of range
726487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.monthDay += mNumDays;
727487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.normalize(true);
728487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            diff = Time.compare(time, mBaseDate);
729487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
730487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            Log.d(TAG, "End   " + mBaseDate.toString());
731487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
732487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.monthDay -= mNumDays;
733487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.normalize(true);
734487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            if (diff < 0) {
735487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                // in visible time
736487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                diff = 0;
737487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            } else if (diff == 0) {
738487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                // Midnight of following day
739487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                diff = 1;
740487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            }
74183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        }
74283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
743487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        Log.d(TAG, "Diff: " + diff);
74483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
745487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.hour = savedHour;
746487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.minute = savedMinute;
747487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.second = savedSec;
748487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        return diff;
74983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
75083b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
751146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void recalc() {
752146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Set the base date to the beginning of the week if we are displaying
753146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // 7 days at a time.
754146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays == 7) {
755146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int dayOfWeek = mBaseDate.weekDay;
756487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            int diff = dayOfWeek - mFirstDayOfWeek;
757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (diff != 0) {
758146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (diff < 0) {
759146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    diff += 7;
760146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
761146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mBaseDate.monthDay -= diff;
762146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mBaseDate.normalize(true /* ignore isDst */);
763146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
764146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
765146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
766146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        final long start = mBaseDate.toMillis(false /* use isDst */);
767146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstJulianDay = Time.getJulianDay(start, mBaseDate.gmtoff);
768146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mLastJulianDay = mFirstJulianDay + mNumDays - 1;
769146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
770146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mMonthLength = mBaseDate.getActualMaximum(Time.MONTH_DAY);
771487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mFirstVisibleDate = mBaseDate.monthDay;
772487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mFirstVisibleDayOfWeek = mBaseDate.weekDay;
773146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
774146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
775146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
776146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected void onSizeChanged(int width, int height, int oldw, int oldh) {
777146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewWidth = width;
778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewHeight = height;
779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int gridAreaWidth = width - mHoursWidth;
780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mCellWidth = (gridAreaWidth - (mNumDays * DAY_GAP)) / mNumDays;
781146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
782146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = new Paint();
783146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(HOURS_FONT_SIZE);
784146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mHoursTextHeight = (int) Math.abs(p.ascent());
785146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        remeasure(width, height);
786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
787146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
78846b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa    /**
78946b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa     * Measures the space needed for various parts of the view after
79046b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa     * loading new events.  This can change if there are all-day events.
79146b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa     */
792146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void remeasure(int width, int height) {
793146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
794146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // First, clear the array of earliest start times, and the array
795146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // indicating presence of an all-day event.
796146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++) {
797146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mEarliestStartHour[day] = 25;  // some big number
798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mHasAllDayEvent[day] = false;
799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
801d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        // Compute the layout relation between each event before measuring cell
802d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        // width, as the cell width should be adjusted along with the relation.
80346b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        //
80446b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // Examples: A (1:00pm - 1:01pm), B (1:02pm - 2:00pm)
80546b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // We should mark them as "overwapped". Though they are not overwapped logically, but
80646b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // minimum cell height implicitly expands the cell height of A and it should look like
80746b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // (1:00pm - 1:15pm) after the cell height adjustment.
80846b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa
809146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Compute the space needed for the all-day events, if any.
810146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Make a pass over all the events, and keep track of the maximum
811146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // number of all-day events in any one day.  Also, keep track of
812146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // the earliest event in each day.
813146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int maxAllDayEvents = 0;
81446b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        final ArrayList<Event> events = mEvents;
81546b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        final int len = events.size();
816c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa        // Num of all-day-events on each day.
817c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa        final int eventsCount[] = new int[mLastJulianDay - mFirstJulianDay + 1];
818c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa        Arrays.fill(eventsCount, 0);
819146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
820146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(ii);
821c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            if (event.startDay > mLastJulianDay || event.endDay < mFirstJulianDay) {
822146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
823c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            }
824146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (event.allDay) {
825c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                final int firstDay = Math.max(event.startDay, mFirstJulianDay);
826c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                final int lastDay = Math.min(event.endDay, mLastJulianDay);
827c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                for (int day = firstDay; day <= lastDay; day++) {
828c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                    final int count = ++eventsCount[day - mFirstJulianDay];
829c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                    if (maxAllDayEvents < count) {
830c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                        maxAllDayEvents = count;
831c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa                    }
832146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
833c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa
834146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int daynum = event.startDay - mFirstJulianDay;
835146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int durationDays = event.endDay - event.startDay + 1;
836146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum < 0) {
837146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    durationDays += daynum;
838146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    daynum = 0;
839146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
840146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum + durationDays > mNumDays) {
841146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    durationDays = mNumDays - daynum;
842146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
843146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                for (int day = daynum; durationDays > 0; day++, durationDays--) {
844146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mHasAllDayEvent[day] = true;
845146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
846146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
847146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int daynum = event.startDay - mFirstJulianDay;
848146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int hour = event.startTime / 60;
849146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum >= 0 && hour < mEarliestStartHour[daynum]) {
850146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mEarliestStartHour[daynum] = hour;
851146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
852146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
853146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Also check the end hour in case the event spans more than
854146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // one day.
855146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                daynum = event.endDay - mFirstJulianDay;
856146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                hour = event.endTime / 60;
857146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum < mNumDays && hour < mEarliestStartHour[daynum]) {
858146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mEarliestStartHour[daynum] = hour;
859146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
860146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
861146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
862146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mMaxAllDayEvents = maxAllDayEvents;
863146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
8649c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        // Calculate mAllDayHeight
8653eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mFirstCell = DAY_HEADER_HEIGHT;
866146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int allDayHeight = 0;
867146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (maxAllDayEvents > 0) {
868146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there is at most one all-day event per day, then use less
869146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // space (but more than the space for a single event).
870146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (maxAllDayEvents == 1) {
871146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                allDayHeight = SINGLE_ALLDAY_HEIGHT;
872146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
873146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Allow the all-day area to grow in height depending on the
874146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // number of all-day events we need to show, up to a limit.
875f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                allDayHeight = maxAllDayEvents * MAX_HEIGHT_OF_ONE_ALLDAY_EVENT;
876146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (allDayHeight > MAX_ALLDAY_HEIGHT) {
877146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    allDayHeight = MAX_ALLDAY_HEIGHT;
878146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
879146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
8803eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            mFirstCell = DAY_HEADER_HEIGHT + allDayHeight + ALLDAY_TOP_MARGIN;
881146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
882146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionAllDay = false;
883146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
884146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mAllDayHeight = allDayHeight;
885146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
886146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mGridAreaHeight = height - mFirstCell;
887d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
888d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        // The min is where 24 hours cover the entire visible area
889f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        mMinCellHeight = (height - DAY_HEADER_HEIGHT) / 24 - HOUR_GAP;
890d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mCellHeight < mMinCellHeight) {
891d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeight = mMinCellHeight;
892d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
893d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
894697157470a6f0d8e7b806af9b4fb7fbe0bccae87Erik        mNumHours = mGridAreaHeight / mCellHeight;
895146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry.setHourHeight(mCellHeight);
896146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
89727d671cdba3e8b50219def2c9e1118abe987f908Daisuke Miyakawa        final long minimumDurationMillis = (long)
89827d671cdba3e8b50219def2c9e1118abe987f908Daisuke Miyakawa                (MIN_EVENT_HEIGHT * DateUtils.MINUTE_IN_MILLIS / (mCellHeight / 60.0f));
89946b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        Event.computePositions(events, minimumDurationMillis);
90046b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa
901c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        // Compute the top of our reachable view
902c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        mMaxViewStartY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP) - mGridAreaHeight;
903d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (DEBUG) {
904d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            Log.e(TAG, "mViewStartY: " + mViewStartY);
905d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            Log.e(TAG, "mMaxViewStartY: " + mMaxViewStartY);
906d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
907d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mViewStartY > mMaxViewStartY) {
908d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mViewStartY = mMaxViewStartY;
909d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            computeFirstHour();
910d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
911146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
912146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour == -1) {
913146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            initFirstHour();
914146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHourOffset = 0;
915146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
916146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
917146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // When we change the base date, the number of all-day events may
918146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // change and that changes the cell height.  When we switch dates,
919146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // we use the mFirstHourOffset from the previous view, but that may
920146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // be too large for the new view if the cell height is smaller.
921146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHourOffset >= mCellHeight + HOUR_GAP) {
922146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHourOffset = mCellHeight + HOUR_GAP - 1;
923146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
924146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewStartY = mFirstHour * (mCellHeight + HOUR_GAP) - mFirstHourOffset;
925146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
92646b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        final int eventAreaWidth = mNumDays * (mCellWidth + DAY_GAP);
927666fc5e8ddbac15c951aad738bd818ee307eae42Erik        //When we get new events we don't want to dismiss the popup unless the event changes
928666fc5e8ddbac15c951aad738bd818ee307eae42Erik        if (mSelectedEvent != null && mLastPopupEventID != mSelectedEvent.id) {
929666fc5e8ddbac15c951aad738bd818ee307eae42Erik            mPopup.dismiss();
930666fc5e8ddbac15c951aad738bd818ee307eae42Erik        }
931146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setWidth(eventAreaWidth - 20);
932146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
933146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
934146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
935146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
936146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Initialize the state for another view.  The given view is one that has
937146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * its own bitmap and will use an animation to replace the current view.
938146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * The current view and new view are either both Week views or both Day
939146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * views.  They differ in their base date.
940146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
941146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param view the view to initialize.
942146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
943d190418220467c02327dd9b3ae1eae238889720bMichael Chan    private void initView(DayView view) {
944146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mSelectionHour = mSelectionHour;
945146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mSelectedEvents.clear();
946146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mComputeSelectedEvents = true;
947146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mFirstHour = mFirstHour;
948146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mFirstHourOffset = mFirstHourOffset;
949146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.remeasure(getWidth(), getHeight());
950e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
951146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mSelectedEvent = null;
9523e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        view.mSelectedLayout = null;
953146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mPrevSelectedEvent = null;
954487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        view.mFirstDayOfWeek = mFirstDayOfWeek;
955146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (view.mEvents.size() > 0) {
956146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionAllDay = mSelectionAllDay;
957146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
958146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionAllDay = false;
959146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
960146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
961146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Redraw the screen so that the selection box will be redrawn.  We may
962146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // have scrolled to a different part of the day in some other view
963146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // so the selection box in this view may no longer be visible.
964146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.recalc();
965146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
966146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
967146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
968146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Switch to another view based on what was selected (an event or a free
969146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * slot) and how it was selected (by touch or by trackball).
970146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
971146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param trackBallSelection true if the selection was made using the
972146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * trackball.
973146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
974146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void switchViews(boolean trackBallSelection) {
975146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event selectedEvent = mSelectedEvent;
976146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
977146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.dismiss();
978666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = INVALID_EVENT_ID;
979146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays > 1) {
980146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // This is the Week view.
981146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // With touch, we always switch to Day/Agenda View
982146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // With track ball, if we selected a free slot, then create an event.
983146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we selected a specific event, switch to EventInfo view.
984146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (trackBallSelection) {
985146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (selectedEvent == null) {
986146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Switch to the EditEvent view
987146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long startMillis = getSelectedTimeInMillis();
988146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
9899e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
9909e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            startMillis, endMillis, 0, 0);
991146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
992146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Switch to the EventInfo view
9939e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
9949e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            selectedEvent.startMillis, selectedEvent.endMillis, 0, 0);
995146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
996146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
997146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // This was a touch selection.  If the touch selected a single
998146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // unambiguous event, then view that event.  Otherwise go to
999146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Day/Agenda view.
1000146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectedEvents.size() == 1) {
10019e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
10029e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            selectedEvent.startMillis, selectedEvent.endMillis, 0, 0);
1003146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1004146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1005146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
1006146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // This is the Day view.
1007146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we selected a free slot, then create an event.
1008146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we selected an event, then go to the EventInfo view.
1009146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (selectedEvent == null) {
1010146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Switch to the EditEvent view
1011146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                long startMillis = getSelectedTimeInMillis();
1012146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
10139e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan
10149e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1, startMillis,
10159e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        endMillis, 0, 0);
1016146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
10179e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
10189e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        selectedEvent.startMillis, selectedEvent.endMillis, 0, 0);
1019146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1020146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1021146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1022146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1023146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
1024146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
1025146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mScrolling = false;
1026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long duration = event.getEventTime() - event.getDownTime();
1027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1028146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        switch (keyCode) {
1029146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            case KeyEvent.KEYCODE_DPAD_CENTER:
1030146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectionMode == SELECTION_HIDDEN) {
1031146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Don't do anything unless the selection is visible.
1032146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
1033146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1034146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1035146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectionMode == SELECTION_PRESSED) {
1036146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This was the first press when there was nothing selected.
1037146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Change the selection from the "pressed" state to the
1038146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // the "selected" state.  We treat short-press and
1039146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // long-press the same here because nothing was selected.
1040146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionMode = SELECTION_SELECTED;
1041146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    invalidate();
1042146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
1043146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1044146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1045146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Check the duration to determine if this was a short press
1046146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (duration < ViewConfiguration.getLongPressTimeout()) {
1047146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    switchViews(true /* trackball */);
1048146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
1049146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionMode = SELECTION_LONGPRESS;
1050146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    invalidate();
1051146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    performLongClick();
1052146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1053146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                break;
1054ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//            case KeyEvent.KEYCODE_BACK:
1055ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                if (event.isTracking() && !event.isCanceled()) {
1056ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                    mPopup.dismiss();
1057ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                    mContext.finish();
1058ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                    return true;
1059ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                }
1060ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                break;
1061146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1062146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return super.onKeyUp(keyCode, event);
1063146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1064146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1065146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
1066146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
1067146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionMode == SELECTION_HIDDEN) {
1068146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
1069146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_UP
1070146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
1071146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Display the selection box but don't move or select it
1072146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // on this key press.
1073146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionMode = SELECTION_SELECTED;
1074146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
1075146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
1076146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
1077146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Display the selection box but don't select it
1078146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // on this key press.
1079146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionMode = SELECTION_PRESSED;
1080146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
1081146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
1082146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1083146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1084146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1085146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_SELECTED;
1086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mScrolling = false;
1087146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        boolean redraw;
1088146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int selectionDay = mSelectionDay;
1089146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        switch (keyCode) {
1091146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_DEL:
1092146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Delete the selected event, if any
1093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event selectedEvent = mSelectedEvent;
1094146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (selectedEvent == null) {
1095146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return false;
1096146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1097146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPopup.dismiss();
1098666fc5e8ddbac15c951aad738bd818ee307eae42Erik            mLastPopupEventID = INVALID_EVENT_ID;
1099146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            long begin = selectedEvent.startMillis;
1101146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            long end = selectedEvent.endMillis;
1102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            long id = selectedEvent.id;
1103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDeleteEventHelper.delete(begin, end, id, -1);
1104146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
1105146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_ENTER:
1106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchViews(true /* trackball or keyboard */);
1107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
1108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_BACK:
1109b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan            if (event.getRepeatCount() == 0) {
1110b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan                event.startTracking();
1111b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan                return true;
1112b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan            }
1113b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan            return super.onKeyDown(keyCode, event);
1114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_DPAD_LEFT:
1115146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
1116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvent = mSelectedEvent.nextLeft;
11173e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                mSelectedLayout = null;
1118146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1119146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent == null) {
1120666fc5e8ddbac15c951aad738bd818ee307eae42Erik                mLastPopupEventID = INVALID_EVENT_ID;
1121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                selectionDay -= 1;
1122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            redraw = true;
1124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            break;
1125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_DPAD_RIGHT:
1127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
1128146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvent = mSelectedEvent.nextRight;
11293e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                mSelectedLayout = null;
1130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent == null) {
1132666fc5e8ddbac15c951aad738bd818ee307eae42Erik                mLastPopupEventID = INVALID_EVENT_ID;
1133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                selectionDay += 1;
1134146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            redraw = true;
1136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            break;
1137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_DPAD_UP:
1139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
1140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvent = mSelectedEvent.nextUp;
11413e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                mSelectedLayout = null;
1142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent == null) {
1144666fc5e8ddbac15c951aad738bd818ee307eae42Erik                mLastPopupEventID = INVALID_EVENT_ID;
1145146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (!mSelectionAllDay) {
1146146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionHour -= 1;
1147146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    adjustHourSelection();
1148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectedEvents.clear();
1149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mComputeSelectedEvents = true;
1150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            redraw = true;
1153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            break;
1154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_DPAD_DOWN:
1156146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
1157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvent = mSelectedEvent.nextDown;
11583e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                mSelectedLayout = null;
1159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent == null) {
1161666fc5e8ddbac15c951aad738bd818ee307eae42Erik                mLastPopupEventID = INVALID_EVENT_ID;
1162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectionAllDay) {
1163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionAllDay = false;
1164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
1165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionHour++;
1166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    adjustHourSelection();
1167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectedEvents.clear();
1168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mComputeSelectedEvents = true;
1169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            redraw = true;
1172146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            break;
1173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        default:
1175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return super.onKeyDown(keyCode, event);
1176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((selectionDay < mFirstJulianDay) || (selectionDay > mLastJulianDay)) {
1179d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView view = (DayView) mViewSwitcher.getNextView();
1180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Time date = view.mBaseDate;
1181146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.set(mBaseDate);
1182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (selectionDay < mFirstJulianDay) {
1183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                date.monthDay -= mNumDays;
1184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
1185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                date.monthDay += mNumDays;
1186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.normalize(true /* ignore isDst */);
1188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionDay = selectionDay;
1189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            initView(view);
119183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
119283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Time end = new Time(date);
119383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            end.monthDay += mNumDays - 1;
119483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Log.d(TAG, "onKeyDown");
11953458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            mController.sendEvent(this, EventType.GO_TO, date, end, -1, ViewType.CURRENT);
1196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
1197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionDay = selectionDay;
1199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
1200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mComputeSelectedEvents = true;
1201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (redraw) {
1203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            invalidate();
1204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
1205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return super.onKeyDown(keyCode, event);
1208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1210ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private View switchViews(boolean forward, float xOffSet, float width) {
1211ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        float progress = Math.abs(xOffSet) / width;
1212ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        if (progress > 1.0f) {
1213ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            progress = 1.0f;
1214ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
1215ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1216ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        float inFromXValue, inToXValue;
1217ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        float outFromXValue, outToXValue;
1218ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        if (forward) {
1219ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inFromXValue = 1.0f - progress;
1220ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inToXValue = 0.0f;
1221ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outFromXValue = -progress;
1222ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outToXValue = -1.0f;
1223ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        } else {
1224ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inFromXValue = progress - 1.0f;
1225ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inToXValue = 0.0f;
1226ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outFromXValue = progress;
1227ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outToXValue = 1.0f;
1228ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
1229ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1230ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        // We have to allocate these animation objects each time we switch views
1231ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        // because that is the only way to set the animation parameters.
1232ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        TranslateAnimation inAnimation = new TranslateAnimation(
1233ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, inFromXValue,
1234ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, inToXValue,
1235ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f,
1236ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f);
1237ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1238ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        TranslateAnimation outAnimation = new TranslateAnimation(
1239ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, outFromXValue,
1240ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, outToXValue,
1241ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f,
1242ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f);
1243ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1244ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        // Reduce the animation duration based on how far we have already swiped.
1245ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        long duration = (long) (ANIMATION_DURATION * (1.0f - progress));
1246ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        inAnimation.setDuration(duration);
1247ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        outAnimation.setDuration(duration);
1248ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher.setInAnimation(inAnimation);
1249ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher.setOutAnimation(outAnimation);
1250ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1251d190418220467c02327dd9b3ae1eae238889720bMichael Chan        DayView view = (DayView) mViewSwitcher.getCurrentView();
1252ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        view.cleanup();
1253ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher.showNext();
1254d190418220467c02327dd9b3ae1eae238889720bMichael Chan        view = (DayView) mViewSwitcher.getCurrentView();
1255ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        view.requestFocus();
1256ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        view.reloadEvents();
1257ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        return view;
1258ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    }
1259ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // This is called after scrolling stops to move the selected hour
1261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // to the visible part of the screen.
1262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void resetSelectedHour() {
1263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour < mFirstHour + 1) {
1264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = mFirstHour + 1;
1265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = null;
12663e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            mSelectedLayout = null;
1267146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvents.clear();
1268146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mComputeSelectedEvents = true;
1269146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (mSelectionHour > mFirstHour + mNumHours - 3) {
1270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = mFirstHour + mNumHours - 3;
1271146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = null;
12723e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            mSelectedLayout = null;
1273146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvents.clear();
1274146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mComputeSelectedEvents = true;
1275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void initFirstHour() {
1279d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mFirstHour = mSelectionHour - mNumHours / 5;
1280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour < 0) {
1281146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHour = 0;
1282146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (mFirstHour + mNumHours > 24) {
1283146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHour = 24 - mNumHours;
1284146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1285146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1286146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1287146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
1288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Recomputes the first full hour that is visible on screen after the
1289146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * screen is scrolled.
1290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
1291146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void computeFirstHour() {
1292146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Compute the first full hour that is visible on screen
1293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstHour = (mViewStartY + mCellHeight + HOUR_GAP - 1) / (mCellHeight + HOUR_GAP);
1294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstHourOffset = mFirstHour * (mCellHeight + HOUR_GAP) - mViewStartY;
1295146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1296146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void adjustHourSelection() {
1298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour < 0) {
1299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = 0;
1300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mMaxAllDayEvents > 0) {
1301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = null;
1302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionAllDay = true;
1303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour > 23) {
1307146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = 23;
1308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If the selected hour is at least 2 time slots from the top and
1311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // bottom of the screen, then don't scroll the view.
1312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour < mFirstHour + 1) {
1313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there are all-days events for the selected day but there
1314146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // are no more normal events earlier in the day, then jump to
1315146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // the all-day event area.
1316146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Exception 1: allow the user to scroll to 8am with the trackball
1317146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // before jumping to the all-day event area.
1318146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Exception 2: if 12am is on screen, then allow the user to select
1319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // 12am before going up to the all-day event area.
1320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int daynum = mSelectionDay - mFirstJulianDay;
1321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mMaxAllDayEvents > 0 && mEarliestStartHour[daynum] > mSelectionHour
1322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    && mFirstHour > 0 && mFirstHour < 8) {
1323146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = null;
1324146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionAllDay = true;
1325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionHour = mFirstHour + 1;
1326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return;
1327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1328146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1329146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mFirstHour > 0) {
1330146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mFirstHour -= 1;
1331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY -= (mCellHeight + HOUR_GAP);
1332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mViewStartY < 0) {
1333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mViewStartY = 0;
1334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return;
1336146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour > mFirstHour + mNumHours - 3) {
1340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mFirstHour < 24 - mNumHours) {
1341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mFirstHour += 1;
1342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY += (mCellHeight + HOUR_GAP);
1343c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik                if (mViewStartY > mMaxViewStartY) {
1344c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik                    mViewStartY = mMaxViewStartY;
1345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1346146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return;
1347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mFirstHour == 24 - mNumHours && mFirstHourOffset > 0) {
1348c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik                mViewStartY = mMaxViewStartY;
1349146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1350146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1351146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1352146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1353146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    void clearCachedEvents() {
1354146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mLastReloadMillis = 0;
1355146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Runnable mCancelCallback = new Runnable() {
1358146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void run() {
1359146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            clearCachedEvents();
1360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1361146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
1362146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
136346b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa    /* package */ void reloadEvents() {
1364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Protect against this being called before this view has been
1365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // initialized.
1366ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//        if (mContext == null) {
1367ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//            return;
1368ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//        }
1369146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1370731f1cb808b7586b93615b408ab2636081fab0dcErik        // Make sure our time zones are up to date
1371731f1cb808b7586b93615b408ab2636081fab0dcErik        mTZUpdater.run();
1372731f1cb808b7586b93615b408ab2636081fab0dcErik
1373146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = null;
1374146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevSelectedEvent = null;
1375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
1376146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
13773e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        mSelectedLayout = null;
13783e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
1379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // The start date is the beginning of the week at 12am
1380731f1cb808b7586b93615b408ab2636081fab0dcErik        Time weekStart = new Time(Utils.getTimeZone(mContext, mTZUpdater));
1381146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.set(mBaseDate);
1382146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.hour = 0;
1383146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.minute = 0;
1384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.second = 0;
1385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = weekStart.normalize(true /* ignore isDst */);
1386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1387146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Avoid reloading events unnecessarily.
1388146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (millis == mLastReloadMillis) {
1389146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
1390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1391146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mLastReloadMillis = millis;
1392146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1393146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // load events in the background
1394ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//        mContext.startProgressSpinner();
1395146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        final ArrayList<Event> events = new ArrayList<Event>();
1396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventLoader.loadEventsInBackground(mNumDays, events, millis, new Runnable() {
1397146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            public void run() {
1398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mEvents = events;
13993e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                mLayouts = new ArrayList<StaticLayout>(events.size()); // New events, new layouts
14003e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                // Fill the layouts with nulls
14013e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                while (mLayouts.size() < events.size()) {
14023e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                    mLayouts.add(null);
14033e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                }
1404146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mRemeasure = true;
1405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mComputeSelectedEvents = true;
1406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                recalc();
1407ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                mContext.stopProgressSpinner();
1408146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
1409146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }, mCancelCallback);
1411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1412146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
1414146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected void onDraw(Canvas canvas) {
1415146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mRemeasure) {
1416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            remeasure(getWidth(), getHeight());
1417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mRemeasure = false;
1418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1419c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.save();
1420146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1421c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        float yTranslate = -mViewStartY + DAY_HEADER_HEIGHT + mAllDayHeight;
1422c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        // offset canvas by the current drag and header position
1423c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.translate(-mViewStartX, yTranslate);
1424c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        // clip to everything below the allDay area
1425c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        Rect dest = mDestRect;
1426c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        dest.top = (int) (mFirstCell - yTranslate);
1427c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        dest.bottom = (int) (mViewHeight - yTranslate);
1428c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        dest.left = 0;
1429c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        dest.right = mViewWidth;
1430c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.save();
1431c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.clipRect(dest);
1432c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        // Draw the movable part of the view
1433c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        doDraw(canvas);
1434c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        // restore to having no clip
1435c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.restore();
1436146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1437146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
1438c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            float xTranslate;
1439146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mViewStartX > 0) {
1440c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik                xTranslate = mViewWidth;
1441146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
1442c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik                xTranslate = -mViewWidth;
1443146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1444c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // Move the canvas around to prep it for the next view
1445c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // specifically, shift it by a screen and undo the
1446c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // yTranslation which will be redone in the nextView's onDraw().
1447c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            canvas.translate(xTranslate, -yTranslate);
1448d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView nextView = (DayView) mViewSwitcher.getNextView();
1449146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1450146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Prevent infinite recursive calls to onDraw().
1451146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            nextView.mTouchMode = TOUCH_MODE_INITIAL_STATE;
1452146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1453146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            nextView.onDraw(canvas);
1454c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // Move it back for this view
1455c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            canvas.translate(-xTranslate, 0);
1456c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        } else {
1457c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // If we drew another view we already translated it back
1458c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // If we didn't draw another view we should be at the edge of the
1459c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            // screen
1460c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik            canvas.translate(mViewStartX, -yTranslate);
1461146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1462146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1463146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the fixed areas (that don't scroll) directly to the canvas.
1464146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        drawAfterScroll(canvas);
1465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mComputeSelectedEvents = false;
1466146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.restore();
1467146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1468146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1469146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawAfterScroll(Canvas canvas) {
1470146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = mPaint;
1471146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect r = mRect;
1472146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1473146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mMaxAllDayEvents != 0) {
1474146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawAllDayEvents(mFirstJulianDay, mNumDays, r, canvas, p);
14753eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//            drawUpperLeftCorner(r, canvas, p);
1476146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1477146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1478c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        drawScrollLine(r, canvas, p);
1479c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik
14803eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        drawDayHeaderLoop(r, canvas, p);
1481146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1482146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the AM and PM indicators if we're in 12 hour mode
1483146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!mIs24HourFormat) {
1484146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawAmPm(canvas, p);
1485146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1486146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1487146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Update the popup window showing the event details, but only if
1488146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // we are not scrolling and we have focus.
1489146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!mScrolling && isFocused()) {
1490146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            updateEventDetails();
1491146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1492146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1493146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1494146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // This isn't really the upper-left corner.  It's the square area just
1495146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // below the upper-left corner, above the hours and to the left of the
1496146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // all-day area.
14973eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//    private void drawUpperLeftCorner(Rect r, Canvas canvas, Paint p) {
14983eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        p.setColor(mCalendarHourBackground);
14993eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        r.top = DAY_HEADER_HEIGHT;
15003eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        r.bottom = r.top + mAllDayHeight + ALLDAY_TOP_MARGIN;
15013eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        r.left = 0;
15023eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        r.right = mHoursWidth;
15033eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//        canvas.drawRect(r, p);
15043eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan//    }
1505146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1506c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik    // TODO cleanup and constant extraction
1507c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik    private void drawScrollLine(Rect r, Canvas canvas, Paint p) {
1508c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        p.setColor(EVENT_OUTLINE_COLOR);
1509c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        p.setStyle(Style.FILL);
1510c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        p.setAntiAlias(false);
1511c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        r.left = 0;
1512c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        r.right = mViewWidth;
1513c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        r.top = mFirstCell - 1;
1514c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        r.bottom = mFirstCell + 1;
1515c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        canvas.drawRect(r, p);
1516c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        p.setAntiAlias(true);
1517c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik    }
1518c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik
1519146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawDayHeaderLoop(Rect r, Canvas canvas, Paint p) {
1520146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the horizontal day background banner
15213eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarDateBannerBackground);
15223eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.top = 0;
15233eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.bottom = DAY_HEADER_HEIGHT;
15243eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.left = 0;
15253eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.right = mHoursWidth + mNumDays * (mCellWidth + DAY_GAP);
15263eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
15273eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        //
1528146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Fill the extra space on the right side with the default background
15293eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.left = r.right;
15303eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.right = mViewWidth;
15313eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarGridAreaBackground);
15323eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
1533146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
15343eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        int todayNum = mTodayJulianDay - mFirstJulianDay;
15353eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        if (mNumDays > 1) {
15363eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            r.top = 0;
15373eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            r.bottom = DAY_HEADER_HEIGHT;
15383eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
15393eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Highlight today
15403eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            if (mFirstJulianDay <= mTodayJulianDay
15413eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                    && mTodayJulianDay < (mFirstJulianDay + mNumDays)) {
15423eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                r.left = mHoursWidth + todayNum * (mCellWidth + DAY_GAP);
15433eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                r.right = r.left + mCellWidth;
15443eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                mTodayHeaderDrawable.setBounds(r);
15453eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                mTodayHeaderDrawable.draw(canvas);
15463eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            }
15473eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
15483eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Draw a highlight on the selected day (if any), but only if we are
15493eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // displaying more than one day.
155011ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            //
155111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // int selectedDayNum = mSelectionDay - mFirstJulianDay;
155211ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // if (mSelectionMode != SELECTION_HIDDEN && selectedDayNum >= 0
155311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // && selectedDayNum < mNumDays) {
155411ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // p.setColor(mCalendarDateSelected);
155511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // r.left = mHoursWidth + selectedDayNum * (mCellWidth + DAY_GAP);
155611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // r.right = r.left + mCellWidth;
155711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // canvas.drawRect(r, p);
155811ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // }
1559146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1560146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
15613eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setTypeface(mBold);
15623eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setTextAlign(Paint.Align.RIGHT);
15633eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        float x = mHoursWidth;
1564146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaX = mCellWidth + DAY_GAP;
1565146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cell = mFirstJulianDay;
1566146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1567146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String[] dayNames;
1568146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mDateStrWidth < mCellWidth) {
1569146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            dayNames = mDayStrs;
1570146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
1571146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            dayNames = mDayStrs2Letter;
1572146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1573146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1574d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setAntiAlias(true);
1575146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++, cell++) {
15761f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan            int dayOfWeek = day + mFirstVisibleDayOfWeek;
15771f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan            if (dayOfWeek >= 14) {
15781f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan                dayOfWeek -= 14;
1579487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            }
1580487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
15813eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            int color = mCalendarDateBannerTextColor;
1582487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            if (Utils.isSaturday(dayOfWeek, mFirstDayOfWeek)) {
15833eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                color = mWeek_saturdayColor;
1584487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            } else if (Utils.isSunday(dayOfWeek, mFirstDayOfWeek)) {
15853eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                color = mWeek_sundayColor;
15863eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            }
15873eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
15883eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            color &= 0x00FFFFFF;
15893eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            if (todayNum == day) {
15903eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                color |= DAY_HEADER_TODAY_ALPHA;
1591487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            } else {
15923eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan                color |= DAY_HEADER_ALPHA;
1593487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            }
1594487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
15953eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            p.setColor(color);
1596487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            drawDayHeader(dayNames[dayOfWeek], day, cell, x, canvas, p);
1597146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            x += deltaX;
1598146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
15993eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setTypeface(null);
1600146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1601146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1602146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawAmPm(Canvas canvas, Paint p) {
1603d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarAmPmLabel);
1604146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(AMPM_FONT_SIZE);
1605146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(mBold);
1606146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
1607146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPaint.setTextAlign(Paint.Align.RIGHT);
1608146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String text = mAmString;
1609146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour >= 12) {
1610146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            text = mPmString;
1611146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1612146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int y = mFirstCell + mFirstHourOffset + 2 * mHoursTextHeight + HOUR_GAP;
1613146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int right = mHoursWidth - HOURS_RIGHT_MARGIN;
1614146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawText(text, right, y, p);
1615146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1616146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour < 12 && mFirstHour + mNumHours > 12) {
1617146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Also draw the "PM"
1618146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            text = mPmString;
1619146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            y = mFirstCell + mFirstHourOffset + (12 - mFirstHour) * (mCellHeight + HOUR_GAP)
1620146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    + 2 * mHoursTextHeight + HOUR_GAP;
1621146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawText(text, right, y, p);
1622146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1623146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1624146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1625f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan    private void drawCurrentTimeLine(Rect r, final int left, final int top, Canvas canvas,
1626f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan            Paint p) {
16273eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        r.left = left - CURRENT_TIME_LINE_SIDE_BUFFER;
16283eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        r.right = left + mCellWidth + CURRENT_TIME_LINE_SIDE_BUFFER;
16293eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
16303eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        r.top = top - mCurrentTimeLine.getIntrinsicHeight() / 2;
16313eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        r.bottom = r.top + mCurrentTimeLine.getIntrinsicHeight();
1632bd0e834aea317236d574f8738fe11a51fdc87968Erik
16333eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mCurrentTimeLine.setBounds(r);
16343eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        mCurrentTimeLine.draw(canvas);
1635bd0e834aea317236d574f8738fe11a51fdc87968Erik    }
1636bd0e834aea317236d574f8738fe11a51fdc87968Erik
1637146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void doDraw(Canvas canvas) {
1638146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = mPaint;
1639146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect r = mRect;
1640bd0e834aea317236d574f8738fe11a51fdc87968Erik        int lineY = mCurrentTime.hour*(mCellHeight + HOUR_GAP)
1641bd0e834aea317236d574f8738fe11a51fdc87968Erik            + ((mCurrentTime.minute * mCellHeight) / 60)
1642bd0e834aea317236d574f8738fe11a51fdc87968Erik            + 1;
1643146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1644146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        drawGridBackground(r, canvas, p);
1645146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        drawHours(r, canvas, p);
1646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1647146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw each day
1648146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int x = mHoursWidth;
1649146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaX = mCellWidth + DAY_GAP;
1650146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cell = mFirstJulianDay;
1651146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++, cell++) {
1652146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawEvents(cell, x, HOUR_GAP, canvas, p);
1653bd0e834aea317236d574f8738fe11a51fdc87968Erik            //If this is today
1654bd0e834aea317236d574f8738fe11a51fdc87968Erik            if(cell == mTodayJulianDay) {
1655bd0e834aea317236d574f8738fe11a51fdc87968Erik                //And the current time shows up somewhere on the screen
1656bd0e834aea317236d574f8738fe11a51fdc87968Erik                if(lineY >= mViewStartY && lineY < mViewStartY + mViewHeight - 2) {
1657bd0e834aea317236d574f8738fe11a51fdc87968Erik                    drawCurrentTimeLine(r, x, lineY, canvas, p);
1658bd0e834aea317236d574f8738fe11a51fdc87968Erik                }
1659bd0e834aea317236d574f8738fe11a51fdc87968Erik            }
1660146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            x += deltaX;
1661146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1662146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1663146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1664146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawHours(Rect r, Canvas canvas, Paint p) {
16653eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Comment out as the background will be a drawable
16663eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
1667146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the background for the hour labels
16683eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarHourBackground);
16693eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.top = 0;
16703eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.bottom = 24 * (mCellHeight + HOUR_GAP) + HOUR_GAP;
16713eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.left = 0;
16723eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.right = mHoursWidth;
16733eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
1674146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1675146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Fill the bottom left corner with the default grid background
16763eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.top = r.bottom;
16773eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.bottom = mBitmapHeight;
16783eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarGridAreaBackground);
16793eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
1680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1681146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw a highlight on the selected hour (if needed)
1682ba902466b19b11d587468e354edc58e542707747Michael Chan        if (mSelectionMode != SELECTION_HIDDEN && !mSelectionAllDay) {
1683ba902466b19b11d587468e354edc58e542707747Michael Chan            // p.setColor(mCalendarHourSelected);
16843937a47bc5a1afb9701e1d0565fae31f5800590dErik            int daynum = mSelectionDay - mFirstJulianDay;
1685ba902466b19b11d587468e354edc58e542707747Michael Chan            r.top = mSelectionHour * (mCellHeight + HOUR_GAP);
1686ba902466b19b11d587468e354edc58e542707747Michael Chan            r.bottom = r.top + mCellHeight + 2 * HOUR_GAP;
16873937a47bc5a1afb9701e1d0565fae31f5800590dErik            r.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP) - DAY_GAP;
16883937a47bc5a1afb9701e1d0565fae31f5800590dErik            r.right = r.left + mCellWidth + DAY_GAP;
1689ba902466b19b11d587468e354edc58e542707747Michael Chan
1690ba902466b19b11d587468e354edc58e542707747Michael Chan            // Draw a border around the highlighted grid hour.
1691ba902466b19b11d587468e354edc58e542707747Michael Chan            Path path = mPath;
1692ba902466b19b11d587468e354edc58e542707747Michael Chan            path.reset();
1693ba902466b19b11d587468e354edc58e542707747Michael Chan            path.addRect(r.left, r.top, r.right, r.bottom, Direction.CW);
1694ba902466b19b11d587468e354edc58e542707747Michael Chan            canvas.drawPath(path, mSelectionPaint);
1695ba902466b19b11d587468e354edc58e542707747Michael Chan            saveSelectionPosition(r.left, r.top, r.right, r.bottom);
16963937a47bc5a1afb9701e1d0565fae31f5800590dErik
16973937a47bc5a1afb9701e1d0565fae31f5800590dErik            // Also draw the highlight on the grid
16983937a47bc5a1afb9701e1d0565fae31f5800590dErik            p.setColor(mCalendarGridAreaSelected);
16993937a47bc5a1afb9701e1d0565fae31f5800590dErik            r.top += HOUR_GAP;
17003937a47bc5a1afb9701e1d0565fae31f5800590dErik            r.bottom -= HOUR_GAP;
17013937a47bc5a1afb9701e1d0565fae31f5800590dErik            r.left += DAY_GAP;
17023937a47bc5a1afb9701e1d0565fae31f5800590dErik            r.right -= DAY_GAP;
17033937a47bc5a1afb9701e1d0565fae31f5800590dErik            canvas.drawRect(r, p);
1704ba902466b19b11d587468e354edc58e542707747Michael Chan        }
1705146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1706d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarHourLabel);
1707146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(HOURS_FONT_SIZE);
1708146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(mBold);
1709146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextAlign(Paint.Align.RIGHT);
1710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
1711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int right = mHoursWidth - HOURS_RIGHT_MARGIN;
1713146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int y = HOUR_GAP + mHoursTextHeight;
1714146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < 24; i++) {
1716146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            String time = mHourStrs[i];
1717146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawText(time, right, y, p);
1718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            y += mCellHeight + HOUR_GAP;
1719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1720146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
17223eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan    private void drawDayHeader(String dayStr, int day, int cell, float x, Canvas canvas, Paint p) {
1723487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int dateNum = mFirstVisibleDate + day;
1724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (dateNum > mMonthLength) {
1725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            dateNum -= mMonthLength;
1726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1727146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
17283eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw day of the month
17293eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        String dateNumStr = String.valueOf(dateNum);
17303eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        if (mNumDays > 1) {
17313eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            float y = DAY_HEADER_HEIGHT - DAY_HEADER_BOTTOM_MARGIN;
17323eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
17333eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Draw day of the month
17343eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            x += mCellWidth - DAY_HEADER_RIGHT_MARGIN;
17353eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            p.setTextSize(DATE_HEADER_FONT_SIZE);
17363eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            canvas.drawText(dateNumStr, x, y, p);
17373eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
17383eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Draw day of the week
17393eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            x -= p.measureText(dateNumStr) + DAY_HEADER_LEFT_MARGIN;
17403eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            p.setTextSize(DAY_HEADER_FONT_SIZE);
17413eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            canvas.drawText(dayStr, x, y, p);
1742146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
17433eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            float y = DAY_HEADER_HEIGHT - DAY_HEADER_ONE_DAY_BOTTOM_MARGIN;
174411ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            p.setTextAlign(Paint.Align.LEFT);
1745146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
17463eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Draw day of the week
17473eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            x += DAY_HEADER_ONE_DAY_LEFT_MARGIN;
17483eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            p.setTextSize(DAY_HEADER_FONT_SIZE);
17493eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            canvas.drawText(dayStr, x, y, p);
1750d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan
17513eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            // Draw day of the month
17523eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            x += p.measureText(dayStr) + DAY_HEADER_ONE_DAY_RIGHT_MARGIN;
17533eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            p.setTextSize(DATE_HEADER_FONT_SIZE);
17543eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            canvas.drawText(dateNumStr, x, y, p);
1755d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        }
1756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1758146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawGridBackground(Rect r, Canvas canvas, Paint p) {
1759146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint.Style savedStyle = p.getStyle();
1760146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
17613937a47bc5a1afb9701e1d0565fae31f5800590dErik//        r.top = 0;
17623937a47bc5a1afb9701e1d0565fae31f5800590dErik//        r.bottom = mMaxViewStartY + mGridAreaHeight;
17633937a47bc5a1afb9701e1d0565fae31f5800590dErik//        r.left = 0;
17643937a47bc5a1afb9701e1d0565fae31f5800590dErik//        r.right = mViewWidth;
17653eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarGridAreaBackground);
17663eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
176711638ad4fb56b978770aebe75deac7a0e6ac60d2Erik        // TODO readd code for drawing bg image instead of color
176811638ad4fb56b978770aebe75deac7a0e6ac60d2Erik        // mBackgroundDrawable.setBounds(r);
176911638ad4fb56b978770aebe75deac7a0e6ac60d2Erik        // mBackgroundDrawable.draw(canvas);
1770c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik//        p.setAntiAlias(false);
1771c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik//        p.setColor(0x00000000);
1772c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik//        p.setStyle(Style.FILL);
1773c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik//        canvas.drawRect(r, p);
1774146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
17753eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the outer horizontal grid lines
1776d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridLineHorizontalColor);
17779c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        p.setStyle(Style.FILL);
17783937a47bc5a1afb9701e1d0565fae31f5800590dErik
1779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(false);
17803eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float startX = 0;
17813eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float stopX = mHoursWidth + (mCellWidth + DAY_GAP) * mNumDays;
1782146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float y = 0;
17833eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float deltaY = mCellHeight + HOUR_GAP;
17843937a47bc5a1afb9701e1d0565fae31f5800590dErik        p.setStrokeWidth(GRID_LINE_WIDTH);
178502041687c35441e8a21cb763f1fc3a26525292efDavid Brown        int linesIndex = 0;
1786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int hour = 0; hour <= 24; hour++) {
178702041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = startX;
178802041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = y;
178902041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopX;
179002041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = y;
1791146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            y += deltaY;
1792146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
179302041687c35441e8a21cb763f1fc3a26525292efDavid Brown        if (mCalendarGridLineVerticalColor != mCalendarGridLineHorizontalColor) {
179402041687c35441e8a21cb763f1fc3a26525292efDavid Brown            canvas.drawLines(mLines, 0, linesIndex, p);
179502041687c35441e8a21cb763f1fc3a26525292efDavid Brown            linesIndex = 0;
179602041687c35441e8a21cb763f1fc3a26525292efDavid Brown            p.setColor(mCalendarGridLineVerticalColor);
179702041687c35441e8a21cb763f1fc3a26525292efDavid Brown        }
1798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
17993eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the outer vertical grid lines
18003eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float startY = 0;
18013eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float stopY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP);
18023eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float deltaX = mCellWidth + DAY_GAP;
1803146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float x = mHoursWidth + mCellWidth;
1804146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++) {
180502041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
180602041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = startY;
180702041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
180802041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopY;
1809146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            x += deltaX;
1810146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
181102041687c35441e8a21cb763f1fc3a26525292efDavid Brown        canvas.drawLines(mLines, 0, linesIndex, p);
1812146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
18133eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the inner horizontal grid lines
18143eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setColor(mCalendarGridLineInnerHorizontalColor);
18153eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setStrokeWidth(GRID_LINE_INNER_WIDTH);
18163eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        y = 0;
18173eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        x = 0;
181802041687c35441e8a21cb763f1fc3a26525292efDavid Brown        linesIndex = 0;
18193eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        for (int hour = 0; hour <= 24; hour++) {
182002041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = startX;
182102041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = y;
182202041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopX;
182302041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = y;
18243eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            y += deltaY;
18253eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        }
182602041687c35441e8a21cb763f1fc3a26525292efDavid Brown        if (mCalendarGridLineInnerVerticalColor != mCalendarGridLineInnerHorizontalColor) {
182702041687c35441e8a21cb763f1fc3a26525292efDavid Brown            canvas.drawLines(mLines, 0, linesIndex, p);
182802041687c35441e8a21cb763f1fc3a26525292efDavid Brown            linesIndex = 0;
182902041687c35441e8a21cb763f1fc3a26525292efDavid Brown            p.setColor(mCalendarGridLineInnerVerticalColor);
183002041687c35441e8a21cb763f1fc3a26525292efDavid Brown        }
18313eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
18323eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the inner vertical grid lines
18333eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        x = mHoursWidth + mCellWidth;
18343eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        for (int day = 0; day < mNumDays; day++) {
183502041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
183602041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = startY;
183702041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
183802041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopY;
18393eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            x += deltaX;
18403eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        }
184102041687c35441e8a21cb763f1fc3a26525292efDavid Brown        canvas.drawLines(mLines, 0, linesIndex, p);
18423eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
1843146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Restore the saved style.
1844146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStyle(savedStyle);
1845146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
1846146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1847146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1848146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Event getSelectedEvent() {
1849146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == null) {
1850146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // There is no event at the selected hour, so create a new event.
1851146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return getNewEvent(mSelectionDay, getSelectedTimeInMillis(),
1852146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    getSelectedMinutesSinceMidnight());
1853146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1854146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return mSelectedEvent;
1855146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1856146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1857146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    boolean isEventSelected() {
1858146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return (mSelectedEvent != null);
1859146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1860146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1861146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Event getNewEvent() {
1862146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return getNewEvent(mSelectionDay, getSelectedTimeInMillis(),
1863146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                getSelectedMinutesSinceMidnight());
1864146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1865146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1866146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    static Event getNewEvent(int julianDay, long utcMillis,
1867146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int minutesSinceMidnight) {
1868146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event event = Event.newInstance();
1869146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.startDay = julianDay;
1870146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.endDay = julianDay;
1871146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.startMillis = utcMillis;
1872146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.endMillis = event.startMillis + MILLIS_PER_HOUR;
1873146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.startTime = minutesSinceMidnight;
1874146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.endTime = event.startTime + MINUTES_PER_HOUR;
1875146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return event;
1876146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1877146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1878146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int computeMaxStringWidth(int currentMax, String[] strings, Paint p) {
1879146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float maxWidthF = 0.0f;
1880146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1881146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int len = strings.length;
1882146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < len; i++) {
1883146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float width = p.measureText(strings[i]);
1884146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            maxWidthF = Math.max(width, maxWidthF);
1885146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1886146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int maxWidth = (int) (maxWidthF + 0.5);
1887146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (maxWidth < currentMax) {
1888146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            maxWidth = currentMax;
1889146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1890146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return maxWidth;
1891146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1892146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1893146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void saveSelectionPosition(float left, float top, float right, float bottom) {
1894146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.left = (int) left;
1895146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.right = (int) right;
1896146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.top = (int) top;
1897146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.bottom = (int) bottom;
1898146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1899146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1900146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect getCurrentSelectionPosition() {
1901146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect box = new Rect();
1902146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.top = mSelectionHour * (mCellHeight + HOUR_GAP);
1903146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.bottom = box.top + mCellHeight + HOUR_GAP;
1904146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int daynum = mSelectionDay - mFirstJulianDay;
1905146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP);
1906146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.right = box.left + mCellWidth + DAY_GAP;
1907146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return box;
1908146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1909146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
19109c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    private void setupTextRect(RectF rf) {
191136a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        if (rf.bottom <= rf.top || rf.right <= rf.left) {
191236a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.bottom = rf.top;
191336a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.right = rf.left;
191436a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            return;
191536a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
191636a4668f603c432d08ad156cd7c731f9838c0212Michael Chan
191736a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        if (rf.bottom - rf.top > EVENT_TEXT_TOP_MARGIN + EVENT_TEXT_BOTTOM_MARGIN) {
191836a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.top += EVENT_TEXT_TOP_MARGIN;
191936a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.bottom -= EVENT_TEXT_BOTTOM_MARGIN;
192036a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
192136a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        if (rf.right - rf.left > EVENT_TEXT_LEFT_MARGIN + EVENT_TEXT_RIGHT_MARGIN) {
192236a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.left += EVENT_TEXT_LEFT_MARGIN;
192336a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.right -= EVENT_TEXT_RIGHT_MARGIN;
192436a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
19259c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    }
19269c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan
19279c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    private void setupAllDayTextRect(RectF rf) {
192836a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        if (rf.bottom <= rf.top || rf.right <= rf.left) {
192936a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.bottom = rf.top;
193036a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.right = rf.left;
193136a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            return;
193236a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
193336a4668f603c432d08ad156cd7c731f9838c0212Michael Chan
193436a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        if (rf.bottom - rf.top > EVENT_ALL_DAY_TEXT_TOP_MARGIN + EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN) {
193536a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.top += EVENT_ALL_DAY_TEXT_TOP_MARGIN;
193636a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.bottom -= EVENT_ALL_DAY_TEXT_BOTTOM_MARGIN;
193736a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
193836a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        if (rf.right - rf.left > EVENT_ALL_DAY_TEXT_LEFT_MARGIN + EVENT_ALL_DAY_TEXT_RIGHT_MARGIN) {
193936a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.left += EVENT_ALL_DAY_TEXT_LEFT_MARGIN;
194036a4668f603c432d08ad156cd7c731f9838c0212Michael Chan            rf.right -= EVENT_ALL_DAY_TEXT_RIGHT_MARGIN;
194136a4668f603c432d08ad156cd7c731f9838c0212Michael Chan        }
19429c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan    }
19439c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan
19443e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    /**
19453e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh     * Return the layout for a numbered event. Create it if not already existing
19463e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh     */
19473e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    private StaticLayout getEventLayout(int i, Event event, Paint paint, RectF rf) {
19483e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        StaticLayout layout = mLayouts.get(i);
1949f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        // Check if we have already initialized the StaticLayout and that
1950f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        // the width hasn't changed (due to vertical resizing which causes
1951f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        // re-layout of events at min height)
1952f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        if (layout == null || rf.width() != layout.getWidth()) {
1953f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan            String text = drawTextSanitizer(event.getTitleAndLocation(), MAX_EVENT_TEXT_LEN);
19543e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
19553e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            // Leave a one pixel boundary on the left and right of the rectangle for the event
19563e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            layout = new StaticLayout(text, 0, text.length(), new TextPaint(paint),
1957f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                    (int) rf.width(), Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true, null,
1958f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                    (int) rf.width());
19593e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
19603e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            mLayouts.set(i, layout);
19613e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        }
19623e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
19633e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        return layout;
19643e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    }
19653e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
19663e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    /**
19673e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh     * Return the layout matching the currently selected event.
19683e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh     */
19693e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    private StaticLayout getSelectedLayout(Paint paint, RectF rf) {
19703e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        if (mSelectedLayout != null) {
19713e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            return mSelectedLayout;
19723e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        }
19733e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
19743e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        int index = mEvents.indexOf(mSelectedEvent);
19753e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        mSelectedLayout = getEventLayout(index, mSelectedEvent, paint, rf);
19763e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
19773e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        return mSelectedLayout;
19783e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh    }
19793e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh
1980146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawAllDayEvents(int firstDay, int numDays,
1981146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Rect r, Canvas canvas, Paint p) {
1982146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(NORMAL_FONT_SIZE);
1983146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextAlign(Paint.Align.LEFT);
1984146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint eventTextPaint = mEventTextPaint;
1985146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1986146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the background for the all-day events area
19873eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.top = DAY_HEADER_HEIGHT;
19883eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.bottom = r.top + mAllDayHeight + ALLDAY_TOP_MARGIN;
19893eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.left = mHoursWidth;
19903eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.right = r.left + mNumDays * (mCellWidth + DAY_GAP);
19913eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarAllDayBackground);
19923eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
1993146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1994146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Fill the extra space on the right side with the default background
19953eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.left = r.right;
19963eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // r.right = mViewWidth;
19973eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // p.setColor(mCalendarGridAreaBackground);
19983eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // canvas.drawRect(r, p);
1999146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
20003eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the outer vertical grid lines
2001d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridLineVerticalColor);
20029c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        p.setStyle(Style.FILL);
20033eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setStrokeWidth(GRID_LINE_WIDTH);
2004146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(false);
20053eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float startY = DAY_HEADER_HEIGHT;
20063eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float stopY = startY + mAllDayHeight + ALLDAY_TOP_MARGIN;
20073eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        final float deltaX = mCellWidth + DAY_GAP;
2008146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float x = mHoursWidth + mCellWidth;
200902041687c35441e8a21cb763f1fc3a26525292efDavid Brown        int linesIndex = 0;
20103eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        for (int day = 0; day < mNumDays; day++) {
201102041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
201202041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = startY;
201302041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
201402041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopY;
2015146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            x += deltaX;
2016146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
201702041687c35441e8a21cb763f1fc3a26525292efDavid Brown        canvas.drawLines(mLines, 0, linesIndex, p);
20183eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
20193eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Draw the inner vertical grid lines
20203eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setColor(mCalendarGridLineInnerVerticalColor);
20213eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        x = mHoursWidth + mCellWidth;
20223eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        p.setStrokeWidth(GRID_LINE_INNER_WIDTH);
202302041687c35441e8a21cb763f1fc3a26525292efDavid Brown        linesIndex = 0;
20243eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        for (int day = 0; day < mNumDays; day++) {
202502041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
202602041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = startY;
202702041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = x;
202802041687c35441e8a21cb763f1fc3a26525292efDavid Brown            mLines[linesIndex++] = stopY;
20293eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            x += deltaX;
20303eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        }
203102041687c35441e8a21cb763f1fc3a26525292efDavid Brown        canvas.drawLines(mLines, 0, linesIndex, p);
20323eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan
2033146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
2034146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStyle(Style.FILL);
2035146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
20363eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        int y = DAY_HEADER_HEIGHT + ALLDAY_TOP_MARGIN;
2037146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float left = mHoursWidth;
2038146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int lastDay = firstDay + numDays - 1;
2039146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ArrayList<Event> events = mEvents;
2040146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numEvents = events.size();
2041146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float drawHeight = mAllDayHeight;
2042146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float numRectangles = mMaxAllDayEvents;
2043146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < numEvents; i++) {
2044146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(i);
2045c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            if (!event.allDay) {
2046146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
2047c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            }
2048146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startDay = event.startDay;
2049146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endDay = event.endDay;
2050c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            if (startDay > lastDay || endDay < firstDay) {
2051146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
2052c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            }
2053c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            if (startDay < firstDay) {
2054146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startDay = firstDay;
2055c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            }
2056c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            if (endDay > lastDay) {
2057146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                endDay = lastDay;
2058c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa            }
2059146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startIndex = startDay - firstDay;
2060146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endIndex = endDay - firstDay;
2061146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float height = drawHeight / numRectangles;
2062146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2063146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Prevent a single event from getting too big
2064f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan            if (height > MAX_HEIGHT_OF_ONE_ALLDAY_EVENT) {
2065f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                height = MAX_HEIGHT_OF_ONE_ALLDAY_EVENT;
2066146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2067146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2068146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Leave a one-pixel space between the vertical day lines and the
2069146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // event rectangle.
20709c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan            event.left = left + startIndex * (mCellWidth + DAY_GAP);
20719c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan            event.right = left + endIndex * (mCellWidth + DAY_GAP) + mCellWidth;
2072146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            event.top = y + height * event.getColumn();
20739c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan            event.bottom = event.top + height;
2074146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
20759c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan            RectF rf = drawEventRect(event, canvas, p, eventTextPaint);
20769c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan            setupAllDayTextRect(rf);
20773e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            StaticLayout layout = getEventLayout(i, event, eventTextPaint, rf);
20783e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            drawEventText(layout, rf, canvas, eventTextPaint, ALL_DAY_TEXT_TOP_MARGIN);
2079146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2080146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Check if this all-day event intersects the selected day
2081146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionAllDay && mComputeSelectedEvents) {
2082146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (startDay <= mSelectionDay && endDay >= mSelectionDay) {
2083146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectedEvents.add(event);
2084146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2085146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2087146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2088146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionAllDay) {
2089146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Compute the neighbors for the list of all-day events that
2090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // intersect the selected day.
2091146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeAllDayNeighbors();
2092146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
2093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event event = mSelectedEvent;
20949c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                RectF rf = drawEventRect(event, canvas, p, eventTextPaint);
20959c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                setupAllDayTextRect(rf);
20963e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                StaticLayout layout = getSelectedLayout(eventTextPaint, rf);
20973e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                drawEventText(layout, rf, canvas, eventTextPaint, ALL_DAY_TEXT_TOP_MARGIN);
2098146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2099146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Draw the highlight on the selected all-day area
21013eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            float top = DAY_HEADER_HEIGHT + 1;
2102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float bottom = top + mAllDayHeight + ALLDAY_TOP_MARGIN - 1;
2103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int daynum = mSelectionDay - mFirstJulianDay;
2104146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            left = mHoursWidth + daynum * (mCellWidth + DAY_GAP) + 1;
2105146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float right = left + mCellWidth + DAY_GAP - 1;
2106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mNumDays == 1) {
2107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // The Day view doesn't have a vertical line on the right.
2108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                right -= 1;
2109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2110146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Path path = mPath;
2111146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            path.reset();
2112146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            path.addRect(left, top, right, bottom, Direction.CW);
2113146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawPath(path, mSelectionPaint);
2114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2115146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Set the selection position to zero so that when we move down
2116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // to the normal event area, we will highlight the topmost event.
2117146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            saveSelectionPosition(0f, 0f, 0f, 0f);
2118146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2119146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2120146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void computeAllDayNeighbors() {
2122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int len = mSelectedEvents.size();
2123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (len == 0 || mSelectedEvent != null) {
2124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // First, clear all the links
2128146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
2129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
2130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextUp = null;
2131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextDown = null;
2132146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextLeft = null;
2133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextRight = null;
2134146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // For each event in the selected event list "mSelectedEvents", find
2137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // its neighbors in the up and down directions.  This could be done
2138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // more efficiently by sorting on the Event.getColumn() field, but
2139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // the list is expected to be very small.
2140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2141146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Find the event in the same row as the previously selected all-day
2142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // event, if any.
2143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int startPosition = -1;
2144146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mPrevSelectedEvent != null && mPrevSelectedEvent.allDay) {
2145146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            startPosition = mPrevSelectedEvent.getColumn();
2146146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2147146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int maxPosition = -1;
2148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event startEvent = null;
2149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event maxPositionEvent = null;
2150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
2151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
2152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int position = ev.getColumn();
2153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (position == startPosition) {
2154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEvent = ev;
2155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (position > maxPosition) {
2156146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                maxPositionEvent = ev;
2157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                maxPosition = position;
2158146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int jj = 0; jj < len; jj++) {
2160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (jj == ii) {
2161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    continue;
2162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event neighbor = mSelectedEvents.get(jj);
2164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int neighborPosition = neighbor.getColumn();
2165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (neighborPosition == position - 1) {
2166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    ev.nextUp = neighbor;
2167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (neighborPosition == position + 1) {
2168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    ev.nextDown = neighbor;
2169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2172146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (startEvent != null) {
2173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = startEvent;
2174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = maxPositionEvent;
2176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
21773e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        mSelectedLayout = null;
2178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2180c514df21767542285fe6cf333b148fff079a30f2Daisuke Miyakawa    private RectF drawAllDayEventRect(Event event, Canvas canvas, Paint p, Paint eventTextPaint) {
2181146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If this event is selected, then use the selection color
2182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == event) {
2183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Also, remember the last selected event that we drew
2184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPrevSelectedEvent = event;
2185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            p.setColor(mSelectionColor);
2186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            eventTextPaint.setColor(mSelectedEventTextColor);
2187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Use the normal color for all-day events
2189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            p.setColor(event.color);
2190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            eventTextPaint.setColor(mEventTextColor);
2191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        RectF rf = mRectF;
2194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.top = event.top;
2195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.bottom = event.bottom;
2196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.left = event.left;
2197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.right = event.right;
21983eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        canvas.drawRect(rf, p);
2199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.left += 2;
2201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.right -= 2;
2202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return rf;
2203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawEvents(int date, int left, int top, Canvas canvas, Paint p) {
2206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint eventTextPaint = mEventTextPaint;
2207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cellWidth = mCellWidth;
2208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cellHeight = mCellHeight;
2209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2210146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Use the selected hour as the selection region
2211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect selectionArea = mRect;
2212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.top = top + mSelectionHour * (cellHeight + HOUR_GAP);
2213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.bottom = selectionArea.top + cellHeight;
2214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.left = left;
2215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.right = selectionArea.left + cellWidth;
2216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ArrayList<Event> events = mEvents;
2218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numEvents = events.size();
2219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        EventGeometry geometry = mEventGeometry;
2220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < numEvents; i++) {
2222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(i);
2223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (!geometry.computeEventRect(date, left, top, cellWidth, event)) {
2224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
2225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (date == mSelectionDay && !mSelectionAllDay && mComputeSelectedEvents
2228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    && geometry.eventIntersectsSelection(event, selectionArea)) {
2229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvents.add(event);
2230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            RectF rf = drawEventRect(event, canvas, p, eventTextPaint);
22339c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan            setupTextRect(rf);
22343e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            StaticLayout layout = getEventLayout(i, event, eventTextPaint, rf);
22353e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            drawEventText(layout, rf, canvas, eventTextPaint, NORMAL_TEXT_TOP_MARGIN);
2236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (date == mSelectionDay && !mSelectionAllDay && isFocused()
2239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                && mSelectionMode != SELECTION_HIDDEN) {
2240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeNeighbors();
2241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
2242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                RectF rf = drawEventRect(mSelectedEvent, canvas, p, eventTextPaint);
22439c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan                setupTextRect(rf);
22443e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                StaticLayout layout = getSelectedLayout(eventTextPaint, rf);
22453e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh                drawEventText(layout, rf, canvas, eventTextPaint, NORMAL_TEXT_TOP_MARGIN);
2246146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2247146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2250146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Computes the "nearest" neighbor event in four directions (left, right,
2251146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // up, down) for each of the events in the mSelectedEvents array.
2252146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void computeNeighbors() {
2253146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int len = mSelectedEvents.size();
2254146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (len == 0 || mSelectedEvent != null) {
2255146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // First, clear all the links
2259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
2260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
2261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextUp = null;
2262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextDown = null;
2263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextLeft = null;
2264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextRight = null;
2265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2267146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event startEvent = mSelectedEvents.get(0);
2268146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int startEventDistance1 = 100000;  // any large number
2269146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int startEventDistance2 = 100000;  // any large number
2270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevLocation = FROM_NONE;
2271146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevTop;
2272146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevBottom;
2273146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevLeft;
2274146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevRight;
2275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevCenter = 0;
2276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect box = getCurrentSelectionPosition();
2277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mPrevSelectedEvent != null) {
2278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevTop = (int) mPrevSelectedEvent.top;
2279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevBottom = (int) mPrevSelectedEvent.bottom;
2280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLeft = (int) mPrevSelectedEvent.left;
2281146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevRight = (int) mPrevSelectedEvent.right;
2282146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Check if the previously selected event intersects the previous
2283146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // selection box.  (The previously selected event may be from a
2284146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // much older selection box.)
2285146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (prevTop >= mPrevBox.bottom || prevBottom <= mPrevBox.top
2286146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || prevRight <= mPrevBox.left || prevLeft >= mPrevBox.right) {
2287146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = null;
2288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevTop = mPrevBox.top;
2289146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevBottom = mPrevBox.bottom;
2290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevLeft = mPrevBox.left;
2291146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevRight = mPrevBox.right;
2292146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
2293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Clip the top and bottom to the previous selection box.
2294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (prevTop < mPrevBox.top) {
2295146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    prevTop = mPrevBox.top;
2296146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (prevBottom > mPrevBox.bottom) {
2298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    prevBottom = mPrevBox.bottom;
2299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Just use the previously drawn selection box
2303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevTop = mPrevBox.top;
2304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevBottom = mPrevBox.bottom;
2305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLeft = mPrevBox.left;
2306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevRight = mPrevBox.right;
2307146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Figure out where we came from and compute the center of that area.
2310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (prevLeft >= box.right) {
2311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was to the right of us.
2312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_RIGHT;
2313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevTop + prevBottom) / 2;
2314146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (prevRight <= box.left) {
2315146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was to the left of us.
2316146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_LEFT;
2317146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevTop + prevBottom) / 2;
2318146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (prevBottom <= box.top) {
2319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was above us.
2320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_ABOVE;
2321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevLeft + prevRight) / 2;
2322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (prevTop >= box.bottom) {
2323146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was below us.
2324146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_BELOW;
2325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevLeft + prevRight) / 2;
2326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2328146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // For each event in the selected event list "mSelectedEvents", search
2329146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // all the other events in that list for the nearest neighbor in 4
2330146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // directions.
2331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
2332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
2333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startTime = ev.startTime;
2335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endTime = ev.endTime;
2336146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int left = (int) ev.left;
2337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int right = (int) ev.right;
2338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int top = (int) ev.top;
2339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (top < box.top) {
2340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                top = box.top;
2341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int bottom = (int) ev.bottom;
2343146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (bottom > box.bottom) {
2344146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                bottom = box.bottom;
2345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2346146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (false) {
2347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL
2348146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
2349ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                if (DateFormat.is24HourFormat(mContext)) {
2350146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    flags |= DateUtils.FORMAT_24HOUR;
2351146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2352ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                String timeRange = DateUtils.formatDateRange(mContext,
2353146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        ev.startMillis, ev.endMillis, flags);
2354146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Log.i("Cal", "left: " + left + " right: " + right + " top: " + top
2355146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        + " bottom: " + bottom + " ev: " + timeRange + " " + ev.title);
2356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int upDistanceMin = 10000;     // any large number
2358146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int downDistanceMin = 10000;   // any large number
2359146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int leftDistanceMin = 10000;   // any large number
2360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int rightDistanceMin = 10000;  // any large number
2361146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event upEvent = null;
2362146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event downEvent = null;
2363146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event leftEvent = null;
2364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event rightEvent = null;
2365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2366146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Pick the starting event closest to the previously selected event,
2367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // if any.  distance1 takes precedence over distance2.
2368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int distance1 = 0;
2369146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int distance2 = 0;
2370146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (prevLocation == FROM_ABOVE) {
2371146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (left >= prevCenter) {
2372146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = left - prevCenter;
2373146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (right <= prevCenter) {
2374146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - right;
2375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2376146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = top - prevBottom;
2377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (prevLocation == FROM_BELOW) {
2378146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (left >= prevCenter) {
2379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = left - prevCenter;
2380146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (right <= prevCenter) {
2381146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - right;
2382146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2383146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = prevTop - bottom;
2384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (prevLocation == FROM_LEFT) {
2385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (bottom <= prevCenter) {
2386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - bottom;
2387146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (top >= prevCenter) {
2388146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = top - prevCenter;
2389146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = left - prevRight;
2391146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (prevLocation == FROM_RIGHT) {
2392146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (bottom <= prevCenter) {
2393146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - bottom;
2394146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (top >= prevCenter) {
2395146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = top - prevCenter;
2396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2397146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = prevLeft - right;
2398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2399146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (distance1 < startEventDistance1
2400146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || (distance1 == startEventDistance1 && distance2 < startEventDistance2)) {
2401146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEvent = ev;
2402146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEventDistance1 = distance1;
2403146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEventDistance2 = distance2;
2404146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // For each neighbor, figure out if it is above or below or left
2407146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // or right of me and compute the distance.
2408146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int jj = 0; jj < len; jj++) {
2409146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (jj == ii) {
2410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    continue;
2411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2412146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event neighbor = mSelectedEvents.get(jj);
2413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int neighborLeft = (int) neighbor.left;
2414146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int neighborRight = (int) neighbor.right;
2415146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (neighbor.endTime <= startTime) {
2416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely above me.
2417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // If we overlap the same column, then compute the distance.
2418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborLeft < right && neighborRight > left) {
2419146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int distance = startTime - neighbor.endTime;
2420146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (distance < upDistanceMin) {
2421146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            upDistanceMin = distance;
2422146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            upEvent = neighbor;
2423146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        } else if (distance == upDistanceMin) {
2424146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int center = (left + right) / 2;
2425146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentDistance = 0;
2426146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentLeft = (int) upEvent.left;
2427146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentRight = (int) upEvent.right;
2428146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (currentRight <= center) {
2429146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = center - currentRight;
2430146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (currentLeft >= center) {
2431146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = currentLeft - center;
2432146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2433146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2434146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int neighborDistance = 0;
2435146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborRight <= center) {
2436146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = center - neighborRight;
2437146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (neighborLeft >= center) {
2438146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = neighborLeft - center;
2439146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2440146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborDistance < currentDistance) {
2441146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                upDistanceMin = distance;
2442146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                upEvent = neighbor;
2443146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2444146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2445146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2446146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (neighbor.startTime >= endTime) {
2447146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely below me.
2448146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // If we overlap the same column, then compute the distance.
2449146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborLeft < right && neighborRight > left) {
2450146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int distance = neighbor.startTime - endTime;
2451146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (distance < downDistanceMin) {
2452146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            downDistanceMin = distance;
2453146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            downEvent = neighbor;
2454146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        } else if (distance == downDistanceMin) {
2455146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int center = (left + right) / 2;
2456146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentDistance = 0;
2457146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentLeft = (int) downEvent.left;
2458146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentRight = (int) downEvent.right;
2459146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (currentRight <= center) {
2460146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = center - currentRight;
2461146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (currentLeft >= center) {
2462146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = currentLeft - center;
2463146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2464146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int neighborDistance = 0;
2466146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborRight <= center) {
2467146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = center - neighborRight;
2468146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (neighborLeft >= center) {
2469146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = neighborLeft - center;
2470146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2471146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborDistance < currentDistance) {
2472146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                downDistanceMin = distance;
2473146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                downEvent = neighbor;
2474146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2475146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2476146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2477146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2478146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2479146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (neighborLeft >= right) {
2480146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely to the right of me.
2481146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Take the closest neighbor in the y direction.
2482146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int center = (top + bottom) / 2;
2483146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int distance = 0;
2484146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborBottom = (int) neighbor.bottom;
2485146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborTop = (int) neighbor.top;
2486146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborBottom <= center) {
2487146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = center - neighborBottom;
2488146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (neighborTop >= center) {
2489146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = neighborTop - center;
2490146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2491146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (distance < rightDistanceMin) {
2492146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        rightDistanceMin = distance;
2493146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        rightEvent = neighbor;
2494146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (distance == rightDistanceMin) {
2495146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // Pick the closest in the x direction
2496146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int neighborDistance = neighborLeft - right;
2497146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int currentDistance = (int) rightEvent.left - right;
2498146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (neighborDistance < currentDistance) {
2499146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            rightDistanceMin = distance;
2500146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            rightEvent = neighbor;
2501146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2502146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2503146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (neighborRight <= left) {
2504146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely to the left of me.
2505146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Take the closest neighbor in the y direction.
2506146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int center = (top + bottom) / 2;
2507146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int distance = 0;
2508146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborBottom = (int) neighbor.bottom;
2509146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborTop = (int) neighbor.top;
2510146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborBottom <= center) {
2511146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = center - neighborBottom;
2512146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (neighborTop >= center) {
2513146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = neighborTop - center;
2514146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2515146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (distance < leftDistanceMin) {
2516146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        leftDistanceMin = distance;
2517146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        leftEvent = neighbor;
2518146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (distance == leftDistanceMin) {
2519146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // Pick the closest in the x direction
2520146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int neighborDistance = left - neighborRight;
2521146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int currentDistance = left - (int) leftEvent.right;
2522146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (neighborDistance < currentDistance) {
2523146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            leftDistanceMin = distance;
2524146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            leftEvent = neighbor;
2525146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2526146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2527146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2528146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2529146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextUp = upEvent;
2530146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextDown = downEvent;
2531146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextLeft = leftEvent;
2532146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextRight = rightEvent;
2533146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2534146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = startEvent;
25353e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        mSelectedLayout = null;
2536146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2537146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2538146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private RectF drawEventRect(Event event, Canvas canvas, Paint p, Paint eventTextPaint) {
253911ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        // Draw the Event Rect
25403eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        RectF rf = mRectF;
254111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.top = event.top + EVENT_RECT_TOP_MARGIN;
254211ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.bottom = event.bottom - EVENT_RECT_BOTTOM_MARGIN;
254311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.left = event.left + EVENT_RECT_LEFT_MARGIN;
254411ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.right = event.right - EVENT_RECT_RIGHT_MARGIN;
2545146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
254611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        // TEMP behavior
254711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        p.setAntiAlias(false);
2548c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        p.setColor(EVENT_OUTLINE_COLOR);
2549c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        p.setStrokeWidth(2);
255011ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        p.setStyle(Style.STROKE);
255111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        canvas.drawRect(rf, p);
2552c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        rf.top++;
2553c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        rf.left ++;
2554c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        rf.right--;
2555c29b2d3342d43c2662dd2fe51a28bc7e8acd7b36Erik        rf.bottom--;
255611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        int color = 0xAAFFFFFF;
255711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        int eventTextColor = mEventTextColor;
2558e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2559146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If this event is selected, then use the selection color
2560146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == event) {
2561146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionMode == SELECTION_PRESSED) {
2562146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Also, remember the last selected event that we drew
2563146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = event;
2564146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // box = mBoxPressed;
256511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                color = mPressedColor; // FIXME:pressed
256611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                eventTextColor = mSelectedEventTextColor;
2567146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionMode == SELECTION_SELECTED) {
2568146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Also, remember the last selected event that we drew
2569146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = event;
2570146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // box = mBoxSelected;
257111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                color = mSelectionColor;
257211ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                eventTextColor = mSelectedEventTextColor;
2573146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionMode == SELECTION_LONGPRESS) {
2574146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // box = mBoxLongPressed;
257511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                color = mPressedColor; // FIXME: longpressed (maybe -- this doesn't seem to work)
257611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                eventTextColor = mSelectedEventTextColor;
2577146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2578146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2579146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
258011ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        p.setColor(color);
258111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        p.setStyle(Style.FILL);
258211ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        eventTextPaint.setColor(eventTextColor);
258311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        canvas.drawRect(rf, p);
258411ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan
258511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        // Draw cal color square border
258611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        // TODO clean up once design is final
258711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.top = event.top - 2;
258811ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.left = event.left - 3;
25899c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        rf.bottom = rf.top + CALENDAR_COLOR_SQUARE_SIZE + 1;
25909c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        rf.right = rf.left + CALENDAR_COLOR_SQUARE_SIZE + 1;
259111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        p.setColor(0xFFFFFFFF);
25929c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        p.setStyle(Style.FILL);
259311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        canvas.drawRect(rf, p);
25948af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project
259511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        // Draw cal color
259611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.top++;
259711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.left++;
25989c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        rf.bottom--;
25999c1f7b6c194a42a39bacdaa25e887dc5f12ec478Michael Chan        rf.right--;
260011ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        p.setColor(event.color);
260111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        p.setStyle(Style.FILL);
26023eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        canvas.drawRect(rf, p);
2603e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
260411ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        boolean declined = (event.selfAttendeeStatus == Attendees.ATTENDEE_STATUS_DECLINED);
260511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        if (declined) {
260611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            boolean aa = p.isAntiAlias();
260711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            if (!aa) {
260811ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                p.setAntiAlias(true);
260911ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            }
261011ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            // Temp behavior
261111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            p.setColor(0x88FFFFFF);
261211ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            canvas.drawLine(rf.right, rf.top, rf.left, rf.bottom, p);
261311ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            if (!aa) {
261411ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan                p.setAntiAlias(false);
261511ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan            }
261611ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        }
261711ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan
26183eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan        // Setup rect for drawEventText which follows
261911ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.top = event.top + EVENT_RECT_TOP_MARGIN;
262011ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.bottom = event.bottom - EVENT_RECT_BOTTOM_MARGIN;
262111ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.left = event.left + EVENT_RECT_LEFT_MARGIN;
262211ca73595534d2b2c18ab8c31a735c9e683c9379Michael Chan        rf.right = event.right - EVENT_RECT_RIGHT_MARGIN;
2623146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return rf;
2624146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2625146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
26260d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    private Pattern drawTextSanitizerFilter = Pattern.compile("[\t\n],");
26270d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan
26280d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    // Sanitize a string before passing it to drawText or else we get little
26290d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    // squares. For newlines and tabs before a comma, delete the character.
26300d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    // Otherwise, just replace them with a space.
2631f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan    private String drawTextSanitizer(String string, int maxEventTextLen) {
26320d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan        Matcher m = drawTextSanitizerFilter.matcher(string);
2633f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        string = m.replaceAll(",");
2634f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan
2635f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        int len = string.length();
2636f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        if (len > maxEventTextLen) {
2637f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan            string = string.substring(0, maxEventTextLen);
2638f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan            len = maxEventTextLen;
2639f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        }
2640f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan
2641f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan        return string.replace('\n', ' ');
26420d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    }
26430d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan
2644f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan    private void drawEventText(StaticLayout eventLayout, RectF rf, Canvas canvas, Paint p,
2645f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan            int topMargin) {
2646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float width = rf.right - rf.left;
2647146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float height = rf.bottom - rf.top;
2648146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2649146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If the rectangle is too small for text, then return
2650f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        if (width < MIN_CELL_WIDTH_FOR_TEXT) {
2651f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan            return;
2652f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        }
2653f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan
2654f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        rf.bottom = 0;
2655f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        int lineCount = eventLayout.getLineCount();
2656f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        for (int i = 0; i < lineCount; i++) {
2657f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan            int lineBottom = eventLayout.getLineBottom(i);
2658f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan            if (lineBottom <= height) {
2659f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan                rf.bottom = lineBottom;
2660f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan            }
2661f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        }
2662f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan
2663f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        if (rf.bottom == 0) {
2664146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2665146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2666146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
26673e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        // Use a StaticLayout to format the string.
2668f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        p.setAntiAlias(true);
26693e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        canvas.save();
2670f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        canvas.translate(rf.left, rf.top);
2671f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        rf.left = 0;
2672f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        rf.right = width;
2673f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        rf.top = 0;
2674f63bf8348e504760a12d840c7107f326c0e2cadaMichael Chan        canvas.clipRect(rf);
26753e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        eventLayout.draw(canvas);
26763e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        canvas.restore();
2677146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2678146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void updateEventDetails() {
2680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == null || mSelectionMode == SELECTION_HIDDEN
2681146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                || mSelectionMode == SELECTION_LONGPRESS) {
2682146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPopup.dismiss();
2683146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2684146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2685666fc5e8ddbac15c951aad738bd818ee307eae42Erik        if (mLastPopupEventID == mSelectedEvent.id) {
2686666fc5e8ddbac15c951aad738bd818ee307eae42Erik            return;
2687666fc5e8ddbac15c951aad738bd818ee307eae42Erik        }
2688666fc5e8ddbac15c951aad738bd818ee307eae42Erik
2689666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = mSelectedEvent.id;
2690146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2691146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Remove any outstanding callbacks to dismiss the popup.
2692146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        getHandler().removeCallbacks(mDismissPopup);
2693146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2694146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event event = mSelectedEvent;
2695146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TextView titleView = (TextView) mPopupView.findViewById(R.id.event_title);
2696146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        titleView.setText(event.title);
2697146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2698146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ImageView imageView = (ImageView) mPopupView.findViewById(R.id.reminder_icon);
2699146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        imageView.setVisibility(event.hasAlarm ? View.VISIBLE : View.GONE);
2700146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2701146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        imageView = (ImageView) mPopupView.findViewById(R.id.repeat_icon);
2702146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        imageView.setVisibility(event.isRepeating ? View.VISIBLE : View.GONE);
2703146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2704146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int flags;
2705146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (event.allDay) {
2706146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags = DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_DATE |
2707146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL;
2708146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2709146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE
2710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL
2711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
2712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2713ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        if (DateFormat.is24HourFormat(mContext)) {
2714146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags |= DateUtils.FORMAT_24HOUR;
2715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2716731f1cb808b7586b93615b408ab2636081fab0dcErik        String timeRange = Utils.formatDateRange(mContext,
2717146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                event.startMillis, event.endMillis, flags);
2718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TextView timeView = (TextView) mPopupView.findViewById(R.id.time);
2719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        timeView.setText(timeRange);
2720146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TextView whereView = (TextView) mPopupView.findViewById(R.id.where);
2722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        final boolean empty = TextUtils.isEmpty(event.location);
2723146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        whereView.setVisibility(empty ? View.GONE : View.VISIBLE);
2724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!empty) whereView.setText(event.location);
2725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.LEFT, mHoursWidth, 5);
2727146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        postDelayed(mDismissPopup, POPUP_DISMISS_DELAY);
2728146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2729146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2730146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // The following routines are called from the parent activity when certain
2731146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // touch events occur.
27324484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doDown(MotionEvent ev) {
2733146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mTouchMode = TOUCH_MODE_DOWN;
2734146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewStartX = 0;
2735146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mOnFlingCalled = false;
2736146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        getHandler().removeCallbacks(mContinueScroll);
2737146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2738146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
27394484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doSingleTapUp(MotionEvent ev) {
2740d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (!mHandleActionUp) {
2741d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            return;
2742d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
2743d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2744146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int x = (int) ev.getX();
2745146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int y = (int) ev.getY();
2746146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int selectedDay = mSelectionDay;
2747146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int selectedHour = mSelectionHour;
2748146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2749146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        boolean validPosition = setSelectionFromPosition(x, y);
2750146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!validPosition) {
275180bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            // return if the touch wasn't on an area of concern
2752146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2753146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2754146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
275580bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        mSelectionMode = SELECTION_SELECTED;
2756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
2757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
275880bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        if (mSelectedEvent != null) {
275980bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            // If the tap is on an event, launch the "View event" view
2760344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, mSelectedEvent.id,
2761344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan                    mSelectedEvent.startMillis, mSelectedEvent.endMillis, (int) ev.getRawX(),
2762344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan                    (int) ev.getRawY());
2763344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan        } else if (selectedDay == mSelectionDay && selectedHour == mSelectionHour) {
2764344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            // If the tap is on an already selected hour slot, then create a new
2765344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            // event
2766344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
2767344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan                    getSelectedTimeInMillis(), 0, (int) ev.getRawX(), (int) ev.getRawY());
2768344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan        } else {
2769344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            Time startTime = new Time(mBaseDate);
2770344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            startTime.setJulianDay(mSelectionDay);
2771344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            startTime.hour = mSelectionHour;
2772344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            startTime.normalize(true /* ignore isDst */);
277383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
277483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Time endTime = new Time(startTime);
277583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            endTime.hour++;
277683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
2777344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            mController.sendEvent(this, EventType.GO_TO, startTime, endTime, -1, ViewType.CURRENT);
2778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
27814484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doLongPress(MotionEvent ev) {
2782d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        // Scale gesture in progress
2783d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mStartingSpanY != 0) {
2784d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            return;
2785d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
2786d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
278780bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        int x = (int) ev.getX();
278880bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        int y = (int) ev.getY();
278980bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan
279080bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        boolean validPosition = setSelectionFromPosition(x, y);
279180bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        if (!validPosition) {
279280bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            // return if the touch wasn't on an area of concern
279380bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            return;
279480bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        }
279580bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan
2796146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_LONGPRESS;
2797146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
2798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        performLongClick();
2799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
28014484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doScroll(MotionEvent e1, MotionEvent e2, float deltaX, float deltaY) {
2802146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Use the distance from the current point to the initial touch instead
2803146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // of deltaX and deltaY to avoid accumulating floating-point rounding
2804146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // errors.  Also, we don't need floats, we can use ints.
2805146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceX = (int) e1.getX() - (int) e2.getX();
2806146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceY = (int) e1.getY() - (int) e2.getY();
2807146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2808146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If we haven't figured out the predominant scroll direction yet,
2809146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // then do it now.
2810146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mTouchMode == TOUCH_MODE_DOWN) {
2811146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int absDistanceX = Math.abs(distanceX);
2812146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int absDistanceY = Math.abs(distanceY);
2813146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mScrollStartY = mViewStartY;
2814146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPreviousDirection = 0;
2815146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2816146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If the x distance is at least twice the y distance, then lock
2817146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // the scroll horizontally.  Otherwise scroll vertically.
2818146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (absDistanceX >= 2 * absDistanceY) {
2819146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mTouchMode = TOUCH_MODE_HSCROLL;
2820146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartX = distanceX;
2821146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                initNextView(-mViewStartX);
2822146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
2823146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mTouchMode = TOUCH_MODE_VSCROLL;
2824146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2825146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
2826146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // We are already scrolling horizontally, so check if we
2827146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // changed the direction of scrolling so that the other week
2828146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // is now visible.
2829146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mViewStartX = distanceX;
2830146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (distanceX != 0) {
2831146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int direction = (distanceX > 0) ? 1 : -1;
2832146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (direction != mPreviousDirection) {
2833146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // The user has switched the direction of scrolling
2834146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // so re-init the next view
2835146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    initNextView(-mViewStartX);
2836146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mPreviousDirection = direction;
2837146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2838146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2839146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2840146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2841146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((mTouchMode & TOUCH_MODE_VSCROLL) != 0) {
2842146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mViewStartY = mScrollStartY + distanceY;
2843146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mViewStartY < 0) {
2844146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = 0;
2845146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mViewStartY > mMaxViewStartY) {
2846146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = mMaxViewStartY;
2847146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2848146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeFirstHour();
2849146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2850146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2851146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mScrolling = true;
2852146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2853146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionMode != SELECTION_HIDDEN) {
2854146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionMode = SELECTION_HIDDEN;
2855146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2856146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
2857146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2858146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
28594484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
2860146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mTouchMode = TOUCH_MODE_INITIAL_STATE;
2861146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_HIDDEN;
2862146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mOnFlingCalled = true;
2863146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaX = (int) e2.getX() - (int) e1.getX();
2864146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceX = Math.abs(deltaX);
2865146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaY = (int) e2.getY() - (int) e1.getY();
2866146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceY = Math.abs(deltaY);
2867146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2868146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((distanceX >= HORIZONTAL_SCROLL_THRESHOLD) && (distanceX > distanceY)) {
286911638ad4fb56b978770aebe75deac7a0e6ac60d2Erik            // initNextView(deltaX);
287011638ad4fb56b978770aebe75deac7a0e6ac60d2Erik
287111638ad4fb56b978770aebe75deac7a0e6ac60d2Erik            switchViews(mViewStartX > 0, mViewStartX, mViewWidth);
287211638ad4fb56b978770aebe75deac7a0e6ac60d2Erik            DayView view = (DayView) mViewSwitcher.getCurrentView();
287383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
287483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Time end = new Time(view.mBaseDate);
28751f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan            end.monthDay += mNumDays;
28761f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan            end.normalize(true);
28773458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            mController
2878487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                    .sendEvent(this, EventType.GO_TO, view.mBaseDate, end, -1, ViewType.CURRENT);
287983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
2880146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mViewStartX = 0;
2881146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2882146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2883146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2884146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Continue scrolling vertically
2885146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mContinueScroll.init((int) velocityY / 20);
2886146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        post(mContinueScroll);
2887146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2888146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2889146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean initNextView(int deltaX) {
2890146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Change the view to the previous day or week
2891d190418220467c02327dd9b3ae1eae238889720bMichael Chan        DayView view = (DayView) mViewSwitcher.getNextView();
2892146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time date = view.mBaseDate;
2893146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        date.set(mBaseDate);
2894146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        boolean switchForward;
2895146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (deltaX > 0) {
2896146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.monthDay -= mNumDays;
2897146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionDay = mSelectionDay - mNumDays;
2898146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchForward = false;
2899146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2900146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.monthDay += mNumDays;
2901146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionDay = mSelectionDay + mNumDays;
2902146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchForward = true;
2903146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2904146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        date.normalize(true /* ignore isDst */);
2905146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        initView(view);
2906ad36a3c3cde7a2ec6d3a35d2529d46f03bd8d59dMichael Chan        view.layout(getLeft(), getTop(), getRight(), getBottom());
2907146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.reloadEvents();
2908146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return switchForward;
2909146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2910146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2911d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    // ScaleGestureDetector.OnScaleGestureListener
2912d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    public boolean onScaleBegin(ScaleGestureDetector detector) {
2913d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mHandleActionUp = false;
2914d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        float gestureCenterInPixels = detector.getFocusY() - DAY_HEADER_HEIGHT - mAllDayHeight;
2915d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mGestureCenterHour = (mViewStartY + gestureCenterInPixels) / (mCellHeight + DAY_GAP);
2916d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2917d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mStartingSpanY = Math.max(MIN_Y_SPAN, Math.abs(detector.getCurrentSpanY()));
2918d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mCellHeightBeforeScaleGesture = mCellHeight;
2919d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2920d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (DEBUG) {
2921d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            float ViewStartHour = mViewStartY / (float) (mCellHeight + DAY_GAP);
2922d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            Log.d(TAG, "mGestureCenterHour:" + mGestureCenterHour + "\tViewStartHour: "
2923d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    + ViewStartHour + "\tmViewStartY:" + mViewStartY + "\tmCellHeight:"
2924d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    + mCellHeight);
2925d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
2926d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2927d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        return true;
2928d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    }
2929d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2930d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    // ScaleGestureDetector.OnScaleGestureListener
2931d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    public boolean onScale(ScaleGestureDetector detector) {
2932d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        float spanY = Math.abs(detector.getCurrentSpanY());
2933d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2934d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mCellHeight = (int) (mCellHeightBeforeScaleGesture * spanY / mStartingSpanY);
2935d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2936d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mCellHeight < mMinCellHeight) {
2937d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            // If mStartingSpanY is too small, even a small increase in the
2938d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            // gesture can bump the mCellHeight beyond MAX_CELL_HEIGHT
2939d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mStartingSpanY = Math.max(MIN_Y_SPAN, spanY);
2940d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeight = mMinCellHeight;
2941d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeightBeforeScaleGesture = mMinCellHeight;
2942d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        } else if (mCellHeight > MAX_CELL_HEIGHT) {
2943d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mStartingSpanY = spanY;
2944d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeight = MAX_CELL_HEIGHT;
2945d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeightBeforeScaleGesture = MAX_CELL_HEIGHT;
2946d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
2947d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2948d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        int gestureCenterInPixels = (int) detector.getFocusY() - DAY_HEADER_HEIGHT - mAllDayHeight;
2949d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mViewStartY = (int) (mGestureCenterHour * (mCellHeight + DAY_GAP)) - gestureCenterInPixels;
2950d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mMaxViewStartY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP) - mGridAreaHeight;
2951d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2952d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (DEBUG) {
2953d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            float ViewStartHour = mViewStartY / (float) (mCellHeight + DAY_GAP);
2954d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            Log.d(TAG, " mGestureCenterHour:" + mGestureCenterHour + "\tViewStartHour: "
2955d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    + ViewStartHour + "\tmViewStartY:" + mViewStartY + "\tmCellHeight:"
2956d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    + mCellHeight + " SpanY:" + detector.getCurrentSpanY());
2957d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
2958d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2959d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mViewStartY < 0) {
2960d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mViewStartY = 0;
2961d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mGestureCenterHour = (mViewStartY + gestureCenterInPixels)
2962d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    / (float) (mCellHeight + DAY_GAP);
2963d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        } else if (mViewStartY > mMaxViewStartY) {
2964d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mViewStartY = mMaxViewStartY;
2965d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mGestureCenterHour = (mViewStartY + gestureCenterInPixels)
2966d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                    / (float) (mCellHeight + DAY_GAP);
2967d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
2968d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        computeFirstHour();
2969d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2970d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mRemeasure = true;
2971d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        invalidate();
2972d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        return true;
2973d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    }
2974d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2975d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    // ScaleGestureDetector.OnScaleGestureListener
2976d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    public void onScaleEnd(ScaleGestureDetector detector) {
2977d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mStartingSpanY = 0;
2978d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    }
2979d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2980146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
2981146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
2982146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int action = ev.getAction();
2983146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2984d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        mScaleGestureDetector.onTouchEvent(ev);
2985d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        if (mScaleGestureDetector.isInProgress()) {
2986d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            return true;
2987d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        }
2988d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
2989146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        switch (action) {
2990146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case MotionEvent.ACTION_DOWN:
2991d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            if (DEBUG) Log.e(TAG, "ACTION_DOWN");
2992d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mHandleActionUp = true;
2993ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            mGestureDetector.onTouchEvent(ev);
2994146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
2995146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2996146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case MotionEvent.ACTION_MOVE:
2997d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            if (DEBUG) Log.e(TAG, "ACTION_MOVE");
2998ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            mGestureDetector.onTouchEvent(ev);
2999146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
3000146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3001146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case MotionEvent.ACTION_UP:
3002d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            if (DEBUG) Log.e(TAG, "ACTION_UP " + mHandleActionUp);
3003ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            mGestureDetector.onTouchEvent(ev);
3004d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            if (!mHandleActionUp) {
3005d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                mHandleActionUp = true;
3006d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan                return true;
3007d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            }
3008146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mOnFlingCalled) {
3009146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
3010146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3011146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
3012146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mTouchMode = TOUCH_MODE_INITIAL_STATE;
3013146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (Math.abs(mViewStartX) > HORIZONTAL_SCROLL_THRESHOLD) {
3014146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // The user has gone beyond the threshold so switch views
3015ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                    switchViews(mViewStartX > 0, mViewStartX, mViewWidth);
30167abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project                    mViewStartX = 0;
30177abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project                    return true;
3018146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
3019146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Not beyond the threshold so invalidate which will cause
3020146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // the view to snap back.  Also call recalc() to ensure
3021146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // that we have the correct starting date and title.
3022146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    recalc();
3023146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    invalidate();
30247abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project                    mViewStartX = 0;
3025146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3028146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we were scrolling, then reset the selected hour so that it
3029146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // is visible.
3030146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mScrolling) {
3031146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mScrolling = false;
3032146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                resetSelectedHour();
3033146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
3034146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3035146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
3036146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3037146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // This case isn't expected to happen.
3038146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case MotionEvent.ACTION_CANCEL:
3039d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            if (DEBUG) Log.e(TAG, "ACTION_CANCEL");
3040ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            mGestureDetector.onTouchEvent(ev);
3041146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mScrolling = false;
3042146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            resetSelectedHour();
3043146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
3044146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3045146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        default:
3046d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            if (DEBUG) Log.e(TAG, "Not MotionEvent");
3047ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            if (mGestureDetector.onTouchEvent(ev)) {
3048146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
3049146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3050146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return super.onTouchEvent(ev);
3051146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3052146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3053146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3054146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
3055146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        MenuItem item;
3056146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3057146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If the trackball is held down, then the context menu pops up and
3058146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // we never get onKeyUp() for the long-press.  So check for it here
3059146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // and change the selection to the long-press state.
3060146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionMode != SELECTION_LONGPRESS) {
3061146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionMode = SELECTION_LONGPRESS;
3062146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            invalidate();
3063146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3064146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3065e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        final long startMillis = getSelectedTimeInMillis();
3066146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int flags = DateUtils.FORMAT_SHOW_TIME
3067146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                | DateUtils.FORMAT_CAP_NOON_MIDNIGHT
3068146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                | DateUtils.FORMAT_SHOW_WEEKDAY;
3069c5f92d7bdeb1950ace783cc022aa41a4b4f00cd6Erik        final String title = Utils.formatDateRange(mContext, startMillis, startMillis, flags);
3070146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        menu.setHeaderTitle(title);
3071e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3072146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numSelectedEvents = mSelectedEvents.size();
3073146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays == 1) {
3074146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Day view.
3075146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3076146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there is a selected event, then allow it to be viewed and
3077146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // edited.
3078146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (numSelectedEvents >= 1) {
30794484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_VIEW, 0, R.string.event_view);
3080146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
3081146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_info_details);
3082146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3083ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                int accessLevel = getEventAccessLevel(mContext, mSelectedEvent);
3084a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel == ACCESS_LEVEL_EDIT) {
30854484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_EDIT, 0, R.string.event_edit);
3086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
3087146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_edit);
3088146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setAlphabeticShortcut('e');
3089a505627659f6bfba8869eac8089f7030f2d0d92cErik                }
3090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3091a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel >= ACCESS_LEVEL_DELETE) {
30924484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_DELETE, 0, R.string.event_delete);
3093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
3094146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_delete);
3095146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3096146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
30974484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
3098146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
3099146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_add);
3100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setAlphabeticShortcut('n');
3101146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Otherwise, if the user long-pressed on a blank hour, allow
3103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // them to create an event.  They can also do this by tapping.
31044484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
3105146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
3106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_add);
3107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setAlphabeticShortcut('n');
3108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
3110146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Week view.
3111e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3112146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there is a selected event, then allow it to be viewed and
3113146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // edited.
3114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (numSelectedEvents >= 1) {
31154484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_VIEW, 0, R.string.event_view);
3116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
3117146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_info_details);
3118146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3119ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                int accessLevel = getEventAccessLevel(mContext, mSelectedEvent);
3120a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel == ACCESS_LEVEL_EDIT) {
31214484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_EDIT, 0, R.string.event_edit);
3122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
3123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_edit);
3124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setAlphabeticShortcut('e');
3125a505627659f6bfba8869eac8089f7030f2d0d92cErik                }
3126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3127a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel >= ACCESS_LEVEL_DELETE) {
31284484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_DELETE, 0, R.string.event_delete);
3129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
3130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_delete);
3131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
31324484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            }
3133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
31344484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
31354484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setOnMenuItemClickListener(mContextMenuHandler);
31364484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setIcon(android.R.drawable.ic_menu_add);
31374484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setAlphabeticShortcut('n');
3138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
31394484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item = menu.add(0, MENU_DAY, 0, R.string.show_day_view);
31404484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setOnMenuItemClickListener(mContextMenuHandler);
31414484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setIcon(android.R.drawable.ic_menu_day);
31424484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setAlphabeticShortcut('d');
3143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
31444484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item = menu.add(0, MENU_AGENDA, 0, R.string.show_agenda_view);
31454484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setOnMenuItemClickListener(mContextMenuHandler);
31464484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setIcon(android.R.drawable.ic_menu_agenda);
31474484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setAlphabeticShortcut('a');
3148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.dismiss();
3151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private class ContextMenuHandler implements MenuItem.OnMenuItemClickListener {
3154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public boolean onMenuItemClick(MenuItem item) {
3155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switch (item.getItemId()) {
31564484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_VIEW: {
3157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (mSelectedEvent != null) {
31589e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT,
31599e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                mSelectedEvent.id, mSelectedEvent.startMillis,
31609e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                mSelectedEvent.endMillis, 0, 0);
3161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
31644484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_EDIT: {
3165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (mSelectedEvent != null) {
31669e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        mController.sendEventRelatedEvent(this, EventType.EDIT_EVENT,
31679e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                mSelectedEvent.id, mSelectedEvent.startMillis,
31689e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                mSelectedEvent.endMillis, 0, 0);
3169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
31724484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_DAY: {
3173487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                    mController.sendEvent(this, EventType.GO_TO, getSelectedTime(), null, -1,
31749e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            ViewType.DAY);
3175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
31774484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_AGENDA: {
3178487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                    mController.sendEvent(this, EventType.GO_TO, getSelectedTime(), null, -1,
31799e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            ViewType.AGENDA);
3180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3181146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
31824484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_CREATE: {
3183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long startMillis = getSelectedTimeInMillis();
3184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
31859e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
31869e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            startMillis, endMillis, 0, 0);
3187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
31894484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_DELETE: {
3190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (mSelectedEvent != null) {
3191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        Event selectedEvent = mSelectedEvent;
3192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        long begin = selectedEvent.startMillis;
3193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        long end = selectedEvent.endMillis;
3194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        long id = selectedEvent.id;
31959e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        mController.sendEventRelatedEvent(this, EventType.DELETE_EVENT, id, begin,
31969e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                end, 0, 0);
3197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
3199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                default: {
3201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    return false;
3202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
3205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3208a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static int getEventAccessLevel(Context context, Event e) {
3209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ContentResolver cr = context.getContentResolver();
3210146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int visibility = Calendars.NO_ACCESS;
3212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Get the calendar id for this event
3214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Cursor cursor = cr.query(ContentUris.withAppendedId(Events.CONTENT_URI, e.id),
3215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                new String[] { Events.CALENDAR_ID },
3216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                null /* selection */,
3217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                null /* selectionArgs */,
3218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                null /* sort */);
3219e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3220e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (cursor == null) {
3221a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_NONE;
3222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3223e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3224e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (cursor.getCount() == 0) {
3225e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            cursor.close();
3226a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_NONE;
3227e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        }
3228e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        cursor.moveToFirst();
3230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long calId = cursor.getLong(0);
3231697bd6a8cec36cc75c72603674e57e4c6fe42dbfKen Shirriff        cursor.close();
3232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Uri uri = Calendars.CONTENT_URI;
3234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String where = String.format(CALENDARS_WHERE, calId);
3235146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        cursor = cr.query(uri, CALENDARS_PROJECTION, where, null, null);
3236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
32376d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        String calendarOwnerAccount = null;
3238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (cursor != null) {
3239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            cursor.moveToFirst();
3240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            visibility = cursor.getInt(CALENDARS_INDEX_ACCESS_LEVEL);
32416d34cec523930368976bc8d358d0a6de1da3462cMichael Chan            calendarOwnerAccount = cursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
3242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            cursor.close();
3243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3244e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
32456d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        if (visibility < Calendars.CONTRIBUTOR_ACCESS) {
3246a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_NONE;
32476d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        }
3248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
32496d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        if (e.guestsCanModify) {
3250a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_EDIT;
3251a505627659f6bfba8869eac8089f7030f2d0d92cErik        }
3252a505627659f6bfba8869eac8089f7030f2d0d92cErik
3253a505627659f6bfba8869eac8089f7030f2d0d92cErik        if (!TextUtils.isEmpty(calendarOwnerAccount) &&
3254a505627659f6bfba8869eac8089f7030f2d0d92cErik                calendarOwnerAccount.equalsIgnoreCase(e.organizer)) {
3255a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_EDIT;
3256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3258a505627659f6bfba8869eac8089f7030f2d0d92cErik        return ACCESS_LEVEL_DELETE;
3259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
3262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Sets mSelectionDay and mSelectionHour based on the (x,y) touch position.
3263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * If the touch position is not within the displayed grid, then this
3264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * method returns false.
3265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
3266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param x the x position of the touch
3267146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param y the y position of the touch
3268146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @return true if the touch position is valid
3269146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
3270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean setSelectionFromPosition(int x, int y) {
3271146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (x < mHoursWidth) {
3272146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return false;
3273146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3274146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int day = (x - mHoursWidth) / (mCellWidth + DAY_GAP);
3276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (day >= mNumDays) {
3277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            day = mNumDays - 1;
3278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        day += mFirstJulianDay;
3280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int hour;
3281146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (y < mFirstCell + mFirstHourOffset) {
3282146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionAllDay = true;
3283146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
3284146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            hour = (y - mFirstCell - mFirstHourOffset) / (mCellHeight + HOUR_GAP);
3285146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            hour += mFirstHour;
3286146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = hour;
3287146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionAllDay = false;
3288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3289146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionDay = day;
3290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        findSelectedEvent(x, y);
3291146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//        Log.i("Cal", "setSelectionFromPosition( " + x + ", " + y + " ) day: " + day
3292146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                + " hour: " + hour
3293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                + " mFirstCell: " + mFirstCell + " mFirstHourOffset: " + mFirstHourOffset);
3294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//        if (mSelectedEvent != null) {
3295146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            Log.i("Cal", "  num events: " + mSelectedEvents.size() + " event: " + mSelectedEvent.title);
3296146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            for (Event ev : mSelectedEvents) {
3297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL
3298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                        | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
3299ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                String timeRange = formatDateRange(mContext,
3300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                        ev.startMillis, ev.endMillis, flags);
3301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//
3302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                Log.i("Cal", "  " + timeRange + " " + ev.title);
3303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            }
3304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//        }
3305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return true;
3306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3307146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void findSelectedEvent(int x, int y) {
3309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int date = mSelectionDay;
3310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cellWidth = mCellWidth;
3311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ArrayList<Event> events = mEvents;
3312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numEvents = events.size();
3313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int left = mHoursWidth + (mSelectionDay - mFirstJulianDay) * (cellWidth + DAY_GAP);
3314146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int top = 0;
3315146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = null;
33163e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh        mSelectedLayout = null;
3317146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3318146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
3319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionAllDay) {
3320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float yDistance;
3321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float minYdistance = 10000.0f;  // any large number
3322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event closestEvent = null;
3323146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float drawHeight = mAllDayHeight;
33243eea5ad7329f522d9fe091ca51ad09b809bba34bMichael Chan            int yOffset = DAY_HEADER_HEIGHT + ALLDAY_TOP_MARGIN;
3325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int i = 0; i < numEvents; i++) {
3326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event event = events.get(i);
3327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (!event.allDay) {
3328146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    continue;
3329146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3330146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (event.startDay <= mSelectionDay && event.endDay >= mSelectionDay) {
3332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float numRectangles = event.getMaxColumns();
3333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float height = drawHeight / numRectangles;
3334f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                    if (height > MAX_HEIGHT_OF_ONE_ALLDAY_EVENT) {
3335f056fac66fe2845bfd88e9571f8fceb9180264a0Michael Chan                        height = MAX_HEIGHT_OF_ONE_ALLDAY_EVENT;
3336146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float eventTop = yOffset + height * event.getColumn();
3338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float eventBottom = eventTop + height;
3339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (eventTop < y && eventBottom > y) {
3340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // If the touch is inside the event rectangle, then
3341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // add the event.
3342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        mSelectedEvents.add(event);
3343146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        closestEvent = event;
3344146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        break;
3345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else {
3346146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // Find the closest event
3347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (eventTop >= y) {
3348146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            yDistance = eventTop - y;
3349146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        } else {
3350146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            yDistance = y - eventBottom;
3351146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
3352146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (yDistance < minYdistance) {
3353146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            minYdistance = yDistance;
3354146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            closestEvent = event;
3355146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
3356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3358146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3359146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = closestEvent;
3360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
3361146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3362146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3363146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Adjust y for the scrollable bitmap
3364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        y += mViewStartY - mFirstCell;
3365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3366146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Use a region around (x,y) for the selection region
3367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect region = mRect;
3368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.left = x - 10;
3369146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.right = x + 10;
3370146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.top = y - 10;
3371146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.bottom = y + 10;
3372146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3373146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        EventGeometry geometry = mEventGeometry;
3374146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < numEvents; i++) {
3376146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(i);
3377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Compute the event rectangle.
3378146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (!geometry.computeEventRect(date, left, top, cellWidth, event)) {
3379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
3380146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3381146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3382146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If the event intersects the selection region, then add it to
3383146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // mSelectedEvents.
3384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (geometry.eventIntersectsSelection(event, region)) {
3385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvents.add(event);
3386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3387146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3388146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3389146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If there are any events in the selected region, then assign the
3390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // closest one to mSelectedEvent.
3391146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvents.size() > 0) {
3392146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int len = mSelectedEvents.size();
3393146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event closestEvent = null;
3394146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float minDist = mViewWidth + mViewHeight;  // some large distance
3395146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int index = 0; index < len; index++) {
3396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event ev = mSelectedEvents.get(index);
3397146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                float dist = geometry.pointToEvent(x, y, ev);
3398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (dist < minDist) {
3399146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    minDist = dist;
3400146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    closestEvent = ev;
3401146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3402146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3403146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = closestEvent;
34043e7015267340b09d142dfcd3ff8acda257711023Shachar Shemesh            mSelectedLayout = null;
3405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Keep the selected hour and day consistent with the selected
3407146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // event.  They could be different if we touched on an empty hour
3408146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // slot very close to an event in the previous hour slot.  In
3409146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // that case we will select the nearby event.
3410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startDay = mSelectedEvent.startDay;
3411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endDay = mSelectedEvent.endDay;
3412146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionDay < startDay) {
3413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionDay = startDay;
3414146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionDay > endDay) {
3415146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionDay = endDay;
3416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startHour = mSelectedEvent.startTime / 60;
3419146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endHour;
3420146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent.startTime < mSelectedEvent.endTime) {
3421146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                endHour = (mSelectedEvent.endTime - 1) / 60;
3422146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3423146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                endHour = mSelectedEvent.endTime / 60;
3424146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3425146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3426146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionHour < startHour) {
3427146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionHour = startHour;
3428146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionHour > endHour) {
3429146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionHour = endHour;
3430146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3431146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3432146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3433146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3434146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Encapsulates the code to continue the scrolling after the
3435146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // finger is lifted.  Instead of stopping the scroll immediately,
3436146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // the scroll continues to "free spin" and gradually slows down.
3437146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private class ContinueScroll implements Runnable {
3438146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int mSignDeltaY;
3439146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int mAbsDeltaY;
3440146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float mFloatDeltaY;
3441146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long mFreeSpinTime;
3442146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final float FRICTION_COEF = 0.7F;
3443146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final long FREE_SPIN_MILLIS = 180;
3444146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final int MAX_DELTA = 60;
3445146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final int SCROLL_REPEAT_INTERVAL = 30;
3446146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3447146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void init(int deltaY) {
3448146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSignDeltaY = 0;
3449146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (deltaY > 0) {
3450146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSignDeltaY = 1;
3451146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (deltaY < 0) {
3452146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSignDeltaY = -1;
3453146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3454146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mAbsDeltaY = Math.abs(deltaY);
3455146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3456146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Limit the maximum speed
3457146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mAbsDeltaY > MAX_DELTA) {
3458146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mAbsDeltaY = MAX_DELTA;
3459146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3460146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFloatDeltaY = mAbsDeltaY;
3461146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFreeSpinTime = System.currentTimeMillis() + FREE_SPIN_MILLIS;
3462146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            Log.i("Cal", "init scroll: mAbsDeltaY: " + mAbsDeltaY
3463146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                    + " mViewStartY: " + mViewStartY);
3464146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3466146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void run() {
3467146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            long time = System.currentTimeMillis();
3468146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3469146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Start out with a frictionless "free spin"
3470146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (time > mFreeSpinTime) {
3471146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // If the delta is small, then apply a fixed deceleration.
3472146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Otherwise
3473146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mAbsDeltaY <= 10) {
3474146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mAbsDeltaY -= 2;
3475146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
3476146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mFloatDeltaY *= FRICTION_COEF;
3477146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mAbsDeltaY = (int) mFloatDeltaY;
3478146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3479146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3480146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mAbsDeltaY < 0) {
3481146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mAbsDeltaY = 0;
3482146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3483146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3484146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3485146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSignDeltaY == 1) {
3486146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY -= mAbsDeltaY;
3487146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3488146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY += mAbsDeltaY;
3489146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3490146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            Log.i("Cal", "  scroll: mAbsDeltaY: " + mAbsDeltaY
3491146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                    + " mViewStartY: " + mViewStartY);
3492146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3493146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mViewStartY < 0) {
3494146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = 0;
3495146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mAbsDeltaY = 0;
3496146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mViewStartY > mMaxViewStartY) {
3497146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = mMaxViewStartY;
3498146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mAbsDeltaY = 0;
3499146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3500146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3501146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeFirstHour();
3502146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3503146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mAbsDeltaY > 0) {
3504146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                postDelayed(this, SCROLL_REPEAT_INTERVAL);
3505146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3506146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Done scrolling.
3507146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mScrolling = false;
3508146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                resetSelectedHour();
3509146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3510146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3511146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            invalidate();
3512146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3513146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3514146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3515146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
3516bd0e834aea317236d574f8738fe11a51fdc87968Erik     * Cleanup the pop-up and timers.
3517146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
3518146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void cleanup() {
3519146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Protect against null-pointer exceptions
3520146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mPopup != null) {
3521146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPopup.dismiss();
3522146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3523666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = INVALID_EVENT_ID;
3524146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Handler handler = getHandler();
3525146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (handler != null) {
3526146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            handler.removeCallbacks(mDismissPopup);
3527bd0e834aea317236d574f8738fe11a51fdc87968Erik            handler.removeCallbacks(mUpdateCurrentTime);
3528146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3529e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
3530d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        Utils.setSharedPreference(mContext, GeneralPreferences.KEY_DEFAULT_CELL_HEIGHT,
3531d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan            mCellHeight);
3532d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
35337abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project        // Turn off redraw
35347abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project        mRemeasure = false;
3535146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3536146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3537bd0e834aea317236d574f8738fe11a51fdc87968Erik    /**
3538bd0e834aea317236d574f8738fe11a51fdc87968Erik     * Restart the update timer
3539bd0e834aea317236d574f8738fe11a51fdc87968Erik     */
3540bd0e834aea317236d574f8738fe11a51fdc87968Erik    public void restartCurrentTimeUpdates() {
3541bd0e834aea317236d574f8738fe11a51fdc87968Erik        post(mUpdateCurrentTime);
3542bd0e834aea317236d574f8738fe11a51fdc87968Erik    }
3543bd0e834aea317236d574f8738fe11a51fdc87968Erik
3544146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override protected void onDetachedFromWindow() {
3545146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        cleanup();
3546146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        super.onDetachedFromWindow();
3547146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3548146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3549146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    class DismissPopup implements Runnable {
3550146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void run() {
3551146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Protect against null-pointer exceptions
3552146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mPopup != null) {
3553146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPopup.dismiss();
3554146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3555146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3556146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3557bd0e834aea317236d574f8738fe11a51fdc87968Erik
3558bd0e834aea317236d574f8738fe11a51fdc87968Erik    class UpdateCurrentTime implements Runnable {
3559bd0e834aea317236d574f8738fe11a51fdc87968Erik        public void run() {
3560bd0e834aea317236d574f8738fe11a51fdc87968Erik            long currentTime = System.currentTimeMillis();
3561bd0e834aea317236d574f8738fe11a51fdc87968Erik            mCurrentTime.set(currentTime);
3562bd0e834aea317236d574f8738fe11a51fdc87968Erik            //% causes update to occur on 5 minute marks (11:10, 11:15, 11:20, etc.)
3563bd0e834aea317236d574f8738fe11a51fdc87968Erik            postDelayed(mUpdateCurrentTime,
3564bd0e834aea317236d574f8738fe11a51fdc87968Erik                    UPDATE_CURRENT_TIME_DELAY - (currentTime % UPDATE_CURRENT_TIME_DELAY));
3565bd0e834aea317236d574f8738fe11a51fdc87968Erik            mTodayJulianDay = Time.getJulianDay(currentTime, mCurrentTime.gmtoff);
3566bd0e834aea317236d574f8738fe11a51fdc87968Erik            invalidate();
3567bd0e834aea317236d574f8738fe11a51fdc87968Erik        }
3568bd0e834aea317236d574f8738fe11a51fdc87968Erik    }
3569ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3570ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener {
3571ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3572ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onSingleTapUp(MotionEvent ev) {
3573d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doSingleTapUp(ev);
3574ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3575ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3576ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3577ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3578ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public void onLongPress(MotionEvent ev) {
3579d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doLongPress(ev);
3580ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3581ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3582ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3583ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
3584d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doScroll(e1, e2, distanceX, distanceY);
3585ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3586ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3587ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3588ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3589ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
3590d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doFling(e1, e2, velocityX, velocityY);
3591ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3592ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3593ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3594ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3595ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onDown(MotionEvent ev) {
3596d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doDown(ev);
3597ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3598ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3599ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    }
3600146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project}
3601