DayView.java revision 46b05ffc746a3150b6bad5d3a72138ffa38b0a99
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.Bitmap;
29146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Canvas;
308af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Projectimport android.graphics.Color;
31146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Paint;
32dd95df57c8c5a58a85c4c0effad5652dec14f621Erikimport android.graphics.Paint.Style;
33146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Path;
34dd95df57c8c5a58a85c4c0effad5652dec14f621Erikimport android.graphics.Path.Direction;
35146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.PorterDuff;
36146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Rect;
37146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.RectF;
38146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.graphics.Typeface;
39146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.net.Uri;
40146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Handler;
41146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Attendees;
42146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Calendars;
43146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Events;
4456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashiimport android.text.TextUtils;
45146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.DateFormat;
46146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.DateUtils;
47146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.Time;
48146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.util.Log;
49146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ContextMenu;
50dd95df57c8c5a58a85c4c0effad5652dec14f621Erikimport android.view.ContextMenu.ContextMenuInfo;
51ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.GestureDetector;
52146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.Gravity;
53146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.KeyEvent;
54146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.LayoutInflater;
55146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.MenuItem;
56146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.MotionEvent;
57146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.View;
58146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ViewConfiguration;
59146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.ViewGroup;
60146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.WindowManager;
61ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.animation.Animation;
62ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.view.animation.TranslateAnimation;
63146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.ImageView;
64146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.PopupWindow;
65146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.TextView;
66ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chanimport android.widget.ViewSwitcher;
67146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
68146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport java.util.ArrayList;
69146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport java.util.Calendar;
700d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chanimport java.util.regex.Matcher;
710d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chanimport java.util.regex.Pattern;
72146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
73146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/**
74d190418220467c02327dd9b3ae1eae238889720bMichael Chan * View for multi-day view. So far only 1 and 7 day have been tested.
75d190418220467c02327dd9b3ae1eae238889720bMichael Chan */
76d190418220467c02327dd9b3ae1eae238889720bMichael Chanpublic class DayView extends View
77146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        implements View.OnCreateContextMenuListener, View.OnClickListener {
78d190418220467c02327dd9b3ae1eae238889720bMichael Chan    private static String TAG = "DayView";
79146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
80705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static float mScale = 0; // Used for supporting different screen densities
81666fc5e8ddbac15c951aad738bd818ee307eae42Erik    private static final long INVALID_EVENT_ID = -1; //This is used for remembering a null event
82ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private static final long ANIMATION_DURATION = 400;
83705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
844484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_AGENDA = 2;
854484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_DAY = 3;
864484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_VIEW = 5;
874484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_CREATE = 6;
884484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_EDIT = 7;
894484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private static final int MENU_EVENT_DELETE = 8;
904484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan
91697157470a6f0d8e7b806af9b4fb7fbe0bccae87Erik    private static int DEFAULT_CELL_HEIGHT = 52;
92697157470a6f0d8e7b806af9b4fb7fbe0bccae87Erik
93146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mOnFlingCalled;
94666fc5e8ddbac15c951aad738bd818ee307eae42Erik    /**
95666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * ID of the last event which was displayed with the toast popup.
96666fc5e8ddbac15c951aad738bd818ee307eae42Erik     *
97666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * This is used to prevent popping up multiple quick views for the same event, especially
98666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * during calendar syncs. This becomes valid when an event is selected, either by default
99666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * on starting calendar or by scrolling to an event. It becomes invalid when the user
100666fc5e8ddbac15c951aad738bd818ee307eae42Erik     * explicitly scrolls to an empty time slot, changes views, or deletes the event.
101666fc5e8ddbac15c951aad738bd818ee307eae42Erik     */
102666fc5e8ddbac15c951aad738bd818ee307eae42Erik    private long mLastPopupEventID;
103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
104ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    protected Context mContext;
105146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String[] CALENDARS_PROJECTION = new String[] {
107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Calendars._ID,          // 0
108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Calendars.ACCESS_LEVEL, // 1
1096d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        Calendars.OWNER_ACCOUNT, // 2
110146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
111146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int CALENDARS_INDEX_ACCESS_LEVEL = 1;
1126d34cec523930368976bc8d358d0a6de1da3462cMichael Chan    private static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2;
113146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String CALENDARS_WHERE = Calendars._ID + "=%d";
114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
115146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String[] ATTENDEES_PROJECTION = new String[] {
116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Attendees._ID,                      // 0
117146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Attendees.ATTENDEE_RELATIONSHIP,    // 1
118146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
119146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ATTENDEES_INDEX_RELATIONSHIP = 1;
120146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=%d";
121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
122705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static float SMALL_ROUND_RADIUS = 3.0F;
123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_NONE = 0;
125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_ABOVE = 1;
126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_BELOW = 2;
127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_LEFT = 4;
128146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int FROM_RIGHT = 8;
129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
130a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static final int ACCESS_LEVEL_NONE = 0;
131a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static final int ACCESS_LEVEL_DELETE = 1;
132a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static final int ACCESS_LEVEL_EDIT = 2;
133a505627659f6bfba8869eac8089f7030f2d0d92cErik
134705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int HORIZONTAL_SCROLL_THRESHOLD = 50;
135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ContinueScroll mContinueScroll = new ContinueScroll();
137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
13898ab9de2fa5ad8dfd37faa6593dc66fa426d8960Michael Chan    static private class DayHeader{
139d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        int cell;
140d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        String dateString;
141d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    }
142d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan
143d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private DayHeader[] dayHeaders = new DayHeader[32];
144e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
145146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Make this visible within the package for more informative debugging
146146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Time mBaseDate;
147bd0e834aea317236d574f8738fe11a51fdc87968Erik    private Time mCurrentTime;
148bd0e834aea317236d574f8738fe11a51fdc87968Erik    //Update the current time line every five minutes if the window is left open that long
149bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static final int UPDATE_CURRENT_TIME_DELAY = 300000;
150bd0e834aea317236d574f8738fe11a51fdc87968Erik    private UpdateCurrentTime mUpdateCurrentTime = new UpdateCurrentTime();
151bd0e834aea317236d574f8738fe11a51fdc87968Erik    private int mTodayJulianDay;
152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Typeface mBold = Typeface.DEFAULT_BOLD;
154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstJulianDay;
155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mLastJulianDay;
156146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mMonthLength;
158487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    private int mFirstVisibleDate;
159487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    private int mFirstVisibleDayOfWeek;
160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int[] mEarliestStartHour;    // indexed by the week day offset
161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean[] mHasAllDayEvent;   // indexed by the week day offset
162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
163731f1cb808b7586b93615b408ab2636081fab0dcErik    private Runnable mTZUpdater = new Runnable() {
164731f1cb808b7586b93615b408ab2636081fab0dcErik        @Override
165731f1cb808b7586b93615b408ab2636081fab0dcErik        public void run() {
166731f1cb808b7586b93615b408ab2636081fab0dcErik            String tz = Utils.getTimeZone(mContext, this);
167731f1cb808b7586b93615b408ab2636081fab0dcErik            mBaseDate.timezone = tz;
168731f1cb808b7586b93615b408ab2636081fab0dcErik            mBaseDate.normalize(true);
169731f1cb808b7586b93615b408ab2636081fab0dcErik            mCurrentTime.switchTimezone(tz);
170731f1cb808b7586b93615b408ab2636081fab0dcErik            invalidate();
171731f1cb808b7586b93615b408ab2636081fab0dcErik        }
172731f1cb808b7586b93615b408ab2636081fab0dcErik    };
173731f1cb808b7586b93615b408ab2636081fab0dcErik
174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * This variable helps to avoid unnecessarily reloading events by keeping
176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * track of the start millis parameter used for the most recent loading
177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * of events.  If the next reload matches this, then the events are not
178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * reloaded.  To force a reload, set this to zero (this is set to zero
179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * in the method clearCachedEvents()).
180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
181146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private long mLastReloadMillis;
182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ArrayList<Event> mEvents = new ArrayList<Event>();
184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mSelectionDay;        // Julian day
185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mSelectionHour;
186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    boolean mSelectionAllDay;
188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mCellWidth;
190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Pre-allocate these objects and re-use them
192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect mRect = new Rect();
193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private RectF mRectF = new RectF();
194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect mSrcRect = new Rect();
195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect mDestRect = new Rect();
196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Paint mPaint = new Paint();
1978af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project    private Paint mPaintBorder = new Paint();
198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Paint mEventTextPaint = new Paint();
199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Paint mSelectionPaint = new Paint();
200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Path mPath = new Path();
201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
202ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    protected boolean mDrawTextInEventRect = true;
203487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    private int mFirstDayOfWeek; // First day of the week
204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private PopupWindow mPopup;
206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private View mPopupView;
207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // The number of milliseconds to show the popup window
209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int POPUP_DISMISS_DELAY = 3000;
210146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private DismissPopup mDismissPopup = new DismissPopup();
211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // For drawing to an off-screen Canvas
213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Bitmap mBitmap;
214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Canvas mCanvas;
215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mRemeasure = true;
216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private final EventLoader mEventLoader;
218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected final EventGeometry mEventGeometry;
219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int DAY_GAP = 1;
221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int HOUR_GAP = 1;
222705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int SINGLE_ALLDAY_HEIGHT = 20;
223705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int MAX_ALLDAY_HEIGHT = 72;
224705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int ALLDAY_TOP_MARGIN = 3;
225705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int MAX_ALLDAY_EVENT_HEIGHT = 18;
226e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* The extra space to leave above the text in all-day events */
228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALL_DAY_TEXT_TOP_MARGIN = 0;
229e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* The extra space to leave above the text in normal events */
231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int NORMAL_TEXT_TOP_MARGIN = 2;
232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int HOURS_LEFT_MARGIN = 2;
234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int HOURS_RIGHT_MARGIN = 4;
235146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int HOURS_MARGIN = HOURS_LEFT_MARGIN + HOURS_RIGHT_MARGIN;
236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
237bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int CURRENT_TIME_LINE_HEIGHT = 2;
238bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int CURRENT_TIME_LINE_BORDER_WIDTH = 1;
239bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int CURRENT_TIME_MARKER_INNER_WIDTH = 6;
240bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int CURRENT_TIME_MARKER_HEIGHT = 6;
241bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int CURRENT_TIME_MARKER_WIDTH = 8;
242bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int CURRENT_TIME_LINE_SIDE_BUFFER = 1;
243bd0e834aea317236d574f8738fe11a51fdc87968Erik
244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MINUTES_PER_HOUR = 60;
245146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * 24;
246146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MILLIS_PER_MINUTE = 60 * 1000;
247146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MILLIS_PER_HOUR = (3600 * 1000);
248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /* package */ static final int MILLIS_PER_DAY = MILLIS_PER_HOUR * 24;
249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
250705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int NORMAL_FONT_SIZE = 12;
251705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int EVENT_TEXT_FONT_SIZE = 12;
252705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int HOURS_FONT_SIZE = 12;
253705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int AMPM_FONT_SIZE = 9;
254705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static int MIN_CELL_WIDTH_FOR_TEXT = 27;
255146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int MAX_EVENT_TEXT_LEN = 500;
256705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan    private static float MIN_EVENT_HEIGHT = 15.0F;  // in pixels
257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static int mSelectionColor;
259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static int mPressedColor;
260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static int mSelectedEventTextColor;
261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static int mEventTextColor;
26264b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok    private static int mWeek_saturdayColor;
26364b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok    private static int mWeek_sundayColor;
264d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarDateBannerTextColor;
265d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarAllDayBackground;
266d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarAmPmLabel;
267d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarDateBannerBackground;
268d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarDateSelected;
269d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarGridAreaBackground;
270d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarGridAreaSelected;
271d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarGridLineHorizontalColor;
272d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarGridLineVerticalColor;
273d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarHourBackground;
274d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarHourLabel;
275d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan    private static int mCalendarHourSelected;
276bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int mCurrentTimeMarkerColor;
277bd0e834aea317236d574f8738fe11a51fdc87968Erik    private static int mCurrentTimeMarkerBorderColor;
278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewStartX;
280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewStartY;
281146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mMaxViewStartY;
282146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mBitmapHeight;
283146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewHeight;
284146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mViewWidth;
285146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mGridAreaHeight;
286146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mCellHeight;
287146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mScrollStartY;
288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mPreviousDirection;
289146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mPreviousDistanceX;
290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
291146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mHoursTextHeight;
292146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mEventTextAscent;
293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mEventTextHeight;
294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mAllDayHeight;
295146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mBannerPlusMargin;
296146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mMaxAllDayEvents;
297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected int mNumDays = 7;
299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mNumHours = 10;
300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mHoursWidth;
301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mDateStrWidth;
302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstCell;
303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstHour = -1;
304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mFirstHourOffset;
305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String[] mHourStrs;
306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String[] mDayStrs;
307146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String[] mDayStrs2Letter;
308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mIs24HourFormat;
309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private float[] mCharWidths = new float[MAX_EVENT_TEXT_LEN];
311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ArrayList<Event> mSelectedEvents = new ArrayList<Event>();
312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mComputeSelectedEvents;
313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Event mSelectedEvent;
314146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Event mPrevSelectedEvent;
315146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect mPrevBox = new Rect();
316146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected final Resources mResources;
317146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String mAmString;
318146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String mPmString;
319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private DeleteEventHelper mDeleteEventHelper;
320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private ContextMenuHandler mContextMenuHandler = new ContextMenuHandler();
322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
323146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
324146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * The initial state of the touch mode when we enter this view.
325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_INITIAL_STATE = 0;
327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
328146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
329146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Indicates we just received the touch event and we are waiting to see if
330146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * it is a tap or a scroll gesture.
331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_DOWN = 1;
333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Indicates the touch gesture is a vertical scroll
336146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_VSCROLL = 0x20;
338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Indicates the touch gesture is a horizontal scroll
341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int TOUCH_MODE_HSCROLL = 0x40;
343146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
344146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mTouchMode = TOUCH_MODE_INITIAL_STATE;
345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
346146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * The selection modes are HIDDEN, PRESSED, SELECTED, and LONGPRESS.
348146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
349146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_HIDDEN = 0;
350146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_PRESSED = 1;
351146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_SELECTED = 2;
352146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int SELECTION_LONGPRESS = 3;
353146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
354146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int mSelectionMode = SELECTION_HIDDEN;
355146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean mScrolling = false;
357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
358146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private String mDateRange;
359146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private TextView mTitleTextView;
360ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private CalendarController mController;
361ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private ViewSwitcher mViewSwitcher;
362ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private GestureDetector mGestureDetector;
363705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
364d190418220467c02327dd9b3ae1eae238889720bMichael Chan    public DayView(Context context, CalendarController controller,
36575d9b567e1fd3b9c6945cd0afe28781f5a19c6c8Michael Chan            ViewSwitcher viewSwitcher, EventLoader eventLoader, int numDays) {
366ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        super(context);
367705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan        if (mScale == 0) {
368705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan            mScale = getContext().getResources().getDisplayMetrics().density;
369705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan            if (mScale != 1) {
370705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                SINGLE_ALLDAY_HEIGHT *= mScale;
371705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                MAX_ALLDAY_HEIGHT *= mScale;
372705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                ALLDAY_TOP_MARGIN *= mScale;
373705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                MAX_ALLDAY_EVENT_HEIGHT *= mScale;
374705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
375705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                NORMAL_FONT_SIZE *= mScale;
376705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                EVENT_TEXT_FONT_SIZE *= mScale;
377705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                HOURS_FONT_SIZE *= mScale;
378705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                AMPM_FONT_SIZE *= mScale;
379705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                MIN_CELL_WIDTH_FOR_TEXT *= mScale;
380705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                MIN_EVENT_HEIGHT *= mScale;
381705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
382705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                HORIZONTAL_SCROLL_THRESHOLD *= mScale;
383e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
384bd0e834aea317236d574f8738fe11a51fdc87968Erik                CURRENT_TIME_MARKER_HEIGHT *= mScale;
385bd0e834aea317236d574f8738fe11a51fdc87968Erik                CURRENT_TIME_MARKER_WIDTH *= mScale;
386bd0e834aea317236d574f8738fe11a51fdc87968Erik                CURRENT_TIME_LINE_HEIGHT *= mScale;
387bd0e834aea317236d574f8738fe11a51fdc87968Erik                CURRENT_TIME_LINE_BORDER_WIDTH *= mScale;
388bd0e834aea317236d574f8738fe11a51fdc87968Erik                CURRENT_TIME_MARKER_INNER_WIDTH *= mScale;
389bd0e834aea317236d574f8738fe11a51fdc87968Erik                CURRENT_TIME_LINE_SIDE_BUFFER *= mScale;
390bd0e834aea317236d574f8738fe11a51fdc87968Erik
391705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan                SMALL_ROUND_RADIUS *= mScale;
392697157470a6f0d8e7b806af9b4fb7fbe0bccae87Erik                DEFAULT_CELL_HEIGHT *= mScale;
393705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan            }
394705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan        }
395705043ffec0bcd8fd0348d4038ac34fd45b09818Michael Chan
396ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mResources = context.getResources();
397ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mEventLoader = eventLoader;
398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry = new EventGeometry();
399146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry.setMinEventHeight(MIN_EVENT_HEIGHT);
400146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry.setHourGap(HOUR_GAP);
401ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mContext = context;
402ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mDeleteEventHelper = new DeleteEventHelper(context, null, false /* don't exit when done */);
403666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = INVALID_EVENT_ID;
404ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mController = controller;
405ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher = viewSwitcher;
406ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mGestureDetector = new GestureDetector(context, new CalendarGestureListener());
40775d9b567e1fd3b9c6945cd0afe28781f5a19c6c8Michael Chan        mNumDays = numDays;
408146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
409ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        init(context);
410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
412146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void init(Context context) {
413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setFocusable(true);
414146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
415146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Allow focus in touch mode so that we can do keyboard shortcuts
416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // even after we've entered touch mode.
417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setFocusableInTouchMode(true);
418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setClickable(true);
419146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        setOnCreateContextMenuListener(this);
420146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
421487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mFirstDayOfWeek = Utils.getFirstDayOfWeek(context);
422146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
423731f1cb808b7586b93615b408ab2636081fab0dcErik        mCurrentTime = new Time(Utils.getTimeZone(context, mTZUpdater));
424bd0e834aea317236d574f8738fe11a51fdc87968Erik        long currentTime = System.currentTimeMillis();
425bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTime.set(currentTime);
426bd0e834aea317236d574f8738fe11a51fdc87968Erik        //The % makes it go off at the next increment of 5 minutes.
427bd0e834aea317236d574f8738fe11a51fdc87968Erik        postDelayed(mUpdateCurrentTime,
428bd0e834aea317236d574f8738fe11a51fdc87968Erik                UPDATE_CURRENT_TIME_DELAY - (currentTime % UPDATE_CURRENT_TIME_DELAY));
429bd0e834aea317236d574f8738fe11a51fdc87968Erik        mTodayJulianDay = Time.getJulianDay(currentTime, mCurrentTime.gmtoff);
430bd0e834aea317236d574f8738fe11a51fdc87968Erik
43164b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok        mWeek_saturdayColor = mResources.getColor(R.color.week_saturday);
43264b3e63d59967eeb11e1d8328c74ee335abc0ffbsatok        mWeek_sundayColor = mResources.getColor(R.color.week_sunday);
433d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarDateBannerTextColor = mResources.getColor(R.color.calendar_date_banner_text_color);
434d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarAllDayBackground = mResources.getColor(R.color.calendar_all_day_background);
435d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarAmPmLabel = mResources.getColor(R.color.calendar_ampm_label);
436d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarDateBannerBackground = mResources.getColor(R.color.calendar_date_banner_background);
437d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarDateSelected = mResources.getColor(R.color.calendar_date_selected);
438d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarGridAreaBackground = mResources.getColor(R.color.calendar_grid_area_background);
439d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarGridAreaSelected = mResources.getColor(R.color.calendar_grid_area_selected);
440d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarGridLineHorizontalColor = mResources.getColor(R.color.calendar_grid_line_horizontal_color);
441d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarGridLineVerticalColor = mResources.getColor(R.color.calendar_grid_line_vertical_color);
442d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarHourBackground = mResources.getColor(R.color.calendar_hour_background);
443d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarHourLabel = mResources.getColor(R.color.calendar_hour_label);
444d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        mCalendarHourSelected = mResources.getColor(R.color.calendar_hour_selected);
445146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionColor = mResources.getColor(R.color.selection);
446146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPressedColor = mResources.getColor(R.color.pressed);
447146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEventTextColor = mResources.getColor(R.color.calendar_event_selected_text_color);
448146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextColor = mResources.getColor(R.color.calendar_event_text_color);
449bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTimeMarkerColor = mResources.getColor(R.color.current_time_marker);
450bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTimeMarkerBorderColor = mResources.getColor(R.color.current_time_marker_border);
451146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setColor(mEventTextColor);
452146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setTextSize(EVENT_TEXT_FONT_SIZE);
453146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setTextAlign(Paint.Align.LEFT);
454146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextPaint.setAntiAlias(true);
455146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
456146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int gridLineColor = mResources.getColor(R.color.calendar_grid_line_highlight_color);
457146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = mSelectionPaint;
458146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setColor(gridLineColor);
459146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStyle(Style.STROKE);
460146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStrokeWidth(2.0f);
461146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(false);
462146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
463146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p = mPaint;
464146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
4668af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        mPaintBorder.setColor(0xffc8c8c8);
4678af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        mPaintBorder.setStyle(Style.STROKE);
4688af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        mPaintBorder.setAntiAlias(true);
4698af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        mPaintBorder.setStrokeWidth(2.0f);
4708af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project
471146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Allocate space for 2 weeks worth of weekday names so that we can
472146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // easily start the week display at any week day.
473146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDayStrs = new String[14];
474146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
475146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Also create an array of 2-letter abbreviations.
476146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDayStrs2Letter = new String[14];
477146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
478146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
479146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int index = i - Calendar.SUNDAY;
480146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // e.g. Tue for Tuesday
481146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_MEDIUM);
482146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs[index + 7] = mDayStrs[index];
483146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // e.g. Tu for Tuesday
484146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs2Letter[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_SHORT);
48552b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer
48652b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer            // If we don't have 2-letter day strings, fall back to 1-letter.
48752b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer            if (mDayStrs2Letter[index].equals(mDayStrs[index])) {
48852b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer                mDayStrs2Letter[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_SHORTEST);
48952b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer            }
49052b2d70115e88b408c994db0d2b1889c9fb48527Eric Fischer
491146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDayStrs2Letter[index + 7] = mDayStrs2Letter[index];
492146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
493146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
494146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Figure out how much space we need for the 3-letter abbrev names
495146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // in the worst case.
496146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(NORMAL_FONT_SIZE);
497146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(mBold);
498146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String[] dateStrs = {" 28", " 30"};
499146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDateStrWidth = computeMaxStringWidth(0, dateStrs, p);
500146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mDateStrWidth += computeMaxStringWidth(0, mDayStrs, p);
501146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
502146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(HOURS_FONT_SIZE);
503146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(null);
50469ab334d6988eda70ba53618506d23ebf7d7b405Erik        updateIs24HourFormat();
505146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
506146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mAmString = DateUtils.getAMPMString(Calendar.AM);
507146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPmString = DateUtils.getAMPMString(Calendar.PM);
508146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String[] ampm = {mAmString, mPmString};
509146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(AMPM_FONT_SIZE);
510146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mHoursWidth = computeMaxStringWidth(mHoursWidth, ampm, p);
511146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mHoursWidth += HOURS_MARGIN;
512146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
513146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        LayoutInflater inflater;
514146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
515146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopupView = inflater.inflate(R.layout.bubble_event, null);
516146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopupView.setLayoutParams(new ViewGroup.LayoutParams(
517df279e3f9d5b0f189f812c52aca78d18178e4445Romain Guy                ViewGroup.LayoutParams.MATCH_PARENT,
518146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                ViewGroup.LayoutParams.WRAP_CONTENT));
519146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup = new PopupWindow(context);
520146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setContentView(mPopupView);
521146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Resources.Theme dialogTheme = getResources().newTheme();
522146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        dialogTheme.applyStyle(android.R.style.Theme_Dialog, true);
523146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TypedArray ta = dialogTheme.obtainStyledAttributes(new int[] {
524146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            android.R.attr.windowBackground });
525146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setBackgroundDrawable(ta.getDrawable(0));
526146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ta.recycle();
527146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
528146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Enable touching the popup window
529146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopupView.setOnClickListener(this);
530146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
531731f1cb808b7586b93615b408ab2636081fab0dcErik        mBaseDate = new Time(Utils.getTimeZone(context, mTZUpdater));
532146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = System.currentTimeMillis();
533146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mBaseDate.set(millis);
534146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
535146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEarliestStartHour = new int[mNumDays];
536146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mHasAllDayEvent = new boolean[mNumDays];
537146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
538ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan// FRAG_TODO. Take this out.
539ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//        mTitleTextView = (TextView) findViewById(R.id.title);
540ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mTitleTextView = new TextView(mContext);
541146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
542146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
543146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
544146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * This is called when the popup window is pressed.
545146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
546146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void onClick(View v) {
547146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (v == mPopupView) {
548146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Pretend it was a trackball click because that will always
549146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // jump to the "View event" screen.
550146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchViews(true /* trackball */);
551146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
552146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
553146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
55469ab334d6988eda70ba53618506d23ebf7d7b405Erik    public void updateIs24HourFormat() {
555ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mIs24HourFormat = DateFormat.is24HourFormat(mContext);
55669ab334d6988eda70ba53618506d23ebf7d7b405Erik        mHourStrs = mIs24HourFormat ? CalendarData.s24Hours : CalendarData.s12HoursNoAmPm;
55769ab334d6988eda70ba53618506d23ebf7d7b405Erik    }
55869ab334d6988eda70ba53618506d23ebf7d7b405Erik
559146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
560146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Returns the start of the selected time in milliseconds since the epoch.
561146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
562146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @return selected time in UTC milliseconds since the epoch.
563146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
564146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    long getSelectedTimeInMillis() {
565146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time time = new Time(mBaseDate);
566146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.setJulianDay(mSelectionDay);
567146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.hour = mSelectionHour;
568146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
569146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // We ignore the "isDst" field because we want normalize() to figure
570146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // out the correct DST value and not adjust the selected time based
571146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // on the current setting of DST.
572146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return time.normalize(true /* ignore isDst */);
573146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
574146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
575146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Time getSelectedTime() {
576146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time time = new Time(mBaseDate);
577146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.setJulianDay(mSelectionDay);
578146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.hour = mSelectionHour;
579146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
580146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // We ignore the "isDst" field because we want normalize() to figure
581146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // out the correct DST value and not adjust the selected time based
582146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // on the current setting of DST.
583146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.normalize(true /* ignore isDst */);
584146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return time;
585146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
586146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
587146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
588146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Returns the start of the selected time in minutes since midnight,
589146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * local time.  The derived class must ensure that this is consistent
590146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * with the return value from getSelectedTimeInMillis().
591146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
592146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    int getSelectedMinutesSinceMidnight() {
593146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return mSelectionHour * MINUTES_PER_HOUR;
594146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
595146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
596146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void setSelectedDay(Time time) {
597146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mBaseDate.set(time);
598146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionHour = mBaseDate.hour;
599146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = null;
600146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevSelectedEvent = null;
601146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = mBaseDate.toMillis(false /* use isDst */);
602146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionDay = Time.getJulianDay(millis, mBaseDate.gmtoff);
603146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
604146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mComputeSelectedEvents = true;
605146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
606146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Force a recalculation of the first visible hour
607146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstHour = -1;
608146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        recalc();
609146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mTitleTextView.setText(mDateRange);
610146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
611146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Force a redraw of the selection box.
612146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_SELECTED;
613146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mRemeasure = true;
614146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
615146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
616146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
617146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public Time getSelectedDay() {
618146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time time = new Time(mBaseDate);
619146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.setJulianDay(mSelectionDay);
620146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.hour = mSelectionHour;
621146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
622146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // We ignore the "isDst" field because we want normalize() to figure
623146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // out the correct DST value and not adjust the selected time based
624146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // on the current setting of DST.
625146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.normalize(true /* ignore isDst */);
626146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return time;
627146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
62983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    /**
630487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan     * return a negative number if "time" is comes before the visible time
631487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan     * range, a positive number if "time" is after the visible time range, and 0
632487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan     * if it is in the visible time range.
63383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     */
634487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan    public int compareToVisibleTimeRange(Time time) {
635487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
636487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int savedHour = mBaseDate.hour;
637487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int savedMinute = mBaseDate.minute;
638487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int savedSec = mBaseDate.second;
639487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
640487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.hour = 0;
641487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.minute = 0;
642487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.second = 0;
643487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
644487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        Log.d(TAG, "Begin " + mBaseDate.toString());
645487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        Log.d(TAG, "Diff  " + time.toString());
646487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
64783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        // Compare beginning of range
64883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        int diff = Time.compare(time, mBaseDate);
649487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        if (diff > 0) {
650487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            // Compare end of range
651487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.monthDay += mNumDays;
652487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.normalize(true);
653487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            diff = Time.compare(time, mBaseDate);
654487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
655487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            Log.d(TAG, "End   " + mBaseDate.toString());
656487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
657487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.monthDay -= mNumDays;
658487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            mBaseDate.normalize(true);
659487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            if (diff < 0) {
660487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                // in visible time
661487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                diff = 0;
662487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            } else if (diff == 0) {
663487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                // Midnight of following day
664487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                diff = 1;
665487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            }
66683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        }
66783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
668487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        Log.d(TAG, "Diff: " + diff);
66983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
670487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.hour = savedHour;
671487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.minute = savedMinute;
672487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mBaseDate.second = savedSec;
673487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        return diff;
67483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
67583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
676146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void recalc() {
677146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Set the base date to the beginning of the week if we are displaying
678146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // 7 days at a time.
679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays == 7) {
680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int dayOfWeek = mBaseDate.weekDay;
681487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            int diff = dayOfWeek - mFirstDayOfWeek;
682146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (diff != 0) {
683146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (diff < 0) {
684146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    diff += 7;
685146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
686146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mBaseDate.monthDay -= diff;
687146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mBaseDate.normalize(true /* ignore isDst */);
688146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
689146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
690146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
691146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        final long start = mBaseDate.toMillis(false /* use isDst */);
692146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long end = start;
693146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstJulianDay = Time.getJulianDay(start, mBaseDate.gmtoff);
694146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mLastJulianDay = mFirstJulianDay + mNumDays - 1;
695146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
696146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mMonthLength = mBaseDate.getActualMaximum(Time.MONTH_DAY);
697487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mFirstVisibleDate = mBaseDate.monthDay;
698487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        mFirstVisibleDayOfWeek = mBaseDate.weekDay;
699146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
700146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int flags = DateUtils.FORMAT_SHOW_YEAR;
701ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        if (DateFormat.is24HourFormat(mContext)) {
702146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags |= DateUtils.FORMAT_24HOUR;
703146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
704146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays > 1) {
705146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mBaseDate.monthDay += mNumDays - 1;
706146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            end = mBaseDate.toMillis(true /* ignore isDst */);
707146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mBaseDate.monthDay -= mNumDays - 1;
708146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags |= DateUtils.FORMAT_NO_MONTH_DAY;
709146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags |= DateUtils.FORMAT_SHOW_WEEKDAY
711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH;
712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
713146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
714ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mDateRange = DateUtils.formatDateRange(mContext, start, end, flags);
715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Do not set the title here because this is called when executing
716146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // initNextView() to prepare the Day view when sliding the finger
717146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // horizontally but we don't always want to change the title.  And
718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // if we change the title here and then change it back in the caller
719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // then we get an annoying flicker.
720146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
723146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected void onSizeChanged(int width, int height, int oldw, int oldh) {
724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewWidth = width;
725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewHeight = height;
726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int gridAreaWidth = width - mHoursWidth;
727146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mCellWidth = (gridAreaWidth - (mNumDays * DAY_GAP)) / mNumDays;
728146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
729146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = new Paint();
730146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(NORMAL_FONT_SIZE);
731146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int bannerTextHeight = (int) Math.abs(p.ascent());
732146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
733146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(HOURS_FONT_SIZE);
734146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mHoursTextHeight = (int) Math.abs(p.ascent());
735146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
736146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(EVENT_TEXT_FONT_SIZE);
737146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float ascent = -p.ascent();
738146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextAscent = (int) Math.ceil(ascent);
739146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float totalHeight = ascent + p.descent();
740146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventTextHeight = (int) Math.ceil(totalHeight);
741146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
742146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays > 1) {
743146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mBannerPlusMargin = bannerTextHeight + 14;
744146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
745146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mBannerPlusMargin = 0;
746146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
747146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
748146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        remeasure(width, height);
749146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
750146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
75146b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa    /**
75246b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa     * Measures the space needed for various parts of the view after
75346b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa     * loading new events.  This can change if there are all-day events.
75446b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa     */
755146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void remeasure(int width, int height) {
756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // First, clear the array of earliest start times, and the array
758146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // indicating presence of an all-day event.
759146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++) {
760146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mEarliestStartHour[day] = 25;  // some big number
761146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mHasAllDayEvent[day] = false;
762146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
763146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
76446b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // We first measure cell height, as the value isn't affected by events.
76546b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // After measuring the cell height, we compute the layout relation between each event
76646b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // before measuring cell width, as the cell width should be adjusted along with the
76746b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // relation.
76846b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        //
76946b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // Examples: A (1:00pm - 1:01pm), B (1:02pm - 2:00pm)
77046b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // We should mark them as "overwapped". Though they are not overwapped logically, but
77146b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // minimum cell height implicitly expands the cell height of A and it should look like
77246b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // (1:00pm - 1:15pm) after the cell height adjustment.
77346b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa
77446b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // TODO: Load preference and change with pinch to zoom
77546b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        mCellHeight = DEFAULT_CELL_HEIGHT;
77646b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa
777146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Compute the space needed for the all-day events, if any.
778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Make a pass over all the events, and keep track of the maximum
779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // number of all-day events in any one day.  Also, keep track of
780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // the earliest event in each day.
781146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int maxAllDayEvents = 0;
78246b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        final ArrayList<Event> events = mEvents;
78346b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        final int len = events.size();
784146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
785146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(ii);
786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (event.startDay > mLastJulianDay || event.endDay < mFirstJulianDay)
787146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
788146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (event.allDay) {
789146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int max = event.getColumn() + 1;
790146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (maxAllDayEvents < max) {
791146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    maxAllDayEvents = max;
792146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
793146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int daynum = event.startDay - mFirstJulianDay;
794146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int durationDays = event.endDay - event.startDay + 1;
795146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum < 0) {
796146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    durationDays += daynum;
797146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    daynum = 0;
798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum + durationDays > mNumDays) {
800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    durationDays = mNumDays - daynum;
801146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
802146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                for (int day = daynum; durationDays > 0; day++, durationDays--) {
803146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mHasAllDayEvent[day] = true;
804146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
805146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
806146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int daynum = event.startDay - mFirstJulianDay;
807146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int hour = event.startTime / 60;
808146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum >= 0 && hour < mEarliestStartHour[daynum]) {
809146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mEarliestStartHour[daynum] = hour;
810146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
811146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
812146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Also check the end hour in case the event spans more than
813146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // one day.
814146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                daynum = event.endDay - mFirstJulianDay;
815146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                hour = event.endTime / 60;
816146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (daynum < mNumDays && hour < mEarliestStartHour[daynum]) {
817146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mEarliestStartHour[daynum] = hour;
818146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
819146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
820146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
821146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mMaxAllDayEvents = maxAllDayEvents;
822146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
82346b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        // Calcurates mAllDayHeight
82446b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa
825146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstCell = mBannerPlusMargin;
826146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int allDayHeight = 0;
827146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (maxAllDayEvents > 0) {
828146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there is at most one all-day event per day, then use less
829146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // space (but more than the space for a single event).
830146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (maxAllDayEvents == 1) {
831146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                allDayHeight = SINGLE_ALLDAY_HEIGHT;
832146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
833146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Allow the all-day area to grow in height depending on the
834146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // number of all-day events we need to show, up to a limit.
835146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                allDayHeight = maxAllDayEvents * MAX_ALLDAY_EVENT_HEIGHT;
836146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (allDayHeight > MAX_ALLDAY_HEIGHT) {
837146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    allDayHeight = MAX_ALLDAY_HEIGHT;
838146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
839146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
840146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstCell = mBannerPlusMargin + allDayHeight + ALLDAY_TOP_MARGIN;
841146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
842146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionAllDay = false;
843146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
844146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mAllDayHeight = allDayHeight;
845146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
846146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mGridAreaHeight = height - mFirstCell;
847697157470a6f0d8e7b806af9b4fb7fbe0bccae87Erik        mNumHours = mGridAreaHeight / mCellHeight;
848146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventGeometry.setHourHeight(mCellHeight);
849146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
85046b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        final float minimumDurationMillis =
85146b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa                MIN_EVENT_HEIGHT * DateUtils.MINUTE_IN_MILLIS / (mCellHeight / 60.0f);
85246b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        Event.computePositions(events, minimumDurationMillis);
85346b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa
854146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Create an off-screen bitmap that we can draw into.
855697157470a6f0d8e7b806af9b4fb7fbe0bccae87Erik        mBitmapHeight = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP);
856146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((mBitmap == null || mBitmap.getHeight() < mBitmapHeight) && width > 0 &&
857146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mBitmapHeight > 0) {
858146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mBitmap != null) {
859146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mBitmap.recycle();
860146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
861146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mBitmap = Bitmap.createBitmap(width, mBitmapHeight, Bitmap.Config.RGB_565);
862146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mCanvas = new Canvas(mBitmap);
863146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
864146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mMaxViewStartY = mBitmapHeight - mGridAreaHeight;
865146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
866146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour == -1) {
867146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            initFirstHour();
868146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHourOffset = 0;
869146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
870146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
871146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // When we change the base date, the number of all-day events may
872146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // change and that changes the cell height.  When we switch dates,
873146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // we use the mFirstHourOffset from the previous view, but that may
874146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // be too large for the new view if the cell height is smaller.
875146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHourOffset >= mCellHeight + HOUR_GAP) {
876146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHourOffset = mCellHeight + HOUR_GAP - 1;
877146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
878146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewStartY = mFirstHour * (mCellHeight + HOUR_GAP) - mFirstHourOffset;
879146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
88046b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa        final int eventAreaWidth = mNumDays * (mCellWidth + DAY_GAP);
881666fc5e8ddbac15c951aad738bd818ee307eae42Erik        //When we get new events we don't want to dismiss the popup unless the event changes
882666fc5e8ddbac15c951aad738bd818ee307eae42Erik        if (mSelectedEvent != null && mLastPopupEventID != mSelectedEvent.id) {
883666fc5e8ddbac15c951aad738bd818ee307eae42Erik            mPopup.dismiss();
884666fc5e8ddbac15c951aad738bd818ee307eae42Erik        }
885146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setWidth(eventAreaWidth - 20);
886146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
887146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
888146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
889146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
890146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Initialize the state for another view.  The given view is one that has
891146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * its own bitmap and will use an animation to replace the current view.
892146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * The current view and new view are either both Week views or both Day
893146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * views.  They differ in their base date.
894146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
895146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param view the view to initialize.
896146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
897d190418220467c02327dd9b3ae1eae238889720bMichael Chan    private void initView(DayView view) {
898146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mSelectionHour = mSelectionHour;
899146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mSelectedEvents.clear();
900146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mComputeSelectedEvents = true;
901146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mFirstHour = mFirstHour;
902146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mFirstHourOffset = mFirstHourOffset;
903146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.remeasure(getWidth(), getHeight());
904e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
905146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mSelectedEvent = null;
906146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.mPrevSelectedEvent = null;
907487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        view.mFirstDayOfWeek = mFirstDayOfWeek;
908146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (view.mEvents.size() > 0) {
909146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionAllDay = mSelectionAllDay;
910146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
911146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionAllDay = false;
912146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
913146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
914146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Redraw the screen so that the selection box will be redrawn.  We may
915146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // have scrolled to a different part of the day in some other view
916146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // so the selection box in this view may no longer be visible.
917146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.recalc();
918146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
919146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
920146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
921146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Switch to another view based on what was selected (an event or a free
922146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * slot) and how it was selected (by touch or by trackball).
923146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
924146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param trackBallSelection true if the selection was made using the
925146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * trackball.
926146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
927146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void switchViews(boolean trackBallSelection) {
928146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event selectedEvent = mSelectedEvent;
929146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
930146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.dismiss();
931666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = INVALID_EVENT_ID;
932146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays > 1) {
933146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // This is the Week view.
934146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // With touch, we always switch to Day/Agenda View
935146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // With track ball, if we selected a free slot, then create an event.
936146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we selected a specific event, switch to EventInfo view.
937146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (trackBallSelection) {
938146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (selectedEvent == null) {
939146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Switch to the EditEvent view
940146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long startMillis = getSelectedTimeInMillis();
941146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
9429e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
9439e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            startMillis, endMillis, 0, 0);
944146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
945146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Switch to the EventInfo view
9469e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
9479e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            selectedEvent.startMillis, selectedEvent.endMillis, 0, 0);
948146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
949146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
950146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // This was a touch selection.  If the touch selected a single
951146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // unambiguous event, then view that event.  Otherwise go to
952146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Day/Agenda view.
953146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectedEvents.size() == 1) {
9549e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
9559e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            selectedEvent.startMillis, selectedEvent.endMillis, 0, 0);
956146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
957146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
958146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
959146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // This is the Day view.
960146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we selected a free slot, then create an event.
961146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we selected an event, then go to the EventInfo view.
962146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (selectedEvent == null) {
963146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Switch to the EditEvent view
964146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                long startMillis = getSelectedTimeInMillis();
965146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
9669e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan
9679e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1, startMillis,
9689e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        endMillis, 0, 0);
969146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
9709e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
9719e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        selectedEvent.startMillis, selectedEvent.endMillis, 0, 0);
972146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
973146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
974146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
975146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
976146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
977146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
978146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mScrolling = false;
979146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long duration = event.getEventTime() - event.getDownTime();
980146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
981146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        switch (keyCode) {
982146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            case KeyEvent.KEYCODE_DPAD_CENTER:
983146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectionMode == SELECTION_HIDDEN) {
984146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Don't do anything unless the selection is visible.
985146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
986146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
987146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
988146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectionMode == SELECTION_PRESSED) {
989146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This was the first press when there was nothing selected.
990146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Change the selection from the "pressed" state to the
991146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // the "selected" state.  We treat short-press and
992146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // long-press the same here because nothing was selected.
993146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionMode = SELECTION_SELECTED;
994146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    invalidate();
995146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
996146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
997146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
998146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Check the duration to determine if this was a short press
999146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (duration < ViewConfiguration.getLongPressTimeout()) {
1000146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    switchViews(true /* trackball */);
1001146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
1002146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionMode = SELECTION_LONGPRESS;
1003146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    invalidate();
1004146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    performLongClick();
1005146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1006146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                break;
1007ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//            case KeyEvent.KEYCODE_BACK:
1008ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                if (event.isTracking() && !event.isCanceled()) {
1009ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                    mPopup.dismiss();
1010ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                    mContext.finish();
1011ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                    return true;
1012ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                }
1013ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                break;
1014146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1015146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return super.onKeyUp(keyCode, event);
1016146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1017146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1018146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
1019146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
1020146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionMode == SELECTION_HIDDEN) {
1021146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
1022146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_UP
1023146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
1024146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Display the selection box but don't move or select it
1025146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // on this key press.
1026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionMode = SELECTION_SELECTED;
1027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
1028146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
1029146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
1030146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Display the selection box but don't select it
1031146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // on this key press.
1032146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionMode = SELECTION_PRESSED;
1033146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
1034146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
1035146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1036146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1037146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1038146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_SELECTED;
1039146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mScrolling = false;
1040146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        boolean redraw;
1041146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int selectionDay = mSelectionDay;
1042146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1043146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        switch (keyCode) {
1044146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_DEL:
1045146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Delete the selected event, if any
1046146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event selectedEvent = mSelectedEvent;
1047146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (selectedEvent == null) {
1048146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return false;
1049146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1050146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPopup.dismiss();
1051666fc5e8ddbac15c951aad738bd818ee307eae42Erik            mLastPopupEventID = INVALID_EVENT_ID;
1052146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1053146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            long begin = selectedEvent.startMillis;
1054146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            long end = selectedEvent.endMillis;
1055146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            long id = selectedEvent.id;
1056146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mDeleteEventHelper.delete(begin, end, id, -1);
1057146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
1058146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_ENTER:
1059146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchViews(true /* trackball or keyboard */);
1060146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
1061146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_BACK:
1062b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan            if (event.getRepeatCount() == 0) {
1063b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan                event.startTracking();
1064b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan                return true;
1065b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan            }
1066b10f5762d0e50bac6ba31ec332e7513869b55bf3Michael Chan            return super.onKeyDown(keyCode, event);
1067146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_DPAD_LEFT:
1068146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
1069146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvent = mSelectedEvent.nextLeft;
1070146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1071146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent == null) {
1072666fc5e8ddbac15c951aad738bd818ee307eae42Erik                mLastPopupEventID = INVALID_EVENT_ID;
1073146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                selectionDay -= 1;
1074146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1075146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            redraw = true;
1076146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            break;
1077146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1078146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_DPAD_RIGHT:
1079146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
1080146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvent = mSelectedEvent.nextRight;
1081146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1082146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent == null) {
1083666fc5e8ddbac15c951aad738bd818ee307eae42Erik                mLastPopupEventID = INVALID_EVENT_ID;
1084146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                selectionDay += 1;
1085146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            redraw = true;
1087146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            break;
1088146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1089146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_DPAD_UP:
1090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
1091146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvent = mSelectedEvent.nextUp;
1092146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent == null) {
1094666fc5e8ddbac15c951aad738bd818ee307eae42Erik                mLastPopupEventID = INVALID_EVENT_ID;
1095146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (!mSelectionAllDay) {
1096146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionHour -= 1;
1097146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    adjustHourSelection();
1098146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectedEvents.clear();
1099146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mComputeSelectedEvents = true;
1100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1101146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            redraw = true;
1103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            break;
1104146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1105146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case KeyEvent.KEYCODE_DPAD_DOWN:
1106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
1107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvent = mSelectedEvent.nextDown;
1108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent == null) {
1110666fc5e8ddbac15c951aad738bd818ee307eae42Erik                mLastPopupEventID = INVALID_EVENT_ID;
1111146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mSelectionAllDay) {
1112146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionAllDay = false;
1113146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
1114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectionHour++;
1115146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    adjustHourSelection();
1116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectedEvents.clear();
1117146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mComputeSelectedEvents = true;
1118146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1119146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1120146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            redraw = true;
1121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            break;
1122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        default:
1124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return super.onKeyDown(keyCode, event);
1125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((selectionDay < mFirstJulianDay) || (selectionDay > mLastJulianDay)) {
1128146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            boolean forward;
1129d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView view = (DayView) mViewSwitcher.getNextView();
1130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Time date = view.mBaseDate;
1131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.set(mBaseDate);
1132146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (selectionDay < mFirstJulianDay) {
1133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                date.monthDay -= mNumDays;
1134146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                forward = false;
1135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
1136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                date.monthDay += mNumDays;
1137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                forward = true;
1138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.normalize(true /* ignore isDst */);
1140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionDay = selectionDay;
1141146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            initView(view);
114383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
114483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Time end = new Time(date);
114583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            end.monthDay += mNumDays - 1;
114683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Log.d(TAG, "onKeyDown");
11473458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            mController.sendEvent(this, EventType.GO_TO, date, end, -1, ViewType.CURRENT);
114883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
1149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mTitleTextView.setText(view.mDateRange);
1150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
1151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionDay = selectionDay;
1153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
1154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mComputeSelectedEvents = true;
1155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1156146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (redraw) {
1157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            invalidate();
1158146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
1159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return super.onKeyDown(keyCode, event);
1162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1164ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    private View switchViews(boolean forward, float xOffSet, float width) {
1165ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        float progress = Math.abs(xOffSet) / width;
1166ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        if (progress > 1.0f) {
1167ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            progress = 1.0f;
1168ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
1169ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1170ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        float inFromXValue, inToXValue;
1171ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        float outFromXValue, outToXValue;
1172ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        if (forward) {
1173ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inFromXValue = 1.0f - progress;
1174ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inToXValue = 0.0f;
1175ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outFromXValue = -progress;
1176ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outToXValue = -1.0f;
1177ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        } else {
1178ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inFromXValue = progress - 1.0f;
1179ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            inToXValue = 0.0f;
1180ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outFromXValue = progress;
1181ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            outToXValue = 1.0f;
1182ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
1183ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1184ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        // We have to allocate these animation objects each time we switch views
1185ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        // because that is the only way to set the animation parameters.
1186ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        TranslateAnimation inAnimation = new TranslateAnimation(
1187ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, inFromXValue,
1188ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, inToXValue,
1189ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f,
1190ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f);
1191ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1192ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        TranslateAnimation outAnimation = new TranslateAnimation(
1193ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, outFromXValue,
1194ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.RELATIVE_TO_SELF, outToXValue,
1195ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f,
1196ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                Animation.ABSOLUTE, 0.0f);
1197ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1198ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        // Reduce the animation duration based on how far we have already swiped.
1199ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        long duration = (long) (ANIMATION_DURATION * (1.0f - progress));
1200ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        inAnimation.setDuration(duration);
1201ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        outAnimation.setDuration(duration);
1202ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher.setInAnimation(inAnimation);
1203ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher.setOutAnimation(outAnimation);
1204ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1205d190418220467c02327dd9b3ae1eae238889720bMichael Chan        DayView view = (DayView) mViewSwitcher.getCurrentView();
1206ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        view.cleanup();
1207ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        mViewSwitcher.showNext();
1208d190418220467c02327dd9b3ae1eae238889720bMichael Chan        view = (DayView) mViewSwitcher.getCurrentView();
1209ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        view.requestFocus();
1210ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        view.reloadEvents();
1211ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        return view;
1212ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    }
1213ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
1214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // This is called after scrolling stops to move the selected hour
1215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // to the visible part of the screen.
1216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void resetSelectedHour() {
1217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour < mFirstHour + 1) {
1218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = mFirstHour + 1;
1219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = null;
1220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvents.clear();
1221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mComputeSelectedEvents = true;
1222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (mSelectionHour > mFirstHour + mNumHours - 3) {
1223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = mFirstHour + mNumHours - 3;
1224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = null;
1225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvents.clear();
1226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mComputeSelectedEvents = true;
1227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void initFirstHour() {
1231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstHour = mSelectionHour - mNumHours / 2;
1232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour < 0) {
1233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHour = 0;
1234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (mFirstHour + mNumHours > 24) {
1235146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFirstHour = 24 - mNumHours;
1236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
1240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Recomputes the first full hour that is visible on screen after the
1241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * screen is scrolled.
1242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
1243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void computeFirstHour() {
1244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Compute the first full hour that is visible on screen
1245146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstHour = (mViewStartY + mCellHeight + HOUR_GAP - 1) / (mCellHeight + HOUR_GAP);
1246146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mFirstHourOffset = mFirstHour * (mCellHeight + HOUR_GAP) - mViewStartY;
1247146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void adjustHourSelection() {
1250146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour < 0) {
1251146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = 0;
1252146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mMaxAllDayEvents > 0) {
1253146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = null;
1254146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionAllDay = true;
1255146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour > 23) {
1259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = 23;
1260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If the selected hour is at least 2 time slots from the top and
1263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // bottom of the screen, then don't scroll the view.
1264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour < mFirstHour + 1) {
1265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there are all-days events for the selected day but there
1266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // are no more normal events earlier in the day, then jump to
1267146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // the all-day event area.
1268146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Exception 1: allow the user to scroll to 8am with the trackball
1269146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // before jumping to the all-day event area.
1270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Exception 2: if 12am is on screen, then allow the user to select
1271146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // 12am before going up to the all-day event area.
1272146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int daynum = mSelectionDay - mFirstJulianDay;
1273146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mMaxAllDayEvents > 0 && mEarliestStartHour[daynum] > mSelectionHour
1274146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    && mFirstHour > 0 && mFirstHour < 8) {
1275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = null;
1276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionAllDay = true;
1277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionHour = mFirstHour + 1;
1278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return;
1279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1281146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mFirstHour > 0) {
1282146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mFirstHour -= 1;
1283146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY -= (mCellHeight + HOUR_GAP);
1284146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mViewStartY < 0) {
1285146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mViewStartY = 0;
1286146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1287146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return;
1288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1289146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1291146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionHour > mFirstHour + mNumHours - 3) {
1292146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mFirstHour < 24 - mNumHours) {
1293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mFirstHour += 1;
1294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY += (mCellHeight + HOUR_GAP);
1295146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mViewStartY > mBitmapHeight - mGridAreaHeight) {
1296146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mViewStartY = mBitmapHeight - mGridAreaHeight;
1297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return;
1299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mFirstHour == 24 - mNumHours && mFirstHourOffset > 0) {
1300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = mBitmapHeight - mGridAreaHeight;
1301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    void clearCachedEvents() {
1306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mLastReloadMillis = 0;
1307146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Runnable mCancelCallback = new Runnable() {
1310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void run() {
1311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            clearCachedEvents();
1312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
1314146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
131546b05ffc746a3150b6bad5d3a72138ffa38b0a99Daisuke Miyakawa    /* package */ void reloadEvents() {
1316146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Protect against this being called before this view has been
1317146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // initialized.
1318ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//        if (mContext == null) {
1319ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//            return;
1320ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//        }
1321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1322731f1cb808b7586b93615b408ab2636081fab0dcErik        // Make sure our time zones are up to date
1323731f1cb808b7586b93615b408ab2636081fab0dcErik        mTZUpdater.run();
1324731f1cb808b7586b93615b408ab2636081fab0dcErik
1325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = null;
1326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevSelectedEvent = null;
1327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
1328146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1329146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // The start date is the beginning of the week at 12am
1330731f1cb808b7586b93615b408ab2636081fab0dcErik        Time weekStart = new Time(Utils.getTimeZone(mContext, mTZUpdater));
1331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.set(mBaseDate);
1332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.hour = 0;
1333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.minute = 0;
1334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        weekStart.second = 0;
1335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = weekStart.normalize(true /* ignore isDst */);
1336146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Avoid reloading events unnecessarily.
1338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (millis == mLastReloadMillis) {
1339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
1340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mLastReloadMillis = millis;
1342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1343146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // load events in the background
1344ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//        mContext.startProgressSpinner();
1345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        final ArrayList<Event> events = new ArrayList<Event>();
1346146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mEventLoader.loadEventsInBackground(mNumDays, events, millis, new Runnable() {
1347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            public void run() {
1348146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mEvents = events;
1349146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mRemeasure = true;
1350146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mComputeSelectedEvents = true;
1351146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                recalc();
1352ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                mContext.stopProgressSpinner();
1353146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
1354146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1355146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }, mCancelCallback);
1356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1358146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
1359146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    protected void onDraw(Canvas canvas) {
1360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mRemeasure) {
1361146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            remeasure(getWidth(), getHeight());
1362146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mRemeasure = false;
1363146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1365dd95df57c8c5a58a85c4c0effad5652dec14f621Erik        if (mCanvas != null) {
1366146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            doDraw(mCanvas);
1367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1369146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
1370146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.save();
1371146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mViewStartX > 0) {
1372146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                canvas.translate(mViewWidth - mViewStartX, 0);
1373146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
1374146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                canvas.translate(-(mViewWidth + mViewStartX), 0);
1375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1376d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView nextView = (DayView) mViewSwitcher.getNextView();
1377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1378146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Prevent infinite recursive calls to onDraw().
1379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            nextView.mTouchMode = TOUCH_MODE_INITIAL_STATE;
1380146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1381146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            nextView.onDraw(canvas);
1382146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.restore();
1383146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.save();
1384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.translate(-mViewStartX, 0);
1385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1387146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mBitmap != null) {
1388146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawCalendarView(canvas);
1389146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1391146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the fixed areas (that don't scroll) directly to the canvas.
1392146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        drawAfterScroll(canvas);
1393146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mComputeSelectedEvents = false;
1394146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1395146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
1396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.restore();
1397146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1399146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1400146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawCalendarView(Canvas canvas) {
1401146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1402146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Copy the scrollable region from the big bitmap to the canvas.
1403146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect src = mSrcRect;
1404146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect dest = mDestRect;
1405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        src.top = mViewStartY;
1407146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        src.bottom = mViewStartY + mGridAreaHeight;
1408146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        src.left = 0;
1409146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        src.right = mViewWidth;
1410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        dest.top = mFirstCell;
1412146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        dest.bottom = mViewHeight;
1413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        dest.left = 0;
1414146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        dest.right = mViewWidth;
14157abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project
1416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.save();
1417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.clipRect(dest);
1418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
1419146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawBitmap(mBitmap, src, dest, null);
1420146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.restore();
1421146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1422146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1423146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawAfterScroll(Canvas canvas) {
1424146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = mPaint;
1425146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect r = mRect;
1426146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1427146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mMaxAllDayEvents != 0) {
1428146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawAllDayEvents(mFirstJulianDay, mNumDays, r, canvas, p);
1429146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawUpperLeftCorner(r, canvas, p);
1430146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1431146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1432146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays > 1) {
1433146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawDayHeaderLoop(r, canvas, p);
1434146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1435146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1436146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the AM and PM indicators if we're in 12 hour mode
1437146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!mIs24HourFormat) {
1438146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawAmPm(canvas, p);
1439146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1440146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1441146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Update the popup window showing the event details, but only if
1442146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // we are not scrolling and we have focus.
1443146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!mScrolling && isFocused()) {
1444146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            updateEventDetails();
1445146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1446146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1447146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1448146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // This isn't really the upper-left corner.  It's the square area just
1449146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // below the upper-left corner, above the hours and to the left of the
1450146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // all-day area.
1451146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawUpperLeftCorner(Rect r, Canvas canvas, Paint p) {
1452d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarHourBackground);
1453146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.top = mBannerPlusMargin;
1454146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.bottom = r.top + mAllDayHeight + ALLDAY_TOP_MARGIN;
1455146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.left = 0;
1456146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.right = mHoursWidth;
1457146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawRect(r, p);
1458146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1459146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1460146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawDayHeaderLoop(Rect r, Canvas canvas, Paint p) {
1461146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the horizontal day background banner
1462d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarDateBannerBackground);
1463146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.top = 0;
1464146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.bottom = mBannerPlusMargin;
1465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.left = 0;
1466146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.right = mHoursWidth + mNumDays * (mCellWidth + DAY_GAP);
1467146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawRect(r, p);
1468146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1469146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Fill the extra space on the right side with the default background
1470146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.left = r.right;
1471146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.right = mViewWidth;
1472d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridAreaBackground);
1473146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawRect(r, p);
1474146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1475146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw a highlight on the selected day (if any), but only if we are
1476146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // displaying more than one day.
1477146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionMode != SELECTION_HIDDEN) {
1478146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mNumDays > 1) {
1479d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan                p.setColor(mCalendarDateSelected);
1480146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                r.top = 0;
1481146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                r.bottom = mBannerPlusMargin;
1482146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int daynum = mSelectionDay - mFirstJulianDay;
1483146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                r.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP);
1484146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                r.right = r.left + mCellWidth;
1485146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                canvas.drawRect(r, p);
1486146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1487146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1488146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1489146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(NORMAL_FONT_SIZE);
1490146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextAlign(Paint.Align.CENTER);
1491146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int x = mHoursWidth;
1492146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaX = mCellWidth + DAY_GAP;
1493146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cell = mFirstJulianDay;
1494146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1495146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String[] dayNames;
1496146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mDateStrWidth < mCellWidth) {
1497146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            dayNames = mDayStrs;
1498146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
1499146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            dayNames = mDayStrs2Letter;
1500146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1501146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1502d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setTypeface(mBold);
1503d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setAntiAlias(true);
1504146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++, cell++) {
15051f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan            int dayOfWeek = day + mFirstVisibleDayOfWeek;
15061f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan            if (dayOfWeek >= 14) {
15071f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan                dayOfWeek -= 14;
1508487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            }
1509487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
1510487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            if (Utils.isSaturday(dayOfWeek, mFirstDayOfWeek)) {
1511487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                p.setColor(mWeek_saturdayColor);
1512487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            } else if (Utils.isSunday(dayOfWeek, mFirstDayOfWeek)) {
1513487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                p.setColor(mWeek_sundayColor);
1514487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            } else {
1515487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                p.setColor(mCalendarDateBannerTextColor);
1516487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            }
1517487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan
1518487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan            drawDayHeader(dayNames[dayOfWeek], day, cell, x, canvas, p);
1519146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            x += deltaX;
1520146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1521146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1522146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1523146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawAmPm(Canvas canvas, Paint p) {
1524d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarAmPmLabel);
1525146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(AMPM_FONT_SIZE);
1526146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(mBold);
1527146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
1528146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPaint.setTextAlign(Paint.Align.RIGHT);
1529146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String text = mAmString;
1530146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour >= 12) {
1531146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            text = mPmString;
1532146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1533146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int y = mFirstCell + mFirstHourOffset + 2 * mHoursTextHeight + HOUR_GAP;
1534146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int right = mHoursWidth - HOURS_RIGHT_MARGIN;
1535146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawText(text, right, y, p);
1536146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1537146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mFirstHour < 12 && mFirstHour + mNumHours > 12) {
1538146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Also draw the "PM"
1539146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            text = mPmString;
1540146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            y = mFirstCell + mFirstHourOffset + (12 - mFirstHour) * (mCellHeight + HOUR_GAP)
1541146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    + 2 * mHoursTextHeight + HOUR_GAP;
1542146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawText(text, right, y, p);
1543146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1544146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1545146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1546bd0e834aea317236d574f8738fe11a51fdc87968Erik    private void drawCurrentTimeMarker(int top, Canvas canvas, Paint p) {
1547bd0e834aea317236d574f8738fe11a51fdc87968Erik        top -= CURRENT_TIME_MARKER_HEIGHT / 2;
1548bd0e834aea317236d574f8738fe11a51fdc87968Erik        p.setColor(mCurrentTimeMarkerColor);
1549bd0e834aea317236d574f8738fe11a51fdc87968Erik        Paint.Style oldStyle = p.getStyle();
1550bd0e834aea317236d574f8738fe11a51fdc87968Erik        p.setStyle(Paint.Style.STROKE);
1551bd0e834aea317236d574f8738fe11a51fdc87968Erik        p.setStrokeWidth(2.0f);
1552bd0e834aea317236d574f8738fe11a51fdc87968Erik        Path mCurrentTimeMarker = mPath;
1553bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTimeMarker.reset();
1554bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTimeMarker.moveTo(0, top);
1555bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTimeMarker.lineTo(0, CURRENT_TIME_MARKER_HEIGHT + top);
1556bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTimeMarker.lineTo(CURRENT_TIME_MARKER_INNER_WIDTH, CURRENT_TIME_MARKER_HEIGHT + top);
1557bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTimeMarker.lineTo(CURRENT_TIME_MARKER_WIDTH, CURRENT_TIME_MARKER_HEIGHT / 2 + top);
1558bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTimeMarker.lineTo(CURRENT_TIME_MARKER_INNER_WIDTH, top);
1559bd0e834aea317236d574f8738fe11a51fdc87968Erik        mCurrentTimeMarker.lineTo(0, top);
1560bd0e834aea317236d574f8738fe11a51fdc87968Erik        canvas.drawPath(mCurrentTimeMarker, p);
1561bd0e834aea317236d574f8738fe11a51fdc87968Erik        p.setStyle(oldStyle);
1562bd0e834aea317236d574f8738fe11a51fdc87968Erik    }
1563bd0e834aea317236d574f8738fe11a51fdc87968Erik
1564bd0e834aea317236d574f8738fe11a51fdc87968Erik    private void drawCurrentTimeLine(Rect r, int left, int top, Canvas canvas, Paint p) {
1565bd0e834aea317236d574f8738fe11a51fdc87968Erik        //Do a white outline so it'll show up on a red event
1566bd0e834aea317236d574f8738fe11a51fdc87968Erik        p.setColor(mCurrentTimeMarkerBorderColor);
1567bd0e834aea317236d574f8738fe11a51fdc87968Erik        r.top = top - CURRENT_TIME_LINE_HEIGHT / 2 - CURRENT_TIME_LINE_BORDER_WIDTH;
1568bd0e834aea317236d574f8738fe11a51fdc87968Erik        r.bottom = top + CURRENT_TIME_LINE_HEIGHT / 2 + CURRENT_TIME_LINE_BORDER_WIDTH;
1569bd0e834aea317236d574f8738fe11a51fdc87968Erik        r.left = left + CURRENT_TIME_LINE_SIDE_BUFFER;
1570bd0e834aea317236d574f8738fe11a51fdc87968Erik        r.right = r.left + mCellWidth - 2 * CURRENT_TIME_LINE_SIDE_BUFFER;
1571bd0e834aea317236d574f8738fe11a51fdc87968Erik        canvas.drawRect(r, p);
1572bd0e834aea317236d574f8738fe11a51fdc87968Erik        //Then draw the red line
1573bd0e834aea317236d574f8738fe11a51fdc87968Erik        p.setColor(mCurrentTimeMarkerColor);
1574bd0e834aea317236d574f8738fe11a51fdc87968Erik        r.top = top - CURRENT_TIME_LINE_HEIGHT / 2;
1575bd0e834aea317236d574f8738fe11a51fdc87968Erik        r.bottom = top + CURRENT_TIME_LINE_HEIGHT / 2;
1576bd0e834aea317236d574f8738fe11a51fdc87968Erik        canvas.drawRect(r, p);
1577bd0e834aea317236d574f8738fe11a51fdc87968Erik    }
1578bd0e834aea317236d574f8738fe11a51fdc87968Erik
1579146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void doDraw(Canvas canvas) {
1580146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint p = mPaint;
1581146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect r = mRect;
1582bd0e834aea317236d574f8738fe11a51fdc87968Erik        int lineY = mCurrentTime.hour*(mCellHeight + HOUR_GAP)
1583bd0e834aea317236d574f8738fe11a51fdc87968Erik            + ((mCurrentTime.minute * mCellHeight) / 60)
1584bd0e834aea317236d574f8738fe11a51fdc87968Erik            + 1;
1585146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1586146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        drawGridBackground(r, canvas, p);
1587146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        drawHours(r, canvas, p);
1588146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1589146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw each day
1590146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int x = mHoursWidth;
1591146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaX = mCellWidth + DAY_GAP;
1592146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cell = mFirstJulianDay;
1593146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++, cell++) {
1594146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawEvents(cell, x, HOUR_GAP, canvas, p);
1595bd0e834aea317236d574f8738fe11a51fdc87968Erik            //If this is today
1596bd0e834aea317236d574f8738fe11a51fdc87968Erik            if(cell == mTodayJulianDay) {
1597bd0e834aea317236d574f8738fe11a51fdc87968Erik                //And the current time shows up somewhere on the screen
1598bd0e834aea317236d574f8738fe11a51fdc87968Erik                if(lineY >= mViewStartY && lineY < mViewStartY + mViewHeight - 2) {
1599bd0e834aea317236d574f8738fe11a51fdc87968Erik                    //draw both the marker and the line
1600bd0e834aea317236d574f8738fe11a51fdc87968Erik                    drawCurrentTimeMarker(lineY, canvas, p);
1601bd0e834aea317236d574f8738fe11a51fdc87968Erik                    drawCurrentTimeLine(r, x, lineY, canvas, p);
1602bd0e834aea317236d574f8738fe11a51fdc87968Erik                }
1603bd0e834aea317236d574f8738fe11a51fdc87968Erik            }
1604146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            x += deltaX;
1605146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1606146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1607146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1608146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawHours(Rect r, Canvas canvas, Paint p) {
1609146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the background for the hour labels
1610d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarHourBackground);
1611146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.top = 0;
1612146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.bottom = 24 * (mCellHeight + HOUR_GAP) + HOUR_GAP;
1613146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.left = 0;
1614146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.right = mHoursWidth;
1615146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawRect(r, p);
1616146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1617146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Fill the bottom left corner with the default grid background
1618146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.top = r.bottom;
1619146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.bottom = mBitmapHeight;
1620d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridAreaBackground);
1621146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawRect(r, p);
1622146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1623146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw a highlight on the selected hour (if needed)
1624146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionMode != SELECTION_HIDDEN && !mSelectionAllDay) {
1625d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan            p.setColor(mCalendarHourSelected);
1626146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            r.top = mSelectionHour * (mCellHeight + HOUR_GAP);
1627146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            r.bottom = r.top + mCellHeight + 2 * HOUR_GAP;
1628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            r.left = 0;
1629146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            r.right = mHoursWidth;
1630146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawRect(r, p);
1631146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1632146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Also draw the highlight on the grid
1633d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan            p.setColor(mCalendarGridAreaSelected);
1634146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int daynum = mSelectionDay - mFirstJulianDay;
1635146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            r.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP);
1636146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            r.right = r.left + mCellWidth;
1637146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawRect(r, p);
1638146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1639146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Draw a border around the highlighted grid hour.
1640146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Path path = mPath;
1641146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            r.top += HOUR_GAP;
1642146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            r.bottom -= HOUR_GAP;
1643146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            path.reset();
1644146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            path.addRect(r.left, r.top, r.right, r.bottom, Direction.CW);
1645146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawPath(path, mSelectionPaint);
1646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            saveSelectionPosition(r.left, r.top, r.right, r.bottom);
1647146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1648146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1649d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarHourLabel);
1650146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(HOURS_FONT_SIZE);
1651146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTypeface(mBold);
1652146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextAlign(Paint.Align.RIGHT);
1653146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
1654146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1655146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int right = mHoursWidth - HOURS_RIGHT_MARGIN;
1656146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int y = HOUR_GAP + mHoursTextHeight;
1657146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1658146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < 24; i++) {
1659146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            String time = mHourStrs[i];
1660146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawText(time, right, y, p);
1661146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            y += mCellHeight + HOUR_GAP;
1662146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1663146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1664146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1665146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawDayHeader(String dateStr, int day, int cell, int x, Canvas canvas, Paint p) {
1666146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float xCenter = x + mCellWidth / 2.0f;
1667146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1668487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan        int dateNum = mFirstVisibleDate + day;
1669146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (dateNum > mMonthLength) {
1670146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            dateNum -= mMonthLength;
1671146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1672146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1673105f2159ae20acc98793e8bc274bb6dd722c50b1Eric Fischer        String dateNumStr;
1674146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Add a leading zero if the date is a single digit
1675146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (dateNum < 10) {
1676105f2159ae20acc98793e8bc274bb6dd722c50b1Eric Fischer            dateNumStr = "0" + dateNum;
1677146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
1678105f2159ae20acc98793e8bc274bb6dd722c50b1Eric Fischer            dateNumStr = String.valueOf(dateNum);
1679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1681d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        DayHeader header = dayHeaders[day];
1682d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        if (header == null || header.cell != cell) {
1683d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan            // The day header string is regenerated on every draw during drag and fling animation.
1684d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan            // Caching day header since formatting the string takes surprising long time.
1685d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan
1686d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan            dayHeaders[day] = new DayHeader();
1687d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan            dayHeaders[day].cell = cell;
1688d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan            dayHeaders[day].dateString = getResources().getString(
1689d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan                    R.string.weekday_day, dateStr, dateNumStr);
1690d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        }
1691d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        dateStr = dayHeaders[day].dateString;
1692105f2159ae20acc98793e8bc274bb6dd722c50b1Eric Fischer
1693146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float y = mBannerPlusMargin - 7;
1694146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawText(dateStr, xCenter, y, p);
1695146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1696146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1697146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawGridBackground(Rect r, Canvas canvas, Paint p) {
1698146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint.Style savedStyle = p.getStyle();
1699146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1700146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Clear the background
1701d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridAreaBackground);
1702146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.top = 0;
1703146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.bottom = mBitmapHeight;
1704146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.left = 0;
1705146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.right = mViewWidth;
1706146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawRect(r, p);
1707146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1708146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the horizontal grid lines
1709d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridLineHorizontalColor);
1710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStyle(Style.STROKE);
1711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStrokeWidth(0);
1712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(false);
1713146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float startX = mHoursWidth;
1714146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float stopX = mHoursWidth + (mCellWidth + DAY_GAP) * mNumDays;
1715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float y = 0;
1716146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float deltaY = mCellHeight + HOUR_GAP;
1717146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int hour = 0; hour <= 24; hour++) {
1718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawLine(startX, y, stopX, y, p);
1719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            y += deltaY;
1720146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the vertical grid lines
1723d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridLineVerticalColor);
1724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float startY = 0;
1725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float stopY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP);
1726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float deltaX = mCellWidth + DAY_GAP;
1727146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float x = mHoursWidth + mCellWidth;
1728146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day < mNumDays; day++) {
1729146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawLine(x, startY, x, stopY, p);
1730146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            x += deltaX;
1731146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1732146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1733146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Restore the saved style.
1734146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStyle(savedStyle);
1735146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
1736146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1737146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1738146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Event getSelectedEvent() {
1739146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == null) {
1740146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // There is no event at the selected hour, so create a new event.
1741146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return getNewEvent(mSelectionDay, getSelectedTimeInMillis(),
1742146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    getSelectedMinutesSinceMidnight());
1743146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1744146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return mSelectedEvent;
1745146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1746146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1747146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    boolean isEventSelected() {
1748146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return (mSelectedEvent != null);
1749146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1750146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1751146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    Event getNewEvent() {
1752146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return getNewEvent(mSelectionDay, getSelectedTimeInMillis(),
1753146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                getSelectedMinutesSinceMidnight());
1754146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1755146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    static Event getNewEvent(int julianDay, long utcMillis,
1757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int minutesSinceMidnight) {
1758146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event event = Event.newInstance();
1759146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.startDay = julianDay;
1760146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.endDay = julianDay;
1761146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.startMillis = utcMillis;
1762146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.endMillis = event.startMillis + MILLIS_PER_HOUR;
1763146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.startTime = minutesSinceMidnight;
1764146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        event.endTime = event.startTime + MINUTES_PER_HOUR;
1765146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return event;
1766146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1767146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1768146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private int computeMaxStringWidth(int currentMax, String[] strings, Paint p) {
1769146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float maxWidthF = 0.0f;
1770146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1771146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int len = strings.length;
1772146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < len; i++) {
1773146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float width = p.measureText(strings[i]);
1774146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            maxWidthF = Math.max(width, maxWidthF);
1775146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1776146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int maxWidth = (int) (maxWidthF + 0.5);
1777146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (maxWidth < currentMax) {
1778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            maxWidth = currentMax;
1779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return maxWidth;
1781146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1782146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1783146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void saveSelectionPosition(float left, float top, float right, float bottom) {
1784146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.left = (int) left;
1785146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.right = (int) right;
1786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.top = (int) top;
1787146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPrevBox.bottom = (int) bottom;
1788146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1789146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1790146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private Rect getCurrentSelectionPosition() {
1791146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect box = new Rect();
1792146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.top = mSelectionHour * (mCellHeight + HOUR_GAP);
1793146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.bottom = box.top + mCellHeight + HOUR_GAP;
1794146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int daynum = mSelectionDay - mFirstJulianDay;
1795146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP);
1796146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        box.right = box.left + mCellWidth + DAY_GAP;
1797146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return box;
1798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawAllDayEvents(int firstDay, int numDays,
1801146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Rect r, Canvas canvas, Paint p) {
1802146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextSize(NORMAL_FONT_SIZE);
1803146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setTextAlign(Paint.Align.LEFT);
1804146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint eventTextPaint = mEventTextPaint;
1805146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1806146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the background for the all-day events area
1807146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.top = mBannerPlusMargin;
1808146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.bottom = r.top + mAllDayHeight + ALLDAY_TOP_MARGIN;
1809146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.left = mHoursWidth;
1810146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.right = r.left + mNumDays * (mCellWidth + DAY_GAP);
1811d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarAllDayBackground);
1812146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawRect(r, p);
1813146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1814146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Fill the extra space on the right side with the default background
1815146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.left = r.right;
1816146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        r.right = mViewWidth;
1817d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridAreaBackground);
1818146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawRect(r, p);
1819146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1820146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Draw the vertical grid lines
1821d06a1bf1cf81b818b3e3dc0f81b7cb07382425f2Michael Chan        p.setColor(mCalendarGridLineVerticalColor);
1822146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStyle(Style.STROKE);
1823146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStrokeWidth(0);
1824146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(false);
1825146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float startY = r.top;
1826146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float stopY = r.bottom;
1827146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float deltaX = mCellWidth + DAY_GAP;
1828146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float x = mHoursWidth + mCellWidth;
1829146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int day = 0; day <= mNumDays; day++) {
1830146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawLine(x, startY, x, stopY, p);
1831146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            x += deltaX;
1832146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1833146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setAntiAlias(true);
1834146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.setStyle(Style.FILL);
1835146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1836146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int y = mBannerPlusMargin + ALLDAY_TOP_MARGIN;
1837146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float left = mHoursWidth;
1838146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int lastDay = firstDay + numDays - 1;
1839146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ArrayList<Event> events = mEvents;
1840146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numEvents = events.size();
1841146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float drawHeight = mAllDayHeight;
1842146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float numRectangles = mMaxAllDayEvents;
1843146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < numEvents; i++) {
1844146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(i);
1845146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (!event.allDay)
1846146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
1847146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startDay = event.startDay;
1848146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endDay = event.endDay;
1849146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (startDay > lastDay || endDay < firstDay)
1850146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
1851146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (startDay < firstDay)
1852146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startDay = firstDay;
1853146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (endDay > lastDay)
1854146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                endDay = lastDay;
1855146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startIndex = startDay - firstDay;
1856146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endIndex = endDay - firstDay;
1857146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float height = drawHeight / numRectangles;
1858146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1859146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Prevent a single event from getting too big
1860146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (height > MAX_ALLDAY_EVENT_HEIGHT) {
1861146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                height = MAX_ALLDAY_EVENT_HEIGHT;
1862146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1863146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1864146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Leave a one-pixel space between the vertical day lines and the
1865146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // event rectangle.
1866146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            event.left = left + startIndex * (mCellWidth + DAY_GAP) + 2;
1867146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            event.right = left + endIndex * (mCellWidth + DAY_GAP) + mCellWidth - 1;
1868146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            event.top = y + height * event.getColumn();
1869146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1870146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Multiply the height by 0.9 to leave a little gap between events
1871146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            event.bottom = event.top + height * 0.9f;
1872146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1873146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            RectF rf = drawAllDayEventRect(event, canvas, p, eventTextPaint);
1874146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawEventText(event, rf, canvas, eventTextPaint, ALL_DAY_TEXT_TOP_MARGIN);
1875146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1876146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Check if this all-day event intersects the selected day
1877146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionAllDay && mComputeSelectedEvents) {
1878146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (startDay <= mSelectionDay && endDay >= mSelectionDay) {
1879146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mSelectedEvents.add(event);
1880146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1881146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1882146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1883146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1884146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionAllDay) {
1885146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Compute the neighbors for the list of all-day events that
1886146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // intersect the selected day.
1887146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeAllDayNeighbors();
1888146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
1889146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event event = mSelectedEvent;
1890146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                RectF rf = drawAllDayEventRect(event, canvas, p, eventTextPaint);
1891146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                drawEventText(event, rf, canvas, eventTextPaint, ALL_DAY_TEXT_TOP_MARGIN);
1892146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1893146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1894146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Draw the highlight on the selected all-day area
1895146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float top = mBannerPlusMargin + 1;
1896146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float bottom = top + mAllDayHeight + ALLDAY_TOP_MARGIN - 1;
1897146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int daynum = mSelectionDay - mFirstJulianDay;
1898146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            left = mHoursWidth + daynum * (mCellWidth + DAY_GAP) + 1;
1899146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float right = left + mCellWidth + DAY_GAP - 1;
1900146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mNumDays == 1) {
1901146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // The Day view doesn't have a vertical line on the right.
1902146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                right -= 1;
1903146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1904146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Path path = mPath;
1905146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            path.reset();
1906146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            path.addRect(left, top, right, bottom, Direction.CW);
1907146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawPath(path, mSelectionPaint);
1908146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1909146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Set the selection position to zero so that when we move down
1910146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // to the normal event area, we will highlight the topmost event.
1911146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            saveSelectionPosition(0f, 0f, 0f, 0f);
1912146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1913146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1914146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1915146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void computeAllDayNeighbors() {
1916146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int len = mSelectedEvents.size();
1917146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (len == 0 || mSelectedEvent != null) {
1918146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
1919146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1920146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1921146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // First, clear all the links
1922146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
1923146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
1924146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextUp = null;
1925146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextDown = null;
1926146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextLeft = null;
1927146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextRight = null;
1928146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1929146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1930146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // For each event in the selected event list "mSelectedEvents", find
1931146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // its neighbors in the up and down directions.  This could be done
1932146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // more efficiently by sorting on the Event.getColumn() field, but
1933146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // the list is expected to be very small.
1934146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1935146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Find the event in the same row as the previously selected all-day
1936146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // event, if any.
1937146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int startPosition = -1;
1938146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mPrevSelectedEvent != null && mPrevSelectedEvent.allDay) {
1939146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            startPosition = mPrevSelectedEvent.getColumn();
1940146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1941146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int maxPosition = -1;
1942146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event startEvent = null;
1943146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event maxPositionEvent = null;
1944146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
1945146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
1946146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int position = ev.getColumn();
1947146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (position == startPosition) {
1948146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEvent = ev;
1949146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (position > maxPosition) {
1950146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                maxPositionEvent = ev;
1951146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                maxPosition = position;
1952146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1953146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int jj = 0; jj < len; jj++) {
1954146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (jj == ii) {
1955146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    continue;
1956146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1957146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event neighbor = mSelectedEvents.get(jj);
1958146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int neighborPosition = neighbor.getColumn();
1959146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (neighborPosition == position - 1) {
1960146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    ev.nextUp = neighbor;
1961146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (neighborPosition == position + 1) {
1962146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    ev.nextDown = neighbor;
1963146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1964146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
1965146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1966146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (startEvent != null) {
1967146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = startEvent;
1968146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
1969146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = maxPositionEvent;
1970146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1971146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1972146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1973146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    RectF drawAllDayEventRect(Event event, Canvas canvas, Paint p, Paint eventTextPaint) {
1974146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If this event is selected, then use the selection color
1975146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == event) {
1976146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Also, remember the last selected event that we drew
1977146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPrevSelectedEvent = event;
1978146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            p.setColor(mSelectionColor);
1979146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            eventTextPaint.setColor(mSelectedEventTextColor);
1980146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
1981146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Use the normal color for all-day events
1982146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            p.setColor(event.color);
1983146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            eventTextPaint.setColor(mEventTextColor);
1984146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1985146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1986146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        RectF rf = mRectF;
1987146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.top = event.top;
1988146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.bottom = event.bottom;
1989146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.left = event.left;
1990146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.right = event.right;
1991146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawRoundRect(rf, SMALL_ROUND_RADIUS, SMALL_ROUND_RADIUS, p);
1992146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1993146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.left += 2;
1994146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.right -= 2;
1995146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return rf;
1996146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
1997146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1998146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawEvents(int date, int left, int top, Canvas canvas, Paint p) {
1999146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Paint eventTextPaint = mEventTextPaint;
2000146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cellWidth = mCellWidth;
2001146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cellHeight = mCellHeight;
2002146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2003146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Use the selected hour as the selection region
2004146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect selectionArea = mRect;
2005146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.top = top + mSelectionHour * (cellHeight + HOUR_GAP);
2006146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.bottom = selectionArea.top + cellHeight;
2007146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.left = left;
2008146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        selectionArea.right = selectionArea.left + cellWidth;
2009146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2010146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ArrayList<Event> events = mEvents;
2011146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numEvents = events.size();
2012146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        EventGeometry geometry = mEventGeometry;
2013146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2014146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < numEvents; i++) {
2015146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(i);
2016146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (!geometry.computeEventRect(date, left, top, cellWidth, event)) {
2017146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
2018146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2019146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2020146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (date == mSelectionDay && !mSelectionAllDay && mComputeSelectedEvents
2021146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    && geometry.eventIntersectsSelection(event, selectionArea)) {
2022146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvents.add(event);
2023146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2024146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2025146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            RectF rf = drawEventRect(event, canvas, p, eventTextPaint);
2026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            drawEventText(event, rf, canvas, eventTextPaint, NORMAL_TEXT_TOP_MARGIN);
2027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2028146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2029146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (date == mSelectionDay && !mSelectionAllDay && isFocused()
2030146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                && mSelectionMode != SELECTION_HIDDEN) {
2031146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeNeighbors();
2032146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent != null) {
2033146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                RectF rf = drawEventRect(mSelectedEvent, canvas, p, eventTextPaint);
2034146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                drawEventText(mSelectedEvent, rf, canvas, eventTextPaint, NORMAL_TEXT_TOP_MARGIN);
2035146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2036146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2037146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2038146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2039146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Computes the "nearest" neighbor event in four directions (left, right,
2040146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // up, down) for each of the events in the mSelectedEvents array.
2041146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void computeNeighbors() {
2042146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int len = mSelectedEvents.size();
2043146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (len == 0 || mSelectedEvent != null) {
2044146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2045146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2046146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2047146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // First, clear all the links
2048146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
2049146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
2050146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextUp = null;
2051146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextDown = null;
2052146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextLeft = null;
2053146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextRight = null;
2054146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2055146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2056146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event startEvent = mSelectedEvents.get(0);
2057146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int startEventDistance1 = 100000;  // any large number
2058146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int startEventDistance2 = 100000;  // any large number
2059146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevLocation = FROM_NONE;
2060146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevTop;
2061146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevBottom;
2062146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevLeft;
2063146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevRight;
2064146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int prevCenter = 0;
2065146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect box = getCurrentSelectionPosition();
2066146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mPrevSelectedEvent != null) {
2067146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevTop = (int) mPrevSelectedEvent.top;
2068146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevBottom = (int) mPrevSelectedEvent.bottom;
2069146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLeft = (int) mPrevSelectedEvent.left;
2070146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevRight = (int) mPrevSelectedEvent.right;
2071146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Check if the previously selected event intersects the previous
2072146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // selection box.  (The previously selected event may be from a
2073146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // much older selection box.)
2074146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (prevTop >= mPrevBox.bottom || prevBottom <= mPrevBox.top
2075146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || prevRight <= mPrevBox.left || prevLeft >= mPrevBox.right) {
2076146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = null;
2077146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevTop = mPrevBox.top;
2078146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevBottom = mPrevBox.bottom;
2079146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevLeft = mPrevBox.left;
2080146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                prevRight = mPrevBox.right;
2081146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
2082146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Clip the top and bottom to the previous selection box.
2083146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (prevTop < mPrevBox.top) {
2084146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    prevTop = mPrevBox.top;
2085146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (prevBottom > mPrevBox.bottom) {
2087146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    prevBottom = mPrevBox.bottom;
2088146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2089146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2091146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Just use the previously drawn selection box
2092146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevTop = mPrevBox.top;
2093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevBottom = mPrevBox.bottom;
2094146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLeft = mPrevBox.left;
2095146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevRight = mPrevBox.right;
2096146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2097146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2098146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Figure out where we came from and compute the center of that area.
2099146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (prevLeft >= box.right) {
2100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was to the right of us.
2101146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_RIGHT;
2102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevTop + prevBottom) / 2;
2103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (prevRight <= box.left) {
2104146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was to the left of us.
2105146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_LEFT;
2106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevTop + prevBottom) / 2;
2107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (prevBottom <= box.top) {
2108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was above us.
2109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_ABOVE;
2110146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevLeft + prevRight) / 2;
2111146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if (prevTop >= box.bottom) {
2112146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // The previously selected event was below us.
2113146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevLocation = FROM_BELOW;
2114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            prevCenter = (prevLeft + prevRight) / 2;
2115146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2117146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // For each event in the selected event list "mSelectedEvents", search
2118146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // all the other events in that list for the nearest neighbor in 4
2119146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // directions.
2120146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int ii = 0; ii < len; ii++) {
2121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event ev = mSelectedEvents.get(ii);
2122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startTime = ev.startTime;
2124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endTime = ev.endTime;
2125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int left = (int) ev.left;
2126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int right = (int) ev.right;
2127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int top = (int) ev.top;
2128146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (top < box.top) {
2129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                top = box.top;
2130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int bottom = (int) ev.bottom;
2132146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (bottom > box.bottom) {
2133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                bottom = box.bottom;
2134146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (false) {
2136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL
2137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
2138ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                if (DateFormat.is24HourFormat(mContext)) {
2139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    flags |= DateUtils.FORMAT_24HOUR;
2140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2141ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                String timeRange = DateUtils.formatDateRange(mContext,
2142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        ev.startMillis, ev.endMillis, flags);
2143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Log.i("Cal", "left: " + left + " right: " + right + " top: " + top
2144146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        + " bottom: " + bottom + " ev: " + timeRange + " " + ev.title);
2145146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2146146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int upDistanceMin = 10000;     // any large number
2147146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int downDistanceMin = 10000;   // any large number
2148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int leftDistanceMin = 10000;   // any large number
2149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int rightDistanceMin = 10000;  // any large number
2150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event upEvent = null;
2151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event downEvent = null;
2152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event leftEvent = null;
2153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event rightEvent = null;
2154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Pick the starting event closest to the previously selected event,
2156146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // if any.  distance1 takes precedence over distance2.
2157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int distance1 = 0;
2158146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int distance2 = 0;
2159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (prevLocation == FROM_ABOVE) {
2160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (left >= prevCenter) {
2161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = left - prevCenter;
2162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (right <= prevCenter) {
2163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - right;
2164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = top - prevBottom;
2166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (prevLocation == FROM_BELOW) {
2167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (left >= prevCenter) {
2168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = left - prevCenter;
2169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (right <= prevCenter) {
2170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - right;
2171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2172146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = prevTop - bottom;
2173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (prevLocation == FROM_LEFT) {
2174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (bottom <= prevCenter) {
2175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - bottom;
2176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (top >= prevCenter) {
2177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = top - prevCenter;
2178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = left - prevRight;
2180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (prevLocation == FROM_RIGHT) {
2181146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (bottom <= prevCenter) {
2182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = prevCenter - bottom;
2183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (top >= prevCenter) {
2184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    distance1 = top - prevCenter;
2185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                distance2 = prevLeft - right;
2187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (distance1 < startEventDistance1
2189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    || (distance1 == startEventDistance1 && distance2 < startEventDistance2)) {
2190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEvent = ev;
2191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEventDistance1 = distance1;
2192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                startEventDistance2 = distance2;
2193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // For each neighbor, figure out if it is above or below or left
2196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // or right of me and compute the distance.
2197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int jj = 0; jj < len; jj++) {
2198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (jj == ii) {
2199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    continue;
2200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event neighbor = mSelectedEvents.get(jj);
2202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int neighborLeft = (int) neighbor.left;
2203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int neighborRight = (int) neighbor.right;
2204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (neighbor.endTime <= startTime) {
2205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely above me.
2206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // If we overlap the same column, then compute the distance.
2207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborLeft < right && neighborRight > left) {
2208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int distance = startTime - neighbor.endTime;
2209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (distance < upDistanceMin) {
2210146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            upDistanceMin = distance;
2211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            upEvent = neighbor;
2212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        } else if (distance == upDistanceMin) {
2213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int center = (left + right) / 2;
2214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentDistance = 0;
2215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentLeft = (int) upEvent.left;
2216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentRight = (int) upEvent.right;
2217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (currentRight <= center) {
2218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = center - currentRight;
2219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (currentLeft >= center) {
2220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = currentLeft - center;
2221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int neighborDistance = 0;
2224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborRight <= center) {
2225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = center - neighborRight;
2226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (neighborLeft >= center) {
2227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = neighborLeft - center;
2228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborDistance < currentDistance) {
2230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                upDistanceMin = distance;
2231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                upEvent = neighbor;
2232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2235146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (neighbor.startTime >= endTime) {
2236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely below me.
2237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // If we overlap the same column, then compute the distance.
2238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborLeft < right && neighborRight > left) {
2239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int distance = neighbor.startTime - endTime;
2240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (distance < downDistanceMin) {
2241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            downDistanceMin = distance;
2242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            downEvent = neighbor;
2243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        } else if (distance == downDistanceMin) {
2244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int center = (left + right) / 2;
2245146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentDistance = 0;
2246146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentLeft = (int) downEvent.left;
2247146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int currentRight = (int) downEvent.right;
2248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (currentRight <= center) {
2249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = center - currentRight;
2250146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (currentLeft >= center) {
2251146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                currentDistance = currentLeft - center;
2252146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2253146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2254146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            int neighborDistance = 0;
2255146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborRight <= center) {
2256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = center - neighborRight;
2257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            } else if (neighborLeft >= center) {
2258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                neighborDistance = neighborLeft - center;
2259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            if (neighborDistance < currentDistance) {
2261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                downDistanceMin = distance;
2262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                                downEvent = neighbor;
2263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            }
2264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2267146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2268146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (neighborLeft >= right) {
2269146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely to the right of me.
2270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Take the closest neighbor in the y direction.
2271146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int center = (top + bottom) / 2;
2272146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int distance = 0;
2273146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborBottom = (int) neighbor.bottom;
2274146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborTop = (int) neighbor.top;
2275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborBottom <= center) {
2276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = center - neighborBottom;
2277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (neighborTop >= center) {
2278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = neighborTop - center;
2279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (distance < rightDistanceMin) {
2281146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        rightDistanceMin = distance;
2282146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        rightEvent = neighbor;
2283146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (distance == rightDistanceMin) {
2284146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // Pick the closest in the x direction
2285146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int neighborDistance = neighborLeft - right;
2286146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int currentDistance = (int) rightEvent.left - right;
2287146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (neighborDistance < currentDistance) {
2288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            rightDistanceMin = distance;
2289146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            rightEvent = neighbor;
2290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2291146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2292146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else if (neighborRight <= left) {
2293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This neighbor is entirely to the left of me.
2294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Take the closest neighbor in the y direction.
2295146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int center = (top + bottom) / 2;
2296146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int distance = 0;
2297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborBottom = (int) neighbor.bottom;
2298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    int neighborTop = (int) neighbor.top;
2299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (neighborBottom <= center) {
2300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = center - neighborBottom;
2301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (neighborTop >= center) {
2302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        distance = neighborTop - center;
2303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (distance < leftDistanceMin) {
2305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        leftDistanceMin = distance;
2306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        leftEvent = neighbor;
2307146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else if (distance == leftDistanceMin) {
2308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // Pick the closest in the x direction
2309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int neighborDistance = left - neighborRight;
2310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        int currentDistance = left - (int) leftEvent.right;
2311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (neighborDistance < currentDistance) {
2312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            leftDistanceMin = distance;
2313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            leftEvent = neighbor;
2314146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
2315146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2316146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2317146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2318146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextUp = upEvent;
2319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextDown = downEvent;
2320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextLeft = leftEvent;
2321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            ev.nextRight = rightEvent;
2322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2323146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = startEvent;
2324146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private RectF drawEventRect(Event event, Canvas canvas, Paint p, Paint eventTextPaint) {
2328146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2329146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int color = event.color;
2330e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Fade visible boxes if event was declined.
2332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        boolean declined = (event.selfAttendeeStatus == Attendees.ATTENDEE_STATUS_DECLINED);
2333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (declined) {
2334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int alpha = color & 0xff000000;
2335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            color &= 0x00ffffff;
2336146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int red = (color & 0x00ff0000) >> 16;
2337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int green = (color & 0x0000ff00) >> 8;
2338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int blue = (color & 0x0000ff);
2339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            color = ((red >> 1) << 16) | ((green >> 1) << 8) | (blue >> 1);
2340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            color += 0x7F7F7F + alpha;
2341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2342e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2343146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If this event is selected, then use the selection color
2344146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == event) {
2345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionMode == SELECTION_PRESSED) {
2346146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Also, remember the last selected event that we drew
2347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = event;
2348146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // box = mBoxPressed;
2349146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                p.setColor(mPressedColor); // FIXME:pressed
2350146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                eventTextPaint.setColor(mSelectedEventTextColor);
2351146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionMode == SELECTION_SELECTED) {
2352146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Also, remember the last selected event that we drew
2353146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPrevSelectedEvent = event;
2354146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // box = mBoxSelected;
2355146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                p.setColor(mSelectionColor);
2356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                eventTextPaint.setColor(mSelectedEventTextColor);
2357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionMode == SELECTION_LONGPRESS) {
2358146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // box = mBoxLongPressed;
2359146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                p.setColor(mPressedColor); // FIXME: longpressed (maybe -- this doesn't seem to work)
2360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                eventTextPaint.setColor(mSelectedEventTextColor);
2361146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
2362146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                p.setColor(color);
2363146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                eventTextPaint.setColor(mEventTextColor);
2364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2366146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            p.setColor(color);
2367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            eventTextPaint.setColor(mEventTextColor);
2368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2369146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2370146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2371146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        RectF rf = mRectF;
2372146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.top = event.top;
2373146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.bottom = event.bottom;
2374146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.left = event.left;
2375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.right = event.right - 1;
2376146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        canvas.drawRoundRect(rf, SMALL_ROUND_RADIUS, SMALL_ROUND_RADIUS, p);
23788af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project
23798af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        // Draw a darker border
23808af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        float[] hsv = new float[3];
23818af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        Color.colorToHSV(p.getColor(), hsv);
23828af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        hsv[1] = 1.0f;
23838af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        hsv[2] *= 0.75f;
23848af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        mPaintBorder.setColor(Color.HSVToColor(hsv));
23858af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project        canvas.drawRoundRect(rf, SMALL_ROUND_RADIUS, SMALL_ROUND_RADIUS, mPaintBorder);
23868af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project
2387146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.left += 2;
2388146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        rf.right -= 2;
2389e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return rf;
2391146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2392146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
23930d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    private Pattern drawTextSanitizerFilter = Pattern.compile("[\t\n],");
23940d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan
23950d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    // Sanitize a string before passing it to drawText or else we get little
23960d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    // squares. For newlines and tabs before a comma, delete the character.
23970d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    // Otherwise, just replace them with a space.
23980d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    private String drawTextSanitizer(String string) {
23990d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan        Matcher m = drawTextSanitizerFilter.matcher(string);
24000d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan        string = m.replaceAll(",").replace('\n', ' ').replace('\n', ' ');
24010d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan        return string;
24020d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan    }
24030d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan
2404146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void drawEventText(Event event, RectF rf, Canvas canvas, Paint p, int topMargin) {
2405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!mDrawTextInEventRect) {
2406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2407146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2408146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2409146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float width = rf.right - rf.left;
2410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float height = rf.bottom - rf.top;
2411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2412146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Leave one pixel extra space between lines
2413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int lineHeight = mEventTextHeight + 1;
2414146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2415146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If the rectangle is too small for text, then return
2416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (width < MIN_CELL_WIDTH_FOR_TEXT || height <= lineHeight) {
2417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2419146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2420146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Truncate the event title to a known (large enough) limit
2421146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String text = event.getTitleAndLocation();
24220d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan
24230d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan        text = drawTextSanitizer(text);
24240d53e947fce63b2a629ea2c32a882eb505e527f7Michael Chan
2425146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int len = text.length();
2426146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (len > MAX_EVENT_TEXT_LEN) {
2427146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            text = text.substring(0, MAX_EVENT_TEXT_LEN);
2428146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            len = MAX_EVENT_TEXT_LEN;
2429146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2430146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2431146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Figure out how much space the event title will take, and create a
2432146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // String fragment that will fit in the rectangle.  Use multiple lines,
2433146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // if available.
2434146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        p.getTextWidths(text, mCharWidths);
2435146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String fragment = text;
2436146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float top = rf.top + mEventTextAscent + topMargin;
2437146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int start = 0;
2438146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2439146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Leave one pixel extra space at the bottom
2440146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        while (start < len && height >= (lineHeight + 1)) {
2441146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            boolean lastLine = (height < 2 * lineHeight + 1);
2442146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Skip leading spaces at the beginning of each line
2443146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            do {
2444146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                char c = text.charAt(start);
2445146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (c != ' ') break;
2446146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                start += 1;
2447146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } while (start < len);
2448146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2449146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float sum = 0;
2450146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int end = start;
2451146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int ii = start; ii < len; ii++) {
2452146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                char c = text.charAt(ii);
2453146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2454146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // If we found the end of a word, then remember the ending
2455146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // position.
2456146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (c == ' ') {
2457146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    end = ii;
2458146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2459146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                sum += mCharWidths[ii];
2460146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // If adding this character would exceed the width and this
2461146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // isn't the last line, then break the line at the previous
2462146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // word.  If there was no previous word, then break this word.
2463146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (sum > width) {
2464146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (end > start && !lastLine) {
2465146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // There was a previous word on this line.
2466146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        fragment = text.substring(start, end);
2467146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        start = end;
2468146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        break;
2469146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2470146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2471146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // This is the only word and it is too long to fit on
2472146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // the line (or this is the last line), so take as many
2473146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // characters of this word as will fit.
2474146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    fragment = text.substring(start, ii);
2475146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    start = ii;
2476146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
2477146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2478146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2479146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2480146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If sum <= width, then we can fit the rest of the text on
2481146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // this line.
2482146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (sum <= width) {
2483146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                fragment = text.substring(start, len);
2484146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                start = len;
2485146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2486146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2487146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            canvas.drawText(fragment, rf.left + 1, top, p);
2488146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2489146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            top += lineHeight;
2490146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            height -= lineHeight;
2491146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2492146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2493146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2494146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void updateEventDetails() {
2495146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvent == null || mSelectionMode == SELECTION_HIDDEN
2496146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                || mSelectionMode == SELECTION_LONGPRESS) {
2497146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPopup.dismiss();
2498146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2499146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2500666fc5e8ddbac15c951aad738bd818ee307eae42Erik        if (mLastPopupEventID == mSelectedEvent.id) {
2501666fc5e8ddbac15c951aad738bd818ee307eae42Erik            return;
2502666fc5e8ddbac15c951aad738bd818ee307eae42Erik        }
2503666fc5e8ddbac15c951aad738bd818ee307eae42Erik
2504666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = mSelectedEvent.id;
2505146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2506146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Remove any outstanding callbacks to dismiss the popup.
2507146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        getHandler().removeCallbacks(mDismissPopup);
2508146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2509146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Event event = mSelectedEvent;
2510146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TextView titleView = (TextView) mPopupView.findViewById(R.id.event_title);
2511146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        titleView.setText(event.title);
2512146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2513146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ImageView imageView = (ImageView) mPopupView.findViewById(R.id.reminder_icon);
2514146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        imageView.setVisibility(event.hasAlarm ? View.VISIBLE : View.GONE);
2515146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2516146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        imageView = (ImageView) mPopupView.findViewById(R.id.repeat_icon);
2517146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        imageView.setVisibility(event.isRepeating ? View.VISIBLE : View.GONE);
2518146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2519146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int flags;
2520146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (event.allDay) {
2521146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags = DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_DATE |
2522146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL;
2523146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2524146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE
2525146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL
2526146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
2527146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2528ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        if (DateFormat.is24HourFormat(mContext)) {
2529146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            flags |= DateUtils.FORMAT_24HOUR;
2530146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2531731f1cb808b7586b93615b408ab2636081fab0dcErik        String timeRange = Utils.formatDateRange(mContext,
2532146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                event.startMillis, event.endMillis, flags);
2533146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TextView timeView = (TextView) mPopupView.findViewById(R.id.time);
2534146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        timeView.setText(timeRange);
2535146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2536146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        TextView whereView = (TextView) mPopupView.findViewById(R.id.where);
2537146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        final boolean empty = TextUtils.isEmpty(event.location);
2538146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        whereView.setVisibility(empty ? View.GONE : View.VISIBLE);
2539146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!empty) whereView.setText(event.location);
2540146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2541146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.LEFT, mHoursWidth, 5);
2542146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        postDelayed(mDismissPopup, POPUP_DISMISS_DELAY);
2543146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2544146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2545146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // The following routines are called from the parent activity when certain
2546146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // touch events occur.
25474484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doDown(MotionEvent ev) {
2548146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mTouchMode = TOUCH_MODE_DOWN;
2549146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mViewStartX = 0;
2550146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mOnFlingCalled = false;
2551146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        getHandler().removeCallbacks(mContinueScroll);
2552146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2553146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
25544484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doSingleTapUp(MotionEvent ev) {
2555146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int x = (int) ev.getX();
2556146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int y = (int) ev.getY();
2557146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int selectedDay = mSelectionDay;
2558146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int selectedHour = mSelectionHour;
2559146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2560146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        boolean validPosition = setSelectionFromPosition(x, y);
2561146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (!validPosition) {
256280bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            // return if the touch wasn't on an area of concern
2563146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2564146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2565146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
256680bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        mSelectionMode = SELECTION_SELECTED;
2567146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
2568146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
256980bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        boolean launchNewView = false;
257080bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        if (mSelectedEvent != null) {
257180bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            // If the tap is on an event, launch the "View event" view
2572344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, mSelectedEvent.id,
2573344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan                    mSelectedEvent.startMillis, mSelectedEvent.endMillis, (int) ev.getRawX(),
2574344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan                    (int) ev.getRawY());
2575344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan        } else if (selectedDay == mSelectionDay && selectedHour == mSelectionHour) {
2576344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            // If the tap is on an already selected hour slot, then create a new
2577344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            // event
2578344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
2579344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan                    getSelectedTimeInMillis(), 0, (int) ev.getRawX(), (int) ev.getRawY());
2580344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan        } else {
2581344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            Time startTime = new Time(mBaseDate);
2582344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            startTime.setJulianDay(mSelectionDay);
2583344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            startTime.hour = mSelectionHour;
2584344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            startTime.normalize(true /* ignore isDst */);
258583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
258683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Time endTime = new Time(startTime);
258783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            endTime.hour++;
258883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
2589344c69e88c32ea40386c40d420c83bece9c2d556Michael Chan            mController.sendEvent(this, EventType.GO_TO, startTime, endTime, -1, ViewType.CURRENT);
2590146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2591146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2592146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
25934484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doLongPress(MotionEvent ev) {
259480bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        int x = (int) ev.getX();
259580bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        int y = (int) ev.getY();
259680bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan
259780bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        boolean validPosition = setSelectionFromPosition(x, y);
259880bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        if (!validPosition) {
259980bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            // return if the touch wasn't on an area of concern
260080bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan            return;
260180bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan        }
260280bbecfb183210ccbe53ec99e8b3d9aab323da2bMichael Chan
2603146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_LONGPRESS;
2604146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
2605146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        performLongClick();
2606146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2607146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
26084484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doScroll(MotionEvent e1, MotionEvent e2, float deltaX, float deltaY) {
2609146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Use the distance from the current point to the initial touch instead
2610146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // of deltaX and deltaY to avoid accumulating floating-point rounding
2611146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // errors.  Also, we don't need floats, we can use ints.
2612146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceX = (int) e1.getX() - (int) e2.getX();
2613146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceY = (int) e1.getY() - (int) e2.getY();
2614146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2615146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If we haven't figured out the predominant scroll direction yet,
2616146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // then do it now.
2617146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mTouchMode == TOUCH_MODE_DOWN) {
2618146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int absDistanceX = Math.abs(distanceX);
2619146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int absDistanceY = Math.abs(distanceY);
2620146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mScrollStartY = mViewStartY;
2621146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPreviousDistanceX = 0;
2622146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPreviousDirection = 0;
2623146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2624146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If the x distance is at least twice the y distance, then lock
2625146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // the scroll horizontally.  Otherwise scroll vertically.
2626146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (absDistanceX >= 2 * absDistanceY) {
2627146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mTouchMode = TOUCH_MODE_HSCROLL;
2628146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartX = distanceX;
2629146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                initNextView(-mViewStartX);
2630146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
2631146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mTouchMode = TOUCH_MODE_VSCROLL;
2632146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2633146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
2634146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // We are already scrolling horizontally, so check if we
2635146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // changed the direction of scrolling so that the other week
2636146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // is now visible.
2637146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mViewStartX = distanceX;
2638146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (distanceX != 0) {
2639146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                int direction = (distanceX > 0) ? 1 : -1;
2640146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (direction != mPreviousDirection) {
2641146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // The user has switched the direction of scrolling
2642146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // so re-init the next view
2643146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    initNextView(-mViewStartX);
2644146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mPreviousDirection = direction;
2645146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2646146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2647e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2648146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we have moved at least the HORIZONTAL_SCROLL_THRESHOLD,
2649146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // then change the title to the new day (or week), but only
2650146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // if we haven't already changed the title.
2651146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (distanceX >= HORIZONTAL_SCROLL_THRESHOLD) {
2652146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mPreviousDistanceX < HORIZONTAL_SCROLL_THRESHOLD) {
2653d190418220467c02327dd9b3ae1eae238889720bMichael Chan                    DayView view = (DayView) mViewSwitcher.getNextView();
2654146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mTitleTextView.setText(view.mDateRange);
2655146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2656146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (distanceX <= -HORIZONTAL_SCROLL_THRESHOLD) {
2657146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mPreviousDistanceX > -HORIZONTAL_SCROLL_THRESHOLD) {
2658d190418220467c02327dd9b3ae1eae238889720bMichael Chan                    DayView view = (DayView) mViewSwitcher.getNextView();
2659146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mTitleTextView.setText(view.mDateRange);
2660146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2661146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
2662146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mPreviousDistanceX >= HORIZONTAL_SCROLL_THRESHOLD
2663146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        || mPreviousDistanceX <= -HORIZONTAL_SCROLL_THRESHOLD) {
2664146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mTitleTextView.setText(mDateRange);
2665146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2666146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2667146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPreviousDistanceX = distanceX;
2668146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2669146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2670146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((mTouchMode & TOUCH_MODE_VSCROLL) != 0) {
2671146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mViewStartY = mScrollStartY + distanceY;
2672146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mViewStartY < 0) {
2673146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = 0;
2674146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mViewStartY > mMaxViewStartY) {
2675146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = mMaxViewStartY;
2676146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2677146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeFirstHour();
2678146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2679146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2680146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mScrolling = true;
2681146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2682146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionMode != SELECTION_HIDDEN) {
2683146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionMode = SELECTION_HIDDEN;
2684146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2685146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        invalidate();
2686146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2687146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
26884484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan    private void doFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
2689146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mTouchMode = TOUCH_MODE_INITIAL_STATE;
2690146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionMode = SELECTION_HIDDEN;
2691146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mOnFlingCalled = true;
2692146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaX = (int) e2.getX() - (int) e1.getX();
2693146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceX = Math.abs(deltaX);
2694146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int deltaY = (int) e2.getY() - (int) e1.getY();
2695146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int distanceY = Math.abs(deltaY);
2696146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2697146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if ((distanceX >= HORIZONTAL_SCROLL_THRESHOLD) && (distanceX > distanceY)) {
2698146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            boolean switchForward = initNextView(deltaX);
2699d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView view = (DayView) mViewSwitcher.getNextView();
2700146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mTitleTextView.setText(view.mDateRange);
270183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
270283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Time end = new Time(view.mBaseDate);
27031f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan            end.monthDay += mNumDays;
27041f711ed63be864c94259a65deef8d5cdf380b9fbMichael Chan            end.normalize(true);
270583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            Log.d(TAG, "doFling");
27063458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            mController
2707487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                    .sendEvent(this, EventType.GO_TO, view.mBaseDate, end, -1, ViewType.CURRENT);
270883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
2709146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mViewStartX = 0;
2710146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
2711146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2712146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2713146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Continue scrolling vertically
2714146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mContinueScroll.init((int) velocityY / 20);
2715146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        post(mContinueScroll);
2716146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2717146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2718146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean initNextView(int deltaX) {
2719146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Change the view to the previous day or week
2720d190418220467c02327dd9b3ae1eae238889720bMichael Chan        DayView view = (DayView) mViewSwitcher.getNextView();
2721146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time date = view.mBaseDate;
2722146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        date.set(mBaseDate);
2723146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        boolean switchForward;
2724146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (deltaX > 0) {
2725146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.monthDay -= mNumDays;
2726146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionDay = mSelectionDay - mNumDays;
2727146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchForward = false;
2728146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2729146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            date.monthDay += mNumDays;
2730146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            view.mSelectionDay = mSelectionDay + mNumDays;
2731146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switchForward = true;
2732146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2733146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        date.normalize(true /* ignore isDst */);
2734146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        initView(view);
2735ad36a3c3cde7a2ec6d3a35d2529d46f03bd8d59dMichael Chan        view.layout(getLeft(), getTop(), getRight(), getBottom());
2736146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        view.reloadEvents();
2737146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return switchForward;
2738146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2739146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2740146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
2741146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
2742146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int action = ev.getAction();
2743146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2744146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        switch (action) {
2745146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case MotionEvent.ACTION_DOWN:
2746ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            mGestureDetector.onTouchEvent(ev);
2747146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
2748146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2749146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case MotionEvent.ACTION_MOVE:
2750ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            mGestureDetector.onTouchEvent(ev);
2751146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
2752146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2753146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case MotionEvent.ACTION_UP:
2754ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            mGestureDetector.onTouchEvent(ev);
2755146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mOnFlingCalled) {
2756146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
2757146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2758146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
2759146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mTouchMode = TOUCH_MODE_INITIAL_STATE;
2760146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (Math.abs(mViewStartX) > HORIZONTAL_SCROLL_THRESHOLD) {
2761146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // The user has gone beyond the threshold so switch views
2762ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                    switchViews(mViewStartX > 0, mViewStartX, mViewWidth);
27637abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project                    mViewStartX = 0;
27647abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project                    return true;
2765146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
2766146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // Not beyond the threshold so invalidate which will cause
2767146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // the view to snap back.  Also call recalc() to ensure
2768146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    // that we have the correct starting date and title.
2769146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    recalc();
2770146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mTitleTextView.setText(mDateRange);
2771146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    invalidate();
27727abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project                    mViewStartX = 0;
2773146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2774146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2775146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2776146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If we were scrolling, then reset the selected hour so that it
2777146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // is visible.
2778146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mScrolling) {
2779146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mScrolling = false;
2780146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                resetSelectedHour();
2781146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                invalidate();
2782146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2783146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
2784146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2785146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // This case isn't expected to happen.
2786146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        case MotionEvent.ACTION_CANCEL:
2787ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            mGestureDetector.onTouchEvent(ev);
2788146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mScrolling = false;
2789146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            resetSelectedHour();
2790146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
2791146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2792146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        default:
2793ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            if (mGestureDetector.onTouchEvent(ev)) {
2794146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                return true;
2795146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2796146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return super.onTouchEvent(ev);
2797146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2798146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2799146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2800146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
2801146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        MenuItem item;
2802146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2803146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If the trackball is held down, then the context menu pops up and
2804146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // we never get onKeyUp() for the long-press.  So check for it here
2805146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // and change the selection to the long-press state.
2806146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionMode != SELECTION_LONGPRESS) {
2807146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionMode = SELECTION_LONGPRESS;
2808146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            invalidate();
2809146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2810146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2811e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        final long startMillis = getSelectedTimeInMillis();
2812146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int flags = DateUtils.FORMAT_SHOW_TIME
2813146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                | DateUtils.FORMAT_CAP_NOON_MIDNIGHT
2814146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                | DateUtils.FORMAT_SHOW_WEEKDAY;
2815ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        final String title = DateUtils.formatDateTime(mContext, startMillis, flags);
2816146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        menu.setHeaderTitle(title);
2817e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2818146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numSelectedEvents = mSelectedEvents.size();
2819146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mNumDays == 1) {
2820146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Day view.
2821146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2822146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there is a selected event, then allow it to be viewed and
2823146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // edited.
2824146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (numSelectedEvents >= 1) {
28254484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_VIEW, 0, R.string.event_view);
2826146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
2827146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_info_details);
2828146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2829ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                int accessLevel = getEventAccessLevel(mContext, mSelectedEvent);
2830a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel == ACCESS_LEVEL_EDIT) {
28314484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_EDIT, 0, R.string.event_edit);
2832146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
2833146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_edit);
2834146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setAlphabeticShortcut('e');
2835a505627659f6bfba8869eac8089f7030f2d0d92cErik                }
2836146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2837a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel >= ACCESS_LEVEL_DELETE) {
28384484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_DELETE, 0, R.string.event_delete);
2839146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
2840146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_delete);
2841146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2842146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
28434484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
2844146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
2845146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_add);
2846146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setAlphabeticShortcut('n');
2847146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
2848146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Otherwise, if the user long-pressed on a blank hour, allow
2849146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // them to create an event.  They can also do this by tapping.
28504484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
2851146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
2852146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_add);
2853146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setAlphabeticShortcut('n');
2854146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2855146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
2856146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Week view.
2857e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2858146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If there is a selected event, then allow it to be viewed and
2859146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // edited.
2860146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (numSelectedEvents >= 1) {
28614484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                item = menu.add(0, MENU_EVENT_VIEW, 0, R.string.event_view);
2862146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setOnMenuItemClickListener(mContextMenuHandler);
2863146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                item.setIcon(android.R.drawable.ic_menu_info_details);
2864146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2865ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan                int accessLevel = getEventAccessLevel(mContext, mSelectedEvent);
2866a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel == ACCESS_LEVEL_EDIT) {
28674484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_EDIT, 0, R.string.event_edit);
2868146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
2869146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_edit);
2870146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setAlphabeticShortcut('e');
2871a505627659f6bfba8869eac8089f7030f2d0d92cErik                }
2872146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2873a505627659f6bfba8869eac8089f7030f2d0d92cErik                if (accessLevel >= ACCESS_LEVEL_DELETE) {
28744484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                    item = menu.add(0, MENU_EVENT_DELETE, 0, R.string.event_delete);
2875146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setOnMenuItemClickListener(mContextMenuHandler);
2876146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    item.setIcon(android.R.drawable.ic_menu_delete);
2877146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
28784484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            }
2879146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
28804484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
28814484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setOnMenuItemClickListener(mContextMenuHandler);
28824484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setIcon(android.R.drawable.ic_menu_add);
28834484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setAlphabeticShortcut('n');
2884146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
28854484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item = menu.add(0, MENU_DAY, 0, R.string.show_day_view);
28864484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setOnMenuItemClickListener(mContextMenuHandler);
28874484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setIcon(android.R.drawable.ic_menu_day);
28884484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setAlphabeticShortcut('d');
2889146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
28904484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item = menu.add(0, MENU_AGENDA, 0, R.string.show_agenda_view);
28914484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setOnMenuItemClickListener(mContextMenuHandler);
28924484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setIcon(android.R.drawable.ic_menu_agenda);
28934484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan            item.setAlphabeticShortcut('a');
2894146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2895146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2896146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mPopup.dismiss();
2897146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2898146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2899146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private class ContextMenuHandler implements MenuItem.OnMenuItemClickListener {
2900146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public boolean onMenuItemClick(MenuItem item) {
2901146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            switch (item.getItemId()) {
29024484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_VIEW: {
2903146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (mSelectedEvent != null) {
29049e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT,
29059e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                mSelectedEvent.id, mSelectedEvent.startMillis,
29069e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                mSelectedEvent.endMillis, 0, 0);
2907146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2908146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
2909146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
29104484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_EDIT: {
2911146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (mSelectedEvent != null) {
29129e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        mController.sendEventRelatedEvent(this, EventType.EDIT_EVENT,
29139e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                mSelectedEvent.id, mSelectedEvent.startMillis,
29149e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                mSelectedEvent.endMillis, 0, 0);
2915146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2916146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
2917146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
29184484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_DAY: {
2919487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                    mController.sendEvent(this, EventType.GO_TO, getSelectedTime(), null, -1,
29209e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            ViewType.DAY);
2921146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
2922146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
29234484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_AGENDA: {
2924487552be8ae3c1b148211c0fbf594d2b73727fd6Michael Chan                    mController.sendEvent(this, EventType.GO_TO, getSelectedTime(), null, -1,
29259e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            ViewType.AGENDA);
2926146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
2927146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
29284484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_CREATE: {
2929146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long startMillis = getSelectedTimeInMillis();
2930146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
29319e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                    mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
29329e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                            startMillis, endMillis, 0, 0);
2933146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
2934146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
29354484b04707d5570a6de4a5a4b228a9bb273bbab7Michael Chan                case MENU_EVENT_DELETE: {
2936146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (mSelectedEvent != null) {
2937146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        Event selectedEvent = mSelectedEvent;
2938146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        long begin = selectedEvent.startMillis;
2939146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        long end = selectedEvent.endMillis;
2940146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        long id = selectedEvent.id;
29419e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                        mController.sendEventRelatedEvent(this, EventType.DELETE_EVENT, id, begin,
29429e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                                end, 0, 0);
2943146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
2944146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    break;
2945146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2946146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                default: {
2947146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    return false;
2948146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2949146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
2950146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return true;
2951146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2952146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
2953146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2954a505627659f6bfba8869eac8089f7030f2d0d92cErik    private static int getEventAccessLevel(Context context, Event e) {
2955146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ContentResolver cr = context.getContentResolver();
2956146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2957146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int visibility = Calendars.NO_ACCESS;
2958146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int relationship = Attendees.RELATIONSHIP_ORGANIZER;
2959146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2960146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Get the calendar id for this event
2961146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Cursor cursor = cr.query(ContentUris.withAppendedId(Events.CONTENT_URI, e.id),
2962146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                new String[] { Events.CALENDAR_ID },
2963146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                null /* selection */,
2964146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                null /* selectionArgs */,
2965146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                null /* sort */);
2966e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2967e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (cursor == null) {
2968a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_NONE;
2969146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2970e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2971e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (cursor.getCount() == 0) {
2972e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            cursor.close();
2973a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_NONE;
2974e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        }
2975e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
2976146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        cursor.moveToFirst();
2977146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long calId = cursor.getLong(0);
2978697bd6a8cec36cc75c72603674e57e4c6fe42dbfKen Shirriff        cursor.close();
2979146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
2980146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Uri uri = Calendars.CONTENT_URI;
2981146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String where = String.format(CALENDARS_WHERE, calId);
2982146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        cursor = cr.query(uri, CALENDARS_PROJECTION, where, null, null);
2983146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
29846d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        String calendarOwnerAccount = null;
2985146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (cursor != null) {
2986146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            cursor.moveToFirst();
2987146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            visibility = cursor.getInt(CALENDARS_INDEX_ACCESS_LEVEL);
29886d34cec523930368976bc8d358d0a6de1da3462cMichael Chan            calendarOwnerAccount = cursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
2989146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            cursor.close();
2990146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2991e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
29926d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        if (visibility < Calendars.CONTRIBUTOR_ACCESS) {
2993a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_NONE;
29946d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        }
2995146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
29966d34cec523930368976bc8d358d0a6de1da3462cMichael Chan        if (e.guestsCanModify) {
2997a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_EDIT;
2998a505627659f6bfba8869eac8089f7030f2d0d92cErik        }
2999a505627659f6bfba8869eac8089f7030f2d0d92cErik
3000a505627659f6bfba8869eac8089f7030f2d0d92cErik        if (!TextUtils.isEmpty(calendarOwnerAccount) &&
3001a505627659f6bfba8869eac8089f7030f2d0d92cErik                calendarOwnerAccount.equalsIgnoreCase(e.organizer)) {
3002a505627659f6bfba8869eac8089f7030f2d0d92cErik            return ACCESS_LEVEL_EDIT;
3003146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3004146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3005a505627659f6bfba8869eac8089f7030f2d0d92cErik        return ACCESS_LEVEL_DELETE;
3006146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3007146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3008146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
3009146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Sets mSelectionDay and mSelectionHour based on the (x,y) touch position.
3010146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * If the touch position is not within the displayed grid, then this
3011146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * method returns false.
3012146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
3013146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param x the x position of the touch
3014146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param y the y position of the touch
3015146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @return true if the touch position is valid
3016146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
3017146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private boolean setSelectionFromPosition(int x, int y) {
3018146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (x < mHoursWidth) {
3019146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return false;
3020146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3021146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3022146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int day = (x - mHoursWidth) / (mCellWidth + DAY_GAP);
3023146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (day >= mNumDays) {
3024146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            day = mNumDays - 1;
3025146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3026146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        day += mFirstJulianDay;
3027146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int hour;
3028146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (y < mFirstCell + mFirstHourOffset) {
3029146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionAllDay = true;
3030146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } else {
3031146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            hour = (y - mFirstCell - mFirstHourOffset) / (mCellHeight + HOUR_GAP);
3032146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            hour += mFirstHour;
3033146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionHour = hour;
3034146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectionAllDay = false;
3035146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3036146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectionDay = day;
3037146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        findSelectedEvent(x, y);
3038146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//        Log.i("Cal", "setSelectionFromPosition( " + x + ", " + y + " ) day: " + day
3039146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                + " hour: " + hour
3040146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                + " mFirstCell: " + mFirstCell + " mFirstHourOffset: " + mFirstHourOffset);
3041146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//        if (mSelectedEvent != null) {
3042146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            Log.i("Cal", "  num events: " + mSelectedEvents.size() + " event: " + mSelectedEvent.title);
3043146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            for (Event ev : mSelectedEvents) {
3044146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL
3045146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                        | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
3046ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan//                String timeRange = formatDateRange(mContext,
3047146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                        ev.startMillis, ev.endMillis, flags);
3048146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//
3049146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                Log.i("Cal", "  " + timeRange + " " + ev.title);
3050146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            }
3051146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//        }
3052146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return true;
3053146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3054146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3055146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void findSelectedEvent(int x, int y) {
3056146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int date = mSelectionDay;
3057146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int cellWidth = mCellWidth;
3058146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ArrayList<Event> events = mEvents;
3059146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int numEvents = events.size();
3060146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int left = mHoursWidth + (mSelectionDay - mFirstJulianDay) * (cellWidth + DAY_GAP);
3061146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int top = 0;
3062146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvent = null;
3063146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3064146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mSelectedEvents.clear();
3065146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectionAllDay) {
3066146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float yDistance;
3067146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float minYdistance = 10000.0f;  // any large number
3068146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event closestEvent = null;
3069146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float drawHeight = mAllDayHeight;
3070146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int yOffset = mBannerPlusMargin + ALLDAY_TOP_MARGIN;
3071146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int i = 0; i < numEvents; i++) {
3072146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event event = events.get(i);
3073146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (!event.allDay) {
3074146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    continue;
3075146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3076146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3077146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (event.startDay <= mSelectionDay && event.endDay >= mSelectionDay) {
3078146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float numRectangles = event.getMaxColumns();
3079146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float height = drawHeight / numRectangles;
3080146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (height > MAX_ALLDAY_EVENT_HEIGHT) {
3081146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        height = MAX_ALLDAY_EVENT_HEIGHT;
3082146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3083146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float eventTop = yOffset + height * event.getColumn();
3084146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    float eventBottom = eventTop + height;
3085146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    if (eventTop < y && eventBottom > y) {
3086146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // If the touch is inside the event rectangle, then
3087146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // add the event.
3088146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        mSelectedEvents.add(event);
3089146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        closestEvent = event;
3090146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        break;
3091146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    } else {
3092146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        // Find the closest event
3093146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (eventTop >= y) {
3094146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            yDistance = eventTop - y;
3095146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        } else {
3096146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            yDistance = y - eventBottom;
3097146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
3098146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        if (yDistance < minYdistance) {
3099146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            minYdistance = yDistance;
3100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                            closestEvent = event;
3101146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                        }
3102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
3103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3104146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3105146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = closestEvent;
3106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
3107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Adjust y for the scrollable bitmap
3110146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        y += mViewStartY - mFirstCell;
3111146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3112146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Use a region around (x,y) for the selection region
3113146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Rect region = mRect;
3114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.left = x - 10;
3115146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.right = x + 10;
3116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.top = y - 10;
3117146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        region.bottom = y + 10;
3118146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3119146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        EventGeometry geometry = mEventGeometry;
3120146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        for (int i = 0; i < numEvents; i++) {
3122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event event = events.get(i);
3123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Compute the event rectangle.
3124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (!geometry.computeEventRect(date, left, top, cellWidth, event)) {
3125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                continue;
3126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3128146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // If the event intersects the selection region, then add it to
3129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // mSelectedEvents.
3130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (geometry.eventIntersectsSelection(event, region)) {
3131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectedEvents.add(event);
3132146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3134146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If there are any events in the selected region, then assign the
3136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // closest one to mSelectedEvent.
3137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mSelectedEvents.size() > 0) {
3138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int len = mSelectedEvents.size();
3139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            Event closestEvent = null;
3140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            float minDist = mViewWidth + mViewHeight;  // some large distance
3141146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            for (int index = 0; index < len; index++) {
3142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Event ev = mSelectedEvents.get(index);
3143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                float dist = geometry.pointToEvent(x, y, ev);
3144146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (dist < minDist) {
3145146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    minDist = dist;
3146146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    closestEvent = ev;
3147146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSelectedEvent = closestEvent;
3150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Keep the selected hour and day consistent with the selected
3152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // event.  They could be different if we touched on an empty hour
3153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // slot very close to an event in the previous hour slot.  In
3154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // that case we will select the nearby event.
3155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startDay = mSelectedEvent.startDay;
3156146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endDay = mSelectedEvent.endDay;
3157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionDay < startDay) {
3158146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionDay = startDay;
3159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionDay > endDay) {
3160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionDay = endDay;
3161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int startHour = mSelectedEvent.startTime / 60;
3164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            int endHour;
3165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectedEvent.startTime < mSelectedEvent.endTime) {
3166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                endHour = (mSelectedEvent.endTime - 1) / 60;
3167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                endHour = mSelectedEvent.endTime / 60;
3169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSelectionHour < startHour) {
3172146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionHour = startHour;
3173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mSelectionHour > endHour) {
3174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSelectionHour = endHour;
3175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // Encapsulates the code to continue the scrolling after the
3180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // finger is lifted.  Instead of stopping the scroll immediately,
3181146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // the scroll continues to "free spin" and gradually slows down.
3182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private class ContinueScroll implements Runnable {
3183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int mSignDeltaY;
3184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        int mAbsDeltaY;
3185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        float mFloatDeltaY;
3186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long mFreeSpinTime;
3187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final float FRICTION_COEF = 0.7F;
3188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final long FREE_SPIN_MILLIS = 180;
3189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final int MAX_DELTA = 60;
3190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        private static final int SCROLL_REPEAT_INTERVAL = 30;
3191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void init(int deltaY) {
3193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mSignDeltaY = 0;
3194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (deltaY > 0) {
3195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSignDeltaY = 1;
3196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (deltaY < 0) {
3197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mSignDeltaY = -1;
3198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mAbsDeltaY = Math.abs(deltaY);
3200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Limit the maximum speed
3202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mAbsDeltaY > MAX_DELTA) {
3203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mAbsDeltaY = MAX_DELTA;
3204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFloatDeltaY = mAbsDeltaY;
3206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mFreeSpinTime = System.currentTimeMillis() + FREE_SPIN_MILLIS;
3207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            Log.i("Cal", "init scroll: mAbsDeltaY: " + mAbsDeltaY
3208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                    + " mViewStartY: " + mViewStartY);
3209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3210146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void run() {
3212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            long time = System.currentTimeMillis();
3213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Start out with a frictionless "free spin"
3215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (time > mFreeSpinTime) {
3216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // If the delta is small, then apply a fixed deceleration.
3217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Otherwise
3218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mAbsDeltaY <= 10) {
3219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mAbsDeltaY -= 2;
3220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                } else {
3221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mFloatDeltaY *= FRICTION_COEF;
3222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mAbsDeltaY = (int) mFloatDeltaY;
3223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                if (mAbsDeltaY < 0) {
3226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    mAbsDeltaY = 0;
3227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
3228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mSignDeltaY == 1) {
3231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY -= mAbsDeltaY;
3232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY += mAbsDeltaY;
3234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3235146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//            Log.i("Cal", "  scroll: mAbsDeltaY: " + mAbsDeltaY
3236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project//                    + " mViewStartY: " + mViewStartY);
3237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mViewStartY < 0) {
3239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = 0;
3240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mAbsDeltaY = 0;
3241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else if (mViewStartY > mMaxViewStartY) {
3242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mViewStartY = mMaxViewStartY;
3243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mAbsDeltaY = 0;
3244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3245146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3246146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            computeFirstHour();
3247146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mAbsDeltaY > 0) {
3249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                postDelayed(this, SCROLL_REPEAT_INTERVAL);
3250146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            } else {
3251146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                // Done scrolling.
3252146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mScrolling = false;
3253146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                resetSelectedHour();
3254146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3255146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            invalidate();
3257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
3261bd0e834aea317236d574f8738fe11a51fdc87968Erik     * Cleanup the pop-up and timers.
3262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
3263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void cleanup() {
3264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // Protect against null-pointer exceptions
3265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mPopup != null) {
3266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mPopup.dismiss();
3267146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3268666fc5e8ddbac15c951aad738bd818ee307eae42Erik        mLastPopupEventID = INVALID_EVENT_ID;
3269146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Handler handler = getHandler();
3270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (handler != null) {
3271146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            handler.removeCallbacks(mDismissPopup);
3272bd0e834aea317236d574f8738fe11a51fdc87968Erik            handler.removeCallbacks(mUpdateCurrentTime);
3273146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3274e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
32757abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project        // Turn off redraw
32767abd8566e5718c43d610e046495bcb412e87847fThe Android Open Source Project        mRemeasure = false;
3277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3279bd0e834aea317236d574f8738fe11a51fdc87968Erik    /**
3280bd0e834aea317236d574f8738fe11a51fdc87968Erik     * Restart the update timer
3281bd0e834aea317236d574f8738fe11a51fdc87968Erik     */
3282bd0e834aea317236d574f8738fe11a51fdc87968Erik    public void restartCurrentTimeUpdates() {
3283bd0e834aea317236d574f8738fe11a51fdc87968Erik        post(mUpdateCurrentTime);
3284bd0e834aea317236d574f8738fe11a51fdc87968Erik    }
3285bd0e834aea317236d574f8738fe11a51fdc87968Erik
3286146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override protected void onDetachedFromWindow() {
3287146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        cleanup();
3288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (mBitmap != null) {
3289146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mBitmap.recycle();
3290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            mBitmap = null;
3291146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3292146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        super.onDetachedFromWindow();
3293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3295146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    class DismissPopup implements Runnable {
3296146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void run() {
3297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // Protect against null-pointer exceptions
3298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (mPopup != null) {
3299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                mPopup.dismiss();
3300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
3301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3303bd0e834aea317236d574f8738fe11a51fdc87968Erik
3304bd0e834aea317236d574f8738fe11a51fdc87968Erik    class UpdateCurrentTime implements Runnable {
3305bd0e834aea317236d574f8738fe11a51fdc87968Erik        public void run() {
3306bd0e834aea317236d574f8738fe11a51fdc87968Erik            long currentTime = System.currentTimeMillis();
3307bd0e834aea317236d574f8738fe11a51fdc87968Erik            mCurrentTime.set(currentTime);
3308bd0e834aea317236d574f8738fe11a51fdc87968Erik            //% causes update to occur on 5 minute marks (11:10, 11:15, 11:20, etc.)
3309bd0e834aea317236d574f8738fe11a51fdc87968Erik            postDelayed(mUpdateCurrentTime,
3310bd0e834aea317236d574f8738fe11a51fdc87968Erik                    UPDATE_CURRENT_TIME_DELAY - (currentTime % UPDATE_CURRENT_TIME_DELAY));
3311bd0e834aea317236d574f8738fe11a51fdc87968Erik            mTodayJulianDay = Time.getJulianDay(currentTime, mCurrentTime.gmtoff);
3312bd0e834aea317236d574f8738fe11a51fdc87968Erik            invalidate();
3313bd0e834aea317236d574f8738fe11a51fdc87968Erik        }
3314bd0e834aea317236d574f8738fe11a51fdc87968Erik    }
3315ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3316ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener {
3317ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3318ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onSingleTapUp(MotionEvent ev) {
3319d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doSingleTapUp(ev);
3320ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3321ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3322ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3323ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3324ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public void onLongPress(MotionEvent ev) {
3325d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doLongPress(ev);
3326ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3327ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3328ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3329ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
3330d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doScroll(e1, e2, distanceX, distanceY);
3331ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3332ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3333ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3334ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3335ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
3336d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doFling(e1, e2, velocityX, velocityY);
3337ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3338ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3339ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan
3340ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        @Override
3341ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        public boolean onDown(MotionEvent ev) {
3342d190418220467c02327dd9b3ae1eae238889720bMichael Chan            DayView.this.doDown(ev);
3343ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan            return true;
3344ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan        }
3345ef1a51d6dda6dd8a013bf0937f10c6eb2041b888Michael Chan    }
3346146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project}
3347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3348