Files
assistant-android/app/src/main/java/com/gh/common/util/DownloadNotificationHelper.kt
2023-04-06 10:31:12 +08:00

203 lines
9.7 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.gh.common.util
import android.app.Notification
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 com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.getMetaExtra
import com.gh.gamecenter.common.utils.isSimulatorGame
import com.gh.gamecenter.common.utils.isVGame
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SpeedUtils
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
object DownloadNotificationHelper {
private const val DOWNLOAD_GROUP_KEY = "download_group_key"
private const val DOWNLOAD_CHANNEL_ID = "download"
private const val DOWNLOAD_NOTIFICATION_FOLD_ID = 889
private const val DOWNLOAD_NOTIFICATION_ID = 888
private const val PROGRESS_MAX = 100
const val ACTION_INSTALL = "com.gh.gamecenter.INSTALL"
const val ACTION_DOWNLOAD = "com.gh.gamecenter.DOWNLOAD"
const val ACTION_VDOWNLOAD = "com.gh.gamecenter.VDOWNLOAD"
private val mNotifyMap: MutableMap<String, Long> by lazy { mutableMapOf() }
private fun getNotificationManager(): NotificationManager {
return HaloApp.getInstance().application.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
@JvmStatic
@Synchronized
fun addOrUpdateDownloadNotification(entity: DownloadEntity) {
var requireUpdateNotificationGroupDelay = false
val notificationManager = getNotificationManager()
val downloadNotificationId = (entity.gameId + entity.packageName).hashCode()
val xapkStatus = entity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
if (entity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.SILENT_UPDATE) return
if (entity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.SIMULATOR_DOWNLOAD) return
val intent = Intent()
if (entity.status == DownloadStatus.done && xapkStatus != XapkUnzipStatus.FAILURE.name) {
intent.putExtra(EntranceConsts.KEY_URL, entity.url)
intent.putExtra(EntranceConsts.KEY_PATH, entity.path)
intent.action = ACTION_INSTALL
} else if (entity.isVGame()) {
intent.action = ACTION_VDOWNLOAD
} else {
intent.action = ACTION_DOWNLOAD
}
val pendingIntent = PendingIntent.getBroadcast(
HaloApp.getInstance().application,
downloadNotificationId,
intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel =
NotificationChannel(DOWNLOAD_CHANNEL_ID, DOWNLOAD_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW)
notificationManager.createNotificationChannel(channel)
}
val whenTime = 1000 * 60 * (System.currentTimeMillis() / 1000 / 60)
val builder = NotificationCompat.Builder(HaloApp.getInstance().application, DOWNLOAD_CHANNEL_ID)
.setContentTitle(entity.name)
.setSmallIcon(getNotificationIcon())
.setContentIntent(pendingIntent)
.setGroup(DOWNLOAD_GROUP_KEY)
.setWhen(whenTime)
if (xapkStatus == XapkUnzipStatus.FAILURE.name) {
builder.setContentText("" + entity.name + "》解压失败,点击查看详情~")
} else {
when (entity.status) {
DownloadStatus.downloading -> builder.setContentText(
String.format(
"%s(剩%s)",
SpeedUtils.getSpeed(entity.speed),
SpeedUtils.getRemainTime(entity.size, entity.progress, entity.speed * 1024)
)
)
DownloadStatus.done -> builder.setContentText("下载完成,点击立即安装")
DownloadStatus.waiting -> builder.setContentText("等待中")
DownloadStatus.subscribe,
DownloadStatus.timeout,
DownloadStatus.diskisfull,
DownloadStatus.neterror -> builder.setContentText("已暂停连接WiFi自动下载")
else -> builder.setContentText("暂停中")
}
builder.setProgress(PROGRESS_MAX, entity.percent.toInt(), false)
}
when (entity.status) {
DownloadStatus.done -> {
builder.setSortKey("A")
builder.setOngoing(true) // 垃圾华为 sortKey 不起效 priority 也不起效,要将下载完成任务的通知置顶只能设置为 ongoing喷了
}
DownloadStatus.downloading -> builder.setSortKey("B")
else -> builder.setSortKey("C")
}
tryCatchInRelease {
val notification = builder.build() // 可能会抛出异常
notification.flags = notification.flags or Notification.FLAG_NO_CLEAR
if (xapkStatus == XapkUnzipStatus.FAILURE.name) {
notification.flags = notification.flags or Notification.FLAG_AUTO_CANCEL
} else {
notification.flags = notification.flags or Notification.FLAG_NO_CLEAR
}
if (entity.status == DownloadStatus.delete
|| entity.status == DownloadStatus.cancel
|| entity.status == DownloadStatus.hijack
|| entity.status == DownloadStatus.unqualified
|| entity.status == DownloadStatus.unavailable
|| entity.status == DownloadStatus.banned
|| entity.status == DownloadStatus.uncertificated
|| entity.status == DownloadStatus.notfound
|| entity.status == DownloadStatus.overflow
|| (entity.status == DownloadStatus.done // 触发安装事件以后也 cancel 掉通知
&& !entity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION].isNullOrEmpty()
&& xapkStatus != XapkUnzipStatus.FAILURE.name)
|| entity.status == DownloadStatus.done && entity.isSimulatorGame()
) {//模拟器游戏下载完需要cancel掉通知
requireUpdateNotificationGroupDelay = true
notificationManager.cancel(entity.path, DOWNLOAD_NOTIFICATION_ID)
} else {
if (entity.status != DownloadStatus.downloading) {
notificationManager.notify(entity.path, DOWNLOAD_NOTIFICATION_ID, notification)
} else {
val time = mNotifyMap[entity.path]
val curTime = System.currentTimeMillis()
if (time == null || curTime - time > 2000) {
mNotifyMap[entity.path] = curTime
notificationManager.notify(entity.path, DOWNLOAD_NOTIFICATION_ID, notification)
}
}
}
}
if (requireUpdateNotificationGroupDelay) {
// 虽然运行到这里时 notification 已经被 cancel 了,但在下面的 notificationManager.getActiveNotifications 里它有可能还是 active 状态,
// 这里延时 100 ms 避免出现所有的任务都取消了以后依旧有一条 notification group 常驻
AppExecutor.uiExecutor.executeWithDelay(Runnable { updateNotificationGroup() }, 100)
} else {
updateNotificationGroup()
}
}
private fun updateNotificationGroup() {
// 部分华为设备调用 getActiveNotifications() 方法时会触发方法内的空指针,这里整体包裹处理了
tryCatchInRelease {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val notificationManager = getNotificationManager()
val activeNotifications = notificationManager.activeNotifications
var downloadNotificationSize = 0
var downloadGroupNotificationSize = 0
for (activeNotification in activeNotifications) {
if (activeNotification.id == DOWNLOAD_NOTIFICATION_ID) {
downloadNotificationSize++
}
if (activeNotification.id == DOWNLOAD_NOTIFICATION_FOLD_ID) {
downloadGroupNotificationSize++
}
}
if (downloadNotificationSize == 0 && downloadGroupNotificationSize != 0) {
// 删除组可能会把组内所有通知一并删除
notificationManager.cancel(DOWNLOAD_NOTIFICATION_FOLD_ID)
} else if (downloadNotificationSize != 0 && downloadGroupNotificationSize == 0) {
val groupBuilder =
NotificationCompat.Builder(HaloApp.getInstance().application, DOWNLOAD_CHANNEL_ID)
.setSmallIcon(getNotificationIcon())
.setGroup(DOWNLOAD_GROUP_KEY)
.setGroupSummary(true)
.setStyle(NotificationCompat.BigTextStyle().bigText("下载任务"))
val groupNotification = groupBuilder.build()
groupNotification.flags = groupNotification.flags or Notification.FLAG_NO_CLEAR
notificationManager.notify(DOWNLOAD_NOTIFICATION_FOLD_ID, groupNotification)
}
}
}
}
private fun getNotificationIcon(): Int {
return R.mipmap.logo
}
}