14970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan/*
24970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan * Copyright (C) 2010 The Android Open Source Project
34970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan *
44970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan * Licensed under the Apache License, Version 2.0 (the "License");
54970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan * you may not use this file except in compliance with the License.
64970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan * You may obtain a copy of the License at
74970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan *
84970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan *      http://www.apache.org/licenses/LICENSE-2.0
94970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan *
104970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan * Unless required by applicable law or agreed to in writing, software
114970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan * distributed under the License is distributed on an "AS IS" BASIS,
124970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan * See the License for the specific language governing permissions and
144970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan * limitations under the License.
154970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan */
164970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan
174970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chanpackage com.android.calendar;
184970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan
19a27a886892fe3ec5edbc63c0b58e0a988623011aRoboErikimport static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
20a27a886892fe3ec5edbc63c0b58e0a988623011aRoboErikimport static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
21edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chanimport static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
226bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelsonimport static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS;
239e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan
245f62079ab9daefe95ede87631766e99e8b4a2220Erikimport com.android.calendar.event.EditEventActivity;
252aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport com.android.calendar.selectcalendars.SelectVisibleCalendarsActivity;
265f62079ab9daefe95ede87631766e99e8b4a2220Erik
27ba1b94afd187279623a57417da1ef78efa1217e2Erikimport android.accounts.Account;
287dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFaddenimport android.accounts.AccountManager;
2983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chanimport android.app.Activity;
306d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawaimport android.app.SearchManager;
316d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawaimport android.app.SearchableInfo;
326d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawaimport android.content.ComponentName;
33ba1b94afd187279623a57417da1ef78efa1217e2Erikimport android.content.ContentResolver;
349e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chanimport android.content.ContentUris;
35ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chanimport android.content.Context;
369e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chanimport android.content.Intent;
37ba1b94afd187279623a57417da1ef78efa1217e2Erikimport android.database.Cursor;
389e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chanimport android.net.Uri;
397116ba44f2aa65a126bc6f0b600bc91bd9d8f170Erikimport android.os.AsyncTask;
40ba1b94afd187279623a57417da1ef78efa1217e2Erikimport android.os.Bundle;
416bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelsonimport android.provider.CalendarContract.Attendees;
42a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Calendars;
43a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Events;
44ba1b94afd187279623a57417da1ef78efa1217e2Erikimport android.text.TextUtils;
454970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chanimport android.text.format.Time;
4683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chanimport android.util.Log;
473864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErikimport android.util.Pair;
4883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
493f348f3ea8a7927566a1283b6d6bb5e220662889Erikimport java.util.Iterator;
503f348f3ea8a7927566a1283b6d6bb5e220662889Erikimport java.util.LinkedHashMap;
51ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chanimport java.util.LinkedList;
523f348f3ea8a7927566a1283b6d6bb5e220662889Erikimport java.util.Map.Entry;
5383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chanimport java.util.WeakHashMap;
5483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
5525251192d80159d4cf0934f3ac5c84cb0b8b7365Erikpublic class CalendarController {
56f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan    private static final boolean DEBUG = false;
5783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    private static final String TAG = "CalendarController";
58ba1b94afd187279623a57417da1ef78efa1217e2Erik    private static final String REFRESH_SELECTION = Calendars.SYNC_EVENTS + "=?";
59ba1b94afd187279623a57417da1ef78efa1217e2Erik    private static final String[] REFRESH_ARGS = new String[] { "1" };
600e1e62408b96e1532eb6f6a609ae4c817751aaf3RoboErik    private static final String REFRESH_ORDER = Calendars.ACCOUNT_NAME + ","
610e1e62408b96e1532eb6f6a609ae4c817751aaf3RoboErik            + Calendars.ACCOUNT_TYPE;
6283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
63a7694eead7cbb293990bc89c3906e17bad36194cErik    public static final String EVENT_EDIT_ON_LAUNCH = "editMode";
64a7694eead7cbb293990bc89c3906e17bad36194cErik
65981874e61ecf29a96a77601a3172b2503b6537eeErik    public static final int MIN_CALENDAR_YEAR = 1970;
66981874e61ecf29a96a77601a3172b2503b6537eeErik    public static final int MAX_CALENDAR_YEAR = 2036;
67981874e61ecf29a96a77601a3172b2503b6537eeErik    public static final int MIN_CALENDAR_WEEK = 0;
68981874e61ecf29a96a77601a3172b2503b6537eeErik    public static final int MAX_CALENDAR_WEEK = 3497; // weeks between 1/1/1970 and 1/1/2037
69981874e61ecf29a96a77601a3172b2503b6537eeErik
706bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson    private final Context mContext;
71ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan
723f348f3ea8a7927566a1283b6d6bb5e220662889Erik    // This uses a LinkedHashMap so that we can replace fragments based on the
733f348f3ea8a7927566a1283b6d6bb5e220662889Erik    // view id they are being expanded into since we can't guarantee a reference
743f348f3ea8a7927566a1283b6d6bb5e220662889Erik    // to the handler will be findable
756bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson    private final LinkedHashMap<Integer,EventHandler> eventHandlers =
763f348f3ea8a7927566a1283b6d6bb5e220662889Erik            new LinkedHashMap<Integer,EventHandler>(5);
776bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson    private final LinkedList<Integer> mToBeRemovedEventHandlers = new LinkedList<Integer>();
786bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson    private final LinkedHashMap<Integer, EventHandler> mToBeAddedEventHandlers = new LinkedHashMap<
79cb81189e4868769ea016253eca104e46df2f033aErik            Integer, EventHandler>();
803864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik    private Pair<Integer, EventHandler> mFirstEventHandler;
813864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik    private Pair<Integer, EventHandler> mToBeAddedFirstEventHandler;
82ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson    private volatile int mDispatchInProgressCounter = 0;
8383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
840558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan    private static WeakHashMap<Context, CalendarController> instances =
850558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan        new WeakHashMap<Context, CalendarController>();
860558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan
876bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson    private final WeakHashMap<Object, Long> filters = new WeakHashMap<Object, Long>(1);
884970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan
893458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan    private int mViewType = -1;
9085e550966b125220af5faa7407a0cfc0b54494aaMichael Chan    private int mDetailViewType = -1;
91ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan    private int mPreviousViewType = -1;
927b92da258a480284dcc15a518ea570072329a31dErik    private long mEventId = -1;
936bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson    private final Time mTime = new Time();
94c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik    private long mDateFlags = 0;
953458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan
966bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson    private final Runnable mUpdateTimezone = new Runnable() {
974679f6009e8d754e4d76c68a0c5a0a32b23f7f0cRoboErik        @Override
984679f6009e8d754e4d76c68a0c5a0a32b23f7f0cRoboErik        public void run() {
994679f6009e8d754e4d76c68a0c5a0a32b23f7f0cRoboErik            mTime.switchTimezone(Utils.getTimeZone(mContext, this));
1004679f6009e8d754e4d76c68a0c5a0a32b23f7f0cRoboErik        }
1014679f6009e8d754e4d76c68a0c5a0a32b23f7f0cRoboErik    };
1024679f6009e8d754e4d76c68a0c5a0a32b23f7f0cRoboErik
1034970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan    /**
10483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * One of the event types that are sent to or from the controller
1054970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan     */
10625251192d80159d4cf0934f3ac5c84cb0b8b7365Erik    public interface EventType {
1079e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        final long CREATE_EVENT = 1L;
108deced8999da73effe4133e2317c262fea7910090Michael Chan
109deced8999da73effe4133e2317c262fea7910090Michael Chan        // Simple view of an event
11083b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        final long VIEW_EVENT = 1L << 1;
111deced8999da73effe4133e2317c262fea7910090Michael Chan
112deced8999da73effe4133e2317c262fea7910090Michael Chan        // Full detail view in read only mode
113deced8999da73effe4133e2317c262fea7910090Michael Chan        final long VIEW_EVENT_DETAILS = 1L << 2;
114deced8999da73effe4133e2317c262fea7910090Michael Chan
115a7694eead7cbb293990bc89c3906e17bad36194cErik        // full detail view in edit mode
116deced8999da73effe4133e2317c262fea7910090Michael Chan        final long EDIT_EVENT = 1L << 3;
117deced8999da73effe4133e2317c262fea7910090Michael Chan
118deced8999da73effe4133e2317c262fea7910090Michael Chan        final long DELETE_EVENT = 1L << 4;
11983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
120deced8999da73effe4133e2317c262fea7910090Michael Chan        final long GO_TO = 1L << 5;
12183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
122deced8999da73effe4133e2317c262fea7910090Michael Chan        final long LAUNCH_SETTINGS = 1L << 6;
123954c871f4753d3182314d7027c0dd17c236d9ca7Erik
124deced8999da73effe4133e2317c262fea7910090Michael Chan        final long EVENTS_CHANGED = 1L << 7;
1254003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang
126deced8999da73effe4133e2317c262fea7910090Michael Chan        final long SEARCH = 1L << 8;
1277b92da258a480284dcc15a518ea570072329a31dErik
1287b92da258a480284dcc15a518ea570072329a31dErik        // User has pressed the home key
129deced8999da73effe4133e2317c262fea7910090Michael Chan        final long USER_HOME = 1L << 9;
130eaafa2b48be7194a61754604ae37b3d62e9118d8Erik
131eaafa2b48be7194a61754604ae37b3d62e9118d8Erik        // date range has changed, update the title
132eaafa2b48be7194a61754604ae37b3d62e9118d8Erik        final long UPDATE_TITLE = 1L << 10;
1332aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
1342aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        // select which calendars to display
1352aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        final long LAUNCH_SELECT_VISIBLE_CALENDARS = 1L << 11;
13683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
1374970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan
1384970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan    /**
13983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * One of the Agenda/Day/Week/Month view types
1404970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan     */
14125251192d80159d4cf0934f3ac5c84cb0b8b7365Erik    public interface ViewType {
142d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        final int DETAIL = -1;
1433458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        final int CURRENT = 0;
1443458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        final int AGENDA = 1;
1453458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        final int DAY = 2;
1463458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        final int WEEK = 3;
1473458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        final int MONTH = 4;
148dd95df57c8c5a58a85c4c0effad5652dec14f621Erik        final int EDIT = 5;
14983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
15083b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
15125251192d80159d4cf0934f3ac5c84cb0b8b7365Erik    public static class EventInfo {
1526bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson
1536bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        private static final long ATTENTEE_STATUS_MASK = 0xFF;
1546bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        private static final long ALL_DAY_MASK = 0x100;
1556bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        private static final int ATTENDEE_STATUS_NONE_MASK = 0x01;
1566bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        private static final int ATTENDEE_STATUS_ACCEPTED_MASK = 0x02;
1576bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        private static final int ATTENDEE_STATUS_DECLINED_MASK = 0x04;
1586bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        private static final int ATTENDEE_STATUS_TENTATIVE_MASK = 0x08;
1596bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson
16000b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tang        public long eventType; // one of the EventType
16100b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tang        public int viewType; // one of the ViewType
16200b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tang        public long id; // event id
16300b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tang        public Time selectedTime; // the selected time in focus
16400b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tang        public Time startTime; // start of a range of time.
16500b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tang        public Time endTime; // end of a range of time.
16600b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tang        public int x; // x coordinate in the activity space
16700b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tang        public int y; // y coordinate in the activity space
16800b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tang        public String query; // query for a user search
1696d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa        public ComponentName componentName;  // used in combination with query
17046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
17146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        /**
17246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan         * For EventType.VIEW_EVENT:
1736bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson         * It is the default attendee response and an all day event indicator.
1746bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson         * Set to Attendees.ATTENDEE_STATUS_NONE, Attendees.ATTENDEE_STATUS_ACCEPTED,
1756bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson         * Attendees.ATTENDEE_STATUS_DECLINED, or Attendees.ATTENDEE_STATUS_TENTATIVE.
1766bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson         * To signal the event is an all-day event, "or" ALL_DAY_MASK with the response.
1776bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson         * Alternatively, use buildViewExtraLong(), getResponse(), and isAllDay().
17846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan         * <p>
179edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan         * For EventType.CREATE_EVENT:
180edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan         * Set to {@link #EXTRA_CREATE_ALL_DAY} for creating an all-day event.
181edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan         * <p>
18246a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan         * For EventType.GO_TO:
18346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan         * Set to {@link #EXTRA_GOTO_TIME} to go to the specified date/time.
18446a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan         * Set to {@link #EXTRA_GOTO_DATE} to consider the date but ignore the time.
185fb0ec227f0d4b3108438c88a6b6d234f5e40fb5cMichael Chan         * Set to {@link #EXTRA_GOTO_BACK_TO_PREVIOUS} if back should bring back previous view.
1865b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik         * Set to {@link #EXTRA_GOTO_TODAY} if this is a user request to go to the current time.
187fb0ec227f0d4b3108438c88a6b6d234f5e40fb5cMichael Chan         * <p>
188fb0ec227f0d4b3108438c88a6b6d234f5e40fb5cMichael Chan         * For EventType.UPDATE_TITLE:
189fb0ec227f0d4b3108438c88a6b6d234f5e40fb5cMichael Chan         * Set formatting flags for Utils.formatDateRange
19046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan         */
19146a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        public long extraLong;
1926bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson
1936bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        public boolean isAllDay() {
1946bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            if (eventType != EventType.VIEW_EVENT) {
1956bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                Log.wtf(TAG, "illegal call to isAllDay , wrong event type " + eventType);
1966bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                return false;
1976bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            }
1986bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            return ((extraLong & ALL_DAY_MASK) != 0) ? true : false;
1996bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        }
2006bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson
2016bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        public  int getResponse() {
2026bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            if (eventType != EventType.VIEW_EVENT) {
2036bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                Log.wtf(TAG, "illegal call to getResponse , wrong event type " + eventType);
2046bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                return Attendees.ATTENDEE_STATUS_NONE;
2056bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            }
2066bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson
2076bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            int response = (int)(extraLong & ATTENTEE_STATUS_MASK);
2086bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            switch (response) {
2096bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                case ATTENDEE_STATUS_NONE_MASK:
2106bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    return Attendees.ATTENDEE_STATUS_NONE;
2116bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                case ATTENDEE_STATUS_ACCEPTED_MASK:
2126bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    return Attendees.ATTENDEE_STATUS_ACCEPTED;
2136bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                case ATTENDEE_STATUS_DECLINED_MASK:
2146bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    return Attendees.ATTENDEE_STATUS_DECLINED;
2156bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                case ATTENDEE_STATUS_TENTATIVE_MASK:
2166bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    return Attendees.ATTENDEE_STATUS_TENTATIVE;
2176bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                default:
2186bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    Log.wtf(TAG,"Unknown attendee response " + response);
2196bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            }
2206bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            return ATTENDEE_STATUS_NONE_MASK;
2216bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        }
2226bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson
2236bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        // Used to build the extra long for a VIEW event.
2246bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        public static long buildViewExtraLong(int response, boolean allDay) {
2256bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            long extra = allDay ? ALL_DAY_MASK : 0;
2266bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson
2276bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            switch (response) {
2286bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                case Attendees.ATTENDEE_STATUS_NONE:
2296bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    extra |= ATTENDEE_STATUS_NONE_MASK;
2306bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    break;
2316bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                case Attendees.ATTENDEE_STATUS_ACCEPTED:
2326bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    extra |= ATTENDEE_STATUS_ACCEPTED_MASK;
2336bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    break;
2346bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                case Attendees.ATTENDEE_STATUS_DECLINED:
2356bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    extra |= ATTENDEE_STATUS_DECLINED_MASK;
2366bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    break;
2376bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                case Attendees.ATTENDEE_STATUS_TENTATIVE:
2386bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    extra |= ATTENDEE_STATUS_TENTATIVE_MASK;
2396bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    break;
2406bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                default:
2416bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    Log.wtf(TAG,"Unknown attendee response " + response);
2426bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    extra |= ATTENDEE_STATUS_NONE_MASK;
2436bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                    break;
2446bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            }
2456bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson            return extra;
2466bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        }
24783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
24883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
24946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    /**
250edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan     * Pass to the ExtraLong parameter for EventType.CREATE_EVENT to create
251edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan     * an all-day event
252edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan     */
253edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan    public static final long EXTRA_CREATE_ALL_DAY = 0x10;
254edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan
255edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan    /**
25646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan     * Pass to the ExtraLong parameter for EventType.GO_TO to signal the time
25746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan     * can be ignored
25846a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan     */
25946a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan    public static final long EXTRA_GOTO_DATE = 1;
260fb0ec227f0d4b3108438c88a6b6d234f5e40fb5cMichael Chan    public static final long EXTRA_GOTO_TIME = 2;
261fb0ec227f0d4b3108438c88a6b6d234f5e40fb5cMichael Chan    public static final long EXTRA_GOTO_BACK_TO_PREVIOUS = 4;
2625b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik    public static final long EXTRA_GOTO_TODAY = 8;
26346a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan
26425251192d80159d4cf0934f3ac5c84cb0b8b7365Erik    public interface EventHandler {
26583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        long getSupportedEventTypes();
26683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        void handleEvent(EventInfo event);
26783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
26883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        /**
269954c871f4753d3182314d7027c0dd17c236d9ca7Erik         * This notifies the handler that the database has changed and it should
270954c871f4753d3182314d7027c0dd17c236d9ca7Erik         * update its view.
27183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan         */
27283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        void eventsChanged();
27383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
27483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
2750558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan    /**
2760558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan     * Creates and/or returns an instance of CalendarController associated with
2770558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan     * the supplied context. It is best to pass in the current Activity.
2780558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan     *
2790558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan     * @param context The activity if at all possible.
2800558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan     */
2810558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan    public static CalendarController getInstance(Context context) {
2820558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan        synchronized (instances) {
2830558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan            CalendarController controller = instances.get(context);
2840558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan            if (controller == null) {
2850558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan                controller = new CalendarController(context);
2860558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan                instances.put(context, controller);
2870558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan            }
2880558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan            return controller;
2890558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan        }
2900558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan    }
2910558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan
292ed61b48c048c5e8f6646f528561988fd25fe7416Erik    /**
293ed61b48c048c5e8f6646f528561988fd25fe7416Erik     * Removes an instance when it is no longer needed. This should be called in
294ed61b48c048c5e8f6646f528561988fd25fe7416Erik     * an activity's onDestroy method.
295ed61b48c048c5e8f6646f528561988fd25fe7416Erik     *
296ed61b48c048c5e8f6646f528561988fd25fe7416Erik     * @param context The activity used to create the controller
297ed61b48c048c5e8f6646f528561988fd25fe7416Erik     */
298ed61b48c048c5e8f6646f528561988fd25fe7416Erik    public static void removeInstance(Context context) {
299ed61b48c048c5e8f6646f528561988fd25fe7416Erik        instances.remove(context);
300ed61b48c048c5e8f6646f528561988fd25fe7416Erik    }
301ed61b48c048c5e8f6646f528561988fd25fe7416Erik
3020558defd2215696cee0768ce2bf2cb4da56efc42Michael Chan    private CalendarController(Context context) {
303ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        mContext = context;
3044679f6009e8d754e4d76c68a0c5a0a32b23f7f0cRoboErik        mUpdateTimezone.run();
3053458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        mTime.setToNow();
30685e550966b125220af5faa7407a0cfc0b54494aaMichael Chan        mDetailViewType = Utils.getSharedPreference(mContext,
3074b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa                GeneralPreferences.KEY_DETAILED_VIEW,
3084b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa                GeneralPreferences.DEFAULT_DETAILED_VIEW);
30983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
3104970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan
311deced8999da73effe4133e2317c262fea7910090Michael Chan    public void sendEventRelatedEvent(Object sender, long eventType, long eventId, long startMillis,
31287f993ff96172f508d3f241f8a425f953c7eb739RoboErik            long endMillis, int x, int y, long selectedMillis) {
3136bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        // TODO: pass the real allDay status or at least a status that says we don't know the
3146bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        // status and have the receiver query the data.
3156bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        // The current use of this method for VIEW_EVENT is by the day view to show an EventInfo
3166bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        // so currently the missing allDay status has no effect.
317edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan        sendEventRelatedEventWithExtra(sender, eventType, eventId, startMillis, endMillis, x, y,
3186bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                EventInfo.buildViewExtraLong(Attendees.ATTENDEE_STATUS_NONE, false),
3196bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                selectedMillis);
320deced8999da73effe4133e2317c262fea7910090Michael Chan    }
321deced8999da73effe4133e2317c262fea7910090Michael Chan
3224970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan    /**
32383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * Helper for sending New/View/Edit/Delete events
32483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     *
32583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * @param sender object of the caller
32683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * @param eventType one of {@link EventType}
32783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * @param eventId event id
3283458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan     * @param startMillis start time
3293458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan     * @param endMillis end time
33083b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * @param x x coordinate in the activity space
33183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * @param y y coordinate in the activity space
3326bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson     * @param extraLong default response value for the "simple event view" and all day indication.
3336bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson     *        Use Attendees.ATTENDEE_STATUS_NONE for no response.
33487f993ff96172f508d3f241f8a425f953c7eb739RoboErik     * @param selectedMillis The time to specify as selected
3354970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan     */
336edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan    public void sendEventRelatedEventWithExtra(Object sender, long eventType, long eventId,
33787f993ff96172f508d3f241f8a425f953c7eb739RoboErik            long startMillis, long endMillis, int x, int y, long extraLong, long selectedMillis) {
33883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        EventInfo info = new EventInfo();
33983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        info.eventType = eventType;
340a7694eead7cbb293990bc89c3906e17bad36194cErik        if (eventType == EventType.EDIT_EVENT || eventType == EventType.VIEW_EVENT_DETAILS) {
3415f62079ab9daefe95ede87631766e99e8b4a2220Erik            info.viewType = ViewType.CURRENT;
342dd95df57c8c5a58a85c4c0effad5652dec14f621Erik        }
34383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        info.id = eventId;
3444679f6009e8d754e4d76c68a0c5a0a32b23f7f0cRoboErik        info.startTime = new Time(Utils.getTimeZone(mContext, mUpdateTimezone));
3459e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        info.startTime.set(startMillis);
34687f993ff96172f508d3f241f8a425f953c7eb739RoboErik        if (selectedMillis != -1) {
3474679f6009e8d754e4d76c68a0c5a0a32b23f7f0cRoboErik            info.selectedTime = new Time(Utils.getTimeZone(mContext, mUpdateTimezone));
34887f993ff96172f508d3f241f8a425f953c7eb739RoboErik            info.selectedTime.set(selectedMillis);
34987f993ff96172f508d3f241f8a425f953c7eb739RoboErik        } else {
35087f993ff96172f508d3f241f8a425f953c7eb739RoboErik            info.selectedTime = info.startTime;
35187f993ff96172f508d3f241f8a425f953c7eb739RoboErik        }
3524679f6009e8d754e4d76c68a0c5a0a32b23f7f0cRoboErik        info.endTime = new Time(Utils.getTimeZone(mContext, mUpdateTimezone));
3539e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        info.endTime.set(endMillis);
35483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        info.x = x;
35583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        info.y = y;
356deced8999da73effe4133e2317c262fea7910090Michael Chan        info.extraLong = extraLong;
35783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        this.sendEvent(sender, info);
35883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
3594970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan
3604970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan    /**
36183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * Helper for sending non-calendar-event events
36283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     *
36383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * @param sender object of the caller
36483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * @param eventType one of {@link EventType}
36583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * @param start start time
36683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * @param end end time
367d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     * @param eventId event id
36883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan     * @param viewType {@link ViewType}
3694970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan     */
37025251192d80159d4cf0934f3ac5c84cb0b8b7365Erik    public void sendEvent(Object sender, long eventType, Time start, Time end, long eventId,
3713458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            int viewType) {
372f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        sendEvent(sender, eventType, start, end, start, eventId, viewType, EXTRA_GOTO_TIME, null,
373f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                null);
3746d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa    }
3756d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa
3766d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa    /**
37746a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan     * sendEvent() variant with extraLong, search query, and search component name.
3786d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa     */
3796d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa    public void sendEvent(Object sender, long eventType, Time start, Time end, long eventId,
38046a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan            int viewType, long extraLong, String query, ComponentName componentName) {
381f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        sendEvent(sender, eventType, start, end, start, eventId, viewType, extraLong, query,
382f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                componentName);
383f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan    }
384f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan
385f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan    public void sendEvent(Object sender, long eventType, Time start, Time end, Time selected,
386f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            long eventId, int viewType, long extraLong, String query, ComponentName componentName) {
38783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        EventInfo info = new EventInfo();
38883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        info.eventType = eventType;
38983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        info.startTime = start;
390f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        info.selectedTime = selected;
39183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        info.endTime = end;
39283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        info.id = eventId;
39383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        info.viewType = viewType;
3946d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa        info.query = query;
3956d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa        info.componentName = componentName;
39646a8b1117b0510a8dfd50586d5d22aa86b8dc1b9Michael Chan        info.extraLong = extraLong;
39783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        this.sendEvent(sender, info);
39883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
39983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
40025251192d80159d4cf0934f3ac5c84cb0b8b7365Erik    public void sendEvent(Object sender, final EventInfo event) {
40183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        // TODO Throw exception on invalid events
40283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
4033f348f3ea8a7927566a1283b6d6bb5e220662889Erik        if (DEBUG) {
4043f348f3ea8a7927566a1283b6d6bb5e220662889Erik            Log.d(TAG, eventInfoToString(event));
4053f348f3ea8a7927566a1283b6d6bb5e220662889Erik        }
40683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
40783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        Long filteredTypes = filters.get(sender);
40883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        if (filteredTypes != null && (filteredTypes.longValue() & event.eventType) != 0) {
40983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            // Suppress event per filter
4103f348f3ea8a7927566a1283b6d6bb5e220662889Erik            if (DEBUG) {
4113f348f3ea8a7927566a1283b6d6bb5e220662889Erik                Log.d(TAG, "Event suppressed");
4123f348f3ea8a7927566a1283b6d6bb5e220662889Erik            }
41383b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan            return;
41483b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        }
41583b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
416ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        mPreviousViewType = mViewType;
41783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
4183458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        // Fix up view if not specified
419d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        if (event.viewType == ViewType.DETAIL) {
42085e550966b125220af5faa7407a0cfc0b54494aaMichael Chan            event.viewType = mDetailViewType;
42185e550966b125220af5faa7407a0cfc0b54494aaMichael Chan            mViewType = mDetailViewType;
422d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        } else if (event.viewType == ViewType.CURRENT) {
4233458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            event.viewType = mViewType;
424f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        } else if (event.viewType != ViewType.EDIT) {
425ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan            mViewType = event.viewType;
42685e550966b125220af5faa7407a0cfc0b54494aaMichael Chan
42763cd053150e00fde045b019dbe0f48b8a9ed3559Erik            if (event.viewType == ViewType.AGENDA || event.viewType == ViewType.DAY
42863cd053150e00fde045b019dbe0f48b8a9ed3559Erik                    || (Utils.getAllowWeekForDetailView() && event.viewType == ViewType.WEEK)) {
42985e550966b125220af5faa7407a0cfc0b54494aaMichael Chan                mDetailViewType = mViewType;
43085e550966b125220af5faa7407a0cfc0b54494aaMichael Chan            }
4313458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        }
4323458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan
433f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        if (DEBUG) {
434f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            Log.e(TAG, "vvvvvvvvvvvvvvv");
435f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            Log.e(TAG, "Start  " + (event.startTime == null ? "null" : event.startTime.toString()));
436f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            Log.e(TAG, "End    " + (event.endTime == null ? "null" : event.endTime.toString()));
437f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            Log.e(TAG, "Select " + (event.selectedTime == null ? "null" : event.selectedTime.toString()));
438f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            Log.e(TAG, "mTime  " + (mTime == null ? "null" : mTime.toString()));
439f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        }
440f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan
441f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        long startMillis = 0;
442f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        if (event.startTime != null) {
443f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            startMillis = event.startTime.toMillis(false);
444f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        }
445f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan
446f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        // Set mTime if selectedTime is set
447f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        if (event.selectedTime != null && event.selectedTime.toMillis(false) != 0) {
448f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            mTime.set(event.selectedTime);
449f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        } else {
450f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            if (startMillis != 0) {
451f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                // selectedTime is not set so set mTime to startTime iff it is not
452f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                // within start and end times
453f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                long mtimeMillis = mTime.toMillis(false);
454f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                if (mtimeMillis < startMillis
455f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                        || (event.endTime != null && mtimeMillis > event.endTime.toMillis(false))) {
456f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                    mTime.set(event.startTime);
457f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                }
458f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            }
459f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            event.selectedTime = mTime;
460f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        }
461c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik        // Store the formatting flags if this is an update to the title
462c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik        if (event.eventType == EventType.UPDATE_TITLE) {
463c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik            mDateFlags = event.extraLong;
464c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik        }
465f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan
4664003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        // Fix up start time if not specified
467f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        if (startMillis == 0) {
468f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            event.startTime = mTime;
469f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        }
470f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan        if (DEBUG) {
471f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            Log.e(TAG, "Start  " + (event.startTime == null ? "null" : event.startTime.toString()));
472f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            Log.e(TAG, "End    " + (event.endTime == null ? "null" : event.endTime.toString()));
473f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            Log.e(TAG, "Select " + (event.selectedTime == null ? "null" : event.selectedTime.toString()));
474f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            Log.e(TAG, "mTime  " + (mTime == null ? "null" : mTime.toString()));
475f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan            Log.e(TAG, "^^^^^^^^^^^^^^^");
4764003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        }
4774003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang
4787b92da258a480284dcc15a518ea570072329a31dErik        // Store the eventId if we're entering edit event
479a7694eead7cbb293990bc89c3906e17bad36194cErik        if ((event.eventType
480a7694eead7cbb293990bc89c3906e17bad36194cErik                & (EventType.CREATE_EVENT | EventType.EDIT_EVENT | EventType.VIEW_EVENT_DETAILS))
481a7694eead7cbb293990bc89c3906e17bad36194cErik                != 0) {
4827b92da258a480284dcc15a518ea570072329a31dErik            if (event.id > 0) {
4837b92da258a480284dcc15a518ea570072329a31dErik                mEventId = event.id;
4847b92da258a480284dcc15a518ea570072329a31dErik            } else {
4857b92da258a480284dcc15a518ea570072329a31dErik                mEventId = -1;
4867b92da258a480284dcc15a518ea570072329a31dErik            }
4877b92da258a480284dcc15a518ea570072329a31dErik        }
4887b92da258a480284dcc15a518ea570072329a31dErik
4894003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        boolean handled = false;
490ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        synchronized (this) {
491ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            mDispatchInProgressCounter ++;
492ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan
4933f348f3ea8a7927566a1283b6d6bb5e220662889Erik            if (DEBUG) {
4943f348f3ea8a7927566a1283b6d6bb5e220662889Erik                Log.d(TAG, "sendEvent: Dispatching to " + eventHandlers.size() + " handlers");
4953f348f3ea8a7927566a1283b6d6bb5e220662889Erik            }
496ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan            // Dispatch to event handler(s)
4973864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik            if (mFirstEventHandler != null) {
4983864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                // Handle the 'first' one before handling the others
4993864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                EventHandler handler = mFirstEventHandler.second;
5003864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                if (handler != null && (handler.getSupportedEventTypes() & event.eventType) != 0
5013864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                        && !mToBeRemovedEventHandlers.contains(mFirstEventHandler.first)) {
5023864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                    handler.handleEvent(event);
5033864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                    handled = true;
5043864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                }
5053864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik            }
5063f348f3ea8a7927566a1283b6d6bb5e220662889Erik            for (Iterator<Entry<Integer, EventHandler>> handlers =
5073f348f3ea8a7927566a1283b6d6bb5e220662889Erik                    eventHandlers.entrySet().iterator(); handlers.hasNext();) {
5083f348f3ea8a7927566a1283b6d6bb5e220662889Erik                Entry<Integer, EventHandler> entry = handlers.next();
5093f348f3ea8a7927566a1283b6d6bb5e220662889Erik                int key = entry.getKey();
5103864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                if (mFirstEventHandler != null && key == mFirstEventHandler.first) {
5113864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                    // If this was the 'first' handler it was already handled
5123864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                    continue;
5133864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                }
5143f348f3ea8a7927566a1283b6d6bb5e220662889Erik                EventHandler eventHandler = entry.getValue();
515ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan                if (eventHandler != null
516ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan                        && (eventHandler.getSupportedEventTypes() & event.eventType) != 0) {
5173f348f3ea8a7927566a1283b6d6bb5e220662889Erik                    if (mToBeRemovedEventHandlers.contains(key)) {
518ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan                        continue;
519ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan                    }
520ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan                    eventHandler.handleEvent(event);
5214003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang                    handled = true;
522ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan                }
523ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan            }
5243458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan
525ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            mDispatchInProgressCounter --;
526cb81189e4868769ea016253eca104e46df2f033aErik
527ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            if (mDispatchInProgressCounter == 0) {
528ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson
529ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                // Deregister removed handlers
530ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                if (mToBeRemovedEventHandlers.size() > 0) {
531ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                    for (Integer zombie : mToBeRemovedEventHandlers) {
532ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                        eventHandlers.remove(zombie);
5333864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                        if (mFirstEventHandler != null && zombie.equals(mFirstEventHandler.first)) {
5343864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                            mFirstEventHandler = null;
5353864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                        }
536ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                    }
537ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                    mToBeRemovedEventHandlers.clear();
53883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan                }
539ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                // Add new handlers
5403864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                if (mToBeAddedFirstEventHandler != null) {
5413864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                    mFirstEventHandler = mToBeAddedFirstEventHandler;
5423864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                    mToBeAddedFirstEventHandler = null;
5433864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                }
544ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                if (mToBeAddedEventHandlers.size() > 0) {
545ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                    for (Entry<Integer, EventHandler> food : mToBeAddedEventHandlers.entrySet()) {
546ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                        eventHandlers.put(food.getKey(), food.getValue());
547ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                    }
548cb81189e4868769ea016253eca104e46df2f033aErik                }
549cb81189e4868769ea016253eca104e46df2f033aErik            }
55083b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        }
5514003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang
5524003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        if (!handled) {
5536b858fc6f8afad95a075595016c5c22547924886Erik            // Launch Settings
5546b858fc6f8afad95a075595016c5c22547924886Erik            if (event.eventType == EventType.LAUNCH_SETTINGS) {
5554003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang                launchSettings();
5564003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang                return;
5574003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            }
5584003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang
5592aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            // Launch Calendar Visible Selector
5602aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            if (event.eventType == EventType.LAUNCH_SELECT_VISIBLE_CALENDARS) {
5612aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                launchSelectVisibleCalendars();
5622aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                return;
5632aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            }
5642aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
5654003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            // Create/View/Edit/Delete Event
5664003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            long endTime = (event.endTime == null) ? -1 : event.endTime.toMillis(false);
5674003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            if (event.eventType == EventType.CREATE_EVENT) {
568edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan                launchCreateEvent(event.startTime.toMillis(false), endTime,
569edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan                        event.extraLong == EXTRA_CREATE_ALL_DAY);
5704003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang                return;
5714003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            } else if (event.eventType == EventType.VIEW_EVENT) {
5726bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                launchViewEvent(event.id, event.startTime.toMillis(false), endTime,
5736bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                        event.getResponse());
5744003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang                return;
5754003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            } else if (event.eventType == EventType.EDIT_EVENT) {
576a7694eead7cbb293990bc89c3906e17bad36194cErik                launchEditEvent(event.id, event.startTime.toMillis(false), endTime, true);
577a7694eead7cbb293990bc89c3906e17bad36194cErik                return;
578a7694eead7cbb293990bc89c3906e17bad36194cErik            } else if (event.eventType == EventType.VIEW_EVENT_DETAILS) {
579a7694eead7cbb293990bc89c3906e17bad36194cErik                launchEditEvent(event.id, event.startTime.toMillis(false), endTime, false);
5804003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang                return;
5814003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            } else if (event.eventType == EventType.DELETE_EVENT) {
5824003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang                launchDeleteEvent(event.id, event.startTime.toMillis(false), endTime);
5834003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang                return;
5846d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa            } else if (event.eventType == EventType.SEARCH) {
5856d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa                launchSearch(event.id, event.query, event.componentName);
5866d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa                return;
5874003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            }
5884003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        }
58983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
59083b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
5913f348f3ea8a7927566a1283b6d6bb5e220662889Erik    /**
5923f348f3ea8a7927566a1283b6d6bb5e220662889Erik     * Adds or updates an event handler. This uses a LinkedHashMap so that we can
5933f348f3ea8a7927566a1283b6d6bb5e220662889Erik     * replace fragments based on the view id they are being expanded into.
5943f348f3ea8a7927566a1283b6d6bb5e220662889Erik     *
5953f348f3ea8a7927566a1283b6d6bb5e220662889Erik     * @param key The view id or placeholder for this handler
5963f348f3ea8a7927566a1283b6d6bb5e220662889Erik     * @param eventHandler Typically a fragment or activity in the calendar app
5973f348f3ea8a7927566a1283b6d6bb5e220662889Erik     */
5983f348f3ea8a7927566a1283b6d6bb5e220662889Erik    public void registerEventHandler(int key, EventHandler eventHandler) {
599ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        synchronized (this) {
600ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            if (mDispatchInProgressCounter > 0) {
601cb81189e4868769ea016253eca104e46df2f033aErik                mToBeAddedEventHandlers.put(key, eventHandler);
602cb81189e4868769ea016253eca104e46df2f033aErik            } else {
603cb81189e4868769ea016253eca104e46df2f033aErik                eventHandlers.put(key, eventHandler);
604cb81189e4868769ea016253eca104e46df2f033aErik            }
605ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        }
60683b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
60783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
6083864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik    public void registerFirstEventHandler(int key, EventHandler eventHandler) {
6093864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik        synchronized (this) {
6103864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik            registerEventHandler(key, eventHandler);
6113864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik            if (mDispatchInProgressCounter > 0) {
6123864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                mToBeAddedFirstEventHandler = new Pair<Integer, EventHandler>(key, eventHandler);
6133864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik            } else {
6143864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                mFirstEventHandler = new Pair<Integer, EventHandler>(key, eventHandler);
6153864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik            }
6163864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik        }
6173864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik    }
6183864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik
6193f348f3ea8a7927566a1283b6d6bb5e220662889Erik    public void deregisterEventHandler(Integer key) {
620ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        synchronized (this) {
621ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            if (mDispatchInProgressCounter > 0) {
622ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan                // To avoid ConcurrencyException, stash away the event handler for now.
6233f348f3ea8a7927566a1283b6d6bb5e220662889Erik                mToBeRemovedEventHandlers.add(key);
624ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan            } else {
6253f348f3ea8a7927566a1283b6d6bb5e220662889Erik                eventHandlers.remove(key);
6263864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                if (mFirstEventHandler != null && mFirstEventHandler.first == key) {
6273864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                    mFirstEventHandler = null;
6283864be025ed7fa5bcb33c7adaae9267d5b34f17fRoboErik                }
629ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan            }
630ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        }
63183b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
63283b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
63361310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook    public void deregisterAllEventHandlers() {
63461310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook        synchronized (this) {
63561310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook            if (mDispatchInProgressCounter > 0) {
63661310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook                // To avoid ConcurrencyException, stash away the event handler for now.
63761310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook                mToBeRemovedEventHandlers.addAll(eventHandlers.keySet());
63861310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook            } else {
63961310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook                eventHandlers.clear();
64061310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook                mFirstEventHandler = null;
64161310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook            }
64261310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook        }
64361310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook    }
64461310b7263c6d6477f252789f6288991d51ec8ccPaul Westbrook
6453458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan    // FRAG_TODO doesn't work yet
64625251192d80159d4cf0934f3ac5c84cb0b8b7365Erik    public void filterBroadcasts(Object sender, long eventTypes) {
64783b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan        filters.put(sender, eventTypes);
64883b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan    }
64983b0fe36b523192a504a1d2baf2f36676a80b9d5Michael Chan
6508e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang    /**
6518e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang     * @return the time that this controller is currently pointed at
6528e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang     */
6538e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang    public long getTime() {
6548e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang        return mTime.toMillis(false);
6558e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang    }
6568e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang
6577b92da258a480284dcc15a518ea570072329a31dErik    /**
658c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik     * @return the last set of date flags sent with
659c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik     *         {@link EventType#UPDATE_TITLE}
660c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik     */
661c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik    public long getDateFlags() {
662c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik        return mDateFlags;
663c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik    }
664c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik
665c8e0f21af5e2508d6e53a59e0f997dffd6a5321cRoboErik    /**
666144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik     * Set the time this controller is currently pointed at
667144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik     *
668144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik     * @param millisTime Time since epoch in millis
669144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik     */
670144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik    public void setTime(long millisTime) {
671144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik        mTime.set(millisTime);
672144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik    }
673144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik
674144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik    /**
6757b92da258a480284dcc15a518ea570072329a31dErik     * @return the last event ID the edit view was launched with
6767b92da258a480284dcc15a518ea570072329a31dErik     */
6777b92da258a480284dcc15a518ea570072329a31dErik    public long getEventId() {
6787b92da258a480284dcc15a518ea570072329a31dErik        return mEventId;
6797b92da258a480284dcc15a518ea570072329a31dErik    }
6807b92da258a480284dcc15a518ea570072329a31dErik
681ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan    public int getViewType() {
682ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        return mViewType;
683ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan    }
684ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan
685ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan    public int getPreviousViewType() {
686ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        return mPreviousViewType;
687ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan    }
6888e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang
6892aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private void launchSelectVisibleCalendars() {
6902aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        Intent intent = new Intent(Intent.ACTION_VIEW);
69107d9fee87bc02849c0dd7b66326a320d53cf5479Michael Chan        intent.setClass(mContext, SelectVisibleCalendarsActivity.class);
6922aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
6932aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mContext.startActivity(intent);
6942aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
6952aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
6969e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan    private void launchSettings() {
6979e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        Intent intent = new Intent(Intent.ACTION_VIEW);
69807d9fee87bc02849c0dd7b66326a320d53cf5479Michael Chan        intent.setClass(mContext, CalendarSettingsActivity.class);
6999e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
700ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        mContext.startActivity(intent);
7019e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan    }
7029e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan
703edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan    private void launchCreateEvent(long startMillis, long endMillis, boolean allDayEvent) {
7049e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        Intent intent = new Intent(Intent.ACTION_VIEW);
70507d9fee87bc02849c0dd7b66326a320d53cf5479Michael Chan        intent.setClass(mContext, EditEventActivity.class);
706a27a886892fe3ec5edbc63c0b58e0a988623011aRoboErik        intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis);
707a27a886892fe3ec5edbc63c0b58e0a988623011aRoboErik        intent.putExtra(EXTRA_EVENT_END_TIME, endMillis);
708edecd9a97e02ff14bd5abeec3414e1bf3cc631dfMichael Chan        intent.putExtra(EXTRA_EVENT_ALL_DAY, allDayEvent);
7097b92da258a480284dcc15a518ea570072329a31dErik        mEventId = -1;
710ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        mContext.startActivity(intent);
7119e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan    }
7129e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan
7136bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson    public void launchViewEvent(long eventId, long startMillis, long endMillis, int response) {
7149e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        Intent intent = new Intent(Intent.ACTION_VIEW);
7159e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
7169e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        intent.setData(eventUri);
71707d9fee87bc02849c0dd7b66326a320d53cf5479Michael Chan        intent.setClass(mContext, AllInOneActivity.class);
718a27a886892fe3ec5edbc63c0b58e0a988623011aRoboErik        intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis);
719a27a886892fe3ec5edbc63c0b58e0a988623011aRoboErik        intent.putExtra(EXTRA_EVENT_END_TIME, endMillis);
7206bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson        intent.putExtra(ATTENDEE_STATUS, response);
7214024dee06fbe7c4bbd5b56e7d58917e86b66802eIsaac Katzenelson        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
722ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        mContext.startActivity(intent);
7239e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan    }
7249e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan
725a7694eead7cbb293990bc89c3906e17bad36194cErik    private void launchEditEvent(long eventId, long startMillis, long endMillis, boolean edit) {
7269e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
7279e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        Intent intent = new Intent(Intent.ACTION_EDIT, uri);
728a27a886892fe3ec5edbc63c0b58e0a988623011aRoboErik        intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis);
729a27a886892fe3ec5edbc63c0b58e0a988623011aRoboErik        intent.putExtra(EXTRA_EVENT_END_TIME, endMillis);
730ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        intent.setClass(mContext, EditEventActivity.class);
731a7694eead7cbb293990bc89c3906e17bad36194cErik        intent.putExtra(EVENT_EDIT_ON_LAUNCH, edit);
7327b92da258a480284dcc15a518ea570072329a31dErik        mEventId = eventId;
733ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        mContext.startActivity(intent);
7349e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan    }
7359e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan
7361881a896a82c425845e3ef2a1a716d329f0e45f1Michael Chan//    private void launchAlerts() {
7371881a896a82c425845e3ef2a1a716d329f0e45f1Michael Chan//        Intent intent = new Intent();
7381881a896a82c425845e3ef2a1a716d329f0e45f1Michael Chan//        intent.setClass(mContext, AlertActivity.class);
7391881a896a82c425845e3ef2a1a716d329f0e45f1Michael Chan//        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
7401881a896a82c425845e3ef2a1a716d329f0e45f1Michael Chan//        mContext.startActivity(intent);
7411881a896a82c425845e3ef2a1a716d329f0e45f1Michael Chan//    }
7421881a896a82c425845e3ef2a1a716d329f0e45f1Michael Chan
7439e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan    private void launchDeleteEvent(long eventId, long startMillis, long endMillis) {
7449e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        launchDeleteEventAndFinish(null, eventId, startMillis, endMillis, -1);
7459e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan    }
7469e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan
7479e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan    private void launchDeleteEventAndFinish(Activity parentActivity, long eventId, long startMillis,
7489e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan            long endMillis, int deleteWhich) {
749ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        DeleteEventHelper deleteEventHelper = new DeleteEventHelper(mContext, parentActivity,
7509e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan                parentActivity != null /* exit when done */);
7519e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan        deleteEventHelper.delete(startMillis, endMillis, eventId, deleteWhich);
7529e89dca0902d13fe27fd2680cc15cbb470e40288Michael Chan    }
7533458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan
7546d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa    private void launchSearch(long eventId, String query, ComponentName componentName) {
7556d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa        final SearchManager searchManager =
7566d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa                (SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE);
7576d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa        final SearchableInfo searchableInfo = searchManager.getSearchableInfo(componentName);
7586d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa        final Intent intent = new Intent(Intent.ACTION_SEARCH);
7596d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa        intent.putExtra(SearchManager.QUERY, query);
7606d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa        intent.setComponent(searchableInfo.getSearchActivity());
7612bd5cc06a7a89a848688416456f1b8f915542d57RoboErik        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
7626d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa        mContext.startActivity(intent);
7636d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa    }
7646d2e6f78726cc167e561148a3efb27aa15524b82Daisuke Miyakawa
7657dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden    /**
7667dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden     * Performs a manual refresh of calendars in all known accounts.
7677dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden     */
768ba1b94afd187279623a57417da1ef78efa1217e2Erik    public void refreshCalendars() {
7697dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden        Account[] accounts = AccountManager.get(mContext).getAccounts();
7707dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden        Log.d(TAG, "Refreshing " + accounts.length + " accounts");
7717dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden
7727dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden        String authority = Calendars.CONTENT_URI.getAuthority();
7737dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden        for (int i = 0; i < accounts.length; i++) {
7747dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden            if (Log.isLoggable(TAG, Log.DEBUG)) {
7757dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden                Log.d(TAG, "Refreshing calendars for: " + accounts[i]);
7767dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden            }
7777dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden            Bundle extras = new Bundle();
7787dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden            extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
7797dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden            ContentResolver.requestSync(accounts[i], authority, extras);
7807dcd301cab15959d0d745f0a460f1dce2065d44eAndy McFadden        }
781ba1b94afd187279623a57417da1ef78efa1217e2Erik    }
782ba1b94afd187279623a57417da1ef78efa1217e2Erik
783dd95df57c8c5a58a85c4c0effad5652dec14f621Erik    // Forces the viewType. Should only be used for initialization.
784dd95df57c8c5a58a85c4c0effad5652dec14f621Erik    public void setViewType(int viewType) {
785dd95df57c8c5a58a85c4c0effad5652dec14f621Erik        mViewType = viewType;
786dd95df57c8c5a58a85c4c0effad5652dec14f621Erik    }
787dd95df57c8c5a58a85c4c0effad5652dec14f621Erik
7887b92da258a480284dcc15a518ea570072329a31dErik    // Sets the eventId. Should only be used for initialization.
7897b92da258a480284dcc15a518ea570072329a31dErik    public void setEventId(long eventId) {
7907b92da258a480284dcc15a518ea570072329a31dErik        mEventId = eventId;
7917b92da258a480284dcc15a518ea570072329a31dErik    }
7927b92da258a480284dcc15a518ea570072329a31dErik
7933458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan    private String eventInfoToString(EventInfo eventInfo) {
7943458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        String tmp = "Unknown";
7953458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan
7963458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        StringBuilder builder = new StringBuilder();
797ab29d9ea9a4fe6b835c7f484a2273e92e8bc323dMichael Chan        if ((eventInfo.eventType & EventType.GO_TO) != 0) {
7983458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            tmp = "Go to time/event";
7993458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        } else if ((eventInfo.eventType & EventType.CREATE_EVENT) != 0) {
8003458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            tmp = "New event";
8013458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        } else if ((eventInfo.eventType & EventType.VIEW_EVENT) != 0) {
8023458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            tmp = "View event";
8036d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        } else if ((eventInfo.eventType & EventType.VIEW_EVENT_DETAILS) != 0) {
8046d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            tmp = "View details";
8053458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        } else if ((eventInfo.eventType & EventType.EDIT_EVENT) != 0) {
8063458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            tmp = "Edit event";
8073458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        } else if ((eventInfo.eventType & EventType.DELETE_EVENT) != 0) {
8083458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            tmp = "Delete event";
8092aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        } else if ((eventInfo.eventType & EventType.LAUNCH_SELECT_VISIBLE_CALENDARS) != 0) {
8102aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            tmp = "Launch select visible calendars";
8113458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        } else if ((eventInfo.eventType & EventType.LAUNCH_SETTINGS) != 0) {
8123458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan            tmp = "Launch settings";
8133f348f3ea8a7927566a1283b6d6bb5e220662889Erik        } else if ((eventInfo.eventType & EventType.EVENTS_CHANGED) != 0) {
8143f348f3ea8a7927566a1283b6d6bb5e220662889Erik            tmp = "Refresh events";
8154003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        } else if ((eventInfo.eventType & EventType.SEARCH) != 0) {
8164003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            tmp = "Search";
8176d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        } else if ((eventInfo.eventType & EventType.USER_HOME) != 0) {
8186d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            tmp = "Gone home";
8196d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan        } else if ((eventInfo.eventType & EventType.UPDATE_TITLE) != 0) {
8206d4ce6ed308da8b4d8f2e62660865e396713c025Michael Chan            tmp = "Update title";
8213458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        }
8223458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(tmp);
8233458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(": id=");
8243458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(eventInfo.id);
825d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        builder.append(", selected=");
826d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        builder.append(eventInfo.selectedTime);
827d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        builder.append(", start=");
8283458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(eventInfo.startTime);
829d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        builder.append(", end=");
8303458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(eventInfo.endTime);
8313458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(", viewType=");
8323458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(eventInfo.viewType);
8333458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(", x=");
8343458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(eventInfo.x);
8353458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(", y=");
8363458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        builder.append(eventInfo.y);
8373458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan        return builder.toString();
8383458a1775920dda53099b7f1913cd4ec4c8b4095Michael Chan    }
8394970159b2e6674fc5d61425aa0fcff8e5fc15bdbMichael Chan}
840