public static void ScheduleDayBeforeAlarm(Context context, AccountDataItem account, DateTime today, AgendaViewItemsGroup agendaItems)
        {
            if (agendaItems == null)
            {
                return;
            }

            DateTime dayBeforeReminderTime = RemindersExtension.GetDayBeforeReminderTime(today, account, agendaItems);

            DateTime timeToScheduleAt;

            // If we haven't reached that time yet for "due tomorrow"
            if (dayBeforeReminderTime > DateTime.Now)
            {
                timeToScheduleAt = dayBeforeReminderTime.AddMilliseconds(1);
            }

            // Otherwise we'll need to set the timer for the "due today"
            else
            {
                timeToScheduleAt = today.AddDays(1).AddMilliseconds(1);
            }

            AlarmManagerHelper.Schedule(
                context: context,
                receiverType: typeof(UpdateDayBeforeNotificationReceiver),
                wakeTime: timeToScheduleAt,
                uriData: "powerplanner:?localAccountId=" + account.LocalAccountId,
                wakeDevice: true);
        }
            private async System.Threading.Tasks.Task InitializeDataAsync()
            {
                List <object> items = null;

                _now = DateTime.Now;
                bool hasAccount  = false;
                bool hasSemester = false;
                List <ViewItemSchedule> schedulesToday = new List <ViewItemSchedule>();

                try
                {
                    await System.Threading.Tasks.Task.Run(async delegate
                    {
                        var account = await AccountsManager.GetLastLogin();

                        if (account != null)
                        {
                            _localAccountId = account.LocalAccountId;
                            hasAccount      = true;

                            const int DAYS_INCLUDING_TODAY = 7;
                            var scheduleTileData           = await ScheduleTileDataHelper.LoadAsync(account, _now.Date, DAYS_INCLUDING_TODAY);

                            if (scheduleTileData.HasSemester)
                            {
                                hasSemester = true;

                                items = new List <object>();

                                foreach (var dayData in scheduleTileData.GetDataForAllDays())
                                {
                                    if (dayData.Holidays.Any())
                                    {
                                        // If we already displayed these holidays, skip subsequent duplicate days
                                        if (items.Count >= dayData.Holidays.Length && items.TakeLast(dayData.Holidays.Length).SequenceEqual(dayData.Holidays))
                                        {
                                            // Skip
                                        }
                                        else
                                        {
                                            // If not today
                                            if (!dayData.IsToday)
                                            {
                                                // We add the date header only for non-today
                                                items.Add(dayData.Date);
                                            }

                                            items.AddRange(dayData.Holidays);
                                        }
                                    }

                                    else if (dayData.Schedules.Any())
                                    {
                                        // If not today
                                        if (!dayData.IsToday)
                                        {
                                            // If there's currently no items
                                            if (items.Count == 0)
                                            {
                                                // Add the text saying no class today!
                                                items.Add(PowerPlannerResources.GetString("String_NoClassToday"));
                                            }

                                            // We add the date header only for non-today
                                            items.Add(dayData.Date);
                                        }

                                        // If today
                                        if (dayData.IsToday)
                                        {
                                            foreach (var s in dayData.Schedules)
                                            {
                                                if (s.EndTime.TimeOfDay > _now.TimeOfDay)
                                                {
                                                    items.Add(s);
                                                    schedulesToday.Add(s);
                                                }
                                            }

                                            if (items.Count == 0)
                                            {
                                                items.Add(PowerPlannerResources.GetString("String_NoMoreClasses"));
                                            }
                                        }
                                        else
                                        {
                                            items.AddRange(dayData.Schedules);
                                        }
                                    }
                                }
                            }
                        }
                    });

                    if (items == null || items.Count == 0)
                    {
                        if (hasSemester)
                        {
                            items = new List <object>()
                            {
                                PowerPlannerResources.GetString("String_NoClassesThisWeek")
                            };
                        }
                        else if (hasAccount)
                        {
                            items = new List <object>()
                            {
                                PowerPlannerResources.GetString("String_NoSemester")
                            };
                        }
                        else
                        {
                            items = new List <object>()
                            {
                                PowerPlannerResources.GetString("String_NoAccount")
                            };
                        }
                    }

                    _items = items;
                }
                catch (Exception ex)
                {
                    TelemetryExtension.Current?.TrackException(ex);
                }

                // Schedule next
                try
                {
                    DateTime nextChangeTime = _now.Date.AddDays(1);
                    if (schedulesToday.Count > 0)
                    {
                        nextChangeTime = _now.Date.Add(schedulesToday.First().EndTime.TimeOfDay);
                    }

                    AlarmManagerHelper.Schedule(
                        context: _context,
                        receiverType: typeof(UpdateWidgetScheduleReceiver),
                        wakeTime: nextChangeTime);
                }
                catch (Exception ex)
                {
                    TelemetryExtension.Current?.TrackException(ex);
                }
            }
        private static async Task UpdateAndScheduleDayOfNotifications(AccountDataItem account, AgendaViewItemsGroup agendaItems, Context context, NotificationManager notificationManager, DateTime now, bool fromForeground)
        {
            string tagForAccountStartsWith = account.LocalAccountId.ToString();
            List <StatusBarNotification> existingNotifs;

            if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.M)
            {
                existingNotifs = notificationManager.GetActiveNotifications().Where(i => i.Id == NotificationIds.DAY_OF_NOTIFICATIONS && i.Tag != null && i.Tag.StartsWith(tagForAccountStartsWith)).ToList();
            }
            else
            {
                // GetActiveNotifications didn't exist before version 23
                existingNotifs = new List <StatusBarNotification>();
            }

            // If no current semester, or no items, then just clear
            if (agendaItems == null || agendaItems.Items.Count == 0)
            {
                foreach (var notif in existingNotifs)
                {
                    notificationManager.Cancel(notif.Tag, NotificationIds.DAY_OF_NOTIFICATIONS);
                }
                return;
            }

            DateTime nextReminderTime;

            var itemsThatCouldHaveNotifs = GetItemsThatCouldHaveDayOfNotifications(account, agendaItems, now, out nextReminderTime);

            // Remove ones that don't exist anymore
            for (int i = 0; i < existingNotifs.Count; i++)
            {
                var  existing = existingNotifs[i];
                Guid identifier;
                if (TryGetItemIdFromDayOfTag(existing.Tag, out identifier))
                {
                    if (!itemsThatCouldHaveNotifs.Any(x => x.Item1.Identifier == identifier))
                    {
                        notificationManager.Cancel(existing.Tag, NotificationIds.DAY_OF_NOTIFICATIONS);
                        existingNotifs.RemoveAt(i);
                        i--;
                    }
                }
            }

            foreach (var item in itemsThatCouldHaveNotifs)
            {
                UpdateDayOfNotification(account.LocalAccountId, item.Item1, item.Item2, context, notificationManager, existingNotifs, fromForeground);
            }

            // Need to mark them as sent
            Guid[] newlySentHomeworkReminders = itemsThatCouldHaveNotifs.Select(i => i.Item1).OfType <ViewItemHomework>().Where(i => !i.HasSentReminder).Select(i => i.Identifier).ToArray();
            Guid[] newlySentExamReminders     = itemsThatCouldHaveNotifs.Select(i => i.Item1).OfType <ViewItemExam>().Where(i => !i.HasSentReminder).Select(i => i.Identifier).ToArray();

            if (newlySentHomeworkReminders.Length > 0 || newlySentExamReminders.Length > 0)
            {
                var dataStore = await AccountDataStore.Get(account.LocalAccountId);

                if (dataStore != null)
                {
                    await dataStore.MarkAndroidRemindersSent(newlySentHomeworkReminders, newlySentExamReminders);
                }
            }

            // Schedule the next alarm
            if (nextReminderTime > now)
            {
                AlarmManagerHelper.Schedule(
                    context: context,
                    receiverType: typeof(UpdateDayOfNotificationsReceiver),
                    wakeTime: nextReminderTime,
                    uriData: "powerplanner:?localAccountId=" + account.LocalAccountId,
                    wakeDevice: true);
            }
        }
            private async System.Threading.Tasks.Task InitializeDataAsync()
            {
                List <object> items = null;
                List <BaseViewItemHomeworkExam> tasks = null;

                _now = DateTime.Now;
                bool hasAccount           = false;
                bool isDisabledInSettings = false;
                bool hasSemester          = false;

                try
                {
                    await System.Threading.Tasks.Task.Run(async delegate
                    {
                        var account = await AccountsManager.GetLastLogin();

                        AccountDataStore data = null;

                        if (account != null)
                        {
                            data = await AccountDataStore.Get(account.LocalAccountId);
                        }

                        if (data != null)
                        {
                            hasAccount = true;

                            isDisabledInSettings = account.MainTileSettings.IsDisabled();

                            if (!isDisabledInSettings)
                            {
                                _localAccountId    = account.LocalAccountId;
                                var currSemesterId = account.CurrentSemesterId;
                                if (currSemesterId != Guid.Empty)
                                {
                                    ScheduleViewItemsGroup scheduleViewGroup;
                                    try
                                    {
                                        scheduleViewGroup = await ScheduleViewItemsGroup.LoadAsync(account.LocalAccountId, account.CurrentSemesterId, trackChanges: true, includeWeightCategories: false);
                                    }
                                    catch
                                    {
                                        // If semester not found
                                        scheduleViewGroup = null;
                                    }

                                    if (scheduleViewGroup != null)
                                    {
                                        DateTime dateToStartDisplayingFrom = DateTime.SpecifyKind(account.MainTileSettings.GetDateToStartDisplayingOn(_now.Date), DateTimeKind.Utc);

                                        // We don't track changes since we need a fresh version that has been filtered right now.
                                        // Otherwise when we update for an event expiring, if we have a cached version, that event wouldn't have expired!
                                        var agendaViewGroup = await AgendaViewItemsGroup.LoadAsync(account.LocalAccountId, scheduleViewGroup.Semester, _now.Date, trackChanges: false);
                                        hasSemester         = true;

                                        // We lock the outside, since we are allowing trackChanges on the view items groups (so we have a chance of loading a cached one)... and since we're on a background thread, the lists inside the
                                        // view items groups could change while we're enumerating, hence throwing an exception. So we lock it to ensure this won't happen, and then we return a copy of the items that we need.
                                        using (await agendaViewGroup.DataChangeLock.LockForReadAsync())
                                        {
                                            var filtered = agendaViewGroup.Items
                                                           .Where(i => i.Date.Date >= dateToStartDisplayingFrom);

                                            if (!account.MainTileSettings.ShowHomework)
                                            {
                                                filtered = filtered.Where(i => !(i is ViewItemHomework));
                                            }

                                            if (!account.MainTileSettings.ShowExams)
                                            {
                                                filtered = filtered.Where(i => !(i is ViewItemExam));
                                            }

                                            // Agenda view group doesn't sort, so we have to sort it
                                            tasks = filtered
                                                    .OrderBy(i => i)
                                                    .Take(20)
                                                    .ToList();

                                            // Add date headers
                                            items = new List <object>();
                                            DateTime lastHeader = DateTime.MinValue;
                                            foreach (var t in tasks)
                                            {
                                                if (lastHeader != t.Date.Date)
                                                {
                                                    items.Add(t.Date.Date);
                                                    lastHeader = t.Date.Date;
                                                }

                                                items.Add(t);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    });

                    if (items == null || items.Count == 0)
                    {
                        if (hasSemester)
                        {
                            items = new List <object>()
                            {
                                PowerPlannerResources.GetString("String_NothingDue")
                            };
                        }
                        else if (isDisabledInSettings)
                        {
                            items = new List <object>()
                            {
                                PowerPlannerResources.GetString("String_WidgetDisabled")
                            };
                        }
                        else if (hasAccount)
                        {
                            items = new List <object>()
                            {
                                PowerPlannerResources.GetString("String_NoSemester")
                            };
                        }
                        else
                        {
                            items = new List <object>()
                            {
                                PowerPlannerResources.GetString("String_NoAccount")
                            };
                        }
                    }

                    _items = items;
                }
                catch (Exception ex)
                {
                    TelemetryExtension.Current?.TrackException(ex);
                }

                // Schedule next
                try
                {
                    if (tasks != null && tasks.Count > 0)
                    {
                        DateTime?nextChangeTime = GetNextAgendaChangeTime(tasks, _now);
                        if (nextChangeTime != null)
                        {
                            AlarmManagerHelper.Schedule(
                                context: _context,
                                receiverType: typeof(UpdateWidgetAgendaReceiver),
                                wakeTime: nextChangeTime.Value);
                        }
                    }
                }
                catch (Exception ex)
                {
                    TelemetryExtension.Current?.TrackException(ex);
                }
            }