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; 8242dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik int selfAttendeeStatus; 83bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 84bdbf15078ad5efdf27c021d7aca8c8aa4693878cMichael Chan long id; 8547d40324272ae39af0872bf5cbf27e1800478021Mason Tang long start; 863ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang long end; 873ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang boolean allDay; 88a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa int color; 8947d40324272ae39af0872bf5cbf27e1800478021Mason Tang 90bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang public EventInfo() { 91bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang visibWhen = View.GONE; 92bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang visibWhere = View.GONE; 93bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang visibTitle = View.GONE; 94bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 95bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 96bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang @Override 97bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang public String toString() { 98bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang StringBuilder builder = new StringBuilder(); 99bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append("EventInfo [visibTitle="); 100bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(visibTitle); 101bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", title="); 102bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(title); 103bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", visibWhen="); 104bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(visibWhen); 105bdbf15078ad5efdf27c021d7aca8c8aa4693878cMichael Chan builder.append(", id="); 106bdbf15078ad5efdf27c021d7aca8c8aa4693878cMichael Chan builder.append(id); 107bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", when="); 108bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(when); 109bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", visibWhere="); 110bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(visibWhere); 111bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(", where="); 112bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append(where); 113a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa builder.append(", color="); 114a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa builder.append(String.format("0x%x", color)); 11542dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik builder.append(", selfAttendeeStatus="); 11642dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik builder.append(selfAttendeeStatus); 117bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append("]"); 118bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return builder.toString(); 119bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 120bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 121bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang @Override 122bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang public int hashCode() { 123bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang final int prime = 31; 124bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang int result = 1; 1253ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang result = prime * result + (allDay ? 1231 : 1237); 126bdbf15078ad5efdf27c021d7aca8c8aa4693878cMichael Chan result = prime * result + (int) (id ^ (id >>> 32)); 1273ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang result = prime * result + (int) (end ^ (end >>> 32)); 1283ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang result = prime * result + (int) (start ^ (start >>> 32)); 129bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + ((title == null) ? 0 : title.hashCode()); 130bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + visibTitle; 131bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + visibWhen; 132bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + visibWhere; 133bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + ((when == null) ? 0 : when.hashCode()); 134bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang result = prime * result + ((where == null) ? 0 : where.hashCode()); 135a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa result = prime * result + color; 13642dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik result = prime * result + selfAttendeeStatus; 137bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return result; 138bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 139bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 140bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang @Override 141bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang public boolean equals(Object obj) { 1423ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (this == obj) 143bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return true; 1443ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (obj == null) 145bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1463ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (getClass() != obj.getClass()) 147bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 148bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang EventInfo other = (EventInfo) obj; 149bdbf15078ad5efdf27c021d7aca8c8aa4693878cMichael Chan if (id != other.id) 150bdbf15078ad5efdf27c021d7aca8c8aa4693878cMichael Chan return false; 1513ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (allDay != other.allDay) 1523ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 1533ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (end != other.end) 1543ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 1553ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (start != other.start) 1563ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 157bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang if (title == null) { 1583ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (other.title != null) 159bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1603ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else if (!title.equals(other.title)) 161bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1623ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (visibTitle != other.visibTitle) 163bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1643ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (visibWhen != other.visibWhen) 165bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 1663ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (visibWhere != other.visibWhere) 167bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 168bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang if (when == null) { 1693ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (other.when != null) 170bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 17142dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik } else if (!when.equals(other.when)) { 172bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 17342dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik } 174bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang if (where == null) { 1753ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (other.where != null) 176bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 177a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa } else if (!where.equals(other.where)) { 178bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return false; 17942dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik } 18042dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik if (color != other.color) { 18142dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik return false; 18242dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik } 18342dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik if (selfAttendeeStatus != other.selfAttendeeStatus) { 184a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa return false; 185a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa } 186bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return true; 187bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 1883ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 1893ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 1903ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** 1913ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * {@link DayInfo} is a class that represents a day header in the widget. It 1923ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * contains all of the data necessary to display that day header, including 1933ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * the properly localized string. 1943ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang */ 1953ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang static class DayInfo { 1963ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 1973ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** The Julian day */ 1983ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final int mJulianDay; 1993ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2003ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** The string representation of this day header, to be displayed */ 2013ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final String mDayLabel; 2023ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2033ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang DayInfo(int julianDay, String label) { 2043ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mJulianDay = julianDay; 2053ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mDayLabel = label; 2063ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 2073ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2083ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang @Override 2093ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang public String toString() { 2103ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return mDayLabel; 2113ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 2123ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2133ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang @Override 2143ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang public int hashCode() { 2153ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final int prime = 31; 2163ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang int result = 1; 2173ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang result = prime * result + ((mDayLabel == null) ? 0 : mDayLabel.hashCode()); 2183ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang result = prime * result + mJulianDay; 2193ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return result; 2203ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 2213ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2223ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang @Override 2233ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang public boolean equals(Object obj) { 2243ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (this == obj) 2253ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return true; 2263ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (obj == null) 2273ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 2283ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (getClass() != obj.getClass()) 2293ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 2303ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang DayInfo other = (DayInfo) obj; 2313ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (mDayLabel == null) { 2323ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (other.mDayLabel != null) 2333ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 2343ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else if (!mDayLabel.equals(other.mDayLabel)) 2353ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 2363ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (mJulianDay != other.mJulianDay) 2373ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return false; 2383ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return true; 2393ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 2403ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2413ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 2423ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2433ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final List<RowInfo> mRowInfos; 2443ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final List<EventInfo> mEventInfos; 2453ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final List<DayInfo> mDayInfos; 2463ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final Context mContext; 2473ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final long mNow; 2483ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final int mTodayJulianDay; 2493ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final int mMaxJulianDay; 2503ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 251ece2fbd8c2695910148ffa20fb46a508443fd034Michael Chan public CalendarAppWidgetModel(Context context, String timeZone) { 2523ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mNow = System.currentTimeMillis(); 253ece2fbd8c2695910148ffa20fb46a508443fd034Michael Chan Time time = new Time(timeZone); 2548b71d11235e7ebc02f62435d2c6583edb43c26a2Michael Chan time.setToNow(); // This is needed for gmtoff to be set 255ece2fbd8c2695910148ffa20fb46a508443fd034Michael Chan mTodayJulianDay = Time.getJulianDay(mNow, time.gmtoff); 2563ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mMaxJulianDay = mTodayJulianDay + CalendarAppWidgetService.MAX_DAYS - 1; 2573ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mEventInfos = new ArrayList<EventInfo>(50); 2583ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mRowInfos = new ArrayList<RowInfo>(50); 2593ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mDayInfos = new ArrayList<DayInfo>(8); 2603ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mContext = context; 2613ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 2623ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 26321a183875fbbfa54f5a2a87779888a5fb7d1af44Erik public void buildFromCursor(Cursor cursor, String timeZone) { 264a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final Time recycle = new Time(timeZone); 2653ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang final ArrayList<LinkedList<RowInfo>> mBuckets = 266a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa new ArrayList<LinkedList<RowInfo>>(CalendarAppWidgetService.MAX_DAYS); 2673ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang for (int i = 0; i < CalendarAppWidgetService.MAX_DAYS; i++) { 2683ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang mBuckets.add(new LinkedList<RowInfo>()); 2693ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 27021a183875fbbfa54f5a2a87779888a5fb7d1af44Erik recycle.setToNow(); 27121a183875fbbfa54f5a2a87779888a5fb7d1af44Erik mShowTZ = !TextUtils.equals(timeZone, Time.getCurrentTimezone()); 27221a183875fbbfa54f5a2a87779888a5fb7d1af44Erik if (mShowTZ) { 27321a183875fbbfa54f5a2a87779888a5fb7d1af44Erik mHomeTZName = TimeZone.getTimeZone(timeZone).getDisplayName(recycle.isDst != 0, 27421a183875fbbfa54f5a2a87779888a5fb7d1af44Erik TimeZone.SHORT); 27521a183875fbbfa54f5a2a87779888a5fb7d1af44Erik } 2763ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2773ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang cursor.moveToPosition(-1); 2789da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik String tz = Utils.getTimeZone(mContext, null); 2793ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang while (cursor.moveToNext()) { 280a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final int rowId = cursor.getPosition(); 281a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final long eventId = cursor.getLong(CalendarAppWidgetService.INDEX_EVENT_ID); 282a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final boolean allDay = cursor.getInt(CalendarAppWidgetService.INDEX_ALL_DAY) != 0; 2833ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang long start = cursor.getLong(CalendarAppWidgetService.INDEX_BEGIN); 2843ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang long end = cursor.getLong(CalendarAppWidgetService.INDEX_END); 285a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final String title = cursor.getString(CalendarAppWidgetService.INDEX_TITLE); 286a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final String location = 287a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa cursor.getString(CalendarAppWidgetService.INDEX_EVENT_LOCATION); 2883ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // we don't compute these ourselves because it seems to produce the 2893ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // wrong endDay for all day events 290a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final int startDay = cursor.getInt(CalendarAppWidgetService.INDEX_START_DAY); 291a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final int endDay = cursor.getInt(CalendarAppWidgetService.INDEX_END_DAY); 292a71e0a520493532dbb7e9bfa164ab78e59e797a3Daisuke Miyakawa final int color = cursor.getInt(CalendarAppWidgetService.INDEX_COLOR); 29342dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik final int selfStatus = cursor 29442dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik .getInt(CalendarAppWidgetService.INDEX_SELF_ATTENDEE_STATUS); 2953ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 2963ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // Adjust all-day times into local timezone 2973ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (allDay) { 2989da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik start = Utils.convertAlldayUtcToLocal(recycle, start, tz); 2999da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik end = Utils.convertAlldayUtcToLocal(recycle, end, tz); 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(); 31442dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik mEventInfos.add(populateEventInfo(eventId, allDay, start, end, startDay, endDay, title, 31542dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik location, color, selfStatus)); 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 338bdbf15078ad5efdf27c021d7aca8c8aa4693878cMichael Chan 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 354bdbf15078ad5efdf27c021d7aca8c8aa4693878cMichael Chan private EventInfo populateEventInfo(long eventId, boolean allDay, long start, long end, 35542dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik int startDay, int endDay, String title, String location, int color, int selfStatus) { 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; 36142dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik int flags = DateUtils.FORMAT_ABBREV_ALL; 36242dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik visibWhen = View.VISIBLE; 3633ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (allDay) { 36442dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik flags |= DateUtils.FORMAT_SHOW_DATE; 36542dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik whenString.append(Utils.formatDateRange(mContext, start, end, flags)); 3663ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else { 3673ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang flags |= DateUtils.FORMAT_SHOW_TIME; 3683ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (DateFormat.is24HourFormat(mContext)) { 3693ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang flags |= DateUtils.FORMAT_24HOUR; 3703ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3713ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (endDay > startDay) { 3723ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang flags |= DateUtils.FORMAT_SHOW_DATE; 37321a183875fbbfa54f5a2a87779888a5fb7d1af44Erik } 37477cf2c757257fdb17320be030001b7c8eff8253dDaisuke Miyakawa whenString.append(Utils.formatDateRange(mContext, start, end, flags)); 37577cf2c757257fdb17320be030001b7c8eff8253dDaisuke Miyakawa 37621a183875fbbfa54f5a2a87779888a5fb7d1af44Erik if (mShowTZ) { 37721a183875fbbfa54f5a2a87779888a5fb7d1af44Erik whenString.append(" ").append(mHomeTZName); 3783ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 379bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 380bdbf15078ad5efdf27c021d7aca8c8aa4693878cMichael Chan eventInfo.id = eventId; 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; 38742dabd1e1e89b0d4af5afb776c6ecc53f6ae9fbaRoboErik eventInfo.selfAttendeeStatus = selfStatus; 3883ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 3893ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // What 3903ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (TextUtils.isEmpty(title)) { 3913ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.title = mContext.getString(R.string.no_title_label); 3923ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else { 3933ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.title = title; 3943ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 3953ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.visibTitle = View.VISIBLE; 3963ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 3973ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang // Where 3983ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (!TextUtils.isEmpty(location)) { 3993ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.visibWhere = View.VISIBLE; 4003ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.where = location; 4013ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else { 4023ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang eventInfo.visibWhere = View.GONE; 4033ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 4043ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return eventInfo; 4053ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 4063ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 4073ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang private DayInfo populateDayInfo(int julianDay, Time recycle) { 4083ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang long millis = recycle.setJulianDay(julianDay); 409937b49cfe0d0e715c06c60369e83ec6fec5e74faRoboErik int flags = DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE; 4103ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 4113ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang String label; 4123ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (julianDay == mTodayJulianDay + 1) { 413937b49cfe0d0e715c06c60369e83ec6fec5e74faRoboErik label = mContext.getString(R.string.agenda_tomorrow, 414937b49cfe0d0e715c06c60369e83ec6fec5e74faRoboErik Utils.formatDateRange(mContext, millis, millis, flags).toString()); 4153ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } else { 416937b49cfe0d0e715c06c60369e83ec6fec5e74faRoboErik flags |= DateUtils.FORMAT_SHOW_WEEKDAY; 417ece2fbd8c2695910148ffa20fb46a508443fd034Michael Chan label = Utils.formatDateRange(mContext, millis, millis, flags); 4183ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 4193ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return new DayInfo(julianDay, label); 420bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 421bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang 422bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang @Override 423bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang public String toString() { 424bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang StringBuilder builder = new StringBuilder(); 425bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append("\nCalendarAppWidgetModel [eventInfos="); 4263ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang builder.append(mEventInfos); 427bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang builder.append("]"); 428bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang return builder.toString(); 429bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang } 430bb3f08abac01e3083d837e5e823b311e3c039e90Mason Tang}