Esempio n. 1
0
  /**
   * 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);
    }
  }
Esempio n. 2
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);
    }
  }
Esempio n. 3
0
  /**
   * 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);
    }
  }
Esempio n. 6
0
  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;
  }
Esempio n. 7
0
  /**
   * 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);
  }
Esempio n. 8
0
  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];
  }
Esempio n. 9
0
  /** 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);
  }
Esempio n. 10
0
    @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;
    }