是否可以在不在 android 日历中创建事件的情况下以编程方式添加提醒?

Is it possible to add a reminder programatically without creating event in android calendar?

我使用 Google Calendar Provider for Android 在我的 Google Calendar 中添加活动: https://developer.android.com/guide/topics/providers/calendar-provider.html#overview

这是为事件添加提醒的示例:

ContentValues values = new ContentValues();
values.put(CalendarContract.Reminders.MINUTES, 15);
values.put(CalendarContract.Reminders.EVENT_ID, reminderEventId);
values.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);
getContentResolver().insert(CalendarContract.Reminders.CONTENT_URI, values);

但在我的 Google Calendar app 中,我可以在没有 EVENT_ID 的情况下创建提醒。是否可以使用 Google Calendar Provider for Android 创建相同的提醒?

同样是这样: https://gsuiteupdates.googleblog.com/2016/04/launch-of-reminders-for-google-calendar.html

https://developer.android.com/guide/topics/providers/calendar-provider.html#overview

所述

Reminders are specified in minutes before the event and have a method that determines how the user will be alerted.

不属于事件的提醒将没有参考时间。

我认为对于您要实现的目标 (),您最好查看 Androids AlarmManager https://developer.android.com/reference/android/app/AlarmManager.html

或者看看其他人对类似事情的看法

我看到 Google 启动了 Google 2016 年日历的提醒(这是与事件提醒不同的提醒),目前我在 Android SDK 中找不到(API 25) 这种 Google 日历提醒(以及以编程方式添加约会时段的可能性)。

我使用的一个棘手的方法是使用 Custom Reminder(和 ContactContract 提供程序)在联系人中创建余数而不是日历。因此,您可以使用任何标签,并在特定日期显示提醒。 缺点: - 您必须启用 "Birthday" 日历 - 余数是基于日期的(不是时间) - 他们不会重复提醒(就像新日历一样)

package es.goodsal.mobile.provider.contact;

import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.provider.ContactsContract.CommonDataKinds.Event;


import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import es.goodsal.mobile.app.App;
import es.goodsal.mobile.model.ReminderType;

/**
 * Created by jmalbarran on 16/9/17.
 */

public class Reminder implements Comparable<Reminder> {
    private static final String TAG = Reminder.class.getSimpleName();
    private static final SimpleDateFormat fullPeriodicDateFormat = new SimpleDateFormat("--MM-dd");
    private static final SimpleDateFormat periodicDateFormat = new SimpleDateFormat("MM-dd");
    private static final SimpleDateFormat nonPeriodicDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    private static final String DUE_DATE = Event.DATA4;
    private static final String COMMENT = Event.DATA5;

    private static final Uri CONTENT_URI = ContactsContract.Data.CONTENT_URI;
    private static final String[] PROJECTION = new String[]{
                    Event._ID,           //0
                    Event.CONTACT_ID,    //1
                    Event.LOOKUP_KEY,    //2
                    Event.START_DATE,    //3
                    Event.TYPE,          //4
                    Event.LABEL,         //5 Label for custom event
                    Reminder.DUE_DATE,   // 6
                    Reminder.COMMENT     // 7 Use this field to save Comments
    };

    static {
        periodicDateFormat.setCalendar(Calendar.getInstance());   // Set local time zone
        nonPeriodicDateFormat.setCalendar(Calendar.getInstance());   // Set local time zone
    }

    private long id = -1;
    private ConContact contact;
    private Date reminderDate;
    private Date dueDate;
    private ReminderType type;
    private String comment;

    // region Constructor

    public Reminder(ConContact contact, Date reminderDate,
                    Date dueDate, ReminderType type, String comment) {
        this.contact = contact;
        this.reminderDate = reminderDate;
        this.dueDate = dueDate;
        this.type = type;
        this.comment = comment;
    }

    public Reminder(@NonNull String reminderUri) {
        this(Uri.parse(reminderUri));
    }

    public Reminder(@NonNull Uri reminderUri) {
        Cursor cursor;
        cursor = App.getContentResolverInstance().query(reminderUri,
                        PROJECTION, null, null, null);
        if (cursor == null) {
            throw new IllegalArgumentException(reminderUri.toString() + " opportunity not found.");
        } else {
            cursor.moveToFirst();
            setFromCursor(null, cursor);
        }
    }

    private Reminder(@NonNull Cursor cursor) {
        this(null, cursor);
    }

    private Reminder(@Nullable ConContact contact, @NonNull Cursor cursor) {
        setFromCursor(contact, cursor);
    }

    private void setFromCursor(@Nullable ConContact contact, @NonNull Cursor cursor) {
        int eventType;
        String eventLabel;
        Calendar calDueDate, calReminderDate;
        Date now;
        String strSplitDate[];
        String strDueDate;

        this.id = cursor.getLong(0);
        if (contact != null) {
            this.contact = contact;
        } else {
            this.contact = new ConContact(cursor.getLong(1), cursor.getString(2));
        }

        // Type
        eventType = cursor.getInt(4); //Event.TYPE
        eventLabel = cursor.getString(5); //Event.LABEL
        switch (eventType) {
            case ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY:
                type = ReminderType.anniversary;
                break;
            case ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY:
                type = ReminderType.birthday;
                break;
            case ContactsContract.CommonDataKinds.Event.TYPE_CUSTOM:
                type = ReminderType.other;
                eventLabel = cursor.getString(5);
                for (ReminderType iType : ReminderType.values()) {
                    if (iType.getLabel().equals(eventLabel)) {
                        type = iType;
                        break;
                    }
                }
                break;
            default:
                type = ReminderType.other;
        }

        // Due / Reminder date

        try {
            now = new Date();
            if (type.isPeriodic()) {

                // Periodic Due date
                calDueDate = Calendar.getInstance();
                calDueDate.setTime(now);
                strSplitDate = cursor.getString(6).split("-"); // DATA4
                if (strSplitDate != null && strSplitDate.length == 3) {
                    calDueDate.set(Calendar.MONTH, Integer.parseInt(strSplitDate[1]));
                    calDueDate.set(Calendar.DAY_OF_MONTH, Integer.parseInt(strSplitDate[2]));
                    if (calDueDate.before(now)) {  // Crossed end-of-year boundary
                        calDueDate.add(Calendar.YEAR, 1); // Next year
                    }
                } else {
                    Log.e(TAG, "getReminders: Invalid date for periodic reminder due date " +
                                    cursor.getString(6));
                }
                dueDate = calDueDate.getTime();

                // Periodic Reminder date
                calReminderDate = Calendar.getInstance();
                calReminderDate.setTime(dueDate);
                strSplitDate = cursor.getString(3).split("-"); // START_DATE
                if (strSplitDate != null && strSplitDate.length == 3) {
                    calReminderDate.set(Calendar.MONTH, Integer.parseInt(strSplitDate[1]));
                    calReminderDate.set(Calendar.DAY_OF_MONTH, Integer.parseInt(strSplitDate[2]));
                    if (calReminderDate.after(dueDate)) {  // Crossed end-of-year boundary
                        calDueDate.add(Calendar.YEAR, -11); // Previous year
                    }
                } else {
                    Log.e(TAG, "getReminders: Invalid date for periodic reminder start date " +
                                    cursor.getString(6));
                }
                reminderDate = calReminderDate.getTime();
            } else {
                // Non periodic date
                reminderDate = nonPeriodicDateFormat.parse(cursor.getString(3)); // START_DATE
                dueDate = nonPeriodicDateFormat.parse(cursor.getString(6)); // DATA4
                dueDate = dueDate !=null ? dueDate : reminderDate;
            }
        } catch (Exception e) { // NullPointer and/or ParseFormat
            dueDate = null;
            reminderDate = null;
        }

        // Comment
        comment = cursor.getString(7); // DATA5
    }

    // endregion Constructor

    // region Getter/Setter
    public Uri getUri() {
        Uri uri;

        uri = null;
        if (id != -1) {
            uri = ContentUris.withAppendedId(CONTENT_URI, id);
        }

        return uri;
    }

    public ConContact getContact() {
        return contact;
    }

    public Date getReminderDate() {
        return reminderDate;
    }

    public Date getDueDate() {
        return dueDate;
    }

    public ReminderType getReminderType() {
        return type;
    }

    public String getComment() {
        return comment;
    }

    public boolean isPeriodic() {
        return type.isPeriodic();
    }

    public void setContact(ConContact contact) {
        this.contact = contact;
    }

    public void setReminderDate(Date reminderDate) {
        this.reminderDate = reminderDate;
    }

    public void setDueDate(Date dueDate) {
        this.dueDate = dueDate;
    }

    public void setType(ReminderType type) {
        this.type = type;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

// endregion Getter/Setter

    // region Commands

    public boolean save() {
        boolean ret;
        ContentValues values;
        Uri savedUri;

        ret = false;

        values = new ContentValues();
        values.put(ContactsContract.CommonDataKinds.Event.MIMETYPE,
                        ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
        //values.put(ContactsContract.CommonDataKinds.Event.CONTACT_ID, contact.getContactId());
        values.put(ContactsContract.CommonDataKinds.Event.RAW_CONTACT_ID, contact.getRawContactId());
        if (type.isPeriodic()) {
            values.put(ContactsContract.CommonDataKinds.Event.START_DATE,
                            fullPeriodicDateFormat.format(reminderDate));
            values.put(ContactsContract.CommonDataKinds.Event.DATA4,
                            fullPeriodicDateFormat.format(dueDate));
        } else {
            values.put(ContactsContract.CommonDataKinds.Event.START_DATE,
                            nonPeriodicDateFormat.format(reminderDate));
            values.put(ContactsContract.CommonDataKinds.Event.DATA4,
                            nonPeriodicDateFormat.format(dueDate));
        }
        values.put(ContactsContract.CommonDataKinds.Event.TYPE,
                        Integer.toString(type.getContactEventType()));
        values.put(ContactsContract.CommonDataKinds.Event.LABEL, type.getLabel());
        values.put(ContactsContract.CommonDataKinds.Event.DATA5, comment);
        if (id == -1L) {
            // Create new
            savedUri = App.getContentResolverInstance().insert(ContactsContract.Data.CONTENT_URI, values);
            id = ContentUris.parseId(savedUri);
            ret = true;
            Log.d(TAG, "save: Inserted uri=" + savedUri + " id=" + id);
        } else {
            // update existing id
//          if (0<App.getContentResolverInstance().update(ContactsContract.Data.CONTENT_URI, values,
//                          ContactsContract.Data._ID + "='" + Long.toString(id) + "'", null)){
            if (0 < App.getContentResolverInstance().update(
                            ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id),
                            values,
                            null,
                            null)) {

                ret = true;
                Log.d(TAG, "save: Updated id=" + id);
            } else {
                Log.e(TAG, "save: Error updating id=" + id);
            }

        }
        contact.resetReminders();

        return ret;
    }

    public boolean delete() {
        boolean ret = false;
        if (id != -1) {
            if (0 < App.getContentResolverInstance().delete(
                            ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id),
                            null,
                            null)) {
                Log.d(TAG, "delete: Deleted id=" + id);
                ret = true;
            } else {
                Log.w(TAG, "delete: Not found id=" + id);
            }
        }
        return ret;
    }

// endregion Commands

    @Override
    public int compareTo(@NonNull Reminder o) {
        if (reminderDate == null) {
            return 1; // null always at end
        } else {
            if (o.reminderDate == null) {
                return -1;
            } else {
                return reminderDate.compareTo(o.reminderDate);
            }
        }
    }

    /**
     * Get reminders for all contact, in a specific date (including periodics)
     *
     * @param date exact to search for (reminder date NOT due date)
     * @return List of reminders
     */
    public static List<Reminder> getReminders(Date date) {
        Cursor cursor;
        ArrayList<Reminder> retList;
        String where;
        String[] selectionArgs;
        Date dueDate;
        String dateSelection;
        String[] strSplitDate;
        Calendar calDueDate;

        retList = null;
        Uri uri = ContactsContract.Data.CONTENT_URI;

        String sortOrder = null;

        // Execute one query per reminder type
        for (ReminderType type : ReminderType.values()) {

            dateSelection = type.isPeriodic() ?
                            "%" + periodicDateFormat.format(date) :
                            "%" + nonPeriodicDateFormat.format(date);

            if (type.getContactEventType() == ContactsContract.CommonDataKinds.Event.TYPE_CUSTOM) {
                // Check event label too
                where = ContactsContract.CommonDataKinds.Event.MIMETYPE + "= ? AND " +
                                ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE ? AND " +
                                ContactsContract.CommonDataKinds.Event.LABEL + "= ? AND " +
                                ContactsContract.CommonDataKinds.Event.TYPE + "=" + type.getContactEventType();

                selectionArgs = new String[]{
                                ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
                                dateSelection,
                                type.getLabel()
                };
            } else {
                // Non custom reminder. Don't check label
                where = ContactsContract.CommonDataKinds.Event.MIMETYPE + "= ? AND " +
                                ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE ? AND " +
                                ContactsContract.CommonDataKinds.Event.TYPE + "=" + type.getContactEventType();
                selectionArgs = new String[]{
                                ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
                                dateSelection
                };
            } // where & selection per event type

            cursor = App.getContentResolverInstance().query(uri, PROJECTION,
                            where, selectionArgs, sortOrder);
            if (cursor != null) {
                retList = new ArrayList<Reminder>();
                while (cursor.moveToNext()) {
                    retList.add(new Reminder(cursor));
                }

                cursor.close();
            } // if cursor
        } // for per every type
        return retList;
    }

    /**
     * Get reminders for a specific contact, from a date forward
     *
     * @param contact Contact for search for
     * @param date    current or future date to search (including periodic)
     * @return List of reminders for current or future search
     */
    public static List<Reminder> getReminders(ConContact contact, Date date) {
        Uri uri;
        Cursor cursor;
        ArrayList<Reminder> retList = null;
        String where;
        String[] selectionArgs;
        String sortOrder;

        int contactEventType;
        String label;
        Calendar calReminderDate, calDueDate;
        String strReminderDate, strDueDate;

        ReminderType type;
        Date reminderDate;
        Date dueDate;
        String strDescription;
        String[] strSplitDate;

        uri = ContactsContract.Data.CONTENT_URI;

        sortOrder = null;

        // Check event label too
        where = ContactsContract.CommonDataKinds.Event.MIMETYPE + " = ? AND " +
                        ContactsContract.CommonDataKinds.Event.CONTACT_ID + " = ? AND " +
                        "(" +
                        ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE '--%' OR " +
                        ContactsContract.CommonDataKinds.Event.START_DATE + " >= ?" +
                        ")";

        selectionArgs = new String[]{
                        ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
                        Long.toString(contact.getContactId()),
                        nonPeriodicDateFormat.format(date)
        };

        sortOrder = ContactsContract.CommonDataKinds.Event.START_DATE;

        cursor = App.getContentResolverInstance().query(uri, PROJECTION,
                        where, selectionArgs, sortOrder);
        if (cursor != null) {
            retList = new ArrayList<Reminder>();
            while (cursor.moveToNext()) {
                retList.add(new Reminder(contact, cursor));
            }
            Collections.sort(retList);
            cursor.close();
        } // if cursor
        // for per every type
        return retList;
    }

} // end Reminder class