Files
assistant-android/app/src/main/java/com/gh/common/util/GameActivityDownloadHelper.kt
2024-04-19 17:32:51 +08:00

678 lines
26 KiB
Kotlin

package com.gh.common.util
import android.annotation.SuppressLint
import android.content.Context
import android.text.TextUtils
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.DefaultJsApi
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureManager
import com.gh.common.history.HistoryHelper
import com.gh.common.repository.ReservationRepository
import com.gh.common.simulator.NewSimulatorGameManager
import com.gh.common.simulator.SimulatorDownloadManager
import com.gh.common.simulator.SimulatorGameManager
import com.gh.download.DownloadManager
import com.gh.download.dialog.DownloadDialog
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.retrofit.ApiResponse
import com.gh.gamecenter.common.retrofit.EmptyResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.feature.entity.ApkEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.utils.ApkActiveUtils
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.teenagermode.TeenagerModeActivity
import com.gh.vspace.VHelper
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import java.io.File
/**
* 游戏活动下载辅助类
*/
object GameActivityDownloadHelper {
private var mTraceEvent: ExposureEvent? = null
private var mGameEntity: GameEntity? = null
fun start(context: Context, event: DefaultJsApi.GameActivityEvent) {
if (mGameEntity != null && mGameEntity?.id == event.gameId) {
runOnUiThread {
handleGameEntity(context, event, mGameEntity!!)
}
} else {
RetrofitManager.getInstance()
.api
.getGameDigest(event.gameId)
.map(ApkActiveUtils.filterMapper)
.compose(observableToMain())
.subscribe(object : Response<GameEntity>() {
override fun onResponse(gameEntity: GameEntity?) {
mGameEntity = gameEntity
gameEntity?.let {
handleGameEntity(context, event, it)
}
}
})
}
}
private fun handleGameEntity(
context: Context,
event: DefaultJsApi.GameActivityEvent,
gameEntity: GameEntity
) {
// 青少年模式
if (isTeenageMode(context)) return
val entrance = "(游戏活动[${event.activityTitle}])"
val location = "游戏活动:${event.activityTitle}-${gameEntity.name}"
if (mTraceEvent == null) {
val exposureSources = arrayListOf(
ExposureSource("游戏活动", "${event.activityTitle}+${event.activityId}")
)
mTraceEvent = ExposureEvent.createEvent(gameEntity, exposureSources, null, ExposureType.EXPOSURE)
}
mTraceEvent?.run {
when {
// 预约
gameEntity.isReservable -> reserve(context, gameEntity, entrance, this)
// 开始玩
gameEntity.getApk().size == 0 && gameEntity.h5Link != null -> play(context, gameEntity)
// 下载
else -> handleDownloadStatus(context, event, gameEntity, entrance, location, this)
}
}
}
// 青少年模式
private fun isTeenageMode(context: Context): Boolean {
if (SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) {
SensorsBridge.trackAdolescentModeDialogShow(
gameId = mGameEntity?.id ?: "",
gameName = mGameEntity?.name ?: "",
gameType = mGameEntity?.categoryChinese ?: ""
)
DialogHelper.showDialog(
context,
"提示",
"当前处于儿童/青少年模式, \n暂不提供游戏下载",
"退出青少年模式",
"关闭",
confirmClickCallback = {
context.startActivity(TeenagerModeActivity.getIntent(context))
SensorsBridge.trackAdolescentModeDialogClick(
buttonName = "退出青少年模式",
gameId = mGameEntity?.id ?: "",
gameName = mGameEntity?.name ?: "",
gameType = mGameEntity?.categoryChinese ?: ""
)
},
cancelClickCallback = {
SensorsBridge.trackAdolescentModeDialogClick(
buttonName = "关闭",
gameId = mGameEntity?.id ?: "",
gameName = mGameEntity?.name ?: "",
gameType = mGameEntity?.categoryChinese ?: ""
)
},
touchOutsideCallback = {
SensorsBridge.trackAdolescentModeDialogClick(
buttonName = "关闭弹窗",
gameId = mGameEntity?.id ?: "",
gameName = mGameEntity?.name ?: "",
gameType = mGameEntity?.categoryChinese ?: ""
)
},
extraConfig = DialogHelper.Config(
centerTitle = true,
centerContent = true
)
)
return true
}
return false
}
// 预约
private fun reserve(
context: Context,
gameEntity: GameEntity,
entrance: String,
traceEvent: ExposureEvent
) {
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.id)) {
CheckLoginUtils.checkLogin(context, entrance) {
ReservationHelper.reserve(context, gameEntity) {
LogUtils.logReservation(gameEntity, traceEvent)
clear()
}
}
} else {
ToastUtils.toast("游戏已成功预约")
}
}
// 开始玩(H5链接)
private fun play(context: Context, gameEntity: GameEntity) {
val linkEntity = gameEntity.h5Link
val isPlay = "play" == linkEntity!!.type // 是否为开始玩
if (isPlay) {
HistoryHelper.insertGameEntity(gameEntity)
}
val i = WebActivity.getIntentForWebGame(
context,
gameEntity.h5Link!!.link,
gameEntity.name,
isPlay,
linkEntity.closeButton
)
context.startActivity(i)
}
// 处理下载的各种状态
private fun handleDownloadStatus(
context: Context,
event: DefaultJsApi.GameActivityEvent,
gameEntity: GameEntity,
entrance: String,
location: String,
traceEvent: ExposureEvent
) {
val apk = getApk(gameEntity, event, true) ?: return
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
val str = GameUtils.getDownloadBtnText(
context = context,
gameEntity = gameEntity,
isFromList = true,
fixedAsVGame = false,
pluginLocation = PluginLocation.only_game
)
if (downloadEntity != null
&& str != context.getString(R.string.install)
&& str != context.getString(R.string.launch)
) {
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
} else {
when {
str == context.getString(R.string.download) || str == context.getString(R.string.attempt) -> {
handleDownloadStatus(context, gameEntity, apk, entrance, location, traceEvent)
}
str == context.getString(R.string.smooth) -> {
handleSmoothStatus(context, gameEntity, apk, entrance, location, traceEvent)
}
str.contains("") -> {
handlePluginStatus(context, gameEntity, apk, entrance, location, traceEvent)
}
str == context.getString(R.string.install) -> {
handleInstallStatus(context, gameEntity, apk, downloadEntity)
}
str == context.getString(R.string.launch) -> {
handleLaunchStatus(context, gameEntity, apk, entrance, location, traceEvent)
}
str == context.getString(R.string.update) -> {
handleUpdateStatus(context, gameEntity, apk, entrance, location, traceEvent)
}
else -> {
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
}
}
}
}
// 处理下载状态
private fun handleDownloadStatus(
context: Context,
gameEntity: GameEntity,
apk: ApkEntity,
entrance: String,
location: String,
traceEvent: ExposureEvent
) {
GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
DialogUtils.checkDownload(
context,
apk.size,
gameEntity.id,
gameEntity.name,
gameEntity.categoryChinese
) { isSubscribe: Boolean ->
download(context, gameEntity, apk, false, isSubscribe, entrance, location, traceEvent)
}
}
DataLogUtils.uploadGameLog(context, gameEntity.id, gameEntity.name, entrance)
}
// 处理畅玩状态
private fun handleSmoothStatus(
context: Context,
gameEntity: GameEntity,
apk: ApkEntity,
entrance: String,
location: String,
traceEvent: ExposureEvent
) {
VHelper.validateVSpaceBeforeAction(context,gameEntity.getUniquePackageName(), gameEntity) {
GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
DialogUtils.checkDownload(
context,
apk.size,
gameEntity.id,
gameEntity.name,
gameEntity.categoryChinese
) { isSubscribe: Boolean ->
download(context, gameEntity, apk, true, isSubscribe, entrance, location, traceEvent)
}
}
}
}
// 处理插件化状态
private fun handlePluginStatus(
context: Context,
gameEntity: GameEntity,
apk: ApkEntity,
entrance: String,
location: String,
traceEvent: ExposureEvent
) {
if (gameEntity.pluggableCollection != null) {
DownloadDialog.showDownloadDialog(context, gameEntity, traceEvent, entrance, location)
} else {
DialogUtils.checkDownload(
context,
apk.size,
gameEntity.id,
gameEntity.name,
gameEntity.categoryChinese
) { isSubscribe: Boolean ->
plugin(context, gameEntity, apk, entrance, location, isSubscribe, traceEvent)
}
}
}
// 处理安装状态
private fun handleInstallStatus(
context: Context,
gameEntity: GameEntity,
apk: ApkEntity,
downloadEntity: DownloadEntity?
) {
com.gh.gamecenter.common.utils.NewFlatLogUtils.logGameInstall(
gameId = downloadEntity?.gameId ?: "",
gameName = downloadEntity?.name ?: "",
trigger = "主动安装"
)
SensorsBridge.trackInstallGameClick(
gameName = downloadEntity?.name ?: "",
gameId = downloadEntity?.gameId ?: "",
action = "主动安装"
)
val simulatorDownloadEntity = SimulatorGameManager.findDownloadEntityByUrl(apk.url)
if (gameEntity.simulator != null) {
val isInstalled =
PackageUtils.isInstalledFromAllPackage(context, gameEntity.simulator!!.apk!!.packageName)
val isInstalledNewSimulator = SimulatorGameManager.isNewSimulatorInstalled(context)
val isInstalledOldSimulator = SimulatorGameManager.isOldSimulatorInstalled(context)
var simulator = gameEntity.simulator
val newSimulator = Config.getNewSimulatorEntitySetting()
// 在没有安装旧的模拟器且有配置新版模拟器 才使用新版模拟器 否则还是用以前旧的
if (!isInstalledOldSimulator && newSimulator != null && newSimulator.active) {
simulator = newSimulator
}
if (simulatorDownloadEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity) && !isInstalled && !isInstalledNewSimulator) {
SimulatorDownloadManager.getInstance().showDownloadDialog(
context, simulator,
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.id, gameEntity.name!!, gameEntity.categoryChinese, null
)
return
}
}
if (downloadEntity?.isVGameDownloadInDualDownloadMode() == true) {
VHelper.installOrLaunch((context as AppCompatActivity), gameEntity)
} else {
downloadEntity?.run { install(context, gameEntity, apk, this) }
}
}
// 处理启动状态
private fun handleLaunchStatus(
context: Context,
gameEntity: GameEntity,
apk: ApkEntity,
entrance: String,
location: String,
traceEvent: ExposureEvent
) {
//启动模拟器游戏
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
if (NewSimulatorGameManager.shouldShowUpdateNewSimulatorAlert(context)) {
NewSimulatorGameManager.showUpdateNewsSimulator(context, gameEntity, null)
return
}
val simulatorDownloadEntity =
SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().firstOrNull()?.url)
if (simulatorDownloadEntity != null) {
val file = File(simulatorDownloadEntity.path)
if (!file.exists()) {
download(
context = context,
gameEntity = gameEntity,
apk = apk,
asVGame = false,
isSubscribe = false,
entrance = entrance,
location = location,
traceEvent = traceEvent
)
return
}
NewFlatLogUtils.logSimulatorGameCardClick("启动")
SimulatorGameManager.launchSimulatorGame(simulatorDownloadEntity, gameEntity)
}
return
}
PackageLauncher.launch(context, gameEntity)
}
// 处理更新状态
private fun handleUpdateStatus(
context: Context,
gameEntity: GameEntity,
apk: ApkEntity,
entrance: String,
location: String,
traceEvent: ExposureEvent
) {
DialogUtils.checkDownload(context, apk.size, gameEntity.id, gameEntity.name, gameEntity.categoryChinese) { isSubscribe: Boolean ->
update(context, gameEntity, apk, entrance, location, isSubscribe, traceEvent)
}
}
private fun getApk(
gameEntity: GameEntity,
event: DefaultJsApi.GameActivityEvent,
isRemoveOther: Boolean
): ApkEntity? {
return when {
gameEntity.getApk().isEmpty() -> null
gameEntity.getApk().size == 1 -> gameEntity.getApk().firstOrNull()
// 找出对应平台版本Apk且移除掉其他平台版本Apk
isRemoveOther -> {
// 当前游戏为多版本时,只保留活动指定的版本即可,方便之后判断
var apk: ApkEntity? = null
val iterator = gameEntity.getApk().iterator()
while (iterator.hasNext()) {
val tempApk = iterator.next()
if (tempApk.getPlatform() == event.platform) {
apk = tempApk
} else {
iterator.remove()
}
}
apk
}
// 找出对应平台版本Apk即可
else -> {
var apk: ApkEntity? = null
run outside@{
gameEntity.getApk().forEach {
if (it.getPlatform() == event.platform) {
apk = it
return@outside
}
}
}
apk
}
}
}
private fun download(
context: Context,
gameEntity: GameEntity,
apk: ApkEntity,
asVGame: Boolean,
isSubscribe: Boolean,
entrance: String,
location: String,
traceEvent: ExposureEvent
) {
val msg = FileUtils.isCanDownload(context, apk.size)
if (TextUtils.isEmpty(msg)) {
DownloadManager.createDownload(context, apk, gameEntity, asVGame, gameEntity.isDualBtnModeEnabled(), entrance, location, isSubscribe, traceEvent)
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
} else {
ToastUtils.toast(msg)
}
}
// 插件化
private fun plugin(
context: Context,
gameEntity: GameEntity,
apk: ApkEntity,
entrance: String,
location: String,
isSubscribe: Boolean,
traceEvent: ExposureEvent?
) {
val msg = FileUtils.isCanDownload(context, apk.size)
if (TextUtils.isEmpty(msg)) {
DownloadManager.createDownload(context, apk, gameEntity, false, false, entrance, location, isSubscribe, traceEvent)
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
} else {
ToastUtils.toast(msg)
}
}
// 安装
private fun install(
context: Context,
gameEntity: GameEntity,
apkEntity: ApkEntity,
downloadEntity: DownloadEntity
) {
val path = downloadEntity.path
when {
FileUtils.isEmptyFile(path) -> {
Utils.toast(context, R.string.install_failure_hint)
DownloadManager.getInstance().cancel(downloadEntity.url)
gameEntity.getEntryMap().remove(apkEntity.getPlatform())
}
PackageUtils.isCanPluggable(apkEntity) -> {
DialogHelper.showPluginDialog(
context,
pluginDesc = gameEntity.pluginDesc,
gameId = gameEntity.id,
gameName = gameEntity.name ?: "",
gameType = gameEntity.categoryChinese,
platform = gameEntity.platform ?: ""
) {
PackageInstaller.uninstall(context, path)
}
}
else -> {
PackageInstaller.install(context, downloadEntity)
}
}
}
// 更新
private fun update(
context: Context,
gameEntity: GameEntity,
apk: ApkEntity,
entrance: String,
location: String,
isSubscribe: Boolean,
traceEvent: ExposureEvent?
) {
DownloadManager.createDownload(context, apk, gameEntity, false, false, entrance, location, isSubscribe, traceEvent)
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
}
@SuppressLint("CheckResult")
fun postTaskComplete(gameId: String) {
val api = RetrofitManager.getInstance().newApi
val single = if (UserManager.getInstance().isLoggedIn) {
api.postGameActivityTask(gameId)
} else {
api.postGameActivityTaskForNoLogin(gameId)
}
single.compose(singleToMain()).subscribe(EmptyResponse())
}
// 判断是否完成任务(预约完成或者已安装且无更新)
@SuppressLint("CheckResult")
fun checkTaskComplete(
context: Context,
event: DefaultJsApi.GameActivityEvent,
handler: CompletionHandler<Any>
) {
// 预约完成
if (ReservationRepository.thisGameHasBeenReserved(event.gameId)) {
postTaskComplete(event.gameId)
handler.complete(true)
return
}
if (mGameEntity != null && mGameEntity?.id == event.gameId) {
handleCheckTaskComplete(context, mGameEntity, event, handler)
} else {
RetrofitManager.getInstance()
.api
.getGameDigest(event.gameId)
.map(ApkActiveUtils.filterMapper)
.compose(observableToMain())
.subscribe(object : Response<GameEntity>() {
override fun onResponse(gameEntity: GameEntity?) {
mGameEntity = gameEntity
handleCheckTaskComplete(context, gameEntity, event, handler)
}
override fun onApiFailure(e: ApiResponse<GameEntity>?) {
super.onApiFailure(e)
handler.complete(false)
}
})
}
}
private fun handleCheckTaskComplete(
context: Context,
gameEntity: GameEntity?,
event: DefaultJsApi.GameActivityEvent,
handler: CompletionHandler<Any>
) {
if (gameEntity == null) {
handler.complete(false)
} else {
val apk = getApk(gameEntity, event, false)
if (apk == null) {
handler.complete(false)
} else {
// 已安装
if (PackageUtils.isInstalled(context, apk.packageName)) {
// 是否可更新
if (PackageUtils.isCanUpdate(apk, event.gameId)
|| PackageUtils.isNonPluginUpdatable(apk, gameEntity)
) {
handler.complete(false)
} else {
// 已安装且无更新
postTaskComplete(event.gameId)
handler.complete(true)
}
} else {
handler.complete(false)
}
}
}
}
fun postExposureEvent(event: DefaultJsApi.GameActivityEvent) {
RetrofitManager.getInstance()
.api
.getGameDigest(event.gameId)
.map(ApkActiveUtils.filterMapper)
.compose(observableToMain())
.subscribe(object : Response<GameEntity>() {
override fun onResponse(gameEntity: GameEntity?) {
mGameEntity = gameEntity
gameEntity?.let {
val exposureSources = arrayListOf(
ExposureSource("游戏活动", "${event.activityTitle}+${event.activityId}")
)
mTraceEvent = ExposureEvent.createEvent(
gameEntity,
exposureSources,
null,
ExposureType.EXPOSURE
)
mTraceEvent?.run { ExposureManager.log(this) }
}
}
})
}
fun clear() {
mTraceEvent = null
mGameEntity = null
}
}