CalendarAppWidgetModel.java revision 77cf2c757257fdb17320be030001b7c8eff8253d
1bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang/* 2bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * Copyright (C) 2010 The Android Open Source Project 3bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * 4bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * Licensed under the Apache License, Version 2.0 (the "License"); 5bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * you may not use this file except in compliance with the License. 6bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * You may obtain a copy of the License at 7bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * 8bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * http://www.apache.org/licenses/LICENSE-2.0 9bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * 10bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * Unless required by applicable law or agreed to in writing, software 11bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * distributed under the License is distributed on an "AS IS" BASIS, 12bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * See the License for the specific language governing permissions and 14bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang * limitations under the License. 15bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang */ 16bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 179a3cb14e28536e4133dddbe952f47189fe344ec1Mason Tangpackage com.android.calendar.widget; 18bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 1921a183875fbbfa54f5a2a87779888a5fb7d1af44Erikimport com.android.calendar.R; 2021a183875fbbfa54f5a2a87779888a5fb7d1af44Erikimport com.android.calendar.Utils; 2121a183875fbbfa54f5a2a87779888a5fb7d1af44Erik 223ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport android.content.Context; 233ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport android.database.Cursor; 243ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport android.text.TextUtils; 253ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport android.text.format.DateFormat; 263ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport android.text.format.DateUtils; 273ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport android.text.format.Time; 283ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport android.util.Log; 29bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tangimport android.view.View; 30bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 313ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport java.util.ArrayList; 323ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport java.util.LinkedList; 333ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport java.util.List; 343ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport java.util.TimeZone; 35bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 36bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tangclass CalendarAppWidgetModel { 373ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang private static final String TAG = CalendarAppWidgetModel.class.getSimpleName(); 383ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang private static final boolean LOGD = false; 393ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 4021a183875fbbfa54f5a2a87779888a5fb7d1af44Erik private String mHomeTZName; 4121a183875fbbfa54f5a2a87779888a5fb7d1af44Erik private boolean mShowTZ; 423ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** 433ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * {@link RowInfo} is a class that represents a single row in the widget. It 443ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * is actually only a pointer to either a {@link DayInfo} or an 453ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * {@link EventInfo} instance, since a row in the widget might be either a 463ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * day header or an event. 47bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang */ 483ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang static class RowInfo { 493ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang static final int TYPE_DAY = 0; 503ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang static final int TYPE_MEETING = 1; 513ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 523ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** 533ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * mType is either a day header (TYPE_DAY) or an event (TYPE_MEETING) 543ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang */ 553ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final int mType; 563ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 573ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** 583ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * If mType is TYPE_DAY, then mData is the index into day infos. 593ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * Otherwise mType is TYPE_MEETING and mData is the index into event 603ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * infos. 613ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang */ 623ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final int mIndex; 63bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 643ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang RowInfo(int type, int index) { 653ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mType = type; 663ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mIndex = index; 67bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 68bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 69bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 703ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** 713ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * {@link EventInfo} is a class that represents an event in the widget. It 723ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * contains all of the data necessary to display that event, including the 733ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * properly localized strings and visibility settings. 743ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang */ 753ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang static class EventInfo { 76bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang int visibWhen; // Visibility value for When textview (View.GONE or View.VISIBLE) 77bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang String when; 78bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang int visibWhere; // Visibility value for Where textview (View.GONE or View.VISIBLE) 79bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang String where; 80bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang int visibTitle; // Visibility value for Title textview (View.GONE or View.VISIBLE) 81bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang String title; 82bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 8347d40324272ae39af0872bf5cbf27e1800478021Mason Tang long start; 843ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang long end; 853ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang boolean allDay; 86a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa int color; 8747d40324272ae39af0872bf5cbf27e1800478021Mason Tang 88bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang public EventInfo() { 89bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang visibWhen = View.GONE; 90bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang visibWhere = View.GONE; 91bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang visibTitle = View.GONE; 92bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 93bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 94bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang @Override 95bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang public String toString() { 96bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang StringBuilder builder = new StringBuilder(); 97bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append("EventInfo [visibTitle="); 98bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(visibTitle); 99bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", title="); 100bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(title); 101bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", visibWhen="); 102bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(visibWhen); 103bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", when="); 104bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(when); 105bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", visibWhere="); 106bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(visibWhere); 107bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", where="); 108bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(where); 109a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa builder.append(", color="); 110a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa builder.append(String.format("0x%x", color)); 111bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append("]"); 112bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return builder.toString(); 113bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 114bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 115bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang @Override 116bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang public int hashCode() { 117bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang final int prime = 31; 118bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang int result = 1; 1193ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang result = prime * result + (allDay ? 1231 : 1237); 1203ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang result = prime * result + (int) (end ^ (end >>> 32)); 1213ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang result = prime * result + (int) (start ^ (start >>> 32)); 122bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + ((title == null) ? 0 : title.hashCode()); 123bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + visibTitle; 124bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + visibWhen; 125bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + visibWhere; 126bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + ((when == null) ? 0 : when.hashCode()); 127bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + ((where == null) ? 0 : where.hashCode()); 128a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa result = prime * result + color; 129bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return result; 130bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 131bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 132bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang @Override 133bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang public boolean equals(Object obj) { 1343ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (this == obj) 135bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return true; 1363ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (obj == null) 137bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1383ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (getClass() != obj.getClass()) 139bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 140bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang EventInfo other = (EventInfo) obj; 1413ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (allDay != other.allDay) 1423ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 1433ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (end != other.end) 1443ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 1453ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (start != other.start) 1463ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 147bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang if (title == null) { 1483ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (other.title != null) 149bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1503ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else if (!title.equals(other.title)) 151bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1523ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (visibTitle != other.visibTitle) 153bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1543ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (visibWhen != other.visibWhen) 155bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1563ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (visibWhere != other.visibWhere) 157bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 158bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang if (when == null) { 1593ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (other.when != null) 160bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1613ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else if (!when.equals(other.when)) 162bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 163bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang if (where == null) { 1643ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (other.where != null) 165bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 166a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa } else if (!where.equals(other.where)) { 167bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 168a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa } else if (color != other.color) { 169a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa return false; 170a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa } 171bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return true; 172bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 1733ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 1743ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 1753ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** 1763ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * {@link DayInfo} is a class that represents a day header in the widget. It 1773ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * contains all of the data necessary to display that day header, including 1783ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * the properly localized string. 1793ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang */ 1803ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang static class DayInfo { 1813ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 1823ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** The Julian day */ 1833ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final int mJulianDay; 1843ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 1853ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** The string representation of this day header, to be displayed */ 1863ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final String mDayLabel; 1873ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 1883ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang DayInfo(int julianDay, String label) { 1893ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mJulianDay = julianDay; 1903ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mDayLabel = label; 1913ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 1923ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 1933ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang @Override 1943ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang public String toString() { 1953ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return mDayLabel; 1963ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 1973ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 1983ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang @Override 1993ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang public int hashCode() { 2003ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final int prime = 31; 2013ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang int result = 1; 2023ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang result = prime * result + ((mDayLabel == null) ? 0 : mDayLabel.hashCode()); 2033ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang result = prime * result + mJulianDay; 2043ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return result; 2053ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 2063ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2073ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang @Override 2083ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang public boolean equals(Object obj) { 2093ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (this == obj) 2103ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return true; 2113ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (obj == null) 2123ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 2133ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (getClass() != obj.getClass()) 2143ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 2153ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang DayInfo other = (DayInfo) obj; 2163ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (mDayLabel == null) { 2173ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (other.mDayLabel != null) 2183ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 2193ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else if (!mDayLabel.equals(other.mDayLabel)) 2203ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 2213ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (mJulianDay != other.mJulianDay) 2223ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 2233ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return true; 2243ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 2253ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2263ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 2273ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2283ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang String mDayOfWeek; 2293ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang String mDayOfMonth; 2303ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final List<RowInfo> mRowInfos; 2313ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final List<EventInfo> mEventInfos; 2323ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final List<DayInfo> mDayInfos; 2333ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final Context mContext; 2343ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final long mNow; 2353ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final long mStartOfNextDay; 2363ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final int mTodayJulianDay; 2373ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final int mMaxJulianDay; 2383ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2393ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang public CalendarAppWidgetModel(Context context) { 2403ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mNow = System.currentTimeMillis(); 2413ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang Time time = new Time(); 2423ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang time.set(mNow); 2433ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang time.monthDay++; 2443ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang time.hour = 0; 2453ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang time.minute = 0; 2463ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang time.second = 0; 2473ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mStartOfNextDay = time.normalize(true); 2483ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2493ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang long localOffset = TimeZone.getDefault().getOffset(mNow) / 1000; 2503ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mTodayJulianDay = Time.getJulianDay(mNow, localOffset); 2513ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mMaxJulianDay = mTodayJulianDay + CalendarAppWidgetService.MAX_DAYS - 1; 2523ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2533ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // Calendar header 2543ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang String dayOfWeek = DateUtils.getDayOfWeekString( 2553ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang time.weekDay + 1, DateUtils.LENGTH_MEDIUM).toUpperCase(); 2563ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2573ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mDayOfWeek = dayOfWeek; 2583ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mDayOfMonth = Integer.toString(time.monthDay); 2593ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2603ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mEventInfos = new ArrayList<EventInfo>(50); 2613ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mRowInfos = new ArrayList<RowInfo>(50); 2623ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mDayInfos = new ArrayList<DayInfo>(8); 2633ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mContext = context; 2643ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 2653ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 26621a183875fbbfa54f5a2a87779888a5fb7d1af44Erik public void buildFromCursor(Cursor cursor, String timeZone) { 267a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final Time recycle = new Time(timeZone); 2683ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final ArrayList<LinkedList<RowInfo>> mBuckets = 269a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa new ArrayList<LinkedList<RowInfo>>(CalendarAppWidgetService.MAX_DAYS); 2703ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang for (int i = 0; i < CalendarAppWidgetService.MAX_DAYS; i++) { 2713ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mBuckets.add(new LinkedList<RowInfo>()); 2723ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 27321a183875fbbfa54f5a2a87779888a5fb7d1af44Erik recycle.setToNow(); 27421a183875fbbfa54f5a2a87779888a5fb7d1af44Erik mShowTZ = !TextUtils.equals(timeZone, Time.getCurrentTimezone()); 27521a183875fbbfa54f5a2a87779888a5fb7d1af44Erik if (mShowTZ) { 27621a183875fbbfa54f5a2a87779888a5fb7d1af44Erik mHomeTZName = TimeZone.getTimeZone(timeZone).getDisplayName(recycle.isDst != 0, 27721a183875fbbfa54f5a2a87779888a5fb7d1af44Erik TimeZone.SHORT); 27821a183875fbbfa54f5a2a87779888a5fb7d1af44Erik } 2793ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2803ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang cursor.moveToPosition(-1); 2813ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang while (cursor.moveToNext()) { 282a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final int rowId = cursor.getPosition(); 283a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final long eventId = cursor.getLong(CalendarAppWidgetService.INDEX_EVENT_ID); 284a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final boolean allDay = cursor.getInt(CalendarAppWidgetService.INDEX_ALL_DAY) != 0; 2853ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang long start = cursor.getLong(CalendarAppWidgetService.INDEX_BEGIN); 2863ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang long end = cursor.getLong(CalendarAppWidgetService.INDEX_END); 287a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final String title = cursor.getString(CalendarAppWidgetService.INDEX_TITLE); 288a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final String location = 289a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa cursor.getString(CalendarAppWidgetService.INDEX_EVENT_LOCATION); 2903ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // we don't compute these ourselves because it seems to produce the 2913ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // wrong endDay for all day events 292a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final int startDay = cursor.getInt(CalendarAppWidgetService.INDEX_START_DAY); 293a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final int endDay = cursor.getInt(CalendarAppWidgetService.INDEX_END_DAY); 294a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final int color = cursor.getInt(CalendarAppWidgetService.INDEX_COLOR); 2953ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2963ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // Adjust all-day times into local timezone 2973ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (allDay) { 2983ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang start = Utils.convertUtcToLocal(recycle, start); 2993ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang end = Utils.convertUtcToLocal(recycle, end); 3003ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 301bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 3023ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (LOGD) { 3033ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang Log.d(TAG, "Row #" + rowId + " allDay:" + allDay + " start:" + start 3043ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang + " end:" + end + " eventId:" + eventId); 3053ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3063ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 3073ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // we might get some extra events when querying, in order to 3083ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // deal with all-day events 3093ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (end < mNow) { 3103ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang continue; 3113ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3123ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 3133ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang int i = mEventInfos.size(); 3143ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mEventInfos.add(populateEventInfo( 315a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa allDay, start, end, startDay, endDay, title, location, color)); 3163ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // populate the day buckets that this event falls into 3173ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang int from = Math.max(startDay, mTodayJulianDay); 3183ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang int to = Math.min(endDay, mMaxJulianDay); 3193ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang for (int day = from; day <= to; day++) { 3203ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang LinkedList<RowInfo> bucket = mBuckets.get(day - mTodayJulianDay); 3213ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang RowInfo rowInfo = new RowInfo(RowInfo.TYPE_MEETING, i); 3223ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (allDay) { 3233ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang bucket.addFirst(rowInfo); 3243ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else { 3253ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang bucket.add(rowInfo); 3263ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3273ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3283ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3293ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 3303ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang int day = mTodayJulianDay; 3313ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang int count = 0; 3323ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang for (LinkedList<RowInfo> bucket : mBuckets) { 3333ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (!bucket.isEmpty()) { 33450088e364aaa3074476e1300a270aafb0653df47Daisuke Miyakawa // We don't show day header in today 33550088e364aaa3074476e1300a270aafb0653df47Daisuke Miyakawa if (day != mTodayJulianDay) { 33650088e364aaa3074476e1300a270aafb0653df47Daisuke Miyakawa final DayInfo dayInfo = populateDayInfo(day, recycle); 33750088e364aaa3074476e1300a270aafb0653df47Daisuke Miyakawa // Add the day header 33850088e364aaa3074476e1300a270aafb0653df47Daisuke Miyakawa final int dayIndex = mDayInfos.size(); 33950088e364aaa3074476e1300a270aafb0653df47Daisuke Miyakawa mDayInfos.add(dayInfo); 34050088e364aaa3074476e1300a270aafb0653df47Daisuke Miyakawa mRowInfos.add(new RowInfo(RowInfo.TYPE_DAY, dayIndex)); 34150088e364aaa3074476e1300a270aafb0653df47Daisuke Miyakawa } 34250088e364aaa3074476e1300a270aafb0653df47Daisuke Miyakawa 3433ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // Add the event row infos 3443ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mRowInfos.addAll(bucket); 3453ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang count += bucket.size(); 3463ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3473ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang day++; 3483ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (count >= CalendarAppWidgetService.EVENT_MIN_COUNT) { 3493ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang break; 3503ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3513ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3523ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3533ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 3543ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang private EventInfo populateEventInfo(boolean allDay, long start, long end, 355a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa int startDay, int endDay, String title, String location, int color) { 3563ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang EventInfo eventInfo = new EventInfo(); 3573ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 3583ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // Compute a human-readable string for the start time of the event 35921a183875fbbfa54f5a2a87779888a5fb7d1af44Erik StringBuilder whenString = new StringBuilder(); 3603ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang int visibWhen; 3613ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (allDay) { 36221a183875fbbfa54f5a2a87779888a5fb7d1af44Erik whenString.setLength(0); 3633ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang visibWhen = View.GONE; 3643ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else { 3653ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang int flags = DateUtils.FORMAT_ABBREV_ALL; 3663ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang flags |= DateUtils.FORMAT_SHOW_TIME; 3673ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (DateFormat.is24HourFormat(mContext)) { 3683ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang flags |= DateUtils.FORMAT_24HOUR; 3693ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3703ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (endDay > startDay) { 3713ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang flags |= DateUtils.FORMAT_SHOW_DATE; 37221a183875fbbfa54f5a2a87779888a5fb7d1af44Erik } 37377cf2c757257fdb17320be030001b7c8eff8253dDaisuke Miyakawa whenString.append(Utils.formatDateRange(mContext, start, end, flags)); 37477cf2c757257fdb17320be030001b7c8eff8253dDaisuke Miyakawa 37521a183875fbbfa54f5a2a87779888a5fb7d1af44Erik String tz = Utils.getTimeZone(mContext, null); 37621a183875fbbfa54f5a2a87779888a5fb7d1af44Erik if (mShowTZ) { 37721a183875fbbfa54f5a2a87779888a5fb7d1af44Erik whenString.append(" ").append(mHomeTZName); 3783ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3793ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang visibWhen = View.VISIBLE; 380bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 3813ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.start = start; 3823ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.end = end; 3833ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.allDay = allDay; 38421a183875fbbfa54f5a2a87779888a5fb7d1af44Erik eventInfo.when = whenString.toString(); 3853ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.visibWhen = visibWhen; 386a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa eventInfo.color = color; 3873ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 3883ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // What 3893ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (TextUtils.isEmpty(title)) { 3903ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.title = mContext.getString(R.string.no_title_label); 3913ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else { 3923ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.title = title; 3933ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3943ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.visibTitle = View.VISIBLE; 3953ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 3963ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // Where 3973ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (!TextUtils.isEmpty(location)) { 3983ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.visibWhere = View.VISIBLE; 3993ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.where = location; 4003ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else { 4013ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.visibWhere = View.GONE; 4023ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 4033ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return eventInfo; 4043ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 4053ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 4063ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang private DayInfo populateDayInfo(int julianDay, Time recycle) { 4073ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang long millis = recycle.setJulianDay(julianDay); 4083ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang int flags = DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_UTC; 4093ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang flags |= DateUtils.FORMAT_SHOW_WEEKDAY; 4103ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 4113ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang String label; 4123ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (julianDay == mTodayJulianDay + 1) { 4133ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang label = mContext.getString(R.string.tomorrow); 4143ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else { 4153ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang label = DateUtils.formatDateRange(mContext, millis, millis, flags); 4163ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 4173ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 4183ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang flags = DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_UTC; 4193ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang flags |= DateUtils.FORMAT_SHOW_DATE; 4203ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 4213ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang label += ", "; 4223ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang label += DateUtils.formatDateRange(mContext, millis, millis, flags); 4233ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 4243ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return new DayInfo(julianDay, label); 425bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 426bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 427bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang @Override 428bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang public String toString() { 429bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang StringBuilder builder = new StringBuilder(); 430bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append("\nCalendarAppWidgetModel [eventInfos="); 4313ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang builder.append(mEventInfos); 432bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", dayOfMonth="); 4333ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang builder.append(mDayOfMonth); 434bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", dayOfWeek="); 4353ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang builder.append(mDayOfWeek); 436bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append("]"); 437bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return builder.toString(); 438bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 439bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang}