闹钟工具类
package com.aijianji.module_sleep.utils
import android.app.Activity
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
import com.aijianji.module_sleep.entity.Alarm
import com.aijianji.module_sleep.entity.AlarmType
import com.aijianji.module_sleep.entity.FrequencyType
import com.aijianji.module_sleep.receiver.AlarmReceiver
import com.blankj.utilcode.util.ToastUtils
import com.fenghuajueli.libbasecoreui.constants.AppConfigInfo
import com.google.gson.Gson
import java.util.*
/**
*
* @Description:
* @author: GordenGao
* @Email: gordengao124@gmail.com
* @date: 2021年07月14日 9:16
*/
object AlarmUtil {
const val ALARM = "alarm"
private lateinit var pendingIntent: PendingIntent
private lateinit var am: AlarmManager
// 初始化Alarm
private fun initAlarm(context: Context, alarm: Alarm, requestCode: Int) {
val flag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
pendingIntent =
PendingIntent.getBroadcast(
context,
requestCode,
getMsgIntent(context, alarm),
flag
)
am = context.getSystemService(Activity.ALARM_SERVICE) as AlarmManager
}
private fun getMsgIntent(context: Context, alarm: Alarm): Intent {
//AlarmReceiver 为广播在下面代码中
val intent = Intent(context, AlarmReceiver::class.java)
intent.action = AlarmReceiver.BC_ACTION
intent.putExtra(ALARM, Gson().toJson(alarm))
return intent
}
//设置定时执行的任务
fun setAlarm(context: Context, alarm: Alarm): Boolean {
initAlarm(context, alarm, alarm.hashCode())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !am.canScheduleExactAlarms()) {
val uri = Uri.parse("package:${AppConfigInfo.APPLICATION_ID}");
val intent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM, uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
return false
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) {
val uri = Uri.parse("package:${AppConfigInfo.APPLICATION_ID}");
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
ToastUtils.showShort("需开启浮窗权限")
return false
}
val frequencyList = getFrequencyList(alarm)
//android Api的改变不同版本中设置有所不同
am.setExact(
AlarmManager.RTC_WAKEUP,
getTimeDiff(frequencyList, alarm.time!!.first.toInt(), alarm.time!!.second.toInt()),
pendingIntent
)
return true
}
//设置定时执行的任务
fun setLateAlarm(alarm: Alarm) {
val frequencyList = getFrequencyList(alarm)
var tempM = alarm.time!!.second.toInt() + 10 // 分钟延迟10
var tempH = alarm.time!!.first.toInt()
if (tempM >= 60) {
tempM %= 10
tempH++
}
//android Api的改变不同版本中设 置有所不同
am.setExact(
AlarmManager.RTC_WAKEUP,
getTimeDiff(frequencyList, tempH, tempM),
pendingIntent
)
}
private fun getTimeDiff(frequencyList: MutableList<Int>, hour: Int, minute: Int): Long {
val systemTime = System.currentTimeMillis()
//这里设置的是当天的15:55分,注意精确到秒,时间可以自由设置
val ca: Calendar = Calendar.getInstance()
// 这里时区需要设置一下,不然可能个别手机会有8个小时的时间差
ca.timeZone = TimeZone.getTimeZone("GMT+8")
ca.set(Calendar.HOUR_OF_DAY, hour)
ca.set(Calendar.MINUTE, minute)
ca.set(Calendar.SECOND, 0)
val selectTime = ca.timeInMillis
val todayOfWeek = ca.get(Calendar.DAY_OF_WEEK) % 7
// 判断当天是否需要设置闹钟a
if (frequencyList.contains(todayOfWeek)) {
// 若当前时间已经超时
if (systemTime > selectTime) {
jumpToNextDay(frequencyList, todayOfWeek, ca)
}
} else {
jumpToNextDay(frequencyList, todayOfWeek, ca)
}
return ca.timeInMillis
}
private fun jumpToNextDay(
frequencyList: MutableList<Int>,
todayOfWeek: Int,
ca: Calendar
) {
// 计算天数差
var deltaDay = 0
for (day in frequencyList) {
if (day < todayOfWeek) {
continue
} else {
deltaDay = day - todayOfWeek
}
}
if (frequencyList.size ==1){
ca.add(Calendar.DAY_OF_MONTH, 1)
}else {
ca.add(Calendar.DAY_OF_MONTH, deltaDay)
}
}
//取消定时任务的执行
fun cancelAlarm(context: Context, alarm: Alarm, requestCode: Int) {
am = context.getSystemService(Activity.ALARM_SERVICE) as AlarmManager
val flag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_IMMUTABLE
} else {
0
}
am.cancel(PendingIntent.getBroadcast(context, requestCode, getMsgIntent(context, alarm), flag))
}
fun getFrequencyStr(alarm: Alarm): String {
when (alarm.frequencyType) {
FrequencyType.EVERYDAY -> return "每天"
FrequencyType.JUSTONE -> return "仅一次"
FrequencyType.DOUBLE -> return "双休"
FrequencyType.ONE -> return "单休(仅本周)"
FrequencyType.TWO -> return "双休(仅本周)"
else -> {}
}
val res = StringBuilder()
res.append("星期")
for (day in alarm.customDay) {
when (day) {
2 -> res.append("一")
3 -> res.append("二")
4 -> res.append("三")
5 -> res.append("四")
6 -> res.append("五")
7 -> res.append("六")
1 -> res.append("七")
}
res.append(",")
}
return res.substring(0, res.length - 1).toString()
}
fun getFrequencyList(alarm: Alarm): MutableList<Int> {
when (alarm.frequencyType) {
FrequencyType.EVERYDAY -> return mutableListOf(7, 1, 2, 3, 4, 5, 6)
FrequencyType.JUSTONE -> {
val ca: Calendar = Calendar.getInstance()
// 这里时区需要设置一下,不然可能个别手机会有8个小时的时间差
ca.timeZone = TimeZone.getTimeZone("GMT+8")
val todayOfWeek = ca.get(Calendar.DAY_OF_WEEK) % 7
return mutableListOf(todayOfWeek)
}
FrequencyType.DOUBLE -> return mutableListOf(1, 2, 3, 4, 5)
FrequencyType.ONE -> return mutableListOf(1, 2, 3, 4, 5, 6)
FrequencyType.TWO -> return mutableListOf(1, 2, 3, 4, 5)
FrequencyType.CUSTOM -> return alarm.customDay
}
}
fun getAlarmTypeStr(alarm: Alarm): String {
return when (alarm.alarmType) {
AlarmType.MUSIC -> "仅响铃"
AlarmType.SHAKE -> "仅震动"
AlarmType.BOTH -> "响铃和震动"
}
}
}
闹钟实体
package com.aijianji.module_sleep.entity
import com.fenghuajueli.greendao.entity.TextTaskEntity
import java.io.Serializable
/**
*
* @Description:
* @author: GordenGao
* @Email: gordengao124@gmail.com
* @date: 2021年07月12日 15:45
*/
data class Alarm(
var time: Pair<String, String>? = null,
var frequencyType: FrequencyType = FrequencyType.EVERYDAY,
var alarmType: AlarmType = AlarmType.SHAKE,
var musicRes: Int = 0,
var tag: String = "生活",
var close: Boolean = false,
var isReRing: Boolean = false,
var taskType: TaskType = TaskType.NONE, // 闹钟任务,
var taskList: ArrayList<TaskItem> = arrayListOf(),
var customDay: MutableList<Int> = mutableListOf(),
var isOpen: Boolean = false,
// 只定时,需关闭音乐使用
var isOnlyTiming: Boolean = false
) : Serializable
data class TaskItem(val taskType: TaskType, var classify: String, var times: Int) : Serializable
data class WordsItem(var selected: Boolean = false, val textEntity: TextTaskEntity)
val taskTextClassify = arrayListOf(
"励志短句",
"高难度短句",
"我的短句"
)
val difficultLevel = arrayListOf(
"非常简单",
"简单",
"一般",
"较难",
"地狱模式"
)
val difficultGameRowNum = arrayListOf(
2, 3, 5, 7, 10
)
val difficultNumberEx = arrayListOf(
"3+4=?",
"11x12=?",
"81x81=?",
"666x256=?",
"1024x1024=?"
)
val difficultGameEx = arrayListOf(
"2x2 瓷砖",
"3x3 瓷砖",
"5x5 瓷砖",
"7x7 瓷砖",
"10x10 瓷砖"
)
enum class TaskType {
NONE,
TEXT,
NUMBER,
GAME
}
enum class AlarmType {
MUSIC,
SHAKE,
BOTH
}
enum class FrequencyType {
EVERYDAY,
JUSTONE,
DOUBLE,
ONE,
TWO,
CUSTOM
}
**
初始化
**
private lateinit var alarm: Alarm
if (!this::alarm.isInitialized){
alarm = Alarm()
alarm.isOpen = true
alarm.isOnlyTiming = true
alarm.frequencyType = FrequencyType.JUSTONE
}
if (this::alarm.isInitialized){
val musicTimingTime = getMusicTimingTime(hour,minute)
alarm.time = Pair(
musicTimingTime[0],
musicTimingTime[1]
)
AlarmUtil.setAlarm(this,alarm)
}
广播接收(响铃)
package com.aijianji.module_sleep.receiver
import android.annotation.SuppressLint
import android.app.KeyguardManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.PowerManager
import android.os.PowerManager.WakeLock
import android.util.Log
import com.aijianji.module_sleep.entity.Alarm
import com.aijianji.module_sleep.mediaPlayer.MediaPlayerUtils
import com.aijianji.module_sleep.utils.AlarmUtil
import com.fenghuajueli.libbasecoreui.constants.AppConfigInfo
import com.google.gson.Gson
/**
*
* @Description:
* @author: GordenGao
* @Email: gordengao124@gmail.com
* @date: 2021年07月13日 17:22
*/
class AlarmReceiver : BroadcastReceiver() {
companion object {
val BC_ACTION = "com.aijianji.action.BC_ACTION"
}
private val TAG = this.javaClass.simpleName
private val CAMERA_PACKAGE_NAME = AppConfigInfo.APPLICATION_ID
// 唤醒屏幕
private var mPowerManager: PowerManager? = null
private var mWakeLock: WakeLock? = null
override fun onReceive(context: Context, intent: Intent) {
Log.e("clock--", "定时到,关闭音乐")
val alarmStr = intent.getStringExtra(AlarmUtil.ALARM)
val alarm = Gson().fromJson(intent.getStringExtra(AlarmUtil.ALARM), Alarm::class.java)
if (alarm.isOnlyTiming && MediaPlayerUtils.getInstance().isPlaying) {
MediaPlayerUtils.getInstance().pause()
}
}
@SuppressLint("Wakelock", "InvalidWakeLockTag")
@SuppressWarnings("deprecation")
fun wakeUpAndUnlock(context: Context) {
// 获取电源管理器对象
val pm = context
.getSystemService(Context.POWER_SERVICE) as PowerManager
// 获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是调试用的Tag
val wl = pm.newWakeLock(
PowerManager.ACQUIRE_CAUSES_WAKEUP
or PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright"
)
// 点亮屏幕
wl.acquire()
// 释放
wl.release()
// 得到键盘锁管理器对象
val km = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
val kl: KeyguardManager.KeyguardLock = km.newKeyguardLock("unLock")
// 解锁
kl.disableKeyguard()
}
}
manifest文件添加
<receiver
android:name=".receiver.AlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.aijianji.action.BC_ACTION" />
</intent-filter>
</receiver>