MonthWeekEventsView.java revision da532a723613001f1175c067aece5f859d079bfc
182b318634af1b6594e60cfd1f2df4d3845f80587Erik/*
282b318634af1b6594e60cfd1f2df4d3845f80587Erik * Copyright (C) 2010 The Android Open Source Project
382b318634af1b6594e60cfd1f2df4d3845f80587Erik *
482b318634af1b6594e60cfd1f2df4d3845f80587Erik * Licensed under the Apache License, Version 2.0 (the "License");
582b318634af1b6594e60cfd1f2df4d3845f80587Erik * you may not use this file except in compliance with the License.
682b318634af1b6594e60cfd1f2df4d3845f80587Erik * You may obtain a copy of the License at
782b318634af1b6594e60cfd1f2df4d3845f80587Erik *
882b318634af1b6594e60cfd1f2df4d3845f80587Erik *      http://www.apache.org/licenses/LICENSE-2.0
982b318634af1b6594e60cfd1f2df4d3845f80587Erik *
1082b318634af1b6594e60cfd1f2df4d3845f80587Erik * Unless required by applicable law or agreed to in writing, software
1182b318634af1b6594e60cfd1f2df4d3845f80587Erik * distributed under the License is distributed on an "AS IS" BASIS,
1282b318634af1b6594e60cfd1f2df4d3845f80587Erik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1382b318634af1b6594e60cfd1f2df4d3845f80587Erik * See the License for the specific language governing permissions and
1482b318634af1b6594e60cfd1f2df4d3845f80587Erik * limitations under the License.
1582b318634af1b6594e60cfd1f2df4d3845f80587Erik */
1682b318634af1b6594e60cfd1f2df4d3845f80587Erik
1782b318634af1b6594e60cfd1f2df4d3845f80587Erikpackage com.android.calendar.month;
1882b318634af1b6594e60cfd1f2df4d3845f80587Erik
193553621c824afe1f3eacbe8555678005ca1264a1Erikimport com.android.calendar.Event;
203553621c824afe1f3eacbe8555678005ca1264a1Erikimport com.android.calendar.R;
2140bcd101b212c9863c3110c05a487a7ae6ebc3caErikimport com.android.calendar.Utils;
22f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErik
23f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErikimport android.app.Service;
2482b318634af1b6594e60cfd1f2df4d3845f80587Erikimport android.content.Context;
253553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.content.res.Configuration;
263553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.content.res.Resources;
273553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.graphics.Canvas;
28092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErikimport android.graphics.Color;
293553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.graphics.Paint;
303553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.graphics.Paint.Align;
313553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.graphics.Paint.Style;
3240bcd101b212c9863c3110c05a487a7ae6ebc3caErikimport android.graphics.Typeface;
3340bcd101b212c9863c3110c05a487a7ae6ebc3caErikimport android.graphics.drawable.Drawable;
34a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErikimport android.provider.CalendarContract.Attendees;
3540bcd101b212c9863c3110c05a487a7ae6ebc3caErikimport android.text.TextPaint;
3640bcd101b212c9863c3110c05a487a7ae6ebc3caErikimport android.text.TextUtils;
3767f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErikimport android.text.format.DateFormat;
3840bcd101b212c9863c3110c05a487a7ae6ebc3caErikimport android.text.format.DateUtils;
393553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.text.format.Time;
403553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.util.Log;
4167f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErikimport android.view.MotionEvent;
4267f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErikimport android.view.accessibility.AccessibilityEvent;
43f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErikimport android.view.accessibility.AccessibilityManager;
443553621c824afe1f3eacbe8555678005ca1264a1Erik
453553621c824afe1f3eacbe8555678005ca1264a1Erikimport java.util.ArrayList;
46f445411ff661014c4b5a37e2f97552989e9278ecRoboErikimport java.util.Arrays;
4740bcd101b212c9863c3110c05a487a7ae6ebc3caErikimport java.util.Formatter;
483553621c824afe1f3eacbe8555678005ca1264a1Erikimport java.util.HashMap;
4940bcd101b212c9863c3110c05a487a7ae6ebc3caErikimport java.util.Iterator;
5040bcd101b212c9863c3110c05a487a7ae6ebc3caErikimport java.util.List;
5140bcd101b212c9863c3110c05a487a7ae6ebc3caErikimport java.util.Locale;
5282b318634af1b6594e60cfd1f2df4d3845f80587Erik
53e21674aefc9755ba519dfc5b3ff4348be4814903Erikpublic class MonthWeekEventsView extends SimpleWeekView {
54092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik
553553621c824afe1f3eacbe8555678005ca1264a1Erik    private static final String TAG = "MonthView";
563553621c824afe1f3eacbe8555678005ca1264a1Erik
573553621c824afe1f3eacbe8555678005ca1264a1Erik    public static final String VIEW_PARAMS_ORIENTATION = "orientation";
583553621c824afe1f3eacbe8555678005ca1264a1Erik
593553621c824afe1f3eacbe8555678005ca1264a1Erik    private static int TEXT_SIZE_MONTH_NUMBER = 32;
603553621c824afe1f3eacbe8555678005ca1264a1Erik    private static int TEXT_SIZE_EVENT = 14;
613553621c824afe1f3eacbe8555678005ca1264a1Erik    private static int TEXT_SIZE_MORE_EVENTS = 12;
623553621c824afe1f3eacbe8555678005ca1264a1Erik    private static int TEXT_SIZE_MONTH_NAME = 14;
633553621c824afe1f3eacbe8555678005ca1264a1Erik    private static int TEXT_SIZE_WEEK_NUM = 12;
643553621c824afe1f3eacbe8555678005ca1264a1Erik
65092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int DNA_MARGIN = 4;
66092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int DNA_ALL_DAY_HEIGHT = 4;
67092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int DNA_MIN_SEGMENT_HEIGHT = 4;
68092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int DNA_WIDTH = 8;
69092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int DNA_ALL_DAY_WIDTH = 32;
70092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int DNA_SIDE_PADDING = 6;
71092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int CONFLICT_COLOR = Color.BLACK;
72092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik
733bff945d29d6ef277391745cd160f3bf16b98905RoboErik    private static int DEFAULT_EDGE_SPACING = 0;
743bff945d29d6ef277391745cd160f3bf16b98905RoboErik    private static int SIDE_PADDING_MONTH_NUMBER = 4;
75763b9308fa13c8c9c3b9a715f4daf8eba497b935RoboErik    private static int TOP_PADDING_MONTH_NUMBER = 4;
76092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int TOP_PADDING_WEEK_NUMBER = 4;
77092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int SIDE_PADDING_WEEK_NUMBER = 20;
783bff945d29d6ef277391745cd160f3bf16b98905RoboErik    private static int DAY_SEPARATOR_OUTER_WIDTH = 0;
7940bcd101b212c9863c3110c05a487a7ae6ebc3caErik    private static int DAY_SEPARATOR_INNER_WIDTH = 1;
8040bcd101b212c9863c3110c05a487a7ae6ebc3caErik    private static int DAY_SEPARATOR_VERTICAL_LENGTH = 53;
8140bcd101b212c9863c3110c05a487a7ae6ebc3caErik    private static int DAY_SEPARATOR_VERTICAL_LENGHT_PORTRAIT = 64;
82092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int MIN_WEEK_WIDTH = 50;
8340bcd101b212c9863c3110c05a487a7ae6ebc3caErik
84f658df6b9c285f24c45cdca3ab90f2ca65e5b7cfRoboErik    private static int EVENT_X_OFFSET_LANDSCAPE = 38;
8540bcd101b212c9863c3110c05a487a7ae6ebc3caErik    private static int EVENT_Y_OFFSET_LANDSCAPE = 11;
863bff945d29d6ef277391745cd160f3bf16b98905RoboErik    private static int EVENT_Y_OFFSET_PORTRAIT = 16;
8740bcd101b212c9863c3110c05a487a7ae6ebc3caErik    private static int EVENT_SQUARE_WIDTH = 10;
88a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik    private static int EVENT_SQUARE_BORDER = 2;
8940bcd101b212c9863c3110c05a487a7ae6ebc3caErik    private static int EVENT_LINE_PADDING = 4;
9040bcd101b212c9863c3110c05a487a7ae6ebc3caErik    private static int EVENT_RIGHT_PADDING = 4;
91f658df6b9c285f24c45cdca3ab90f2ca65e5b7cfRoboErik    private static int EVENT_BOTTOM_PADDING = 8;
923553621c824afe1f3eacbe8555678005ca1264a1Erik
9382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
94092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private static int SPACING_WEEK_NUMBER = 24;
9540bcd101b212c9863c3110c05a487a7ae6ebc3caErik    private static boolean mScaled = false;
963bff945d29d6ef277391745cd160f3bf16b98905RoboErik    private static boolean mShowDetailsInMonth;
973553621c824afe1f3eacbe8555678005ca1264a1Erik
983553621c824afe1f3eacbe8555678005ca1264a1Erik    protected Time mToday = new Time();
993553621c824afe1f3eacbe8555678005ca1264a1Erik    protected boolean mHasToday = false;
1003553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mTodayIndex = -1;
1013553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mOrientation = Configuration.ORIENTATION_LANDSCAPE;
10240bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected List<ArrayList<Event>> mEvents = null;
103092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    HashMap<Integer, Utils.DNAStrand> mDna = null;
104f445411ff661014c4b5a37e2f97552989e9278ecRoboErik    // This is for drawing the outlines around event chips and supports up to 10
105f445411ff661014c4b5a37e2f97552989e9278ecRoboErik    // events being drawn on each day. The code will expand this if necessary.
106f445411ff661014c4b5a37e2f97552989e9278ecRoboErik    protected FloatRef mEventOutlines = new FloatRef(10 * 4 * 4 * 7);
10740bcd101b212c9863c3110c05a487a7ae6ebc3caErik
10871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson
10971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson
11040bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected static StringBuilder mStringBuilder = new StringBuilder(50);
11140bcd101b212c9863c3110c05a487a7ae6ebc3caErik    // TODO recreate formatter when locale changes
11240bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected static Formatter mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
1133553621c824afe1f3eacbe8555678005ca1264a1Erik
1143553621c824afe1f3eacbe8555678005ca1264a1Erik    protected Paint mMonthNamePaint;
11540bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected TextPaint mEventPaint;
11640bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected TextPaint mEventExtrasPaint;
1173553621c824afe1f3eacbe8555678005ca1264a1Erik    protected Paint mWeekNumPaint;
118092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    protected Paint mDNAAllDayPaint;
119092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    protected Paint mDNATimePaint;
120a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik    protected Paint mEventSquarePaint;
12171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson
1223553621c824afe1f3eacbe8555678005ca1264a1Erik
12340bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected Drawable mTodayDrawable;
12440bcd101b212c9863c3110c05a487a7ae6ebc3caErik
1253553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthNumHeight;
1263553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mEventHeight;
1273553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mExtrasHeight;
1283553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mWeekNumHeight;
1293553621c824afe1f3eacbe8555678005ca1264a1Erik
13067d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik    protected int mMonthBGColor;
13167d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik    protected int mMonthBGOtherColor;
13267d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik    protected int mMonthBGTodayColor;
1333553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthNumColor;
1343553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthNumOtherColor;
1353553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthNumTodayColor;
1363553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthNameColor;
1373553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthNameOtherColor;
1383553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthEventColor;
1393553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthEventExtraColor;
1403553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthEventOtherColor;
1413553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthEventExtraOtherColor;
1423553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mMonthWeekNumColor;
14382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson    protected int mMonthBusyBitsBgColor;
14471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson    protected int mMonthBusyBitsBusyTimeColor;
14571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson    protected int mMonthBusyBitsConflictTimeColor;
14682b318634af1b6594e60cfd1f2df4d3845f80587Erik
14740bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected int mEventChipOutlineColor = 0xFFFFFFFF;
148e9baa2499d9592343e30c983116e3f8dc921d3b0RoboErik    protected int mDaySeparatorInnerColor;
14940bcd101b212c9863c3110c05a487a7ae6ebc3caErik
150092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private int[] mDayXs;
15182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
15282b318634af1b6594e60cfd1f2df4d3845f80587Erik    /**
153f445411ff661014c4b5a37e2f97552989e9278ecRoboErik     * This provides a reference to a float array which allows for easy size
154f445411ff661014c4b5a37e2f97552989e9278ecRoboErik     * checking and reallocation. Used for drawing lines.
155f445411ff661014c4b5a37e2f97552989e9278ecRoboErik     */
156f445411ff661014c4b5a37e2f97552989e9278ecRoboErik    private class FloatRef {
157f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        float[] array;
158f445411ff661014c4b5a37e2f97552989e9278ecRoboErik
159f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        public FloatRef(int size) {
160f445411ff661014c4b5a37e2f97552989e9278ecRoboErik            array = new float[size];
161f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        }
162f445411ff661014c4b5a37e2f97552989e9278ecRoboErik
163f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        public void ensureSize(int newSize) {
164f445411ff661014c4b5a37e2f97552989e9278ecRoboErik            if (newSize >= array.length) {
165f445411ff661014c4b5a37e2f97552989e9278ecRoboErik                // Add enough space for 7 more boxes to be drawn
166f445411ff661014c4b5a37e2f97552989e9278ecRoboErik                array = Arrays.copyOf(array, newSize + 16 * 7);
167f445411ff661014c4b5a37e2f97552989e9278ecRoboErik            }
168f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        }
169f445411ff661014c4b5a37e2f97552989e9278ecRoboErik    }
170f445411ff661014c4b5a37e2f97552989e9278ecRoboErik
17182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
172f445411ff661014c4b5a37e2f97552989e9278ecRoboErik    /**
17382b318634af1b6594e60cfd1f2df4d3845f80587Erik     * @param context
17482b318634af1b6594e60cfd1f2df4d3845f80587Erik     */
17582b318634af1b6594e60cfd1f2df4d3845f80587Erik    public MonthWeekEventsView(Context context) {
17682b318634af1b6594e60cfd1f2df4d3845f80587Erik        super(context);
177092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    }
178092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik
179092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    // Sets the list of events for this week. Takes a sorted list of arrays
180092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    // divided up by day for generating the large month version and the full
181092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    // arraylist sorted by start time to generate the dna version.
182092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    public void setEvents(List<ArrayList<Event>> sortedEvents, ArrayList<Event> unsortedEvents) {
183092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        setEvents(sortedEvents);
184092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        // The MIN_WEEK_WIDTH is a hack to prevent the view from trying to
185092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        // generate dna bits before its width has been fixed.
1867d66103066f04ba2b7c4ddfcfdafd0368ad9d9cbAndy McFadden        if (unsortedEvents == null || mWidth <= MIN_WEEK_WIDTH || getContext() == null) {
187092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            mDna = null;
188092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            return;
189092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        }
190092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        // Create the drawing coordinates for dna
191092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        if (!mShowDetailsInMonth) {
192092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            int numDays = mEvents.size();
193763b9308fa13c8c9c3b9a715f4daf8eba497b935RoboErik            int effectiveWidth = mWidth - mPadding * 2;
194763b9308fa13c8c9c3b9a715f4daf8eba497b935RoboErik            if (mShowWeekNum) {
195763b9308fa13c8c9c3b9a715f4daf8eba497b935RoboErik                effectiveWidth -= SPACING_WEEK_NUMBER;
196763b9308fa13c8c9c3b9a715f4daf8eba497b935RoboErik            }
197092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            DNA_ALL_DAY_WIDTH = effectiveWidth / numDays - 2 * DNA_SIDE_PADDING;
198092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            mDNAAllDayPaint.setStrokeWidth(DNA_ALL_DAY_WIDTH);
199092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            mDayXs = new int[numDays];
200092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            for (int day = 0; day < numDays; day++) {
201092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                mDayXs[day] = computeDayLeftPosition(day) + DNA_WIDTH / 2 + DNA_SIDE_PADDING;
202092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik
203092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            }
204092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik
205092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            int top = DAY_SEPARATOR_INNER_WIDTH + DNA_MARGIN + DNA_ALL_DAY_HEIGHT + 1;
206092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            int bottom = mHeight - DNA_MARGIN;
207092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            mDna = Utils.createDNAStrands(mFirstJulianDay, unsortedEvents, top, bottom,
2087d66103066f04ba2b7c4ddfcfdafd0368ad9d9cbAndy McFadden                    DNA_MIN_SEGMENT_HEIGHT, mDayXs, getContext());
209092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        }
2103553621c824afe1f3eacbe8555678005ca1264a1Erik    }
2113553621c824afe1f3eacbe8555678005ca1264a1Erik
21240bcd101b212c9863c3110c05a487a7ae6ebc3caErik    public void setEvents(List<ArrayList<Event>> sortedEvents) {
2133553621c824afe1f3eacbe8555678005ca1264a1Erik        mEvents = sortedEvents;
2143553621c824afe1f3eacbe8555678005ca1264a1Erik        if (sortedEvents == null) {
2153553621c824afe1f3eacbe8555678005ca1264a1Erik            return;
2163553621c824afe1f3eacbe8555678005ca1264a1Erik        }
2173553621c824afe1f3eacbe8555678005ca1264a1Erik        if (sortedEvents.size() != mNumDays) {
2183553621c824afe1f3eacbe8555678005ca1264a1Erik            if (Log.isLoggable(TAG, Log.ERROR)) {
2193553621c824afe1f3eacbe8555678005ca1264a1Erik                Log.wtf(TAG, "Events size must be same as days displayed: size="
2203553621c824afe1f3eacbe8555678005ca1264a1Erik                        + sortedEvents.size() + " days=" + mNumDays);
2213553621c824afe1f3eacbe8555678005ca1264a1Erik            }
2223553621c824afe1f3eacbe8555678005ca1264a1Erik            mEvents = null;
2233553621c824afe1f3eacbe8555678005ca1264a1Erik            return;
2243553621c824afe1f3eacbe8555678005ca1264a1Erik        }
2253553621c824afe1f3eacbe8555678005ca1264a1Erik    }
2263553621c824afe1f3eacbe8555678005ca1264a1Erik
2273553621c824afe1f3eacbe8555678005ca1264a1Erik    protected void loadColors(Context context) {
2283553621c824afe1f3eacbe8555678005ca1264a1Erik        Resources res = context.getResources();
2293553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthWeekNumColor = res.getColor(R.color.month_week_num_color);
2303553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNumColor = res.getColor(R.color.month_day_number);
2313553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNumOtherColor = res.getColor(R.color.month_day_number_other);
2323553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNumTodayColor = res.getColor(R.color.month_today_number);
2333553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNameColor = mMonthNumColor;
2343553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNameOtherColor = mMonthNumOtherColor;
2353553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthEventColor = res.getColor(R.color.month_event_color);
2363553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthEventExtraColor = res.getColor(R.color.month_event_extra_color);
2373553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthEventOtherColor = res.getColor(R.color.month_event_other_color);
2383553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthEventExtraOtherColor = res.getColor(R.color.month_event_extra_other_color);
23967d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        mMonthBGTodayColor = res.getColor(R.color.month_today_bgcolor);
24067d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        mMonthBGOtherColor = res.getColor(R.color.month_other_bgcolor);
24167d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        mMonthBGColor = res.getColor(R.color.month_bgcolor);
242e9baa2499d9592343e30c983116e3f8dc921d3b0RoboErik        mDaySeparatorInnerColor = res.getColor(R.color.month_grid_lines);
24340bcd101b212c9863c3110c05a487a7ae6ebc3caErik
24440bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mTodayDrawable = res.getDrawable(R.drawable.today_blue_week_holo_light);
2453553621c824afe1f3eacbe8555678005ca1264a1Erik    }
2463553621c824afe1f3eacbe8555678005ca1264a1Erik
2473553621c824afe1f3eacbe8555678005ca1264a1Erik    /**
2483553621c824afe1f3eacbe8555678005ca1264a1Erik     * Sets up the text and style properties for painting. Override this if you
2493553621c824afe1f3eacbe8555678005ca1264a1Erik     * want to use a different paint.
2503553621c824afe1f3eacbe8555678005ca1264a1Erik     */
2513553621c824afe1f3eacbe8555678005ca1264a1Erik    @Override
2527203d809b39fb07caab177d8e8bd9428097b73b6Erik    protected void initView() {
2537203d809b39fb07caab177d8e8bd9428097b73b6Erik        super.initView();
2547203d809b39fb07caab177d8e8bd9428097b73b6Erik
2553bff945d29d6ef277391745cd160f3bf16b98905RoboErik        if (!mScaled) {
2563bff945d29d6ef277391745cd160f3bf16b98905RoboErik            Resources resources = getContext().getResources();
2577d66103066f04ba2b7c4ddfcfdafd0368ad9d9cbAndy McFadden            mShowDetailsInMonth = Utils.getConfigBool(getContext(), R.bool.show_details_in_month);
2583bff945d29d6ef277391745cd160f3bf16b98905RoboErik            TEXT_SIZE_MONTH_NUMBER = resources.getInteger(R.integer.text_size_month_number);
2593bff945d29d6ef277391745cd160f3bf16b98905RoboErik            SIDE_PADDING_MONTH_NUMBER = resources.getInteger(R.integer.month_day_number_margin);
260092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            CONFLICT_COLOR = resources.getColor(R.color.month_dna_conflict_time_color);
2613bff945d29d6ef277391745cd160f3bf16b98905RoboErik            if (mScale != 1) {
2623bff945d29d6ef277391745cd160f3bf16b98905RoboErik                TOP_PADDING_MONTH_NUMBER *= mScale;
263092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                TOP_PADDING_WEEK_NUMBER *= mScale;
2643bff945d29d6ef277391745cd160f3bf16b98905RoboErik                SIDE_PADDING_MONTH_NUMBER *= mScale;
2653bff945d29d6ef277391745cd160f3bf16b98905RoboErik                SIDE_PADDING_WEEK_NUMBER *= mScale;
2663bff945d29d6ef277391745cd160f3bf16b98905RoboErik                SPACING_WEEK_NUMBER *= mScale;
2673bff945d29d6ef277391745cd160f3bf16b98905RoboErik                TEXT_SIZE_MONTH_NUMBER *= mScale;
2683bff945d29d6ef277391745cd160f3bf16b98905RoboErik                TEXT_SIZE_EVENT *= mScale;
2693bff945d29d6ef277391745cd160f3bf16b98905RoboErik                TEXT_SIZE_MORE_EVENTS *= mScale;
2703bff945d29d6ef277391745cd160f3bf16b98905RoboErik                TEXT_SIZE_MONTH_NAME *= mScale;
2713bff945d29d6ef277391745cd160f3bf16b98905RoboErik                TEXT_SIZE_WEEK_NUM *= mScale;
2723bff945d29d6ef277391745cd160f3bf16b98905RoboErik                DAY_SEPARATOR_OUTER_WIDTH *= mScale;
2733bff945d29d6ef277391745cd160f3bf16b98905RoboErik                DAY_SEPARATOR_INNER_WIDTH *= mScale;
2743bff945d29d6ef277391745cd160f3bf16b98905RoboErik                DAY_SEPARATOR_VERTICAL_LENGTH *= mScale;
2753bff945d29d6ef277391745cd160f3bf16b98905RoboErik                DAY_SEPARATOR_VERTICAL_LENGHT_PORTRAIT *= mScale;
2763bff945d29d6ef277391745cd160f3bf16b98905RoboErik                EVENT_X_OFFSET_LANDSCAPE *= mScale;
2773bff945d29d6ef277391745cd160f3bf16b98905RoboErik                EVENT_Y_OFFSET_LANDSCAPE *= mScale;
2783bff945d29d6ef277391745cd160f3bf16b98905RoboErik                EVENT_Y_OFFSET_PORTRAIT *= mScale;
2793bff945d29d6ef277391745cd160f3bf16b98905RoboErik                EVENT_SQUARE_WIDTH *= mScale;
280a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik                EVENT_SQUARE_BORDER *= mScale;
2813bff945d29d6ef277391745cd160f3bf16b98905RoboErik                EVENT_LINE_PADDING *= mScale;
2823bff945d29d6ef277391745cd160f3bf16b98905RoboErik                EVENT_BOTTOM_PADDING *= mScale;
2833bff945d29d6ef277391745cd160f3bf16b98905RoboErik                EVENT_RIGHT_PADDING *= mScale;
284092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                DNA_MARGIN *= mScale;
285092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                DNA_WIDTH *= mScale;
286092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                DNA_ALL_DAY_HEIGHT *= mScale;
287092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                DNA_MIN_SEGMENT_HEIGHT *= mScale;
288092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                DNA_SIDE_PADDING *= mScale;
2893bff945d29d6ef277391745cd160f3bf16b98905RoboErik                DEFAULT_EDGE_SPACING *= mScale;
290092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                DNA_ALL_DAY_WIDTH *= mScale;
291092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            }
292092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            if (!mShowDetailsInMonth) {
293092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                TOP_PADDING_MONTH_NUMBER += DNA_ALL_DAY_HEIGHT + DNA_MARGIN;
2943bff945d29d6ef277391745cd160f3bf16b98905RoboErik            }
2957203d809b39fb07caab177d8e8bd9428097b73b6Erik            mScaled = true;
2967203d809b39fb07caab177d8e8bd9428097b73b6Erik        }
2973bff945d29d6ef277391745cd160f3bf16b98905RoboErik        mPadding = DEFAULT_EDGE_SPACING;
2983f888688c0f2644ad3de032d5d1cf623a7b092fdAndy McFadden        loadColors(getContext());
2993553621c824afe1f3eacbe8555678005ca1264a1Erik        // TODO modify paint properties depending on isMini
3003553621c824afe1f3eacbe8555678005ca1264a1Erik
3013553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNumPaint = new Paint();
30240bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mMonthNumPaint.setFakeBoldText(false);
3033553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNumPaint.setAntiAlias(true);
3043553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNumPaint.setTextSize(TEXT_SIZE_MONTH_NUMBER);
3053553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNumPaint.setColor(mMonthNumColor);
3063553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNumPaint.setStyle(Style.FILL);
307a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        mMonthNumPaint.setTextAlign(Align.RIGHT);
30864d67bea6bdb8516c1685b0bb19bc217c3cbe14eRoboErik        mMonthNumPaint.setTypeface(Typeface.DEFAULT);
3093553621c824afe1f3eacbe8555678005ca1264a1Erik
3103553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNumHeight = (int) (-mMonthNumPaint.ascent());
3113553621c824afe1f3eacbe8555678005ca1264a1Erik
31240bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mEventPaint = new TextPaint();
313f658df6b9c285f24c45cdca3ab90f2ca65e5b7cfRoboErik        mEventPaint.setFakeBoldText(true);
3143553621c824afe1f3eacbe8555678005ca1264a1Erik        mEventPaint.setAntiAlias(true);
3153553621c824afe1f3eacbe8555678005ca1264a1Erik        mEventPaint.setTextSize(TEXT_SIZE_EVENT);
3163553621c824afe1f3eacbe8555678005ca1264a1Erik        mEventPaint.setColor(mMonthEventColor);
3173553621c824afe1f3eacbe8555678005ca1264a1Erik
3183553621c824afe1f3eacbe8555678005ca1264a1Erik        mEventHeight = (int) (-mEventPaint.ascent());
3193553621c824afe1f3eacbe8555678005ca1264a1Erik
32040bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mEventExtrasPaint = new TextPaint();
3213553621c824afe1f3eacbe8555678005ca1264a1Erik        mEventExtrasPaint.setFakeBoldText(false);
3223553621c824afe1f3eacbe8555678005ca1264a1Erik        mEventExtrasPaint.setAntiAlias(true);
32340bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mEventExtrasPaint.setStrokeWidth(EVENT_SQUARE_BORDER);
3243553621c824afe1f3eacbe8555678005ca1264a1Erik        mEventExtrasPaint.setTextSize(TEXT_SIZE_EVENT);
3253553621c824afe1f3eacbe8555678005ca1264a1Erik        mEventExtrasPaint.setColor(mMonthEventExtraColor);
3263553621c824afe1f3eacbe8555678005ca1264a1Erik        mEventExtrasPaint.setStyle(Style.FILL);
3273553621c824afe1f3eacbe8555678005ca1264a1Erik        mEventExtrasPaint.setTextAlign(Align.LEFT);
3283553621c824afe1f3eacbe8555678005ca1264a1Erik
3293553621c824afe1f3eacbe8555678005ca1264a1Erik        mWeekNumPaint = new Paint();
3303553621c824afe1f3eacbe8555678005ca1264a1Erik        mWeekNumPaint.setFakeBoldText(false);
3313553621c824afe1f3eacbe8555678005ca1264a1Erik        mWeekNumPaint.setAntiAlias(true);
3323553621c824afe1f3eacbe8555678005ca1264a1Erik        mWeekNumPaint.setTextSize(TEXT_SIZE_WEEK_NUM);
3333553621c824afe1f3eacbe8555678005ca1264a1Erik        mWeekNumPaint.setColor(mWeekNumColor);
3343553621c824afe1f3eacbe8555678005ca1264a1Erik        mWeekNumPaint.setStyle(Style.FILL);
3353553621c824afe1f3eacbe8555678005ca1264a1Erik        mWeekNumPaint.setTextAlign(Align.RIGHT);
3363553621c824afe1f3eacbe8555678005ca1264a1Erik
3373553621c824afe1f3eacbe8555678005ca1264a1Erik        mWeekNumHeight = (int) (-mWeekNumPaint.ascent());
33871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson
339092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mDNAAllDayPaint = new Paint();
340092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mDNATimePaint = new Paint();
341092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mDNATimePaint.setColor(mMonthBusyBitsBusyTimeColor);
342092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mDNATimePaint.setStyle(Style.FILL_AND_STROKE);
343092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mDNATimePaint.setStrokeWidth(DNA_WIDTH);
344092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mDNATimePaint.setAntiAlias(false);
345092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mDNAAllDayPaint.setColor(mMonthBusyBitsConflictTimeColor);
346092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mDNAAllDayPaint.setStyle(Style.FILL_AND_STROKE);
347092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mDNAAllDayPaint.setStrokeWidth(DNA_ALL_DAY_WIDTH);
348092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mDNAAllDayPaint.setAntiAlias(false);
349a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik
350a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        mEventSquarePaint = new Paint();
351a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        mEventSquarePaint.setStrokeWidth(EVENT_SQUARE_BORDER);
352a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        mEventSquarePaint.setAntiAlias(false);
3533553621c824afe1f3eacbe8555678005ca1264a1Erik    }
3543553621c824afe1f3eacbe8555678005ca1264a1Erik
3553553621c824afe1f3eacbe8555678005ca1264a1Erik    @Override
3563553621c824afe1f3eacbe8555678005ca1264a1Erik    public void setWeekParams(HashMap<String, Integer> params, String tz) {
3573553621c824afe1f3eacbe8555678005ca1264a1Erik        super.setWeekParams(params, tz);
3583553621c824afe1f3eacbe8555678005ca1264a1Erik
35940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        if (params.containsKey(VIEW_PARAMS_ORIENTATION)) {
36040bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mOrientation = params.get(VIEW_PARAMS_ORIENTATION);
36140bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
36240bcd101b212c9863c3110c05a487a7ae6ebc3caErik
3633553621c824afe1f3eacbe8555678005ca1264a1Erik        mToday.timezone = tz;
3643553621c824afe1f3eacbe8555678005ca1264a1Erik        mToday.setToNow();
3653553621c824afe1f3eacbe8555678005ca1264a1Erik        mToday.normalize(true);
3663553621c824afe1f3eacbe8555678005ca1264a1Erik        int julianToday = Time.getJulianDay(mToday.toMillis(false), mToday.gmtoff);
3673553621c824afe1f3eacbe8555678005ca1264a1Erik        if (julianToday >= mFirstJulianDay && julianToday < mFirstJulianDay + mNumDays) {
3683553621c824afe1f3eacbe8555678005ca1264a1Erik            mHasToday = true;
3693553621c824afe1f3eacbe8555678005ca1264a1Erik            mTodayIndex = julianToday - mFirstJulianDay;
3703553621c824afe1f3eacbe8555678005ca1264a1Erik        } else {
3713553621c824afe1f3eacbe8555678005ca1264a1Erik            mHasToday = false;
3723553621c824afe1f3eacbe8555678005ca1264a1Erik            mTodayIndex = -1;
3733553621c824afe1f3eacbe8555678005ca1264a1Erik        }
374ef896fda8812d5f31aa87e8e1525d6f9d8b61e9cErik        mNumCells = mNumDays + 1;
3753553621c824afe1f3eacbe8555678005ca1264a1Erik    }
3763553621c824afe1f3eacbe8555678005ca1264a1Erik
3773553621c824afe1f3eacbe8555678005ca1264a1Erik    @Override
37840bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected void onDraw(Canvas canvas) {
37940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        drawBackground(canvas);
38040bcd101b212c9863c3110c05a487a7ae6ebc3caErik        drawWeekNums(canvas);
38140bcd101b212c9863c3110c05a487a7ae6ebc3caErik        drawDaySeparators(canvas);
382ff5c4345f794ec12b0a92f284434ddc1c88ff3a8Isaac Katzenelson        if (mShowDetailsInMonth) {
38396a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson            drawEvents(canvas);
38482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        } else {
385092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            drawDNA(canvas);
386092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        }
387092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    }
388092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik
389092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    // TODO move into SimpleWeekView
390092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    // Computes the x position for the left side of the given day
391092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    private int computeDayLeftPosition(int day) {
392092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        int effectiveWidth = mWidth;
393092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        int x = 0;
394092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        int xOffset = 0;
395092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        if (mShowWeekNum) {
396092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            xOffset = SPACING_WEEK_NUMBER + mPadding;
397092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            effectiveWidth -= xOffset;
39896a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson        }
399092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        x = day * effectiveWidth / mNumDays + xOffset;
400092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        return x;
40140bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
40240bcd101b212c9863c3110c05a487a7ae6ebc3caErik
40340bcd101b212c9863c3110c05a487a7ae6ebc3caErik    @Override
40440bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected void drawDaySeparators(Canvas canvas) {
40540bcd101b212c9863c3110c05a487a7ae6ebc3caErik        float lines[] = new float[8 * 4];
406092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        int count = 6 * 4;
40740bcd101b212c9863c3110c05a487a7ae6ebc3caErik        int wkNumOffset = 0;
408092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        int i = 0;
409092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        if (mShowWeekNum) {
410092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            // This adds the first line separating the week number
411092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            int xOffset = SPACING_WEEK_NUMBER + mPadding;
412092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            count += 4;
413092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            lines[i++] = xOffset;
414092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            lines[i++] = 0;
415092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            lines[i++] = xOffset;
416092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            lines[i++] = mHeight;
417092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            wkNumOffset++;
418092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        }
419bf4aa400663a072813c87cf9c8aaee2d07abc945Erik        count += 4;
420092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        lines[i++] = 0;
421092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        lines[i++] = 0;
422092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        lines[i++] = mWidth;
423092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        lines[i++] = 0;
4243bff945d29d6ef277391745cd160f3bf16b98905RoboErik        int y0 = 0;
4253bff945d29d6ef277391745cd160f3bf16b98905RoboErik        int y1 = mHeight;
42640bcd101b212c9863c3110c05a487a7ae6ebc3caErik
427092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        while (i < count) {
428092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            int x = computeDayLeftPosition(i / 4 - wkNumOffset);
42940bcd101b212c9863c3110c05a487a7ae6ebc3caErik            lines[i++] = x;
43040bcd101b212c9863c3110c05a487a7ae6ebc3caErik            lines[i++] = y0;
43140bcd101b212c9863c3110c05a487a7ae6ebc3caErik            lines[i++] = x;
43240bcd101b212c9863c3110c05a487a7ae6ebc3caErik            lines[i++] = y1;
43340bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
43440bcd101b212c9863c3110c05a487a7ae6ebc3caErik        p.setColor(mDaySeparatorInnerColor);
43540bcd101b212c9863c3110c05a487a7ae6ebc3caErik        p.setStrokeWidth(DAY_SEPARATOR_INNER_WIDTH);
43640bcd101b212c9863c3110c05a487a7ae6ebc3caErik        canvas.drawLines(lines, 0, count, p);
43740bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
43840bcd101b212c9863c3110c05a487a7ae6ebc3caErik
43940bcd101b212c9863c3110c05a487a7ae6ebc3caErik    @Override
4403553621c824afe1f3eacbe8555678005ca1264a1Erik    protected void drawBackground(Canvas canvas) {
44167d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        int i = 0;
44267d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        int offset = 0;
443092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        r.top = DAY_SEPARATOR_INNER_WIDTH;
4443553621c824afe1f3eacbe8555678005ca1264a1Erik        r.bottom = mHeight;
44567d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        if (mShowWeekNum) {
44667d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            i++;
44767d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            offset++;
44867d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        }
449e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik        if (!mFocusDay[i]) {
450e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik            while (++i < mFocusDay.length && !mFocusDay[i])
45167d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik                ;
45267d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            r.right = computeDayLeftPosition(i - offset);
45367d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            r.left = 0;
454e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik            p.setColor(mMonthBGOtherColor);
45567d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            canvas.drawRect(r, p);
45667d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            // compute left edge for i, set up r, draw
457e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik        } else if (!mFocusDay[(i = mFocusDay.length - 1)]) {
458e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik            while (--i >= offset && !mFocusDay[i])
45967d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik                ;
46067d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            i++;
46167d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            // compute left edge for i, set up r, draw
46267d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            r.right = mWidth;
46367d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            r.left = computeDayLeftPosition(i - offset);
464e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik            p.setColor(mMonthBGOtherColor);
46567d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            canvas.drawRect(r, p);
46667d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        }
46767d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        if (mHasToday) {
46867d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            p.setColor(mMonthBGTodayColor);
46967d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            r.left = computeDayLeftPosition(mTodayIndex);
47067d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            r.right = computeDayLeftPosition(mTodayIndex + 1);
47167d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            canvas.drawRect(r, p);
47267d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        }
4733553621c824afe1f3eacbe8555678005ca1264a1Erik    }
4743553621c824afe1f3eacbe8555678005ca1264a1Erik
4753553621c824afe1f3eacbe8555678005ca1264a1Erik    @Override
4763553621c824afe1f3eacbe8555678005ca1264a1Erik    protected void drawWeekNums(Canvas canvas) {
477bf4aa400663a072813c87cf9c8aaee2d07abc945Erik        int y;
4783553621c824afe1f3eacbe8555678005ca1264a1Erik
4793553621c824afe1f3eacbe8555678005ca1264a1Erik        int i = 0;
480a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        int offset = -1;
4813553621c824afe1f3eacbe8555678005ca1264a1Erik        int todayIndex = mTodayIndex;
482092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        int x = 0;
483ef896fda8812d5f31aa87e8e1525d6f9d8b61e9cErik        int numCount = mNumDays;
4843553621c824afe1f3eacbe8555678005ca1264a1Erik        if (mShowWeekNum) {
485092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            x = SIDE_PADDING_WEEK_NUMBER + mPadding;
486092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            y = mWeekNumHeight + TOP_PADDING_WEEK_NUMBER;
4873553621c824afe1f3eacbe8555678005ca1264a1Erik            canvas.drawText(mDayNumbers[0], x, y, mWeekNumPaint);
488ef896fda8812d5f31aa87e8e1525d6f9d8b61e9cErik            numCount++;
489ef896fda8812d5f31aa87e8e1525d6f9d8b61e9cErik            i++;
490ef896fda8812d5f31aa87e8e1525d6f9d8b61e9cErik            todayIndex++;
491ef896fda8812d5f31aa87e8e1525d6f9d8b61e9cErik            offset++;
492092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik
4933553621c824afe1f3eacbe8555678005ca1264a1Erik        }
4943553621c824afe1f3eacbe8555678005ca1264a1Erik
4953bff945d29d6ef277391745cd160f3bf16b98905RoboErik        y = (mMonthNumHeight + TOP_PADDING_MONTH_NUMBER);
4963553621c824afe1f3eacbe8555678005ca1264a1Erik
4973553621c824afe1f3eacbe8555678005ca1264a1Erik        boolean isFocusMonth = mFocusDay[i];
49867d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik        boolean isBold = false;
4993553621c824afe1f3eacbe8555678005ca1264a1Erik        mMonthNumPaint.setColor(isFocusMonth ? mMonthNumColor : mMonthNumOtherColor);
500ef896fda8812d5f31aa87e8e1525d6f9d8b61e9cErik        for (; i < numCount; i++) {
5013553621c824afe1f3eacbe8555678005ca1264a1Erik            if (mHasToday && todayIndex == i) {
5023553621c824afe1f3eacbe8555678005ca1264a1Erik                mMonthNumPaint.setColor(mMonthNumTodayColor);
50367d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik                mMonthNumPaint.setFakeBoldText(isBold = true);
504259b8f9a21fffd3858218581e9daaf689b6b888fErik                if (i + 1 < numCount) {
5053553621c824afe1f3eacbe8555678005ca1264a1Erik                    // Make sure the color will be set back on the next
5063553621c824afe1f3eacbe8555678005ca1264a1Erik                    // iteration
5073553621c824afe1f3eacbe8555678005ca1264a1Erik                    isFocusMonth = !mFocusDay[i + 1];
5083553621c824afe1f3eacbe8555678005ca1264a1Erik                }
5093553621c824afe1f3eacbe8555678005ca1264a1Erik            } else if (mFocusDay[i] != isFocusMonth) {
5103553621c824afe1f3eacbe8555678005ca1264a1Erik                isFocusMonth = mFocusDay[i];
5113553621c824afe1f3eacbe8555678005ca1264a1Erik                mMonthNumPaint.setColor(isFocusMonth ? mMonthNumColor : mMonthNumOtherColor);
5123553621c824afe1f3eacbe8555678005ca1264a1Erik            }
513a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik            x = computeDayLeftPosition(i - offset) - (SIDE_PADDING_MONTH_NUMBER);
5143553621c824afe1f3eacbe8555678005ca1264a1Erik            canvas.drawText(mDayNumbers[i], x, y, mMonthNumPaint);
51567d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            if (isBold) {
51667d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik                mMonthNumPaint.setFakeBoldText(isBold = false);
51767d628eaed439a4b109e5e35f2d536c99680aaf6RoboErik            }
5183553621c824afe1f3eacbe8555678005ca1264a1Erik        }
5193553621c824afe1f3eacbe8555678005ca1264a1Erik    }
5203553621c824afe1f3eacbe8555678005ca1264a1Erik
52140bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected void drawEvents(Canvas canvas) {
52240bcd101b212c9863c3110c05a487a7ae6ebc3caErik        if (mEvents == null) {
52340bcd101b212c9863c3110c05a487a7ae6ebc3caErik            return;
52440bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
52540bcd101b212c9863c3110c05a487a7ae6ebc3caErik
52640bcd101b212c9863c3110c05a487a7ae6ebc3caErik        int day = -1;
52740bcd101b212c9863c3110c05a487a7ae6ebc3caErik        for (ArrayList<Event> eventDay : mEvents) {
52840bcd101b212c9863c3110c05a487a7ae6ebc3caErik            day++;
52940bcd101b212c9863c3110c05a487a7ae6ebc3caErik            if (eventDay == null || eventDay.size() == 0) {
53040bcd101b212c9863c3110c05a487a7ae6ebc3caErik                continue;
53140bcd101b212c9863c3110c05a487a7ae6ebc3caErik            }
53240bcd101b212c9863c3110c05a487a7ae6ebc3caErik            int ySquare;
533a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik            int xSquare = computeDayLeftPosition(day) + SIDE_PADDING_MONTH_NUMBER + 1;
534a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik            int rightEdge = computeDayLeftPosition(day + 1);
535a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik
53640bcd101b212c9863c3110c05a487a7ae6ebc3caErik            if (mOrientation == Configuration.ORIENTATION_PORTRAIT) {
5373bff945d29d6ef277391745cd160f3bf16b98905RoboErik                ySquare = EVENT_Y_OFFSET_PORTRAIT + mMonthNumHeight + TOP_PADDING_MONTH_NUMBER;
538a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik                rightEdge -= SIDE_PADDING_MONTH_NUMBER + 1;
53940bcd101b212c9863c3110c05a487a7ae6ebc3caErik            } else {
54040bcd101b212c9863c3110c05a487a7ae6ebc3caErik                ySquare = EVENT_Y_OFFSET_LANDSCAPE;
541a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik                rightEdge -= EVENT_X_OFFSET_LANDSCAPE;
54240bcd101b212c9863c3110c05a487a7ae6ebc3caErik            }
54340bcd101b212c9863c3110c05a487a7ae6ebc3caErik            int eventCount = 0;
54440bcd101b212c9863c3110c05a487a7ae6ebc3caErik            Iterator<Event> iter = eventDay.iterator();
54540bcd101b212c9863c3110c05a487a7ae6ebc3caErik            while (iter.hasNext()) {
54640bcd101b212c9863c3110c05a487a7ae6ebc3caErik                Event event = iter.next();
54740bcd101b212c9863c3110c05a487a7ae6ebc3caErik                int newY = drawEvent(canvas, event, xSquare, ySquare, rightEdge, iter.hasNext());
54840bcd101b212c9863c3110c05a487a7ae6ebc3caErik                if (newY == ySquare) {
54940bcd101b212c9863c3110c05a487a7ae6ebc3caErik                    break;
55040bcd101b212c9863c3110c05a487a7ae6ebc3caErik                }
55140bcd101b212c9863c3110c05a487a7ae6ebc3caErik                eventCount++;
55240bcd101b212c9863c3110c05a487a7ae6ebc3caErik                ySquare = newY;
55340bcd101b212c9863c3110c05a487a7ae6ebc3caErik            }
55440bcd101b212c9863c3110c05a487a7ae6ebc3caErik
55540bcd101b212c9863c3110c05a487a7ae6ebc3caErik            int remaining = eventDay.size() - eventCount;
55640bcd101b212c9863c3110c05a487a7ae6ebc3caErik            if (remaining > 0) {
55740bcd101b212c9863c3110c05a487a7ae6ebc3caErik                drawMoreEvents(canvas, remaining, xSquare);
55840bcd101b212c9863c3110c05a487a7ae6ebc3caErik            }
55940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
56040bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
56140bcd101b212c9863c3110c05a487a7ae6ebc3caErik
562f445411ff661014c4b5a37e2f97552989e9278ecRoboErik    protected int addChipOutline(FloatRef lines, int count, int x, int y) {
563f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.ensureSize(count + 16);
56440bcd101b212c9863c3110c05a487a7ae6ebc3caErik        // top of box
565f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = x;
566f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = y;
567f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = x + EVENT_SQUARE_WIDTH;
568f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = y;
56940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        // right side of box
570f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = x + EVENT_SQUARE_WIDTH;
571f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = y;
572f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = x + EVENT_SQUARE_WIDTH;
573f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = y + EVENT_SQUARE_WIDTH;
57440bcd101b212c9863c3110c05a487a7ae6ebc3caErik        // left side of box
575f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = x;
576f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = y;
577f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = x;
578f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = y + EVENT_SQUARE_WIDTH + 1;
57940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        // bottom of box
580f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = x;
581f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = y + EVENT_SQUARE_WIDTH;
5822fda24534978f55711526dbde747aa50d68dec40RoboErik        lines.array[count++] = x + EVENT_SQUARE_WIDTH + 1;
583f445411ff661014c4b5a37e2f97552989e9278ecRoboErik        lines.array[count++] = y + EVENT_SQUARE_WIDTH;
58440bcd101b212c9863c3110c05a487a7ae6ebc3caErik
58540bcd101b212c9863c3110c05a487a7ae6ebc3caErik        return count;
58640bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
58740bcd101b212c9863c3110c05a487a7ae6ebc3caErik
58840bcd101b212c9863c3110c05a487a7ae6ebc3caErik    /**
58940bcd101b212c9863c3110c05a487a7ae6ebc3caErik     * Attempts to draw the given event. Returns the y for the next event or the
59040bcd101b212c9863c3110c05a487a7ae6ebc3caErik     * original y if the event will not fit. An event is considered to not fit
59140bcd101b212c9863c3110c05a487a7ae6ebc3caErik     * if the event and its extras won't fit or if there are more events and the
59240bcd101b212c9863c3110c05a487a7ae6ebc3caErik     * more events line would not fit after drawing this event.
59340bcd101b212c9863c3110c05a487a7ae6ebc3caErik     *
59440bcd101b212c9863c3110c05a487a7ae6ebc3caErik     * @param event the event to draw
59540bcd101b212c9863c3110c05a487a7ae6ebc3caErik     * @param x the top left corner for this event's color chip
59640bcd101b212c9863c3110c05a487a7ae6ebc3caErik     * @param y the top left corner for this event's color chip
59740bcd101b212c9863c3110c05a487a7ae6ebc3caErik     * @return the y for the next event or the original y if it won't fit
59840bcd101b212c9863c3110c05a487a7ae6ebc3caErik     */
59940bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected int drawEvent(
60040bcd101b212c9863c3110c05a487a7ae6ebc3caErik            Canvas canvas, Event event, int x, int y, int rightEdge, boolean moreEvents) {
60140bcd101b212c9863c3110c05a487a7ae6ebc3caErik        int requiredSpace = EVENT_LINE_PADDING + mEventHeight;
60240bcd101b212c9863c3110c05a487a7ae6ebc3caErik        int multiplier = 1;
60340bcd101b212c9863c3110c05a487a7ae6ebc3caErik        if (moreEvents) {
60440bcd101b212c9863c3110c05a487a7ae6ebc3caErik            multiplier++;
60540bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
60640bcd101b212c9863c3110c05a487a7ae6ebc3caErik        if (!event.allDay) {
60740bcd101b212c9863c3110c05a487a7ae6ebc3caErik            multiplier++;
60840bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
60940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        requiredSpace *= multiplier;
610a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        // The last one doesn't need the EVENT_LINE_PADDING as it will have
611a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        // EVENT_BOTTOM_PADDING instead
612a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        requiredSpace -= EVENT_LINE_PADDING;
613a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        if (requiredSpace + y > mHeight - EVENT_BOTTOM_PADDING) {
61440bcd101b212c9863c3110c05a487a7ae6ebc3caErik            // Not enough space, return
61540bcd101b212c9863c3110c05a487a7ae6ebc3caErik            return y;
61640bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
61740bcd101b212c9863c3110c05a487a7ae6ebc3caErik        r.left = x;
61840bcd101b212c9863c3110c05a487a7ae6ebc3caErik        r.right = x + EVENT_SQUARE_WIDTH;
61940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        r.top = y;
62040bcd101b212c9863c3110c05a487a7ae6ebc3caErik        r.bottom = y + EVENT_SQUARE_WIDTH;
621a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        mEventSquarePaint.setColor(event.color);
622a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        Style style = event.selfAttendeeStatus == Attendees.ATTENDEE_STATUS_NONE ? Style.STROKE
623a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik                : Style.FILL_AND_STROKE;
624a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        mEventSquarePaint.setStyle(style);
625a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        canvas.drawRect(r, mEventSquarePaint);
62640bcd101b212c9863c3110c05a487a7ae6ebc3caErik
62740bcd101b212c9863c3110c05a487a7ae6ebc3caErik        int textX = x + EVENT_SQUARE_WIDTH + EVENT_LINE_PADDING;
62840bcd101b212c9863c3110c05a487a7ae6ebc3caErik        int textY = y + mEventHeight - EVENT_LINE_PADDING / 2;
62940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        float avail = rightEdge - textX;
63040bcd101b212c9863c3110c05a487a7ae6ebc3caErik        CharSequence text = TextUtils.ellipsize(
63140bcd101b212c9863c3110c05a487a7ae6ebc3caErik                event.title, mEventPaint, avail, TextUtils.TruncateAt.END);
63240bcd101b212c9863c3110c05a487a7ae6ebc3caErik        canvas.drawText(text.toString(), textX, textY, mEventPaint);
63340bcd101b212c9863c3110c05a487a7ae6ebc3caErik        if (!event.allDay) {
63440bcd101b212c9863c3110c05a487a7ae6ebc3caErik            textY += mEventHeight + EVENT_LINE_PADDING;
63540bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mStringBuilder.setLength(0);
6363f888688c0f2644ad3de032d5d1cf623a7b092fdAndy McFadden            text = DateUtils.formatDateRange(getContext(), mFormatter, event.startMillis,
63740bcd101b212c9863c3110c05a487a7ae6ebc3caErik                    event.endMillis, DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL,
6383f888688c0f2644ad3de032d5d1cf623a7b092fdAndy McFadden                    Utils.getTimeZone(getContext(), null)).toString();
63940bcd101b212c9863c3110c05a487a7ae6ebc3caErik            text = TextUtils.ellipsize(text, mEventExtrasPaint, avail, TextUtils.TruncateAt.END);
64040bcd101b212c9863c3110c05a487a7ae6ebc3caErik            canvas.drawText(text.toString(), textX, textY, mEventExtrasPaint);
64140bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
64240bcd101b212c9863c3110c05a487a7ae6ebc3caErik
64340bcd101b212c9863c3110c05a487a7ae6ebc3caErik        return textY + EVENT_LINE_PADDING;
64440bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
64540bcd101b212c9863c3110c05a487a7ae6ebc3caErik
64640bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected void drawMoreEvents(Canvas canvas, int remainingEvents, int x) {
64740bcd101b212c9863c3110c05a487a7ae6ebc3caErik        int y = mHeight - EVENT_BOTTOM_PADDING + EVENT_LINE_PADDING / 2 - mEventHeight;
648a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        r.left = x;
649a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        r.top = y;
650a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        r.right = x + EVENT_SQUARE_WIDTH;
651a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        r.bottom = y + EVENT_SQUARE_WIDTH;
652a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        mEventSquarePaint.setColor(mMonthEventExtraColor);
653a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        mEventSquarePaint.setStyle(Style.STROKE);
654a8d8ebd77b91ea94f9d680d343ee1c891bec7f5cRoboErik        canvas.drawRect(r, mEventSquarePaint);
655e9cd8f4513c141ca486bbd141f0fe34bb3c27f3aRoboErik        mEventExtrasPaint.setAntiAlias(true);
6563f888688c0f2644ad3de032d5d1cf623a7b092fdAndy McFadden        String text = getContext().getResources().getQuantityString(
65740bcd101b212c9863c3110c05a487a7ae6ebc3caErik                R.plurals.month_more_events, remainingEvents);
65840bcd101b212c9863c3110c05a487a7ae6ebc3caErik        y = mHeight - EVENT_BOTTOM_PADDING;
65940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        x += EVENT_SQUARE_WIDTH + EVENT_LINE_PADDING;
66040bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mEventExtrasPaint.setFakeBoldText(true);
66140bcd101b212c9863c3110c05a487a7ae6ebc3caErik        canvas.drawText(String.format(text, remainingEvents), x, y, mEventExtrasPaint);
66240bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mEventExtrasPaint.setFakeBoldText(false);
66340bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
66440bcd101b212c9863c3110c05a487a7ae6ebc3caErik
66571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson    /**
666092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik     * Draws a line showing busy times in each day of week The method draws
667092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik     * non-conflicting times in the event color and times with conflicting
668092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik     * events in the dna conflict color defined in colors.
66971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson     *
67071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson     * @param canvas
67171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson     */
672092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    protected void drawDNA(Canvas canvas) {
673092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        // Draw event and conflict times
674092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        if (mDna != null) {
675092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            for (Utils.DNAStrand strand : mDna.values()) {
676092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                if (strand.color == CONFLICT_COLOR || strand.points == null
677092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                        || strand.points.length == 0) {
678092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                    continue;
679092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                }
680092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                mDNATimePaint.setColor(strand.color);
681092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                canvas.drawLines(strand.points, mDNATimePaint);
682092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            }
683092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            // Draw black last to make sure it's on top
684092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            Utils.DNAStrand strand = mDna.get(CONFLICT_COLOR);
685092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            if (strand != null && strand.points != null && strand.points.length != 0) {
686092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                mDNATimePaint.setColor(strand.color);
687092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                canvas.drawLines(strand.points, mDNATimePaint);
68871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson            }
689092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            if (mDayXs == null) {
690092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                return;
691092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            }
692092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            int numDays = mDayXs.length;
693092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            int xOffset = (DNA_ALL_DAY_WIDTH - DNA_WIDTH) / 2;
694092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            if (strand != null && strand.allDays != null && strand.allDays.length == numDays) {
695092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                for (int i = 0; i < numDays; i++) {
696092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                    // this adds at most 7 draws. We could sort it by color and
697092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                    // build an array instead but this is easier.
698092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                    if (strand.allDays[i] != 0) {
699092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                        mDNAAllDayPaint.setColor(strand.allDays[i]);
700092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                        canvas.drawLine(mDayXs[i] + xOffset, DNA_MARGIN, mDayXs[i] + xOffset,
701092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                                DNA_MARGIN + DNA_ALL_DAY_HEIGHT, mDNAAllDayPaint);
702092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                    }
703092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik                }
70482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
70582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        }
70682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson    }
70782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
7083553621c824afe1f3eacbe8555678005ca1264a1Erik    @Override
7093553621c824afe1f3eacbe8555678005ca1264a1Erik    protected void updateSelectionPositions() {
7103553621c824afe1f3eacbe8555678005ca1264a1Erik        if (mHasSelectedDay) {
7113553621c824afe1f3eacbe8555678005ca1264a1Erik            int selectedPosition = mSelectedDay - mWeekStart;
7123553621c824afe1f3eacbe8555678005ca1264a1Erik            if (selectedPosition < 0) {
7133553621c824afe1f3eacbe8555678005ca1264a1Erik                selectedPosition += 7;
7143553621c824afe1f3eacbe8555678005ca1264a1Erik            }
7153553621c824afe1f3eacbe8555678005ca1264a1Erik            int effectiveWidth = mWidth - mPadding * 2;
716bf4aa400663a072813c87cf9c8aaee2d07abc945Erik            effectiveWidth -= SPACING_WEEK_NUMBER;
7173553621c824afe1f3eacbe8555678005ca1264a1Erik            mSelectedLeft = selectedPosition * effectiveWidth / mNumDays + mPadding;
7183553621c824afe1f3eacbe8555678005ca1264a1Erik            mSelectedRight = (selectedPosition + 1) * effectiveWidth / mNumDays + mPadding;
719bf4aa400663a072813c87cf9c8aaee2d07abc945Erik            mSelectedLeft += SPACING_WEEK_NUMBER;
720bf4aa400663a072813c87cf9c8aaee2d07abc945Erik            mSelectedRight += SPACING_WEEK_NUMBER;
7213553621c824afe1f3eacbe8555678005ca1264a1Erik        }
7223553621c824afe1f3eacbe8555678005ca1264a1Erik    }
7233553621c824afe1f3eacbe8555678005ca1264a1Erik
7243553621c824afe1f3eacbe8555678005ca1264a1Erik    @Override
7253553621c824afe1f3eacbe8555678005ca1264a1Erik    public Time getDayFromLocation(float x) {
726da532a723613001f1175c067aece5f859d079bfcRoboErik        int dayStart = mShowWeekNum ? SPACING_WEEK_NUMBER + mPadding : mPadding;
7273553621c824afe1f3eacbe8555678005ca1264a1Erik        if (x < dayStart || x > mWidth - mPadding) {
7283553621c824afe1f3eacbe8555678005ca1264a1Erik            return null;
7293553621c824afe1f3eacbe8555678005ca1264a1Erik        }
7303553621c824afe1f3eacbe8555678005ca1264a1Erik        // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels
7313553621c824afe1f3eacbe8555678005ca1264a1Erik        int dayPosition = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding));
7323553621c824afe1f3eacbe8555678005ca1264a1Erik        int day = mFirstJulianDay + dayPosition;
7333553621c824afe1f3eacbe8555678005ca1264a1Erik
7343553621c824afe1f3eacbe8555678005ca1264a1Erik        Time time = new Time(mTimeZone);
7353553621c824afe1f3eacbe8555678005ca1264a1Erik        if (mWeek == 0) {
7363553621c824afe1f3eacbe8555678005ca1264a1Erik            // This week is weird...
7373553621c824afe1f3eacbe8555678005ca1264a1Erik            if (day < Time.EPOCH_JULIAN_DAY) {
7383553621c824afe1f3eacbe8555678005ca1264a1Erik                day++;
7393553621c824afe1f3eacbe8555678005ca1264a1Erik            } else if (day == Time.EPOCH_JULIAN_DAY) {
7403553621c824afe1f3eacbe8555678005ca1264a1Erik                time.set(1, 0, 1970);
7413553621c824afe1f3eacbe8555678005ca1264a1Erik                time.normalize(true);
7423553621c824afe1f3eacbe8555678005ca1264a1Erik                return time;
7433553621c824afe1f3eacbe8555678005ca1264a1Erik            }
7443553621c824afe1f3eacbe8555678005ca1264a1Erik        }
7453553621c824afe1f3eacbe8555678005ca1264a1Erik
7463553621c824afe1f3eacbe8555678005ca1264a1Erik        time.setJulianDay(day);
7473553621c824afe1f3eacbe8555678005ca1264a1Erik        return time;
74882b318634af1b6594e60cfd1f2df4d3845f80587Erik    }
74982b318634af1b6594e60cfd1f2df4d3845f80587Erik
75067f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik    @Override
75167f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik    public boolean onHoverEvent(MotionEvent event) {
752f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErik        Context context = getContext();
753f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErik        // only send accessibility events if accessibility and exploration are
754f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErik        // on.
75593c08b7693d8246305c75dc2416f70321ce9c1a2RoboErik        AccessibilityManager am = (AccessibilityManager) context
75693c08b7693d8246305c75dc2416f70321ce9c1a2RoboErik                .getSystemService(Service.ACCESSIBILITY_SERVICE);
757f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErik        if (!am.isEnabled() || !am.isTouchExplorationEnabled()) {
758f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErik            return super.onHoverEvent(event);
759f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErik        }
76067f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik        if (event.getAction() != MotionEvent.ACTION_HOVER_EXIT) {
76167f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik            Time hover = getDayFromLocation(event.getX());
76267f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik            if (hover != null
76367f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                    && (mLastHoverTime == null || Time.compare(hover, mLastHoverTime) != 0)) {
76467f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                Long millis = hover.toMillis(true);
765f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErik                String date = Utils.formatDateRange(context, millis, millis,
76667f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                        DateUtils.FORMAT_SHOW_DATE);
76767f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                AccessibilityEvent accessEvent = AccessibilityEvent
76867f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                        .obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
76967f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                accessEvent.getText().add(date);
770044a43c3c1789ba93d83ae68d799d94dc4e4ecf2Michael Chan                if (mShowDetailsInMonth && mEvents != null) {
77167f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                    int dayStart = SPACING_WEEK_NUMBER + mPadding;
77267f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                    int dayPosition = (int) ((event.getX() - dayStart) * mNumDays / (mWidth
77367f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                            - dayStart - mPadding));
77467f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                    ArrayList<Event> events = mEvents.get(dayPosition);
77567f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                    List<CharSequence> text = accessEvent.getText();
77667f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                    for (Event e : events) {
77767f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                        text.add(e.getTitleAndLocation() + ". ");
77867f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                        int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
77967f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                        if (!e.allDay) {
78067f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                            flags |= DateUtils.FORMAT_SHOW_TIME;
781f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErik                            if (DateFormat.is24HourFormat(context)) {
78267f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                                flags |= DateUtils.FORMAT_24HOUR;
78367f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                            }
784aeebdbcf782a531bc972078cf05e70f21112ecafRoboErik                        } else {
785aeebdbcf782a531bc972078cf05e70f21112ecafRoboErik                            flags |= DateUtils.FORMAT_UTC;
78667f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                        }
787f9cb58df1deab65ad426d7997fe3e3fdfeef2850RoboErik                        text.add(Utils.formatDateRange(context, e.startMillis, e.endMillis,
78867f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                                flags) + ". ");
78967f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                    }
79067f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                }
79167f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                sendAccessibilityEventUnchecked(accessEvent);
79267f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik                mLastHoverTime = hover;
79367f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik            }
79467f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik        }
79567f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik        return true;
79667f16905cd1efe0fef4e86ff5ddea7069b80b98dRoboErik    }
79782b318634af1b6594e60cfd1f2df4d3845f80587Erik}
798