diff --git a/app/src/main/java/com/gamedog/vididin/main/MainActivity.kt b/app/src/main/java/com/gamedog/vididin/main/MainActivity.kt index d01d3c7..e1e7de6 100644 --- a/app/src/main/java/com/gamedog/vididin/main/MainActivity.kt +++ b/app/src/main/java/com/gamedog/vididin/main/MainActivity.kt @@ -227,6 +227,7 @@ class MainActivity : AppViewsActivity(), OnTabS "Notific_Type" to when (notifyFrom) { NotificationCheckController.NotificationType.UNLOCK.string -> 1 NotificationCheckController.NotificationType.BACKGROUND.string -> 1 + NotificationCheckController.NotificationType.FIXTIMEPOINT.string -> 1 NotificationCheckController.NotificationType.KEEPALIVE.string -> 1 NotificationCheckController.NotificationType.FCM.string -> 3 NotificationCheckController.NotificationType.RESIDENT.string -> 4 @@ -256,6 +257,7 @@ class MainActivity : AppViewsActivity(), OnTabS "Notific_Type" to when (intent.getStringExtra(LANDING_NOTIFICATION_FROM).orEmpty()) { NotificationCheckController.NotificationType.UNLOCK.string -> 1 NotificationCheckController.NotificationType.BACKGROUND.string -> 1 + NotificationCheckController.NotificationType.FIXTIMEPOINT.string -> 1 NotificationCheckController.NotificationType.KEEPALIVE.string -> 1 NotificationCheckController.NotificationType.FCM.string -> 3 NotificationCheckController.NotificationType.RESIDENT.string -> 4 diff --git a/notification/src/main/assets/push_config.json b/notification/src/main/assets/push_config.json index 2418de1..aa2afdd 100644 --- a/notification/src/main/assets/push_config.json +++ b/notification/src/main/assets/push_config.json @@ -4,7 +4,7 @@ "unlock_push_interval": "10", "background_push_interval": "1", "hover_duration_strategy_switch": 1, - "hover_duration_loop_count": 8888888, + "hover_duration_loop_count": 88888888, "new_user_cooldown": 0, "do_not_disturb_start": "02:00", "do_not_disturb_end": "08:00", @@ -16,7 +16,7 @@ "unlock_push_interval": "10", "background_push_interval": "1", "hover_duration_strategy_switch": 1, - "hover_duration_loop_count": 8888888, + "hover_duration_loop_count": 88888888, "new_user_cooldown": "24", "do_not_disturb_start": "02:00", "do_not_disturb_end": "08:00", diff --git a/notification/src/main/java/com/remax/notification/beans/FixTimeRecord.kt b/notification/src/main/java/com/remax/notification/beans/FixTimeRecord.kt new file mode 100644 index 0000000..47fd52f --- /dev/null +++ b/notification/src/main/java/com/remax/notification/beans/FixTimeRecord.kt @@ -0,0 +1,8 @@ +package com.remax.notification.beans + +import com.ama.core.architecture.util.DateUtil + +data class FixTimeRecord ( + private val mDayStartTime: Long = DateUtil.getTodayStartTimeMs(), + private val mHasShowTimePointList: MutableList = mutableListOf() +) \ No newline at end of file diff --git a/notification/src/main/java/com/remax/notification/builder/NotificationDataFactory.kt b/notification/src/main/java/com/remax/notification/builder/NotificationDataFactory.kt index 35df83b..7a803fc 100644 --- a/notification/src/main/java/com/remax/notification/builder/NotificationDataFactory.kt +++ b/notification/src/main/java/com/remax/notification/builder/NotificationDataFactory.kt @@ -282,6 +282,87 @@ class GeneralModelManager() { } } + +class FixTimeModelManager() { + + fun getModel(context: Context,type:NotificationCheckController.NotificationType): GeneralNotificationData { + val notificationId = type2notificationId[NotificationType.GENERAL] ?: 0 + val data = PushContentController.getNextPushContent()!! + val title = data.title + val content = data.desc + val pendingIntent = entryPointPendingIntent(context, notificationId) { + it.putExtra(LANDING_NOTIFICATION_ACTION, data.actionType) + it.putExtra(LANDING_NOTIFICATION_FROM, type.string) + it.putExtra(LANDING_NOTIFICATION_TITLE, title) + it.putExtra(LANDING_NOTIFICATION_CONTENT, content) + } + + val badgeCount = Random.nextInt(1, 100).toString() + val contentView = NotificationRemoteViewsBuilder( + context.packageName, + R.layout.layout_notification_beauty_12, + R.layout.layout_notification_beauty + ) + .setImageViewResource( + R.id.iv, when (data.iconType) { + PushContent.ICON_TYPE_PHOTO -> R.drawable.ic_noti_photo + PushContent.ICON_TYPE_VIDEO -> R.drawable.ic_noti_video + PushContent.ICON_TYPE_DOCUMENT -> R.drawable.ic_noti_document + PushContent.ICON_TYPE_AUDIO -> R.drawable.ic_noti_audio + PushContent.ICON_TYPE_SCREENSHOT -> R.drawable.ic_noti_shot + PushContent.ICON_TYPE_RECOVERED -> R.drawable.ic_noti_recover + else -> R.drawable.ic_noti_photo + } + ) + .setTextViewText(R.id.tvCount, badgeCount) + .setTextViewText(R.id.tvTitle, title) + .setTextViewText(R.id.tvDesc, content) + .setTextViewText( + R.id.tvAction, when (data.iconType) { + PushContent.ICON_TYPE_SCREENSHOT -> StringUtils.getString(R.string.noti_clean) + else -> StringUtils.getString(R.string.noti_recovery) + } + ) + .build() + + val bigContentView = NotificationRemoteViewsBuilder( + context.packageName, + R.layout.layout_notification_beauty_12, + R.layout.layout_notification_beauty + ) + .setImageViewResource( + R.id.iv, when (data.iconType) { + PushContent.ICON_TYPE_PHOTO -> R.drawable.ic_noti_photo + PushContent.ICON_TYPE_VIDEO -> R.drawable.ic_noti_video + PushContent.ICON_TYPE_DOCUMENT -> R.drawable.ic_noti_document + PushContent.ICON_TYPE_AUDIO -> R.drawable.ic_noti_audio + PushContent.ICON_TYPE_SCREENSHOT -> R.drawable.ic_noti_shot + PushContent.ICON_TYPE_RECOVERED -> R.drawable.ic_noti_recover + else -> R.drawable.ic_noti_photo + } + ) + .setTextViewText(R.id.tvCount, badgeCount) + .setTextViewText(R.id.tvTitle, title) + .setTextViewText(R.id.tvDesc, content) + .setTextViewText( + R.id.tvAction, when (data.iconType) { + PushContent.ICON_TYPE_SCREENSHOT -> StringUtils.getString(R.string.noti_clean) + else -> StringUtils.getString(R.string.noti_recovery) + } + ) + .build() + + return GeneralNotificationData( + notificationId = notificationId, + contentTitle = title, + contentContent = content, + contentIntent = pendingIntent, + contentView = contentView, + bigContentView = bigContentView + ) + } +} + class ResidentModelManger { fun getModel(context: Context): GeneralNotificationData { diff --git a/notification/src/main/java/com/remax/notification/check/NotificationCheckController.kt b/notification/src/main/java/com/remax/notification/check/NotificationCheckController.kt index ff2ad00..84b82ba 100644 --- a/notification/src/main/java/com/remax/notification/check/NotificationCheckController.kt +++ b/notification/src/main/java/com/remax/notification/check/NotificationCheckController.kt @@ -47,7 +47,8 @@ class NotificationCheckController private constructor() { */ enum class NotificationType(val string: String) { UNLOCK("local_push"), // 解锁通知 - BACKGROUND("local_push"), // 后台通知 + BACKGROUND("local_push"), // app后台 - for withdraw + FIXTIMEPOINT("fix_time_point_push"), // 每日固定时间点 "9:10""12:10""13:10""19:10""21:00""22:30""23:30" KEEPALIVE("local_push"), // 保活通知(无间隔限制) FCM("firebase_push"), // FCM 推送通知(无间隔限制) RESIDENT("top_notification") // 常驻(无间隔限制) diff --git a/notification/src/main/java/com/remax/notification/controller/NotificationTriggerController.kt b/notification/src/main/java/com/remax/notification/controller/NotificationTriggerController.kt index 8f84073..5afecae 100644 --- a/notification/src/main/java/com/remax/notification/controller/NotificationTriggerController.kt +++ b/notification/src/main/java/com/remax/notification/controller/NotificationTriggerController.kt @@ -13,25 +13,32 @@ import android.os.Looper import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.core.content.ContextCompat +import com.ama.core.architecture.util.DateUtil +import com.ama.core.architecture.util.SpUtil import com.remax.base.ext.canSendNotification import com.remax.base.report.DataReportManager import com.remax.notification.NotifyConst import com.remax.notification.R +import com.remax.notification.builder.FixTimeModelManager import com.remax.notification.builder.GeneralModelManager import com.remax.notification.builder.GeneralNotificationData import com.remax.notification.builder.NotificationType import com.remax.notification.builder.ResidentModelManger import com.remax.notification.builder.type2notificationId -import com.remax.notification.config.NotificationConfigController import com.remax.notification.check.NotificationCheckController -import com.remax.notification.utils.NotiLogger +import com.remax.notification.config.NotificationConfigController +import com.remax.notification.newUtil.NotificationRecorder import com.remax.notification.receiver.NotificationDeleteReceiver +import com.remax.notification.timing.NotificationTimingController +import com.remax.notification.utils.NotiLogger +import com.remax.notification.utils.TimeCheckUtil import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import kotlinx.coroutines.withContext + /** * 通知触发控制器 * 提供常驻通知和普通通知的触发功能 @@ -42,10 +49,13 @@ object NotificationTriggerController { const val CHANNEL_ID_RESIDENT = "resident_notification" const val CHANNEL_ID_GENERAL = "general_notification" const val CHANNEL_ID_GENERAL_SILENT = "general_silent_notification" + const val CHANNEL_ID_BEAUTY = "general_beauty" const val CHANNEL_NAME_RESIDENT = "recovery_resident" const val CHANNEL_NAME_GENERAL = "recovery_single" const val CHANNEL_NAME_GENERAL_SILENT = "recovery_loop" + const val CHANNEL_NAME_BEAUTY = "beauty_single" + private var notificationManager: NotificationManagerCompat? = null private var context: Context? = null @@ -58,10 +68,14 @@ object NotificationTriggerController { private var repeatCount: Int = 0 private var currentNotificationId: Int = 0 + private var mFixTimeHandler: Handler? = null + private var mFixTimeRunnable: Runnable? = null + /** * 初始化通知通道 * @param context 上下文 */ + @SuppressLint("NewApi") fun initializeChannels(context: Context) { this.context = context this.notificationManager = NotificationManagerCompat.from(context) @@ -86,6 +100,16 @@ object NotificationTriggerController { enableVibration(false) } + // beauty + val beautyChannel = NotificationChannel( + CHANNEL_ID_BEAUTY, CHANNEL_NAME_BEAUTY, NotificationManager.IMPORTANCE_HIGH + ).apply { + description = "for beauty notification" + setShowBadge(true) + enableLights(false) + enableVibration(false) + } + // 静音通知通道 val silentChannel = NotificationChannel( CHANNEL_ID_GENERAL_SILENT, @@ -101,7 +125,7 @@ object NotificationTriggerController { notificationManager?.createNotificationChannels( listOf( - residentChannel, generalChannel, silentChannel + residentChannel, generalChannel, silentChannel, beautyChannel ) ) NotiLogger.d("通知通道创建完成") @@ -207,6 +231,7 @@ object NotificationTriggerController { // 创建 Handler repeatHandler = Handler(Looper.getMainLooper()) + // 创建重复任务 repeatRunnable = object : Runnable { override fun run() { @@ -237,6 +262,30 @@ object NotificationTriggerController { repeatHandler?.postDelayed(repeatRunnable!!, 4000) } + + private fun checkAndStartFixTimeNotification() { + + stopFixTimeNotification() + + mFixTimeHandler = Handler(Looper.getMainLooper()) + + mFixTimeRunnable = object : Runnable { + override fun run() { + val lastFixNotifiShowMs = NotificationRecorder.getLastWithdrawShowTime() + if (/*TimeCheckUtil.isTargetTime() && */(DateUtil.getCurTimeMs() - lastFixNotifiShowMs > 60000)) { + NotificationTimingController.getInstance().triggerNotificationIfAllowed(NotificationCheckController.NotificationType.FIXTIMEPOINT) + NotificationRecorder.saveLastWithdrawShowTime(DateUtil.getCurTimeMs()) + NotiLogger.d("固定时间节点通知,第${repeatCount + 1}次") + } + + mFixTimeHandler?.postDelayed(this, 1000) + } + } + + mFixTimeHandler?.postDelayed(mFixTimeRunnable!!, 1000) + } + + /** * 停止重复通知 */ @@ -245,11 +294,17 @@ object NotificationTriggerController { repeatHandler = null repeatRunnable = null repeatCount = 0 - currentNotificationId = 0 NotiLogger.d("停止重复通知") } + fun stopFixTimeNotification() { + mFixTimeHandler?.removeCallbacks(mFixTimeRunnable ?: return) + mFixTimeHandler = null + mFixTimeRunnable = null + NotiLogger.d("停止时间节点通知") + } + fun triggerResidentNotification() { if (context?.canSendNotification() == true) { triggerNotification( @@ -274,11 +329,15 @@ object NotificationTriggerController { onNotificationSent?.invoke() generalTrack(type, notificationData) // 检查是否需要重复通知 - checkAndStartRepeatNotification(notificationData, notification,type) + checkAndStartRepeatNotification(notificationData, notification, type) }) } } + fun triggerFixTimeNotification() { + checkAndStartFixTimeNotification() + } + private fun resident(model: GeneralNotificationData) = NotificationCompat.Builder(context!!, CHANNEL_ID_RESIDENT) .setColor(ContextCompat.getColor(context!!, R.color.noti_color)) @@ -330,6 +389,39 @@ object NotificationTriggerController { }.build() } + private fun fixTime(model: GeneralNotificationData): Notification { + // 根据重复通知配置选择通道 + val channelId = CHANNEL_ID_BEAUTY + + // 创建删除监听 Intent + val deleteIntent = Intent(context, NotificationDeleteReceiver::class.java).apply { + action = "com.remax.notification.ACTION_NOTIFICATION_DELETE" + } + val deletePendingIntent = PendingIntent.getBroadcast( + context, + System.currentTimeMillis().toInt(), + deleteIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + + val builder = NotificationCompat.Builder(context!!, channelId) + .setPriority(NotificationCompat.PRIORITY_MAX) + .setColor(ContextCompat.getColor(context!!, R.color.noti_color)) + .setSmallIcon(R.drawable.ic_noti_icon).setAutoCancel(true) + .setGroup("push_" + System.currentTimeMillis()).setContentText(model.contentTitle) + .setContentIntent(model.contentIntent).setDeleteIntent(deletePendingIntent) // 设置删除监听 + .setCustomContentView(model.contentView).setCustomBigContentView(model.bigContentView) + + // 记录使用的通道 + NotiLogger.d("使用普通通道发送通知: $channelId") + + return builder.apply { + if (Build.VERSION.SDK_INT >= 31) { + setCustomHeadsUpContentView(model.contentView) + } + }.build() + } + /** * 取消通知 * @param notificationId 通知ID @@ -428,6 +520,30 @@ object NotificationTriggerController { "Notific_Type" to when (type) { NotificationCheckController.NotificationType.UNLOCK -> 1 NotificationCheckController.NotificationType.BACKGROUND -> 1 + NotificationCheckController.NotificationType.FIXTIMEPOINT -> 1 + NotificationCheckController.NotificationType.KEEPALIVE -> 1 + NotificationCheckController.NotificationType.FCM -> 3 + else -> 4 + }, + "Notific_Position" to 1, + "Notific_Priority" to "PRIORITY_MAX", + "event_id" to "customer_general_style", + "title" to notificationData.contentTitle, + "text" to notificationData.contentContent, + ) + ) + } + + private fun fixTimeTrack( + type: NotificationCheckController.NotificationType, + notificationData: GeneralNotificationData + ) { + DataReportManager.reportData( + "Notific_Show", mapOf( + "Notific_Type" to when (type) { + NotificationCheckController.NotificationType.UNLOCK -> 1 + NotificationCheckController.NotificationType.BACKGROUND -> 1 + NotificationCheckController.NotificationType.FIXTIMEPOINT -> 1 NotificationCheckController.NotificationType.KEEPALIVE -> 1 NotificationCheckController.NotificationType.FCM -> 3 else -> 4 diff --git a/notification/src/main/java/com/remax/notification/newUtil/NotificationConfig.kt b/notification/src/main/java/com/remax/notification/newUtil/NotificationConfig.kt index b4d5c0b..d81b3f3 100644 --- a/notification/src/main/java/com/remax/notification/newUtil/NotificationConfig.kt +++ b/notification/src/main/java/com/remax/notification/newUtil/NotificationConfig.kt @@ -1,6 +1,7 @@ package com.remax.notification.newUtil import android.app.PendingIntent +import com.google.gson.annotations.SerializedName class NotificationConfig(val notificationId: Int = System.currentTimeMillis().toInt(), val channelId: String, @@ -11,4 +12,5 @@ class NotificationConfig(val notificationId: Int = System.currentTimeMillis().to val intent: PendingIntent? = null, val useFullScreenIntent: Boolean = false, ) { -} \ No newline at end of file +} + diff --git a/notification/src/main/java/com/remax/notification/newUtil/NotificationDatas.kt b/notification/src/main/java/com/remax/notification/newUtil/NotificationDatas.kt index 0a9aa40..8226835 100644 --- a/notification/src/main/java/com/remax/notification/newUtil/NotificationDatas.kt +++ b/notification/src/main/java/com/remax/notification/newUtil/NotificationDatas.kt @@ -1,10 +1,9 @@ package com.remax.notification.newUtil import android.annotation.SuppressLint -import android.app.PendingIntent import android.content.Context -import android.content.Intent import com.ama.core.architecture.BaseApp +import com.ama.core.architecture.util.AndroidUtil import com.ama.core.architecture.util.ResUtil import com.remax.notification.R import com.remax.notification.builder.LANDING_NOTIFICATION_ACTION @@ -17,8 +16,10 @@ import com.remax.notification.config.PushContent import java.util.concurrent.ConcurrentHashMap + @SuppressLint("StaticFieldLeak") object NotificationDatas { + private var mCurRandomIndex = 0 const val GAP_FOR_WITHDRAW_NOTIFY = 30 * 1000 var context: Context = BaseApp.appContext() @@ -28,37 +29,62 @@ object NotificationDatas { const val NOTI_TYPE_BG_RANDOM = "NOTI_TYPE_BG_RANDOM" const val NOTI_TYPE_RESIDENT = "NOTI_TYPE_RESIDENT" const val NOTI_TYPE_UNLOCK = "NOTI_TYPE_UNLOCK" + const val NOTI_TYPE_FXITIME = "NOTI_TYPE_FXITIME" // notifi id const val NOTI_ID_TYPE_BG_WITHDRAW = 666 const val NOTI_ID_TYPE_BG_RANDOM = 667 const val NOTI_ID_TYPE_RESIDENT = 668 const val NOTI_ID_TYPE_UNLOCK = 669 + const val NOTI_ID_TYPE_FXITIME = 670 + + const val NOTI_ID_TYPE_RANDOM_1 = 670 + const val NOTI_ID_TYPE_RANDOM_2 = 671 + const val NOTI_ID_TYPE_RANDOM_3 = 672 + const val NOTI_ID_TYPE_RANDOM_4 = 673 + const val NOTI_ID_TYPE_RANDOM_5 = 674 + const val NOTI_ID_TYPE_RANDOM_6 = 675 + const val NOTI_ID_TYPE_RANDOM_7 = 676 + const val NOTI_ID_TYPE_RANDOM_8 = 677 + const val NOTI_ID_TYPE_RANDOM_9 = 678 + const val NOTI_ID_TYPE_RANDOM_10 = 679 + const val NOTI_ID_TYPE_RANDOM_11 = 680 // channelId type const val CHANNEL_TYPE_BG_WITHDRAW = "CHANNEL_TYPE_BG_WITHDRAW" const val CHANNEL_TYPE_BG_RANDOM = "CHANNEL_TYPE_BG_RANDOM" const val CHANNEL_TYPE_RESIDENT = "CHANNEL_TYPE_RESIDENT" const val CHANNEL_TYPE_UNLOCK = "CHANNEL_TYPE_UNLOCK" + const val CHANNEL_TYPE_RANDOM = "CHANNEL_TYPE_RANDOM" // channelId name const val CHANNEL_TYPE_BG_WITHDRAW_NAME = "CHANNEL_TYPE_BG_WITHDRAW_NAME" const val CHANNEL_TYPE_BG_RANDOM_NAME = "CHANNEL_TYPE_BG_RANDOM_NAME" const val CHANNEL_TYPE_RESIDENT_NAME = "CHANNEL_TYPE_RESIDENT_NAME" const val CHANNEL_TYPE_UNLOCK_NAME = "CHANNEL_TYPE_UNLOCK_NAME" + const val CHANNEL_TYPE_RANDOM_NAME = "CHANNEL_TYPE_RANDOM_NAME" - private val mConfigList: ConcurrentHashMap = ConcurrentHashMap() + private val mConfigMap: ConcurrentHashMap = ConcurrentHashMap() + private val mRandomConfigList: MutableList = mutableListOf() + init { + + initRandomConfigs() + + + + + // # 切换后台 - 提现 val bgWithdrawIntent = entryPointPendingIntent(context, type2notificationId[NotificationType.RESIDENT_WITHDRAW] ?: 0 ) { it.putExtra(LANDING_NOTIFICATION_ACTION, PushContent.ACTION_TYPE_WITHDRAW) it.putExtra(LANDING_NOTIFICATION_FROM, NotificationCheckController.NotificationType.RESIDENT.string) } - mConfigList.put(NOTI_TYPE_BG_WITHDRAW, NotificationConfig( + mConfigMap.put(NOTI_TYPE_BG_WITHDRAW, NotificationConfig( NOTI_ID_TYPE_BG_WITHDRAW, CHANNEL_TYPE_BG_WITHDRAW, CHANNEL_TYPE_BG_WITHDRAW_NAME, @@ -68,12 +94,144 @@ object NotificationDatas { bgWithdrawIntent, true, )) + + + + } + private fun initRandomConfigs() { + try { + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_1, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "Time to claim coins!", + "You have free coins today!Open to claim!", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_1)) + ) + + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_2, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "Time to claim cash!", + "You have free cash today!Open to claim!", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_2)) + ) + + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_3, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "Hey!", + "You received R$10, click to withdraw immediately!", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_3)) + ) + + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_4, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "\uD83D\uDCDE\uD83D\uDCDE\uD83D\uDCDE Do you miss me? ", + "Come play the game and withdraw now!", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_4)) + ) + + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_5, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "\uD83D\uDCDE\uD83D\uDCDE\uD83D\uDCDE Do you miss me? ", + "Come play the game and withdraw now!", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_5)) + ) + + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_6, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "\uD83D\uDCDE\uD83D\uDCDE\uD83D\uDCDE Do you miss me? ", + "Come play the game and withdraw now!", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_6)) + ) + + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_7, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "\uD83D\uDCDE\uD83D\uDCDE\uD83D\uDCDE Do you miss me? ", + "Come play the game and withdraw now!", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_7)) + ) + + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_8, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "Today’s 1,024th Cash-Out Champion is HERE!", + "You’re the missing piece! Join now!", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_8)) + ) + + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_9, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "User #888 Just Cashed Out!", + "Don’t be left behind! Tap to claim yours!", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_9)) + ) + + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_10, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "You missed(2) calls", + "+86-12345, +86-666999", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_10)) + ) + + mRandomConfigList.add(NotificationConfig( + NOTI_ID_TYPE_RANDOM_11, + CHANNEL_TYPE_RANDOM, + CHANNEL_TYPE_RANDOM_NAME, + "Gmail", + "support.gov@gmail.com", + R.mipmap.task_cash, + entryPointPendingIntent(context, NOTI_ID_TYPE_RANDOM_11)) + ) + + } catch (e: Exception) { + e.printStackTrace() + } + } fun getConfigForType(notifiType: String): NotificationConfig? { - return mConfigList[notifiType] + return mConfigMap[notifiType] + } + + fun getRandomConfig(): NotificationConfig { + var randomIndex = AndroidUtil.randomInt(0, mRandomConfigList.size - 1) + if (mCurRandomIndex == randomIndex) { + randomIndex++ + if (randomIndex >= mRandomConfigList.size) { + randomIndex = 0 + } + } + mCurRandomIndex = randomIndex + return mRandomConfigList[mCurRandomIndex] } } \ No newline at end of file diff --git a/notification/src/main/java/com/remax/notification/newUtil/NotificationUtil.kt b/notification/src/main/java/com/remax/notification/newUtil/NotificationUtil.kt index f36d476..ad87013 100644 --- a/notification/src/main/java/com/remax/notification/newUtil/NotificationUtil.kt +++ b/notification/src/main/java/com/remax/notification/newUtil/NotificationUtil.kt @@ -16,10 +16,10 @@ import com.ama.core.architecture.BaseApp import com.ama.core.architecture.util.permission.PermissionUtil class NotificationUtil private constructor() { - + companion object { private var instance: NotificationUtil? = null - + fun getInstance(): NotificationUtil { return instance ?: synchronized(this) { instance ?: NotificationUtil().also { instance = it } @@ -30,7 +30,7 @@ class NotificationUtil private constructor() { private var mContext = BaseApp.appContext() private var notificationManager: NotificationManager = mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - + /** * 创建通知渠道(Android 8.0+必需) */ @@ -45,11 +45,32 @@ class NotificationUtil private constructor() { notificationManager.createNotificationChannel(channel) } } - + /** * 1. 基本通知 */ - fun showBasicNotification( + fun showBasicNotification(notifiConfig: NotificationConfig) { + val notificationId = notifiConfig.notificationId + val channelId = notifiConfig.channelId + val channelName = notifiConfig.channelName + val title = notifiConfig.title + val content = notifiConfig.content + val smallIcon = notifiConfig.smallIcon + val pendingIntent = notifiConfig.intent + + val notification = NotificationCompat.Builder(mContext, channelId) + .setContentTitle(title) + .setContentText(content) + .setSmallIcon(smallIcon) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .build() + + showNotification(notificationId, notification, channelName) + } + + fun showBasicNotification_old( channelId: String, title: String, content: String, @@ -60,7 +81,7 @@ class NotificationUtil private constructor() { val pendingIntent = intent?.let { PendingIntent.getActivity(mContext, 0, it, PendingIntent.FLAG_IMMUTABLE) } - + val notification = NotificationCompat.Builder(mContext, channelId) .setContentTitle(title) .setContentText(content) @@ -72,7 +93,7 @@ class NotificationUtil private constructor() { showNotification(notificationId, notification, "name") } - + /** * 2. 大文本样式通知 */ @@ -88,12 +109,12 @@ class NotificationUtil private constructor() { val pendingIntent = intent?.let { PendingIntent.getActivity(mContext, 0, it, PendingIntent.FLAG_IMMUTABLE) } - + val bigTextStyle = NotificationCompat.BigTextStyle() .bigText(bigText) .setBigContentTitle(title) .setSummaryText(content) - + val notification = NotificationCompat.Builder(mContext, channelId) .setStyle(bigTextStyle) .setContentTitle(title) @@ -105,7 +126,7 @@ class NotificationUtil private constructor() { showNotification(notificationId, notification, "name") } - + /** * 3. 大图片样式通知 */ @@ -121,13 +142,13 @@ class NotificationUtil private constructor() { val pendingIntent = intent?.let { PendingIntent.getActivity(mContext, 0, it, PendingIntent.FLAG_IMMUTABLE) } - + val bigPicture = BitmapFactory.decodeResource(mContext.resources, bigPictureResId) val bigPictureStyle = NotificationCompat.BigPictureStyle() .bigPicture(bigPicture) .setBigContentTitle(title) .setSummaryText(content) - + val notification = NotificationCompat.Builder(mContext, channelId) .setStyle(bigPictureStyle) .setContentTitle(title) @@ -139,7 +160,7 @@ class NotificationUtil private constructor() { showNotification(notificationId, notification, "name") } - + /** * 4. 进度条通知 */ @@ -164,7 +185,7 @@ class NotificationUtil private constructor() { showNotification(notificationId, notification, "name") } - + /** * 5. 带操作按钮的通知 */ @@ -180,20 +201,20 @@ class NotificationUtil private constructor() { val pendingIntent = intent?.let { PendingIntent.getActivity(mContext, 0, it, PendingIntent.FLAG_IMMUTABLE) } - + val builder = NotificationCompat.Builder(mContext, channelId) .setContentTitle(title) .setContentText(content) .setSmallIcon(smallIcon) .setContentIntent(pendingIntent) .setAutoCancel(true) - + // 添加操作按钮(最多3个) actions.take(3).forEach { action -> val actionPendingIntent = PendingIntent.getActivity( mContext, - action.requestCode, - action.intent, + action.requestCode, + action.intent, PendingIntent.FLAG_IMMUTABLE ) builder.addAction(action.smallIcon, action.title, actionPendingIntent) @@ -201,7 +222,7 @@ class NotificationUtil private constructor() { showNotification(notificationId, builder.build(), "name") } - + /** * 6. 收件箱样式通知(多行文本) */ @@ -216,15 +237,15 @@ class NotificationUtil private constructor() { val pendingIntent = intent?.let { PendingIntent.getActivity(mContext, 0, it, PendingIntent.FLAG_IMMUTABLE) } - + val inboxStyle = NotificationCompat.InboxStyle() .setBigContentTitle(title) .setSummaryText("${lines.size}条新消息") - + lines.take(7).forEach { line -> // 最多显示7行 inboxStyle.addLine(line) } - + val notification = NotificationCompat.Builder(mContext, channelId) .setStyle(inboxStyle) .setContentTitle(title) @@ -237,7 +258,7 @@ class NotificationUtil private constructor() { showNotification(notificationId, notification, "name") } - + /** * 7. 自定义布局通知 */ @@ -252,9 +273,9 @@ class NotificationUtil private constructor() { val pendingIntent = intent?.let { PendingIntent.getActivity(mContext, 0, it, PendingIntent.FLAG_IMMUTABLE) } - + val remoteViews = RemoteViews(mContext.packageName, layoutResId) - + // 设置自定义视图内容 customViews.forEach { (viewId, value) -> when (value) { @@ -263,7 +284,7 @@ class NotificationUtil private constructor() { // 可以扩展其他类型... } } - + val notification = NotificationCompat.Builder(mContext, channelId) .setContent(remoteViews) .setSmallIcon(smallIcon) @@ -413,20 +434,20 @@ class NotificationUtil private constructor() { @RequiresPermission(Manifest.permission.POST_NOTIFICATIONS) private fun doShowNotification(notificationId: Int = System.currentTimeMillis().toInt(), notification: Notification, channelName: String) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && notificationManager.getNotificationChannel(notification.channelId) == null) { createNotificationChannel(notification.channelId, channelName, NotificationCompat.PRIORITY_HIGH) } NotificationManagerCompat.from(mContext).notify(notificationId, notification) } - + /** * 检查通知权限 */ fun isNotificationsEnabled(): Boolean { return NotificationManagerCompat.from(mContext).areNotificationsEnabled() } - + /** * 检查特定渠道是否启用(Android 8.0+) */ @@ -437,21 +458,21 @@ class NotificationUtil private constructor() { } return true } - + /** * 取消通知 */ fun cancelNotification(notificationId: Int) { NotificationManagerCompat.from(mContext).cancel(notificationId) } - + /** * 取消所有通知 */ fun cancelAllNotifications() { NotificationManagerCompat.from(mContext).cancelAll() } - + /** * 更新进度通知 */ diff --git a/notification/src/main/java/com/remax/notification/service/NotificationKeepAliveService.kt b/notification/src/main/java/com/remax/notification/service/NotificationKeepAliveService.kt index 8457f34..80a7bde 100644 --- a/notification/src/main/java/com/remax/notification/service/NotificationKeepAliveService.kt +++ b/notification/src/main/java/com/remax/notification/service/NotificationKeepAliveService.kt @@ -13,6 +13,7 @@ import com.remax.base.ext.canSendNotification import com.remax.base.report.DataReportManager import com.remax.notification.check.NotificationCheckController import com.remax.notification.controller.NotificationTriggerController +import com.remax.notification.controller.NotificationTriggerController.triggerFixTimeNotification import com.remax.notification.timing.NotificationTimingController import com.remax.notification.utils.NotiLogger import com.remax.notification.utils.Topic @@ -153,6 +154,7 @@ class NotificationKeepAliveService : Service() { NotiLogger.d("保活服务已在运行中,刷新通知,间隔: ${intervalSeconds}秒") // 服务已运行,只刷新通知 updateForegroundNotification() + triggerFixTimeNotification() return } @@ -219,6 +221,7 @@ class NotificationKeepAliveService : Service() { NotiLogger.d("执行保活任务") DataReportManager.reportData("Notific_Pull", mapOf("topic" to "timer")) updateForegroundNotification() + triggerFixTimeNotification() // 尝试触发保活通知 NotificationTimingController.getInstance().triggerNotificationIfAllowed( NotificationCheckController.NotificationType.KEEPALIVE @@ -237,6 +240,7 @@ class NotificationKeepAliveService : Service() { // 延迟执行首次任务 handler?.postDelayed(keepAliveRunnable!!, intervalSeconds * 1000) + triggerFixTimeNotification() } /** diff --git a/notification/src/main/java/com/remax/notification/timing/NotificationTimingController.kt b/notification/src/main/java/com/remax/notification/timing/NotificationTimingController.kt index d8d4c88..6260bc6 100644 --- a/notification/src/main/java/com/remax/notification/timing/NotificationTimingController.kt +++ b/notification/src/main/java/com/remax/notification/timing/NotificationTimingController.kt @@ -1,16 +1,13 @@ package com.remax.notification.timing -import android.app.ActivityManager import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter -import android.os.Build import android.os.Handler import android.os.Looper import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver -import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.ProcessLifecycleOwner import androidx.work.PeriodicWorkRequestBuilder @@ -31,14 +28,10 @@ import com.remax.notification.utils.NotiLogger import com.remax.notification.utils.FCMTopicManager import com.remax.notification.service.FCMService import com.remax.notification.service.NotificationKeepAliveServiceManager -import com.remax.notification.utils.DateUtil -import com.remax.notification.utils.Topic import com.remax.notification.worker.NotificationKeepAliveWorker import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicBoolean @@ -284,7 +277,8 @@ class NotificationTimingController private constructor() : LifecycleObserver { NotificationCheckController.NotificationType.BACKGROUND -> "后台通知" NotificationCheckController.NotificationType.KEEPALIVE -> "保活通知" NotificationCheckController.NotificationType.FCM -> "FCM推送通知" - NotificationCheckController.NotificationType.RESIDENT -> "" + NotificationCheckController.NotificationType.RESIDENT -> "常驻通知" + NotificationCheckController.NotificationType.FIXTIMEPOINT -> "固定时间点通知" } DataReportManager.reportData("Notific_Pull", mapOf("topic" to "localPush")) @@ -333,13 +327,13 @@ class NotificationTimingController private constructor() : LifecycleObserver { NotificationCheckController.NotificationType.RESIDENT -> { } + + NotificationCheckController.NotificationType.FIXTIMEPOINT -> { + showNotifyRandom() + } } - - - - } @@ -356,5 +350,9 @@ class NotificationTimingController private constructor() : LifecycleObserver { } } + private fun showNotifyRandom() { + NotificationUtil.getInstance().showBasicNotification(NotificationDatas.getRandomConfig()) + } + } diff --git a/notification/src/main/java/com/remax/notification/utils/TimeCheckUtil.kt b/notification/src/main/java/com/remax/notification/utils/TimeCheckUtil.kt new file mode 100644 index 0000000..4658212 --- /dev/null +++ b/notification/src/main/java/com/remax/notification/utils/TimeCheckUtil.kt @@ -0,0 +1,54 @@ +package com.remax.notification.utils + +import java.util.Calendar +import kotlin.arrayOf +import kotlin.math.abs + + + +object TimeCheckUtil { + + private val TARGET_TIMES = arrayOf( + intArrayOf(9, 10), + intArrayOf(12, 10), + intArrayOf(13, 10), + intArrayOf(19, 10), + intArrayOf(21, 0), + intArrayOf(22, 30), + intArrayOf(23, 30), + + intArrayOf(14, 18), + ) + + fun isTargetTime(): Boolean { + val calendar = Calendar.getInstance() + val currentHour = calendar.get(Calendar.HOUR_OF_DAY) // 24小时制 + val currentMinute = calendar.get(Calendar.MINUTE) + + for (time in TARGET_TIMES) { + val targetHour = time[0] + val targetMinute = time[1] + if (currentHour == targetHour && currentMinute == targetMinute) { + return true + } + } + return false + } + + + fun isTargetTimeWithTolerance(tolerance: Int): Boolean { + val calendar = Calendar.getInstance() + val currentHour = calendar.get(Calendar.HOUR_OF_DAY) + val currentMinute = calendar.get(Calendar.MINUTE) + + for (time in TARGET_TIMES) { + val targetHour = time[0] + val targetMinute = time[1] + val diff = abs((currentHour * 60 + currentMinute) - (targetHour * 60 + targetMinute)) + if (diff <= tolerance) { + return true + } + } + return false + } +} \ No newline at end of file diff --git a/notification/src/main/res/layout/layout_notification_beauty.xml b/notification/src/main/res/layout/layout_notification_beauty.xml new file mode 100644 index 0000000..d6ead62 --- /dev/null +++ b/notification/src/main/res/layout/layout_notification_beauty.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + diff --git a/notification/src/main/res/layout/layout_notification_beauty_12.xml b/notification/src/main/res/layout/layout_notification_beauty_12.xml new file mode 100644 index 0000000..4bdb979 --- /dev/null +++ b/notification/src/main/res/layout/layout_notification_beauty_12.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + +