1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
|
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_TIME_CALENDAR_MODEL_H_
#define ASH_SYSTEM_TIME_CALENDAR_MODEL_H_
#include <deque>
#include <list>
#include <map>
#include <memory>
#include <set>
#include "ash/ash_export.h"
#include "ash/public/cpp/session/session_observer.h"
#include "ash/system/time/calendar_event_fetch.h"
#include "ash/system/time/calendar_event_fetch_types.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "google_apis/calendar/calendar_api_response_types.h"
#include "google_apis/common/api_error_codes.h"
namespace ash {
class CalendarEventFetch;
// A simple std::list of calendar events, used to store a single day's events
// in EventMap. Not to be confused with google_apis::calendar::EventList,
// which represents the return value of a query from the GoogleCalendar API.
using SingleDayEventList = std::list<google_apis::calendar::CalendarEvent>;
// Controller of the `CalendarView`.
class ASH_EXPORT CalendarModel : public SessionObserver {
public:
// `kNa` is used to represent the fetching status when on the non-logged-in
// screens. If `kNa` is returned, the loading bar won't be shown since events
// are not being fetched.
// `kRefetching` is used to represent the fetching status when there're cached
// events for a month but another fetching request has been sent. In this
// case, the event indicator dots and the tooltip will show the cached events.
// `kNever` is used as the default state when we experience an error or
// timeout or haven't fetched anything.
enum FetchingStatus { kNever, kFetching, kRefetching, kSuccess, kError, kNa };
CalendarModel();
CalendarModel(const CalendarModel& other) = delete;
CalendarModel& operator=(const CalendarModel& other) = delete;
~CalendarModel() override;
// SessionObserver:
void OnSessionStateChanged(session_manager::SessionState state) override;
void OnActiveUserSessionChanged(const AccountId& account_id) override;
// Maps a day, i.e. midnight on the day of the event's start_time, to a
// SingleDayEventList.
using SingleMonthEventMap = std::map<base::Time, SingleDayEventList>;
// Maps a month, i.e. midnight on the first day of the month, to a
// SingleMonthEventMap.
using MonthToEventsMap = std::map<base::Time, SingleMonthEventMap>;
class Observer : public base::CheckedObserver {
public:
// Invoked when a month of events has been fetched.
virtual void OnEventsFetched(const FetchingStatus status,
const base::Time start_time) {}
};
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Completely, unconditionally clears out any cached events. Intended for when
// we log out or switch users.
void ClearAllCachedEvents();
// Clears out all events that start in a non-prunable month.
void ClearAllPrunableEvents();
// Returns true if the event storage for a given month is populated with at
// least one event.
bool MonthHasEvents(const base::Time start_of_month);
// Logs to UMA all event fetch metrics recorded over the lifetime of a
// calendar session.
void UploadLifetimeMetrics();
// Adds `month` to the set of non-prunable months.
void AddNonPrunableMonth(const base::Time& month);
// Adds every month in `months` to the set of non-prunable months.
void AddNonPrunableMonths(const std::set<base::Time>& months);
// Requests events for the month starting at `start_of_month` if there is not
// currently a calendar list fetch in progress.
void MaybeFetchEvents(base::Time start_of_month);
// Requests events for the month starting at `start_of_month`. If there is no
// calendar list, or Multi-Calendar is disabled, only primary calendar events
// are fetched.
void FetchEvents(base::Time start_of_month);
// Requests events for the month starting at `start_of_month` for the primary
// calendar.
void FetchPrimaryCalendarEvents(const base::Time start_of_month);
// Cancels any pending event fetch for `start_of_month`.
void CancelFetch(const base::Time& start_of_month);
// Gets the number of events of the passed in day.
int EventsNumberOfDay(base::Time day, SingleDayEventList* events);
// Finds the event list of the given day, with no impact on our MRU list. Use
// this if you don't care about making the month in which `day` resides less
// likely to be pruned if we need to trim down to stay within storage limits.
SingleDayEventList FindEvents(base::Time day) const;
// Uses the `FindEvents` method to get events for that day and then filters
// the result into two lists of multi-day and same day events.
std::tuple<SingleDayEventList, SingleDayEventList>
FindEventsSplitByMultiDayAndSameDay(base::Time day) const;
// Uses the `FindEvents` method to get events for that day and then filters
// the result into events that start or end in the next two hours.
std::list<google_apis::calendar::CalendarEvent> FindUpcomingEvents(
base::Time now_local) const;
// Checks the `FetchingStatus` of a given start time.
FetchingStatus FindFetchingStatus(base::Time start_time);
// Redistributes all the fetched events to the date map with the
// time difference. This method is only called when there's a timezone change.
void RedistributeEvents();
private:
// For unit tests.
friend class CalendarModelTest;
friend class CalendarMonthViewFetchTest;
friend class CalendarMonthViewTest;
friend class CalendarUpNextViewAnimationTest;
friend class CalendarUpNextViewPixelTest;
friend class CalendarUpNextViewTest;
friend class CalendarViewPixelTest;
friend class CalendarViewAnimationTest;
friend class CalendarViewEventListViewFetchTest;
friend class CalendarViewEventListViewTest;
friend class CalendarViewTest;
friend class CalendarViewWithUpNextViewAnimationTest;
friend class CalendarViewWithUpNextViewTest;
// Checks if the event has allowed statuses and is eligible for insertion.
bool ShouldInsertEvent(
const google_apis::calendar::CalendarEvent* event) const;
// Inserts a single `event` that spans more than one day in the EventCache.
void InsertMultiDayEvent(const google_apis::calendar::CalendarEvent* event,
const base::Time start_of_month);
// Finds or creates a new SingleMonthEventMap to then insert the `event` into
// an event list of that month.
void InsertEventInMonth(const google_apis::calendar::CalendarEvent* event,
const base::Time start_of_month,
const base::Time start_time_midnight);
// Inserts a single `event` in a SingleDayEventList of a SingleMonthEventMap.
void InsertEventInMonthEventList(
SingleMonthEventMap& month,
const google_apis::calendar::CalendarEvent* event,
const base::Time start_time_midnight);
// Frees up months of events as needed to keep us within storage limits.
void PruneEventCache();
// Moves this month to the top of our queue that's ordered from
// most-recently-used to least-recently-used.
void PromoteMonth(base::Time start_of_month);
// Based on error(s) received during a month's fetch(es), notify observers.
void NotifyObservers(base::Time start_of_month);
// Actual callback invoked when an event fetch is complete.
void OnEventsFetched(base::Time start_of_month,
std::string calendar_id,
google_apis::ApiErrorCode error,
const google_apis::calendar::EventList* events);
// Callback invoked when an event fetch failed with an internal error.
void OnEventFetchFailedInternalError(
base::Time start_of_month,
std::string calendar_id,
CalendarEventFetchInternalErrorCode error);
// Internal storage for fetched events, with each fetched month having a
// map of days to events.
MonthToEventsMap event_months_;
// Months whose events we've fetched, in most-recently-used (MRU) order.
std::deque<base::Time> mru_months_;
// Set of months that are not prunable.
std::set<base::Time> non_prunable_months_;
// Set of months we've already fetched.
std::set<base::Time> months_fetched_;
// All fetch requests that are still in-progress. Maps each start of month
// timestamp to a map linking each calendar ID to a CalendarEventFetch
// object.
std::map<base::Time,
std::map<std::string, std::unique_ptr<CalendarEventFetch>>>
pending_fetches_;
// Maps a month to a set of error codes returned by the month's event
// fetches.
std::map<base::Time, std::set<google_apis::ApiErrorCode>> fetch_error_codes_;
// Timestamp of the start of the first event fetch created, for use in
// duration metrics when Multi-Calendar is enabled.
base::TimeTicks fetches_start_time_;
// Maps a non-prunable month to an indicator that equals true if new event
// fetches for the month have completed successfully.
std::map<base::Time, bool> events_have_fetched_;
ScopedSessionObserver session_observer_;
base::ObserverList<Observer> observers_;
base::WeakPtrFactory<CalendarModel> weak_factory_{this};
};
} // namespace ash
#endif // ASH_SYSTEM_TIME_CALENDAR_MODEL_H_
|