Android-系统日历功能相关



文章目录

  • Android-系统日历功能相关
  • 一、需求描述
  • 二、需求具体实现
  • 1、【需求2】实现(不需要权限)
  • 2、【需求1】相关实现(需要权限)
  • 1)、权限申请和判断
  • 2)、日历编辑
  • 1.添加用户
  • 2.添加日历事件
  • 3.更新日历事件
  • 4.删除日历事件


一、需求描述

  1. 需求1:用户在预约了APP某个活动后,自动把这个活动添加日历中,活动开始前几分钟提醒
  2. 需求2:添加到日历按钮,用户点击后跳转到日历,同时把相关信息带过去,用户在自己确认提醒时间

二、需求具体实现

1、【需求2】实现(不需要权限)

直接打开手机日历APP。

/**
* scheme 只有部分手机支持scheme设置
*/
fun Context.addCalendar(title: String?, des: String?,scheme:String?) {
        val startMillis: Long = System.currentTimeMillis()+60*1000
        val endMillis: Long = System.currentTimeMillis() + 60*5
        val tz = TimeZone.getDefault()
        val intent = Intent(Intent.ACTION_INSERT)
            .setData(CalendarContract.Events.CONTENT_URI)
            .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, startMillis)
            .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endMillis)
            .putExtra(CalendarContract.Events.TITLE, title)
            .putExtra(CalendarContract.Events.DESCRIPTION, des)
            .putExtra(CalendarContract.Events.EVENT_LOCATION, tz.displayName)
            .putExtra(CalendarContract.Events.CUSTOM_APP_PACKAGE, packageName)
            .putExtra(CalendarContract.Events.CUSTOM_APP_URI, scheme)  
        startActivity(intent)
}

2、【需求1】相关实现(需要权限)

1)、权限申请和判断

日历权限是需要动态申请,所有需要在AndroidManifest.xml中添加

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

同时

//判断是否具有权限  
fun checkPermission(context: AppCompatActivity): Boolean {
        return context.hasPermission(Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CALENDAR, isRequest = true)
}

fun AppCompatActivity.hasPermission(vararg permissions: String, isRequest: Boolean = true): Boolean {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true
    val permissionsCheck: MutableList<String> = ArrayList()
    for (permission in permissions) {
        if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
            permissionsCheck.add(permission)
        }
    }
    if (permissionsCheck.isEmpty()) return true
    if (isRequest) {
        ActivityCompat.requestPermissions(this as Activity, permissionsCheck.toTypedArray(), 100)
    }
    return false
}

2)、日历编辑

1.添加用户

因为所有的日历编辑都需要一个用户所有需要一个用户

/**
     * 检查是否已经添加了日历账户,如果没有添加先添加一个日历账户再查询
     * 获取账户成功返回账户id,否则返回-1
     */
    private fun checkAndAddCalendarAccount(context: Context): Int {
        val oldId = checkCalendarAccount(context)
        return if (oldId >= 0) {
            oldId
        } else {
            val addId = addCalendarAccount(context)
            if (addId >= 0) {
                checkCalendarAccount(context)
            } else {
                -1
            }
        }
    }

    /**
     * 检查是否存在现有账户,存在则返回账户id,否则返回-1
     */
    private fun checkCalendarAccount(context: Context): Int {
        val userCursor = context.contentResolver.query(Uri.parse(CALENDER_URL), null, null, null, null)
        return try {
            if (userCursor == null) { //查询返回空值
                return -1
            }
            val count = userCursor.count
            if (count > 0) { //存在现有账户,取第一个账户的id返回
                userCursor.moveToFirst()
                userCursor.getInt(userCursor.getColumnIndex(CalendarContract.Calendars._ID))
            } else {
                -1
            }
        } finally {
            userCursor?.close()
        }
    }

    /**
     * 添加日历账户,账户创建成功则返回账户id,否则返回-1
     */
    private fun addCalendarAccount(context: Context): Long {
        val timeZone = TimeZone.getDefault()
        val value = 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.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.id)
        value.put(CalendarContract.Calendars.OWNER_ACCOUNT, CALENDARS_ACCOUNT_NAME)
        value.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 0)
        var calendarUri = Uri.parse(CALENDER_URL)
        calendarUri = calendarUri.buildUpon()
                .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
                .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME)
                .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE)
                .build()
        val result = context.contentResolver.insert(calendarUri, value)
        return if (result == null) -1 else ContentUris.parseId(result)
    }
2.添加日历事件

这里回返回日历的id,用来更新或者删除,只有部分手机支持scheme设置

/**
     * @param remindTime 提醒的事件
     * @param previousTime 提前时间分钟开始提示
     * @param packageName 包名
     * @param scheme 部分手机支持跳转
     */
	fun addCalendarEvent(context: Context?, title: String?, des: String?,
						 remindTime: Long,endTime: Long?, previousTime: Long, packageName: String? = null, scheme: String? = null): Long {
        if (context == null) {
            return -1
        }
        val calId = checkAndAddCalendarAccount(context) //获取日历账户的id
        if (calId < 0) { //获取账户id失败直接返回,添加日历事件失败
            return -1
        }

        //添加日历事件
        val mCalendar = Calendar.getInstance()
        mCalendar.timeInMillis = remindTime //设置开始时间
        val start = mCalendar.time.time
        mCalendar.timeInMillis = start + 10 * 60 * 1000 //设置终止时间,开始时间加10分钟
        val end = endTime ?: mCalendar.time.time
        val event = ContentValues()
        event.put(CalendarContract.Events.TITLE, title)
        event.put(CalendarContract.Events.DESCRIPTION, des)
        event.put(CalendarContract.Events.CALENDAR_ID, calId) //插入账户的id
        event.put(CalendarContract.Events.DTSTART, start)
        event.put(CalendarContract.Events.DTEND, end)
        event.put(CalendarContract.Events.HAS_ALARM, 1) //设置有闹钟提醒
        event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().displayName) //这个是时区,必须有
        event.put(CalendarContract.Events.CUSTOM_APP_PACKAGE, packageName)
        event.put(CalendarContract.Events.CUSTOM_APP_URI, scheme)
        val newEvent = context.contentResolver.insert(Uri.parse(CALENDER_EVENT_URL), event)
                ?: //添加日历事件失败直接返回
                return -1//添加事件

        //事件提醒的设定
        val values = ContentValues()
        val eventID = ContentUris.parseId(newEvent)
        values.put(CalendarContract.Reminders.EVENT_ID, eventID)
        values.put(CalendarContract.Reminders.MINUTES, previousTime) // 提前previousDate分钟有提醒
        values.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT)
        context.contentResolver.insert(Uri.parse(CALENDER_REMINDER_URL), values)
                ?: //添加事件提醒失败直接返回
                return -1
        return eventID
    }
3.更新日历事件

需要上面addCalendarEvent返回的日历id

fun updateRemindEvent(context: Context, calId: Int, eventId: Long, title: String?, des: String?,
                          remindTime: Long,
                          endTime: Long?,
                          previousTime: Long, packageName: String? = null, scheme: String? = null): Boolean {

        val mCalendar = Calendar.getInstance()
        mCalendar.timeInMillis = remindTime //设置开始时间
        val start = mCalendar.time.time
        mCalendar.timeInMillis = start + 10 * 60 * 1000 //设置终止时间,开始时间加10分钟
        val end = endTime ?: mCalendar.time.time

        return try {
            val tz = TimeZone.getDefault()        // 获取默认时区
            /* 更新日程 */
            val values = ContentValues()
            values.put(CalendarContract.Events.DTSTART, start)
            values.put(CalendarContract.Events.DTEND, end)
            values.put(CalendarContract.Events.TITLE, title)
            values.put(CalendarContract.Events.DESCRIPTION, des)
            values.put(CalendarContract.Events.CALENDAR_ID, calId)
            values.put(CalendarContract.Events.ACCESS_LEVEL, CalendarContract.Events.ACCESS_DEFAULT)
            values.put(CalendarContract.Events.EVENT_LOCATION, tz.displayName)
            values.put(CalendarContract.Events.EVENT_TIMEZONE, tz.id)
            val updateUri = ContentUris.withAppendedId(Uri.parse(CALENDER_REMINDER_URL), eventId)
            val rowNum = context.contentResolver.update(updateUri, values, null, null)
            if (rowNum <= 0) {
                /*更新event不成功,说明用户在日历中删除了提醒事件,重新添加*/
                if (addCalendarEvent(context, title, des, remindTime, endTime, previousTime, packageName, scheme) != -1L) {
                    return true
                }
                return false
            } else {
                val reminderValues = ContentValues()
                reminderValues.put(CalendarContract.Reminders.MINUTES, previousTime) // 提前提醒
                val rUri = Uri.parse(CALENDER_REMINDER_URL)
                context.contentResolver.update(rUri, reminderValues, CalendarContract.Reminders.EVENT_ID + "= ?", arrayOf(eventId.toString()))
                true
            }
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }
4.删除日历事件

需要上面addCalendarEvent返回的日历id

fun deleteCalendarEvent(context: Context, id: Long): Int {
        val deleteUri = ContentUris.withAppendedId(Uri.parse(CALENDER_EVENT_URL), id)
        return context.contentResolver.delete(deleteUri, null, null)
}