1、创建闹钟和倒计时
必须的权限:

< uses-permission android:name=“com.android.alarm.permission.SET_ALARM” />


闹钟:如果我们借助AlarmManager开发一个用药提醒的APP,一旦APP进程被用户干掉后,就没法提醒了,这时我们就只能借助系统闹钟来曲线救国了。

private void createAlarm(String message, int hour, int minutes, int resId) {
        ArrayList<Integer> testDays = new ArrayList<>();
        testDays.add(Calendar.MONDAY);//周一
        testDays.add(Calendar.TUESDAY);//周二
        testDays.add(Calendar.FRIDAY);//周五

        String packageName = getApplication().getPackageName();
        Uri ringtoneUri = Uri.parse("android.resource://" + packageName + "/" + resId);
        //action为AlarmClock.ACTION_SET_ALARM
        Intent intent = new Intent(AlarmClock.ACTION_SET_ALARM)
                //闹钟的小时
                .putExtra(AlarmClock.EXTRA_HOUR, hour)
                //闹钟的分钟
                .putExtra(AlarmClock.EXTRA_MINUTES, minutes)
                //响铃时提示的信息
                .putExtra(AlarmClock.EXTRA_MESSAGE, message)
                //用于指定该闹铃触发时是否振动
                .putExtra(AlarmClock.EXTRA_VIBRATE, true)
                //一个 content: URI,用于指定闹铃使用的铃声,也可指定 VALUE_RINGTONE_SILENT 以不使用铃声。
                //如需使用默认铃声,则无需指定此 extra。
                .putExtra(AlarmClock.EXTRA_RINGTONE, ringtoneUri)
                //一个 ArrayList,其中包括应重复触发该闹铃的每个周日。
                // 每一天都必须使用 Calendar 类中的某个整型值(如 MONDAY)进行声明。
                //对于一次性闹铃,无需指定此 extra
                .putExtra(AlarmClock.EXTRA_DAYS, testDays)
                //如果为true,则调用startActivity()不会进入手机的闹钟设置界面
                .putExtra(AlarmClock.EXTRA_SKIP_UI, true);
        if (intent.resolveActivity(getPackageManager()) != null) {
            startActivity(intent);
        }
    }

倒计时

public void startTimer(String message, int seconds) {
 //action为AlarmClock.ACTION_SET_TIMER
        Intent intent = new Intent(AlarmClock.ACTION_SET_TIMER)
                .putExtra(AlarmClock.EXTRA_MESSAGE, message)
                //倒计总时长,以秒为单位
                .putExtra(AlarmClock.EXTRA_LENGTH, seconds)
                //是否要进入系统的倒计时设置界面
                .putExtra(AlarmClock.EXTRA_SKIP_UI, false);
        if (intent.resolveActivity(getPackageManager()) != null) {
            startActivity(intent);
        }
    }

2、添加系统日历事件并定时提醒

添加系统日历事件有两种方式:显示添加和静默添加,显示添加是指需要跳转到设备的日历事件添加界面,由用户编辑并手动保存;静默添加则无需跳入设备的相关界面,在用户无感知的情况下添加。

2.1、显示添加

private static void addCalendarEvent(Context context, String meetingName, long startTime,
                                         long endTime) {
        //该方式需跳到系统日历事件界面由用户手动保存
        Calendar beginC = Calendar.getInstance();
        //提前15分钟提醒
        beginC.setTimeInMillis(startTime - 15 * 60 * 1000);
        Calendar endC = Calendar.getInstance();
        endC.setTimeInMillis(endTime);
        String desc = "您的会议:" + meetingName + " 将于15分钟后开始,请及时入会。";
        //action为Intent.ACTION_INSERT
        Intent intent = new Intent(Intent.ACTION_INSERT)
                .setData(CalendarContract.Events.CONTENT_URI)
                //事件的开始时间(从新纪年开始计算的毫秒数)。
                .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginC.getTimeInMillis())
                //事件的结束时间(从新纪年开始计算的毫秒数)。
                .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endC.getTimeInMillis())
                //指定此事件是否为全天事件。
                .putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, false)
                //事件地点。
                .putExtra(CalendarContract.Events.EVENT_LOCATION, "")
                //事件标题。
                .putExtra(CalendarContract.Events.TITLE, "会议提醒")
                //事件说明
                .putExtra(CalendarContract.Events.DESCRIPTION, desc);
        if (intent.resolveActivity(context.getPackageManager()) != null) {
            context.startActivity(intent);
        }
    }

Android日历计算某一个日期的前一天 安卓日历倒计时怎么弄_UI

Android日历计算某一个日期的前一天 安卓日历倒计时怎么弄_android_02

2.2、静默添加

首先,在清单文件中声明如下权限:

<uses-permission android:name="android.permission.READ_CALENDAR"/>
    <uses-permission android:name="android.permission.WRITE_CALENDAR"/>

静默添加需要先获取用户设备中的日历账户id,可通过下面这个工具类获取:

public class CalendarUtil {

    private static String CALENDARS_NAME = "yjb";
    private static String CALENDARS_ACCOUNT_NAME = "yjb@gmail.com";
//    private static String CALENDARS_ACCOUNT_TYPE = "com.android.exchange";
    private static String CALENDARS_DISPLAY_NAME = "yjb_user";


    //检查是否已经添加了日历账户,如果没有添加先添加一个日历账户再查询
    public static int checkAndAddCalendarAccount(Context context){
        int oldId = checkCalendarAccount(context);
        if( oldId >= 0 ){
            return oldId;
        }else{
            long addId = addCalendarAccount(context);
            if (addId >= 0) {
                return checkCalendarAccount(context);
            } else {
                return -1;
            }
        }
    }

    private static long addCalendarAccount(Context context) {
        TimeZone timeZone = TimeZone.getDefault();
        ContentValues value = new ContentValues();
        value.put(CalendarContract.Calendars.NAME, CALENDARS_NAME);

        value.put(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME);
//        value.put(CalendarContract.Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE);
        value.put(CalendarContract.Calendars.ACCOUNT_TYPE, ACCOUNT_TYPE_LOCAL);
        value.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, CALENDARS_DISPLAY_NAME);
        value.put(CalendarContract.Calendars.VISIBLE, 1);
        value.put(CalendarContract.Calendars.CALENDAR_COLOR, Color.BLUE);
        //事件不可编辑、删除
        value.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_OWNER);
        value.put(CalendarContract.Calendars.SYNC_EVENTS, 1);
        value.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, timeZone.getID());
        value.put(CalendarContract.Calendars.OWNER_ACCOUNT, CALENDARS_ACCOUNT_NAME);
        value.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 0);

        Uri calendarUri = CalendarContract.Calendars.CONTENT_URI;
        calendarUri = calendarUri.buildUpon()
                .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
                .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME)
                .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, ACCOUNT_TYPE_LOCAL)
                .build();

        Uri result = context.getContentResolver().insert(calendarUri, value);
        long id = result == null ? -1 : ContentUris.parseId(result);
        return id;
    }

    private static int checkCalendarAccount(Context context) {
        Cursor userCursor = context.getContentResolver().query(CalendarContract.Calendars.CONTENT_URI, null,
                null, null, null);
        try {
            if (userCursor == null)//查询返回空值
                return -1;
            int count = userCursor.getCount();
            if (count > 0) {//存在现有账户,取第一个账户的id返回
                userCursor.moveToFirst();
                return userCursor.getInt(userCursor.getColumnIndex(CalendarContract.Calendars._ID));
            } else {
                return -1;
            }
        } finally {
            if (userCursor != null) {
                userCursor.close();
            }
        }
    }
}

获取了日历账户id后,执行添加:

//静默插入日历事件提醒
        int calID = CalendarUtil.checkAndAddCalendarAccount(context);
        if (calID < 0) {
            return;
        }
        Calendar beginC = Calendar.getInstance();
        beginC.setTimeInMillis(startTime);
        Calendar endC = Calendar.getInstance();
        endC.setTimeInMillis(endTime);
        String desc = "您的会议:" + meetingName + " 将于15分钟后开始,请及时入会。";

        ContentValues eValues = new ContentValues();  //插入事件
        TimeZone tz = TimeZone.getDefault();//获取默认时区

        //插入日程
        eValues.put(CalendarContract.Events.DTSTART, beginC.getTimeInMillis());
        eValues.put(CalendarContract.Events.DTEND, endC.getTimeInMillis());
        eValues.put(CalendarContract.Events.TITLE, "会议提醒");
        eValues.put(CalendarContract.Events.DESCRIPTION, desc);
        eValues.put(CalendarContract.Events.CALENDAR_ID, calID);
        eValues.put(CalendarContract.Events.EVENT_LOCATION, "");
        eValues.put(CalendarContract.Events.EVENT_TIMEZONE, tz.getID());
        eValues.put(CalendarContract.Events.GUESTS_CAN_MODIFY, true);
        Uri uri = context.getContentResolver().insert(CalendarContract.Events.CONTENT_URI, eValues);

        //插完日程之后必须再插入以下代码段才能实现提醒功能
        ContentValues rValues = new ContentValues();  //插入提醒,与事件配合起来才有效
        String myEventsId = uri.getLastPathSegment(); // 得到当前表的_id
        rValues.put(CalendarContract.Reminders.MINUTES, 15);
        rValues.put(CalendarContract.Reminders.EVENT_ID, Long.parseLong(myEventsId));
        rValues.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);

        context.getContentResolver().insert(CalendarContract.Reminders.CONTENT_URI, rValues);