package com.example.firstapp.service
|
|
import android.app.NotificationChannel
|
import android.app.NotificationManager
|
import android.app.PendingIntent
|
import android.content.Context
|
import android.content.Intent
|
import android.os.Build
|
import androidx.core.app.NotificationCompat
|
import androidx.work.*
|
import androidx.work.CoroutineWorker
|
import androidx.work.WorkerParameters
|
import com.example.firstapp.MainActivity
|
import com.example.firstapp.R
|
import com.example.firstapp.activity.PhoneLoginActivity
|
import com.example.firstapp.core.Core
|
import com.example.firstapp.database.entity.ReminderRecord
|
import com.example.firstapp.database.repository.ReminderRecordRepository
|
import com.example.firstapp.database.repository.ReminderRepository
|
import com.example.firstapp.model.StationGroup
|
import com.example.firstapp.utils.PreferencesManager
|
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.withContext
|
import java.util.Calendar
|
import java.util.concurrent.TimeUnit
|
|
/**
|
* 提醒工作类,定期检查是否有需要提醒的内容
|
* 目前设置为每天检查一次
|
*/
|
class ReminderWorker(
|
appContext: Context,
|
workerParams: WorkerParameters
|
) : CoroutineWorker(appContext, workerParams) {
|
|
private val reminderRepository = ReminderRepository(appContext)
|
private val reminderRecordRepository = ReminderRecordRepository(appContext)
|
|
override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
|
android.util.Log.d("ReminderWorker", "doWork 开始执行")
|
try {
|
// 获取当前时间
|
val currentTime = System.currentTimeMillis()
|
val scheduledTime = inputData.getLong("scheduled_time", 0)
|
|
// 如果有设定的预定时间且当前时间与预定时间相差超过30分钟,则跳过执行
|
if (scheduledTime > 0 && Math.abs(currentTime - scheduledTime) > 30 * 60 * 1000) {
|
android.util.Log.d("ReminderWorker", "当前时间与预定时间相差过大,跳过执行")
|
return@withContext Result.success()
|
}
|
|
// 获取所有提醒设置
|
val reminderList = reminderRepository.getAllReminders().first()
|
android.util.Log.d("ReminderWorker", "获取到 ${reminderList.size} 条提醒设置")
|
|
if (reminderList.isNotEmpty()) {
|
for (reminder in reminderList) {
|
try {
|
android.util.Log.d("ReminderWorker", "处理提醒: ${reminder.categoryName}")
|
checkCategoryContent(reminder.categoryId, reminder.categoryName, reminder.notificationMethod)
|
} catch (e: Exception) {
|
e.printStackTrace()
|
android.util.Log.e("ReminderWorker", "处理提醒失败: ${e.message}")
|
}
|
}
|
}
|
|
android.util.Log.d("ReminderWorker", "doWork 执行成功")
|
Result.success()
|
} catch (e: Exception) {
|
e.printStackTrace()
|
android.util.Log.e("ReminderWorker", "doWork 执行失败: ${e.message}")
|
Result.failure()
|
}
|
}
|
|
private suspend fun checkCategoryContent(categoryId: Int, categoryName: String, notificationMethod: String) {
|
// 根据categoryId从Code表中查询pickup=0的数据
|
when (categoryId) {
|
1, 2, 3, 4, 5 -> {
|
val type = getCategoryType(categoryId)
|
val stationGroups = Core.code.getStationsByType(type)
|
|
if (stationGroups.isNotEmpty()) {
|
// 有未处理的数据,创建提醒
|
createRemindersForStations(categoryId, categoryName, stationGroups, notificationMethod)
|
}
|
}
|
else -> {
|
// 其他类型的提醒处理
|
}
|
}
|
}
|
|
private fun getCategoryType(categoryId: Int): String {
|
return when(categoryId) {
|
1 -> "快递"
|
2 -> "还款"
|
3 -> "收入"
|
4 -> "航班"
|
5 -> "火车票"
|
else -> ""
|
}
|
}
|
|
private suspend fun createRemindersForStations(
|
categoryId: Int,
|
categoryName: String,
|
stationGroups: List<StationGroup>,
|
notificationMethod: String
|
) {
|
stationGroups.forEach { stationGroup ->
|
val content = generateReminderContent(categoryId, stationGroup.stationName, stationGroup.count)
|
|
// 创建提醒记录
|
val record = ReminderRecord(
|
categoryId = categoryId,
|
categoryName = categoryName,
|
content = content,
|
notificationMethod = notificationMethod,
|
status = ReminderRecord.STATUS_UNREAD
|
)
|
val recordId = reminderRecordRepository.insertRecord(record)
|
|
// 发送通知
|
if (notificationMethod.contains("PHONE")) {
|
sendNotification(
|
recordId,
|
"新${categoryName}提醒",
|
content
|
)
|
}
|
}
|
}
|
|
private fun generateReminderContent(categoryId: Int, stationName: String, count: Int): String {
|
return when(categoryId) {
|
1 -> "您有${count}个包裹在${stationName}未取,请及时取件"
|
2 -> "您有${count}笔还款,请及时处理"
|
3 -> "您有${count}笔收入待确认"
|
4 -> "您有${count}个航班信息待处理"
|
5 -> "您有${count}张火车票信息待处理"
|
else -> "您有新的提醒"
|
}
|
}
|
|
private fun sendNotification(id: Long, title: String, content: String) {
|
val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
// 创建启动应用的Intent
|
val intent = createAppIntent()
|
|
// 创建PendingIntent
|
val pendingIntent = PendingIntent.getActivity(
|
applicationContext,
|
id.toInt(),
|
intent,
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
)
|
|
// 创建通知渠道(Android 8.0及以上需要)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val channel = NotificationChannel(
|
CHANNEL_ID,
|
"提醒通知",
|
NotificationManager.IMPORTANCE_HIGH // 提高重要性级别
|
).apply {
|
enableLights(true) // 开启指示灯
|
enableVibration(true) // 开启震动
|
description = "重要提醒通知" // 设置描述
|
}
|
notificationManager.createNotificationChannel(channel)
|
}
|
|
// 创建通知
|
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
|
.setSmallIcon(R.drawable.ic_reminder) // 使用自定义图标
|
.setContentTitle(title)
|
.setContentText(content)
|
.setPriority(NotificationCompat.PRIORITY_HIGH) // 提高通知优先级
|
.setCategory(NotificationCompat.CATEGORY_REMINDER) // 设置为提醒类别
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) // 在锁屏上显示完整通知
|
.setAutoCancel(true)
|
.setContentIntent(pendingIntent)
|
.build()
|
|
// 发送通知
|
notificationManager.notify(id.toInt(), notification)
|
}
|
|
// 添加创建跳转Intent的方法
|
private fun createAppIntent(): Intent {
|
// 判断用户是否已登录
|
val isLoggedIn = PreferencesManager.getToken() != null
|
|
return if (isLoggedIn) {
|
// 已登录,跳转到主页
|
Intent(applicationContext, MainActivity::class.java).apply {
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
}
|
} else {
|
// 未登录,跳转到登录页
|
Intent(applicationContext, PhoneLoginActivity::class.java).apply {
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
}
|
}
|
}
|
|
// 修改测试通知方法,添加点击事件
|
private fun sendTestNotification() {
|
val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
// 创建启动应用的Intent
|
val intent = createAppIntent()
|
|
// 创建PendingIntent
|
val pendingIntent = PendingIntent.getActivity(
|
applicationContext,
|
1000,
|
intent,
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
)
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val channel = NotificationChannel(
|
CHANNEL_ID,
|
"测试通知",
|
NotificationManager.IMPORTANCE_HIGH
|
)
|
notificationManager.createNotificationChannel(channel)
|
}
|
|
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
|
.setSmallIcon(R.drawable.ic_reminder) // 使用自定义图标
|
.setContentTitle("测试通知")
|
.setContentText("这是一条测试通知,证明 Worker 已执行")
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
.setAutoCancel(true)
|
.setContentIntent(pendingIntent)
|
.build()
|
|
notificationManager.notify(1000, notification)
|
}
|
|
companion object {
|
private const val CHANNEL_ID = "reminder_channel"
|
private const val MISSED_PREF_KEY = "last_checked_reminder_time"
|
|
// 定时任务执行频率(不再使用)
|
val REPEAT_INTERVAL = 24L // 设置为每24小时运行一次
|
val REPEAT_INTERVAL_TIME_UNIT = TimeUnit.HOURS
|
|
// 创建在指定时间运行的定时任务
|
fun setupScheduledWorker(context: Context, hour: Int, minute: Int) {
|
val calendar = Calendar.getInstance()
|
val now = Calendar.getInstance()
|
|
calendar.set(Calendar.HOUR_OF_DAY, hour)
|
calendar.set(Calendar.MINUTE, minute)
|
calendar.set(Calendar.SECOND, 0)
|
|
// 如果设定时间已经过了,则设置为明天这个时间
|
if (calendar.timeInMillis < now.timeInMillis) {
|
calendar.add(Calendar.DAY_OF_MONTH, 1)
|
}
|
|
// 计算初始延迟
|
val initialDelay = calendar.timeInMillis - now.timeInMillis
|
|
// 先取消所有现有的提醒任务
|
WorkManager.getInstance(context).cancelAllWorkByTag("reminder_worker")
|
|
// 创建周期性工作请求(每天同一时间)
|
val dailyWorkRequest = PeriodicWorkRequestBuilder<ReminderWorker>(
|
24, TimeUnit.HOURS
|
)
|
.setInitialDelay(initialDelay, TimeUnit.MILLISECONDS)
|
.setConstraints(
|
Constraints.Builder()
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
.build()
|
)
|
// 设置灵活时间窗口为0,确保尽量准时执行
|
.setInputData(Data.Builder().putLong("scheduled_time", calendar.timeInMillis).build())
|
.addTag("reminder_worker")
|
.build()
|
|
// 使用 REPLACE 策略确保新配置生效
|
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
|
"daily_reminder_${hour}_${minute}",
|
ExistingPeriodicWorkPolicy.REPLACE,
|
dailyWorkRequest
|
)
|
|
android.util.Log.d("ReminderWorker", "设置定时提醒: ${hour}:${minute}, 初始延迟: ${initialDelay/1000/60}分钟")
|
|
// 记录预定的下次执行时间
|
val prefs = context.getSharedPreferences("reminder_prefs", Context.MODE_PRIVATE)
|
prefs.edit().putLong("next_reminder_time_${hour}_${minute}", calendar.timeInMillis).apply()
|
}
|
|
// 应用启动时检查是否有错过的提醒
|
fun checkMissedReminders(context: Context) {
|
val prefs = context.getSharedPreferences("reminder_prefs", Context.MODE_PRIVATE)
|
val lastCheckedTime = prefs.getLong(MISSED_PREF_KEY, 0)
|
val currentTime = System.currentTimeMillis()
|
|
// 如果上次检查时间是0,说明是首次运行应用
|
if (lastCheckedTime == 0L) {
|
prefs.edit().putLong(MISSED_PREF_KEY, currentTime).apply()
|
return
|
}
|
|
// 检查是否错过了提醒时间点
|
val lastCheckedCalendar = Calendar.getInstance().apply { timeInMillis = lastCheckedTime }
|
val currentCalendar = Calendar.getInstance().apply { timeInMillis = currentTime }
|
|
// 如果不是同一天,或者超过了设定的提醒时间点
|
val missedReminder = checkIfMissedReminderTime(lastCheckedCalendar, currentCalendar)
|
|
if (missedReminder) {
|
android.util.Log.d("ReminderWorker", "检测到错过的提醒,立即执行一次")
|
// 立即安排一次性任务执行提醒检查
|
val oneTimeRequest = OneTimeWorkRequestBuilder<ReminderWorker>()
|
.setConstraints(
|
Constraints.Builder()
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
.build()
|
)
|
.build()
|
|
WorkManager.getInstance(context).enqueue(oneTimeRequest)
|
}
|
|
// 更新最后检查时间
|
prefs.edit().putLong(MISSED_PREF_KEY, currentTime).apply()
|
}
|
|
// 检查是否错过了提醒时间点
|
private fun checkIfMissedReminderTime(lastChecked: Calendar, current: Calendar): Boolean {
|
// 如果日期不同,说明至少过了一天
|
if (lastChecked.get(Calendar.DAY_OF_YEAR) != current.get(Calendar.DAY_OF_YEAR) ||
|
lastChecked.get(Calendar.YEAR) != current.get(Calendar.YEAR)) {
|
|
// 检查当前时间是否超过了9:00或13:50
|
val currentHour = current.get(Calendar.HOUR_OF_DAY)
|
val currentMinute = current.get(Calendar.MINUTE)
|
|
return (currentHour > 9 || (currentHour == 9 && currentMinute >= 0)) ||
|
(currentHour > 13 || (currentHour == 13 && currentMinute >= 50))
|
}
|
|
// 如果同一天,检查是否在上次检查后经过了9:00或13:50时间点
|
val lastHour = lastChecked.get(Calendar.HOUR_OF_DAY)
|
val lastMinute = lastChecked.get(Calendar.MINUTE)
|
val currentHour = current.get(Calendar.HOUR_OF_DAY)
|
val currentMinute = current.get(Calendar.MINUTE)
|
|
// 检查是否错过了9:00
|
if ((lastHour < 9 || (lastHour == 9 && lastMinute == 0)) &&
|
(currentHour > 9 || (currentHour == 9 && currentMinute > 0))) {
|
return true
|
}
|
|
// 检查是否错过了13:50
|
if ((lastHour < 13 || (lastHour == 13 && lastMinute < 50)) &&
|
(currentHour > 13 || (currentHour == 13 && currentMinute >= 50))) {
|
return true
|
}
|
|
return false
|
}
|
}
|
}
|