/** * Schedules alarms for a single task * * @param shouldPerformPropertyCheck whether to check if task has requisite properties */ private void scheduleAlarm(Task task, boolean shouldPerformPropertyCheck) { if (task == null || !task.isSaved()) return; // read data if necessary if (shouldPerformPropertyCheck) { for (Property<?> property : NOTIFICATION_PROPERTIES) { if (!task.containsValue(property)) { task = taskDao.fetch(task.getId(), NOTIFICATION_PROPERTIES); if (task == null) return; break; } } } // Make sure no alarms are scheduled other than the next one. When that one is shown, it // will schedule the next one after it, and so on and so forth. clearAllAlarms(task); if (task.isCompleted() || task.isDeleted() || !Task.USER_ID_SELF.equals(task.getValue(Task.USER_ID))) { return; } // snooze reminder long whenSnooze = calculateNextSnoozeReminder(task); // random reminders long whenRandom = calculateNextRandomReminder(task); // notifications at due date long whenDueDate = calculateNextDueDateReminder(task); // notifications after due date long whenOverdue = calculateNextOverdueReminder(task); // For alarms around/before now, increment the now value so the next one will be later if (whenDueDate <= now || whenOverdue <= now) { whenDueDate = now; whenOverdue = now; now += 30 * DateUtilities.ONE_MINUTE; // Prevents overdue tasks from being scheduled all at once } // if random reminders are too close to due date, favor due date if (whenRandom != NO_ALARM && whenDueDate - whenRandom < DateUtilities.ONE_DAY) whenRandom = NO_ALARM; // snooze trumps all if (whenSnooze != NO_ALARM) { scheduler.createAlarm(task, whenSnooze, TYPE_SNOOZE); } else if (whenRandom < whenDueDate && whenRandom < whenOverdue) { scheduler.createAlarm(task, whenRandom, TYPE_RANDOM); } else if (whenDueDate < whenOverdue) { scheduler.createAlarm(task, whenDueDate, TYPE_DUE); } else if (whenOverdue != NO_ALARM) { scheduler.createAlarm(task, whenOverdue, TYPE_OVERDUE); } else { scheduler.createAlarm(task, 0, 0); } }
private void write(GtasksTaskContainer task) throws IOException { // merge astrid dates with google dates if (!task.task.isSaved() && actFmPreferenceService.isLoggedIn()) titleMatchWithActFm(task.task); if (task.task.isSaved()) { Task local = PluginServices.getTaskService() .fetchById(task.task.getId(), Task.DUE_DATE, Task.COMPLETION_DATE); if (local == null) { task.task.clearValue(Task.ID); } else { mergeDates(task.task, local); if (task.task.isCompleted() && !local.isCompleted()) StatisticsService.reportEvent(StatisticsConstants.GTASKS_TASK_COMPLETED); } } else { // Set default importance and reminders for remotely created tasks task.task.setValue( Task.IMPORTANCE, Preferences.getIntegerFromString( R.string.p_default_importance_key, Task.IMPORTANCE_SHOULD_DO)); TaskDao.setDefaultReminders(task.task); } if (!TextUtils.isEmpty(task.task.getValue(Task.TITLE))) { task.task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true); gtasksMetadataService.saveTaskAndMetadata(task); } }
/** * Show a new notification about the given task. Returns false if there was some sort of error or * the alarm should be disabled. */ public boolean showTaskNotification(long id, int type, String reminder) { Task task; try { task = taskDao.fetch( id, Task.ID, Task.TITLE, Task.HIDE_UNTIL, Task.COMPLETION_DATE, Task.DUE_DATE, Task.DELETION_DATE, Task.REMINDER_FLAGS); if (task == null) throw new IllegalArgumentException("cound not find item with id"); // $NON-NLS-1$ } catch (Exception e) { exceptionService.reportError("show-notif", e); // $NON-NLS-1$ return false; } // you're done - don't sound, do delete if (task.isCompleted() || task.isDeleted()) return false; // it's hidden - don't sound, don't delete if (task.isHidden() && type == ReminderService.TYPE_RANDOM) return true; // task due date was changed, but alarm wasn't rescheduled if ((type == ReminderService.TYPE_DUE || type == ReminderService.TYPE_OVERDUE) && (!task.hasDueDate() || task.getValue(Task.DUE_DATE) > DateUtilities.now())) return true; // read properties String taskTitle = task.getValue(Task.TITLE); boolean nonstopMode = task.getFlag(Task.REMINDER_FLAGS, Task.NOTIFY_MODE_NONSTOP); boolean ringFiveMode = task.getFlag(Task.REMINDER_FLAGS, Task.NOTIFY_MODE_FIVE); int ringTimes = nonstopMode ? -1 : (ringFiveMode ? 5 : 1); // update last reminder time task.setValue(Task.REMINDER_LAST, DateUtilities.now()); taskDao.saveExisting(task); Context context = ContextManager.getContext(); String title = context.getString(R.string.app_name); String text = reminder + " " + taskTitle; // $NON-NLS-1$ Intent notifyIntent = new Intent(context, NotificationActivity.class); notifyIntent.setAction("NOTIFY" + id); // $NON-NLS-1$ notifyIntent.putExtra(NotificationActivity.TOKEN_ID, id); notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); showNotification((int) id, notifyIntent, type, title, text, ringTimes); return true; }
@Override public void onReceive(Context context, Intent intent) { ContextManager.setContext(context); DependencyInjectionService.getInstance().inject(this); long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1); if (taskId == -1) return; Task task = PluginServices.getTaskService().fetchById(taskId, Task.PROPERTIES); if (task == null || !task.isCompleted()) return; String recurrence = task.getValue(Task.RECURRENCE); if (recurrence != null && recurrence.length() > 0) { long newDueDate; try { newDueDate = computeNextDueDate(task, recurrence); if (newDueDate == -1) return; } catch (ParseException e) { PluginServices.getExceptionService().reportError("repeat-parse", e); // $NON-NLS-1$ return; } StatisticsService.reportEvent(StatisticsConstants.V2_TASK_REPEAT); long oldDueDate = task.getValue(Task.DUE_DATE); long repeatUntil = task.getValue(Task.REPEAT_UNTIL); boolean repeatFinished = repeatUntil > 0 && newDueDate >= repeatUntil; if (repeatFinished) { Intent repeatFinishedIntent = new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_REPEAT_FINISHED); repeatFinishedIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId()); repeatFinishedIntent.putExtra(AstridApiConstants.EXTRAS_OLD_DUE_DATE, oldDueDate); repeatFinishedIntent.putExtra(AstridApiConstants.EXTRAS_NEW_DUE_DATE, newDueDate); context.sendOrderedBroadcast(repeatFinishedIntent, null); return; } rescheduleTask(task, newDueDate); // send a broadcast Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_REPEATED); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId()); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_OLD_DUE_DATE, oldDueDate); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_NEW_DUE_DATE, newDueDate); context.sendOrderedBroadcast(broadcastIntent, null); Flags.set(Flags.REFRESH); return; } }
@Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1); if (taskId == -1) { return; } Task task = taskService.fetchById(taskId, Task.PROPERTIES); if (task == null || !task.isCompleted()) { return; } String recurrence = task.sanitizedRecurrence(); boolean repeatAfterCompletion = task.repeatAfterCompletion(); if (recurrence != null && recurrence.length() > 0) { long newDueDate; try { newDueDate = computeNextDueDate(task, recurrence, repeatAfterCompletion); if (newDueDate == -1) { return; } } catch (ParseException e) { log.error(e.getMessage(), e); return; } long oldDueDate = task.getDueDate(); long repeatUntil = task.getRepeatUntil(); if (repeatFinished(newDueDate, repeatUntil)) { return; } rescheduleTask(context, gcalHelper, taskService, task, newDueDate); // send a broadcast Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_REPEATED); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId()); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_OLD_DUE_DATE, oldDueDate); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_NEW_DUE_DATE, newDueDate); context.sendOrderedBroadcast(broadcastIntent, null); Flags.set(Flags.REFRESH); } }
public RemoteViews buildUpdate(int position) { try { Task task = getTask(position); String textContent; Resources r = context.getResources(); int textColor = r.getColor(dark ? R.color.widget_text_color_dark : R.color.widget_text_color_light); textContent = task.getTitle(); RemoteViews row = new RemoteViews(Constants.PACKAGE, R.layout.widget_row); if (task.isCompleted()) { textColor = r.getColor(R.color.task_list_done); row.setInt(R.id.text, "setPaintFlags", Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); } else { row.setInt(R.id.text, "setPaintFlags", Paint.ANTI_ALIAS_FLAG); if (task.hasDueDate() && task.isOverdue()) { textColor = r.getColor(R.color.task_list_overdue); } } row.setTextViewText(R.id.text, textContent); row.setTextColor(R.id.text, textColor); row.setImageViewResource(R.id.completeBox, getCheckbox(task)); Intent editIntent = new Intent(); editIntent.setAction(TasksWidget.EDIT_TASK); editIntent.putExtra(TaskEditFragment.TOKEN_ID, task.getId()); editIntent.putExtra(TaskListActivity.OPEN_TASK, task.getId()); row.setOnClickFillInIntent(R.id.text, editIntent); Intent completeIntent = new Intent(); completeIntent.setAction(TasksWidget.COMPLETE_TASK); completeIntent.putExtra(TaskEditFragment.TOKEN_ID, task.getId()); row.setOnClickFillInIntent(R.id.completeBox, completeIntent); return row; } catch (Exception e) { // can happen if database is not ready Log.e("WIDGET-UPDATE", "Error updating widget", e); } return null; }
/** * Called after the task is saved. This differs from the call in TaskApiDao in that it runs hooks * that need to be run from within Astrid. Order matters here! */ public static void afterSave(Task task, ContentValues values) { if (values == null) return; task.markSaved(); if (values.containsKey(Task.COMPLETION_DATE.name) && task.isCompleted()) afterComplete(task, values); else { if (values.containsKey(Task.DUE_DATE.name) || values.containsKey(Task.REMINDER_FLAGS.name) || values.containsKey(Task.REMINDER_PERIOD.name) || values.containsKey(Task.REMINDER_LAST.name) || values.containsKey(Task.REMINDER_SNOOZE.name)) ReminderService.getInstance().scheduleAlarm(task); } // run api save hooks TaskApiDao.afterSave(task, values); }
private int getCheckbox(Task task) { boolean completed = task.isCompleted(); int value = task.getImportance(); if (value >= TaskAdapter.IMPORTANCE_RESOURCES.length) { value = TaskAdapter.IMPORTANCE_RESOURCES.length - 1; } int[] boxes; if (!TextUtils.isEmpty(task.getRecurrence())) { boxes = completed ? TaskAdapter.IMPORTANCE_REPEAT_RESOURCES_CHECKED : TaskAdapter.IMPORTANCE_REPEAT_RESOURCES; } else { boxes = completed ? TaskAdapter.IMPORTANCE_RESOURCES_CHECKED : TaskAdapter.IMPORTANCE_RESOURCES; } return boxes[value]; }
/** Synchronize with server when data changes */ public void pushTaskOnSave(Task task, ContentValues values, GtasksInvoker invoker, boolean sleep) throws IOException { if (sleep) AndroidUtilities.sleepDeep(1000L); // Wait for metadata to be saved Metadata gtasksMetadata = gtasksMetadataService.getTaskMetadata(task.getId()); com.google.api.services.tasks.model.Task remoteModel = null; boolean newlyCreated = false; String remoteId = null; String listId = Preferences.getStringValue(GtasksPreferenceService.PREF_DEFAULT_LIST); if (listId == null) { com.google.api.services.tasks.model.TaskList defaultList = invoker.getGtaskList(DEFAULT_LIST); if (defaultList != null) { listId = defaultList.getId(); Preferences.setString(GtasksPreferenceService.PREF_DEFAULT_LIST, listId); } else { listId = DEFAULT_LIST; } } if (gtasksMetadata == null || !gtasksMetadata.containsNonNullValue(GtasksMetadata.ID) || TextUtils.isEmpty(gtasksMetadata.getValue(GtasksMetadata.ID))) { // Create case if (gtasksMetadata == null) { gtasksMetadata = GtasksMetadata.createEmptyMetadata(task.getId()); } if (gtasksMetadata.containsNonNullValue(GtasksMetadata.LIST_ID)) { listId = gtasksMetadata.getValue(GtasksMetadata.LIST_ID); } remoteModel = new com.google.api.services.tasks.model.Task(); newlyCreated = true; } else { // update case remoteId = gtasksMetadata.getValue(GtasksMetadata.ID); listId = gtasksMetadata.getValue(GtasksMetadata.LIST_ID); remoteModel = new com.google.api.services.tasks.model.Task(); remoteModel.setId(remoteId); } // If task was newly created but without a title, don't sync--we're in the middle of // creating a task which may end up being cancelled if (newlyCreated && (!values.containsKey(Task.TITLE.name) || TextUtils.isEmpty(task.getValue(Task.TITLE)))) { return; } // Update the remote model's changed properties if (values.containsKey(Task.DELETION_DATE.name) && task.isDeleted()) { remoteModel.setDeleted(true); } if (values.containsKey(Task.TITLE.name)) { remoteModel.setTitle(task.getValue(Task.TITLE)); } if (values.containsKey(Task.NOTES.name)) { remoteModel.setNotes(task.getValue(Task.NOTES)); } if (values.containsKey(Task.DUE_DATE.name) && task.hasDueDate()) { remoteModel.setDue(GtasksApiUtilities.unixTimeToGtasksDueDate(task.getValue(Task.DUE_DATE))); } if (values.containsKey(Task.COMPLETION_DATE.name)) { if (task.isCompleted()) { remoteModel.setCompleted( GtasksApiUtilities.unixTimeToGtasksCompletionTime(task.getValue(Task.COMPLETION_DATE))); remoteModel.setStatus("completed"); // $NON-NLS-1$ } else { remoteModel.setCompleted(null); remoteModel.setStatus("needsAction"); // $NON-NLS-1$ } } if (!newlyCreated) { invoker.updateGtask(listId, remoteModel); } else { String parent = gtasksMetadataService.getRemoteParentId(gtasksMetadata); String priorSibling = gtasksMetadataService.getRemoteSiblingId(listId, gtasksMetadata); CreateRequest create = new CreateRequest(invoker, listId, remoteModel, parent, priorSibling); com.google.api.services.tasks.model.Task created = create.executePush(); if (created != null) { // Update the metadata for the newly created task gtasksMetadata.setValue(GtasksMetadata.ID, created.getId()); gtasksMetadata.setValue(GtasksMetadata.LIST_ID, listId); } else return; } task.setValue(Task.MODIFICATION_DATE, DateUtilities.now()); gtasksMetadata.setValue(GtasksMetadata.LAST_SYNC, DateUtilities.now() + 1000L); metadataService.save(gtasksMetadata); task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true); taskDao.saveExistingWithSqlConstraintCheck(task); }
@SuppressWarnings("nls") public RemoteViews buildUpdate(Context context, int widgetId) { DependencyInjectionService.getInstance().inject(this); RemoteViews views = null; views = new RemoteViews(context.getPackageName(), R.layout.widget_initialized); int[] textIDs = TEXT_IDS; int[] separatorIDs = SEPARATOR_IDS; int numberOfTasks = 5; for (int i = 0; i < textIDs.length; i++) views.setTextViewText(textIDs[i], ""); TodorooCursor<Task> cursor = null; Filter filter = null; try { filter = getFilter(widgetId); views.setTextViewText(R.id.widget_title, filter.title); SharedPreferences publicPrefs = AstridPreferences.getPublicPrefs(this); int flags = publicPrefs.getInt(SortHelper.PREF_SORT_FLAGS, 0); int sort = publicPrefs.getInt(SortHelper.PREF_SORT_SORT, 0); String query = SortHelper.adjustQueryForFlagsAndSort(filter.sqlQuery, flags, sort) .replaceAll("LIMIT \\d+", "") + " LIMIT " + numberOfTasks; database.openForReading(); cursor = taskService.fetchFiltered( query, null, Task.ID, Task.TITLE, Task.DUE_DATE, Task.COMPLETION_DATE); Task task = new Task(); for (int i = 0; i < cursor.getCount() && i < numberOfTasks; i++) { cursor.moveToPosition(i); task.readFromCursor(cursor); String textContent = ""; int textColor = Color.WHITE; textContent = task.getValue(Task.TITLE); if (task.isCompleted()) textColor = context.getResources().getColor(R.color.task_list_done); else if (task.hasDueDate() && task.getValue(Task.DUE_DATE) < DateUtilities.now()) textColor = context.getResources().getColor(R.color.task_list_overdue); if (i > 0) views.setViewVisibility(separatorIDs[i - 1], View.VISIBLE); views.setTextViewText(textIDs[i], textContent); views.setTextColor(textIDs[i], textColor); } for (int i = cursor.getCount() - 1; i < separatorIDs.length; i++) { if (i >= 0) views.setViewVisibility(separatorIDs[i], View.INVISIBLE); } } catch (Exception e) { // can happen if database is not ready Log.e("WIDGET-UPDATE", "Error updating widget", e); } finally { if (cursor != null) cursor.close(); } updateForScreenSize(views); Intent listIntent = new Intent(context, TaskListActivity.class); String customIntent = Preferences.getStringValue(WidgetConfigActivity.PREF_CUSTOM_INTENT + widgetId); if (customIntent != null) { listIntent.setComponent(ComponentName.unflattenFromString(customIntent)); String serializedExtras = Preferences.getStringValue(WidgetConfigActivity.PREF_CUSTOM_EXTRAS + widgetId); Bundle extras = AndroidUtilities.bundleFromSerializedString(serializedExtras); listIntent.putExtras(extras); } listIntent.putExtra(TaskListActivity.TOKEN_SOURCE, Constants.SOURCE_WIDGET); listIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); if (filter != null) { listIntent.putExtra(TaskListActivity.TOKEN_FILTER, filter); listIntent.setAction("L" + widgetId + filter.sqlQuery); } PendingIntent pendingIntent = PendingIntent.getActivity( context, widgetId, listIntent, PendingIntent.FLAG_CANCEL_CURRENT); views.setOnClickPendingIntent(R.id.taskbody, pendingIntent); Intent editIntent = new Intent(context, TaskEditActivity.class); editIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); if (filter != null && filter.valuesForNewTasks != null) { String values = AndroidUtilities.contentValuesToSerializedString(filter.valuesForNewTasks); editIntent.putExtra(TaskEditActivity.TOKEN_VALUES, values); editIntent.setType(values); } pendingIntent = PendingIntent.getActivity(context, 0, editIntent, 0); views.setOnClickPendingIntent(R.id.widget_button, pendingIntent); return views; }