diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2021-06-26 02:01:44 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-06-26 02:01:44 +0000 |
commit | 63162818c9f1b965122382ce22f6238be6b81531 (patch) | |
tree | 9e2a0181c9ab3dd02c4a14d491a621a692361f89 | |
parent | a31c76485b924cacf9c63b3763874257f8a276b4 (diff) | |
parent | af3d93fb1ce9ce0aa2d34cf15ea33e43a08dbd30 (diff) | |
download | Calendar-63162818c9f1b965122382ce22f6238be6b81531.tar.gz |
Merge changes from topic "CalendarAppWidgetModel"
* changes:
AOSP/Calendar - CalendarAppWidgetModel fully converted with bp file
AOSP/Calendar - Copy of CalendarAppWidgetModel.java
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | src/com/android/calendar/widget/CalendarAppWidgetModel.kt | 409 |
2 files changed, 410 insertions, 0 deletions
@@ -27,6 +27,7 @@ exclude_srcsd = [ "src/**/calendar/alerts/InitAlarmsService.java", "src/**/calendar/alerts/NotificationMgr.java", "src/**/calendar/alerts/QuickResponseActivity.java", + "src/**/calendar/widget/CalendarAppWidgetModel.java", "src/**/calendar/CalendarController.java", "src/**/calendar/DayOfMonthDrawable.java", "src/**/calendar/Event.java", diff --git a/src/com/android/calendar/widget/CalendarAppWidgetModel.kt b/src/com/android/calendar/widget/CalendarAppWidgetModel.kt new file mode 100644 index 00000000..440d178b --- /dev/null +++ b/src/com/android/calendar/widget/CalendarAppWidgetModel.kt @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.calendar.widget + +import com.android.calendar.R +import com.android.calendar.Utils +import android.content.Context +import android.database.Cursor +import android.text.TextUtils +import android.text.format.DateFormat +import android.text.format.DateUtils +import android.text.format.Time +import android.util.Log +import android.view.View +import java.util.ArrayList +import java.util.LinkedList +import java.util.TimeZone + +internal class CalendarAppWidgetModel(context: Context, timeZone: String?) { + private var mHomeTZName: String? = null + private var mShowTZ = false + + /** + * [RowInfo] is a class that represents a single row in the widget. It + * is actually only a pointer to either a [DayInfo] or an + * [EventInfo] instance, since a row in the widget might be either a + * day header or an event. + */ + internal class RowInfo( + /** + * mType is either a day header (TYPE_DAY) or an event (TYPE_MEETING) + */ + @JvmField val mType: Int, + /** + * If mType is TYPE_DAY, then mData is the index into day infos. + * Otherwise mType is TYPE_MEETING and mData is the index into event + * infos. + */ + @JvmField val mIndex: Int + ) { + companion object { + const val TYPE_DAY = 0 + const val TYPE_MEETING = 1 + } + } + + /** + * [EventInfo] is a class that represents an event in the widget. It + * contains all of the data necessary to display that event, including the + * properly localized strings and visibility settings. + */ + internal class EventInfo { + // Visibility value for When textview (View.GONE or View.VISIBLE) + @JvmField var visibWhen: Int + @JvmField var `when`: String? = null + // Visibility value for Where textview (View.GONE or View.VISIBLE) + @JvmField var visibWhere: Int + @JvmField var where: String? = null + // Visibility value for Title textview (View.GONE or View.VISIBLE) + @JvmField var visibTitle: Int + @JvmField var title: String? = null + @JvmField var selfAttendeeStatus = 0 + @JvmField var id: Long = 0 + @JvmField var start: Long = 0 + @JvmField var end: Long = 0 + @JvmField var allDay = false + @JvmField var color = 0 + + @Override + override fun toString(): String { + val builder = StringBuilder() + builder.append("EventInfo [visibTitle=") + builder.append(visibTitle) + builder.append(", title=") + builder.append(title) + builder.append(", visibWhen=") + builder.append(visibWhen) + builder.append(", id=") + builder.append(id) + builder.append(", when=") + builder.append(`when`) + builder.append(", visibWhere=") + builder.append(visibWhere) + builder.append(", where=") + builder.append(where) + builder.append(", color=") + builder.append(String.format("0x%x", color)) + builder.append(", selfAttendeeStatus=") + builder.append(selfAttendeeStatus) + builder.append("]") + return builder.toString() + } + + @Override + override fun hashCode(): Int { + val prime = 31 + var result = 1 + result = prime * result + if (allDay) 1231 else 1237 + result = prime * result + (id xor (id ushr 32)).toInt() + result = prime * result + (end xor (end ushr 32)).toInt() + result = prime * result + (start xor (start ushr 32)).toInt() + result = prime * result + if (title == null) 0 else title!!.hashCode() + result = prime * result + visibTitle + result = prime * result + visibWhen + result = prime * result + visibWhere + result = prime * result + if (`when` == null) 0 else `when`!!.hashCode() + result = prime * result + if (where == null) 0 else where!!.hashCode() + result = prime * result + color + result = prime * result + selfAttendeeStatus + return result + } + + @Override + override fun equals(obj: Any?): Boolean { + if (this == obj) return true + if (obj == null) return false + if (this::class != obj::class) return false + val other = obj as EventInfo + if (id != other.id) return false + if (allDay != other.allDay) return false + if (end != other.end) return false + if (start != other.start) return false + if (title == null) { + if (other.title != null) return false + } else if (!title!!.equals(other.title)) return false + if (visibTitle != other.visibTitle) return false + if (visibWhen != other.visibWhen) return false + if (visibWhere != other.visibWhere) return false + if (`when` == null) { + if (other.`when` != null) return false + } else if (!`when`!!.equals(other.`when`)) { + return false + } + if (where == null) { + if (other.where != null) return false + } else if (!where!!.equals(other.where)) { + return false + } + if (color != other.color) { + return false + } + return if (selfAttendeeStatus != other.selfAttendeeStatus) { + false + } else true + } + + init { + visibWhen = View.GONE + visibWhere = View.GONE + visibTitle = View.GONE + } + } + + /** + * [DayInfo] is a class that represents a day header in the widget. It + * contains all of the data necessary to display that day header, including + * the properly localized string. + */ + internal class DayInfo( + /** The Julian day */ + @JvmField var mJulianDay: Int, + /** The string representation of this day header, to be displayed */ + @JvmField var mDayLabel: String? = null + ) { + @Override + override fun toString(): String { + return mDayLabel as String + } + + @Override + override fun hashCode(): Int { + val prime = 31 + var result = 1 + result = prime * result + (mDayLabel?.hashCode() ?: 0) + result = prime * result + mJulianDay + return result + } + + @Override + override fun equals(obj: Any?): Boolean { + if (this == obj) return true + if (obj == null) return false + if (this::class !== obj::class) return false + val other = obj as DayInfo + if (mDayLabel == null) { + if (other.mDayLabel != null) return false + } else if (!mDayLabel.equals(other.mDayLabel)) return false + return if (mJulianDay != other.mJulianDay) false else true + } + } + + @JvmField val mRowInfos: ArrayList<RowInfo> + @JvmField val mEventInfos: ArrayList<EventInfo> + @JvmField val mDayInfos: ArrayList<DayInfo> + @JvmField val mContext: Context? + @JvmField val mNow: Long + @JvmField val mTodayJulianDay: Int + @JvmField val mMaxJulianDay: Int + fun buildFromCursor(cursor: Cursor, timeZone: String?) { + val recycle = Time(timeZone) + val mBuckets: ArrayList<LinkedList<RowInfo>> = + ArrayList<LinkedList<RowInfo>>(CalendarAppWidgetService.MAX_DAYS) + for (i in 0 until CalendarAppWidgetService.MAX_DAYS) { + mBuckets.add(LinkedList<RowInfo>()) + } + recycle.setToNow() + mShowTZ = !TextUtils.equals(timeZone, Time.getCurrentTimezone()) + if (mShowTZ) { + mHomeTZName = TimeZone.getTimeZone(timeZone).getDisplayName( + recycle.isDst !== 0, + TimeZone.SHORT + ) + } + cursor.moveToPosition(-1) + val tz = Utils.getTimeZone(mContext, null) + while (cursor.moveToNext()) { + val rowId: Int = cursor.getPosition() + val eventId: Long = cursor.getLong(CalendarAppWidgetService.INDEX_EVENT_ID) + val allDay = cursor.getInt(CalendarAppWidgetService.INDEX_ALL_DAY) !== 0 + var start: Long = cursor.getLong(CalendarAppWidgetService.INDEX_BEGIN) + var end: Long = cursor.getLong(CalendarAppWidgetService.INDEX_END) + val title: String = cursor.getString(CalendarAppWidgetService.INDEX_TITLE) + val location: String = cursor.getString(CalendarAppWidgetService.INDEX_EVENT_LOCATION) + // we don't compute these ourselves because it seems to produce the + // wrong endDay for all day events + val startDay: Int = cursor.getInt(CalendarAppWidgetService.INDEX_START_DAY) + val endDay: Int = cursor.getInt(CalendarAppWidgetService.INDEX_END_DAY) + val color: Int = cursor.getInt(CalendarAppWidgetService.INDEX_COLOR) + val selfStatus: Int = cursor + .getInt(CalendarAppWidgetService.INDEX_SELF_ATTENDEE_STATUS) + + // Adjust all-day times into local timezone + if (allDay) { + start = Utils.convertAlldayUtcToLocal(recycle, start, tz as String) + end = Utils.convertAlldayUtcToLocal(recycle, end, tz as String) + } + if (LOGD) { + Log.d( + TAG, "Row #" + rowId + " allDay:" + allDay + " start:" + start + + " end:" + end + " eventId:" + eventId + ) + } + + // we might get some extra events when querying, in order to + // deal with all-day events + if (end < mNow) { + continue + } + val i: Int = mEventInfos.size + mEventInfos.add( + populateEventInfo( + eventId, allDay, start, end, startDay, endDay, title, + location, color, selfStatus + ) + ) + // populate the day buckets that this event falls into + val from: Int = Math.max(startDay, mTodayJulianDay) + val to: Int = Math.min(endDay, mMaxJulianDay) + for (day in from..to) { + val bucket: LinkedList<RowInfo> = mBuckets.get(day - mTodayJulianDay) + val rowInfo = RowInfo(RowInfo.TYPE_MEETING, i) + if (allDay) { + bucket.addFirst(rowInfo) + } else { + bucket.add(rowInfo) + } + } + } + var day = mTodayJulianDay + var count = 0 + for (bucket in mBuckets) { + if (!bucket.isEmpty()) { + // We don't show day header in today + if (day != mTodayJulianDay) { + val dayInfo = populateDayInfo(day, recycle) + // Add the day header + val dayIndex: Int = mDayInfos.size + mDayInfos.add(dayInfo as CalendarAppWidgetModel.DayInfo) + mRowInfos.add(RowInfo(RowInfo.TYPE_DAY, dayIndex)) + } + + // Add the event row infos + mRowInfos.addAll(bucket) + count += bucket.size + } + day++ + if (count >= CalendarAppWidgetService.EVENT_MIN_COUNT) { + break + } + } + } + + private fun populateEventInfo( + eventId: Long, + allDay: Boolean, + start: Long, + end: Long, + startDay: Int, + endDay: Int, + title: String, + location: String, + color: Int, + selfStatus: Int + ): EventInfo { + val eventInfo = EventInfo() + + // Compute a human-readable string for the start time of the event + val whenString = StringBuilder() + val visibWhen: Int + var flags: Int = DateUtils.FORMAT_ABBREV_ALL + visibWhen = View.VISIBLE + if (allDay) { + flags = flags or DateUtils.FORMAT_SHOW_DATE + whenString.append(Utils.formatDateRange(mContext, start, end, flags)) + } else { + flags = flags or DateUtils.FORMAT_SHOW_TIME + if (DateFormat.is24HourFormat(mContext)) { + flags = flags or DateUtils.FORMAT_24HOUR + } + if (endDay > startDay) { + flags = flags or DateUtils.FORMAT_SHOW_DATE + } + whenString.append(Utils.formatDateRange(mContext, start, end, flags)) + if (mShowTZ) { + whenString.append(" ").append(mHomeTZName) + } + } + eventInfo.id = eventId + eventInfo.start = start + eventInfo.end = end + eventInfo.allDay = allDay + eventInfo.`when` = whenString.toString() + eventInfo.visibWhen = visibWhen + eventInfo.color = color + eventInfo.selfAttendeeStatus = selfStatus + + // What + if (TextUtils.isEmpty(title)) { + eventInfo.title = mContext?.getString(R.string.no_title_label) + } else { + eventInfo.title = title + } + eventInfo.visibTitle = View.VISIBLE + + // Where + if (!TextUtils.isEmpty(location)) { + eventInfo.visibWhere = View.VISIBLE + eventInfo.where = location + } else { + eventInfo.visibWhere = View.GONE + } + return eventInfo + } + + private fun populateDayInfo(julianDay: Int, recycle: Time?): DayInfo? { + val millis: Long = recycle?.setJulianDay(julianDay) as Long + var flags: Int = DateUtils.FORMAT_ABBREV_ALL or DateUtils.FORMAT_SHOW_DATE + val label: String? + if (julianDay == mTodayJulianDay + 1) { + label = mContext?.getString( + R.string.agenda_tomorrow, + Utils.formatDateRange(mContext, millis, millis, flags).toString() + ) + } else { + flags = flags or DateUtils.FORMAT_SHOW_WEEKDAY + label = Utils.formatDateRange(mContext, millis, millis, flags) + } + return DayInfo(julianDay, label as String) + } + + @Override + override fun toString(): String { + val builder = StringBuilder() + builder.append("\nCalendarAppWidgetModel [eventInfos=") + builder.append(mEventInfos) + builder.append("]") + return builder.toString() + } + + companion object { + private val TAG: String = CalendarAppWidgetModel::class.java.getSimpleName() + private const val LOGD = false + } + + init { + mNow = System.currentTimeMillis() + val time = Time(timeZone) + time.setToNow() // This is needed for gmtoff to be set + mTodayJulianDay = Time.getJulianDay(mNow, time.gmtoff) + mMaxJulianDay = mTodayJulianDay + CalendarAppWidgetService.MAX_DAYS - 1 + mEventInfos = ArrayList<EventInfo>(50) + mRowInfos = ArrayList<RowInfo>(50) + mDayInfos = ArrayList<DayInfo>(8) + mContext = context + } +}
\ No newline at end of file |