Compare commits

...

35 Commits

Author SHA1 Message Date
42d5d46e53 chore: 版本更新至 5.28.2 2023-07-18 16:13:09 +08:00
cdccc35703 Merge branch 'feature-GHZS-2946' into 'release'
fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2946

See merge request halo/android/assistant-android!1207
2023-07-18 16:08:44 +08:00
d3e2fea019 fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2946 2023-07-18 16:08:44 +08:00
f343841233 Merge branch 'fix/GHZS-2948' into 'release'
fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2948

See merge request halo/android/assistant-android!1206
2023-07-18 14:58:47 +08:00
f62083eff2 fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2948 2023-07-18 14:58:47 +08:00
8594e998c2 Merge branch 'fix/vspace_dialog_dismiss_issue' into 'release'
fix: 修复畅玩弹窗在组件安装完成以后的 dismiss 问题

See merge request halo/android/assistant-android!1205
2023-07-17 17:54:15 +08:00
6865706b0f fix: 修复畅玩弹窗在组件安装完成以后的 dismiss 问题 2023-07-17 17:50:23 +08:00
b6d8ca4d84 Merge branch 'feat/GHZS-2959' into 'release'
feat: 神策渠道调整 https://jira.shanqu.cc/browse/GHZS-2959

See merge request halo/android/assistant-android!1203
2023-07-17 16:14:05 +08:00
455e1f0432 feat: 神策渠道调整 https://jira.shanqu.cc/browse/GHZS-2959 2023-07-17 16:12:29 +08:00
15276cc4b3 Merge branch 'hotfix/v5.28.1-911/crashes' into 'release'
修复部分线上闪退

See merge request halo/android/assistant-android!1202
2023-07-17 11:53:17 +08:00
130a7cdf2a fix: 修复因为混淆造成的下载数据恢复闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/281841/?project=22 2023-07-17 11:08:11 +08:00
164ec0c368 fix: 捕抓首页 tab 的 roundToInt 闪退异常 2023-07-17 11:07:11 +08:00
991bd22511 Merge branch 'fix/sensors_log' into 'release'
fix: 修复畅玩助手下载弹窗错误上报安装点击事件的问题

See merge request halo/android/assistant-android!1199
2023-07-14 17:05:55 +08:00
df1ab5221d fix: 修复畅玩助手下载弹窗错误上报安装点击事件的问题 2023-07-14 16:41:51 +08:00
226d6c4f2c chore: 版本更新至 5.28.1 2023-07-13 17:25:06 +08:00
896adc9d36 Merge branch 'feature-data-watcher-patch' into 'release'
fix: Sentry312134...

See merge request halo/android/assistant-android!1198
2023-07-13 15:35:48 +08:00
0e33abebdd fix: Sentry312134... 2023-07-13 15:35:48 +08:00
c8ed126605 Merge branch 'fix/GHZS-2926' into 'release'
fix:【光环助手】游戏单封面图显示问题 https://jira.shanqu.cc/browse/GHZS-2926

See merge request halo/android/assistant-android!1196
2023-07-12 14:48:17 +08:00
b510a329b6 fix:【光环助手】游戏单封面图显示问题 https://jira.shanqu.cc/browse/GHZS-2926 2023-07-12 14:36:38 +08:00
2de1ba4e1d Merge branch 'fix/GHZS-2907' into 'release'
fix: 神策埋点—07/10测试 (3) https://jira.shanqu.cc/browse/GHZS-2907

See merge request halo/android/assistant-android!1195
2023-07-11 15:37:47 +08:00
e4a0f0e68b fix: 神策埋点—07/10测试 (3) https://jira.shanqu.cc/browse/GHZS-2907 2023-07-11 15:31:44 +08:00
c064f9d3a6 Merge branch 'feat/core_event_with_toast' into 'release'
fix: 特殊包上报比例为 1 时关键行为进行 toast 提示(方便测试)

See merge request halo/android/assistant-android!1190
2023-07-11 13:52:00 +08:00
759401d9ae Merge branch 'fix/CWZS-91' into 'release'
fix: 推送更新测试问题—测试问题07/06 https://jira.shanqu.cc/browse/CWZS-91

See merge request halo/android/assistant-android!1191
2023-07-11 13:51:53 +08:00
e56209d15e fix: 处理弹窗 dismiss 问题 2023-07-11 13:38:59 +08:00
c466ff1f21 fix: 处理弹窗 dismiss 问题 2023-07-11 11:51:41 +08:00
e09cf299f0 Merge branch 'feature-GHZS-2771-patch-3' into 'release'
fix: 支持xapk格式的apks文件解压-0706测试

See merge request halo/android/assistant-android!1193
2023-07-11 10:40:24 +08:00
25352ba609 fix: 支持xapk格式的apks文件解压-0706测试 2023-07-11 10:40:24 +08:00
3cd065cb6e fix: 处理弹窗 dismiss 问题 2023-07-10 16:21:01 +08:00
919a98ffe6 fix: 处理弹窗 dismiss 问题 2023-07-10 11:26:22 +08:00
eff84218a8 fix: 特殊包上报比例为 1 时关键行为进行 toast 提示(方便测试) 2023-07-07 11:32:44 +08:00
7c9c363422 fix: 推送更新测试问题—测试问题07/06 https://jira.shanqu.cc/browse/CWZS-91 2023-07-07 10:04:41 +08:00
8b1a38214c Merge branch 'feature-GHZS-2771-patch-2' into 'release'
feat: 支持xapk格式的apks文件解压—0705测试

See merge request halo/android/assistant-android!1185
2023-07-06 09:47:32 +08:00
2acde0af00 feat: 支持xapk格式的apks文件解压—0705测试 2023-07-06 09:47:32 +08:00
201c1207f9 Merge branch 'feature-GHZS-2771-patch-1' into 'release'
feat: 支持xapk格式的apks文件解压—0704测试

See merge request halo/android/assistant-android!1183
2023-07-05 14:24:55 +08:00
75d86b5a91 feat: 支持xapk格式的apks文件解压—0704测试 2023-07-05 14:24:55 +08:00
32 changed files with 360 additions and 305 deletions

View File

@ -3,10 +3,13 @@ package com.gh.gamecenter.provider
import android.app.Activity
import android.app.Application
import android.text.TextUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.KuaishouHelper
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.halo.assistant.HaloApp
import com.kwai.monitor.payload.TurboHelper
@ -44,6 +47,11 @@ class FlavorProviderImp : IFlavorProvider {
override fun logCoreEvent() {
logEvent("EVENT_KEY_PATH_OPTIMIZATION")
if (BuildConfig.ACTIVATE_REPORTING_RATIO == 1) {
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast("关键行为 EVENT_KEY_PATH_OPTIMIZATION")
}, 500)
}
}
companion object {

View File

@ -830,8 +830,9 @@
</intent-filter>
</receiver>
<receiver
<activity
android:name="com.gh.common.xapk.XapkInstallReceiver"
android:theme="@style/Theme.Transparent"
android:exported="false" />
<receiver

View File

@ -1,23 +0,0 @@
package com.gh.common.chain
import android.content.Context
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.feature.entity.GameEntity
class AutoSwitchAssistantInstallHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
if (BrowserInstallHelper.isUseBrowserToInstallEnabled()
&& BrowserInstallHelper.shouldUseBrowserToInstall()
&& gameEntity.isSplitXApk()) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
}
}

View File

@ -1,5 +1,6 @@
package com.gh.common.databind;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
@ -19,7 +20,6 @@ import androidx.core.content.ContextCompat;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.common.chain.AutoSwitchAssistantInstallHandler;
import com.gh.common.chain.BrowserInstallHandler;
import com.gh.common.chain.CertificationHandler;
import com.gh.common.chain.ChainBuilder;
@ -52,6 +52,7 @@ import com.gh.common.util.PackageUtils;
import com.gh.common.util.ReservationHelper;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
import com.gh.download.server.BrowserInstallHelper;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
@ -66,6 +67,7 @@ import com.gh.gamecenter.common.view.DrawableView;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.core.utils.NumberUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.databinding.KaifuDetailItemRowBinding;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.CommunityVideoEntity;
@ -414,7 +416,7 @@ public class BindingAdapters {
builder.addHandler(new CheckDownloadHandler());
builder.setProcessEndCallback(o -> {
download(progressBar, gameEntity, traceEvent, (boolean) o, entrance, location);
download(v.getContext(), progressBar, gameEntity, traceEvent, (boolean) o, entrance, location);
return null;
});
final ChainHandler chainHandler = builder.buildHandlerChain();
@ -452,7 +454,7 @@ public class BindingAdapters {
if (downloadEntity != null) {
File file = new File(downloadEntity.getPath());
if (!file.exists()) {
download(progressBar, gameEntity, traceEvent, false, entrance, location);
download(v.getContext(), progressBar, gameEntity, traceEvent, false, entrance, location);
return;
}
@ -678,12 +680,16 @@ public class BindingAdapters {
// 开始下载
private static void download(DownloadButton progressBar,
private static void download(Context context,
DownloadButton progressBar,
GameEntity gameEntity,
ExposureEvent traceEvent,
boolean isSubscribe,
String entrance,
String location) {
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint));
}
String str = progressBar.getText().toString();
String method;
if (str.contains("更新")) {

View File

@ -31,6 +31,7 @@ import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
@ -1014,10 +1015,13 @@ object DownloadItemUtils {
isSubscribe,
traceEvent
)
ToastUtils.toast(gameEntity.name + "已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
Utils.toast(context, gameEntity.name + "已加入下载队列")
if (downloadBtn is DownloadButton) {
downloadBtn.text = "0%"
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
@ -1041,10 +1045,13 @@ object DownloadItemUtils {
val msg = FileUtils.isCanDownload(context, gameEntity.getApk()[0].size ?: "")
if (TextUtils.isEmpty(msg)) {
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location, isSubscribe, traceEvent)
ToastUtils.toast(gameEntity.name + "已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
Utils.toast(context, gameEntity.name + "已加入下载队列")
if (downloadBtn is DownloadButton) {
downloadBtn.setText(R.string.downloading)
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN

View File

@ -27,6 +27,7 @@ import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.common.utils.singleToMain
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.MtaHelper
@ -183,10 +184,13 @@ object GameActivityDownloadHelper {
str != context.getString(R.string.install) &&
str != context.getString(R.string.launch)
) {
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
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) -> {
@ -208,10 +212,13 @@ object GameActivityDownloadHelper {
handleUpdateStatus(context, gameEntity, apk, entrance, location, traceEvent)
}
else -> {
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
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)
}
}
}
}
@ -430,10 +437,13 @@ object GameActivityDownloadHelper {
R.string.download
), entrance, location, isSubscribe, traceEvent
)
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
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)
}
@ -452,10 +462,13 @@ object GameActivityDownloadHelper {
val msg = FileUtils.isCanDownload(context, apk.size)
if (TextUtils.isEmpty(msg)) {
DownloadManager.createDownload(context, apk, gameEntity, "插件化", entrance, location, isSubscribe, traceEvent)
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
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)
}
@ -495,10 +508,13 @@ object GameActivityDownloadHelper {
traceEvent: ExposureEvent?
) {
DownloadManager.createDownload(context, apk, gameEntity, "更新", entrance, location, isSubscribe, traceEvent)
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
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")

View File

@ -4,9 +4,12 @@ import android.app.Activity
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller.SessionCallback
import android.net.Uri
import android.os.Build
import android.util.Log
import android.view.View
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import com.gh.common.dialog.InstallPermissionDialogFragment
@ -18,6 +21,7 @@ import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.getMetaExtra
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.ToastUtils
@ -161,14 +165,13 @@ object PackageInstaller {
}
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
} else {
PendingIntent.FLAG_UPDATE_CURRENT
PendingIntent.FLAG_CANCEL_CURRENT
}
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, flags)
val pendingIntent = PendingIntent.getActivity(context, sessionId, intent, flags)
// 提交数据流并执行安装
session.commit(pendingIntent.intentSender)
session.close()
}
/**

View File

@ -1,30 +1,35 @@
package com.gh.common.xapk
import android.content.BroadcastReceiver
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionInfo
import android.os.Build
import android.os.Bundle
import androidx.annotation.RequiresApi
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class XapkInstallReceiver : BroadcastReceiver() {
class XapkInstallReceiver : Activity() {
companion object {
const val KEY_PACKAGE_PATH = "package_path"
}
override fun onReceive(context: Context, intent: Intent) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
overridePendingTransition(0, 0)
handleIntent(this, intent)
}
private fun handleIntent(context: Context, intent: Intent) {
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
val installIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
if (installIntent != null) {
val installPackagePath = intent.getStringExtra(KEY_PACKAGE_PATH)
val installSessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
XapkInstaller.onPendingUserAction(installPackagePath!!, installSessionId)
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(installIntent)
updatePendingSessionInfoStatus(intent, XapkPendingSessionInfo.STATUS_PENDING_USER_ACTION)
finish()
}
}
PackageInstaller.STATUS_FAILURE,
@ -34,11 +39,21 @@ class XapkInstallReceiver : BroadcastReceiver() {
PackageInstaller.STATUS_FAILURE_INCOMPATIBLE,
PackageInstaller.STATUS_FAILURE_INVALID,
PackageInstaller.STATUS_FAILURE_STORAGE -> {
val installPackagePath = intent.getStringExtra(KEY_PACKAGE_PATH)
if (!installPackagePath.isNullOrEmpty()) {
XapkInstaller.onInstallCanceled(installPackagePath)
}
updatePendingSessionInfoStatus(intent, XapkPendingSessionInfo.STATUS_INSTALL_CANCELED)
finish()
}
else -> {
updatePendingSessionInfoStatus(intent, XapkPendingSessionInfo.STATUS_INSTALL_SUCCESS)
finish()
}
}
}
private fun updatePendingSessionInfoStatus(intent: Intent, status: Int) {
val installPackagePath = intent.getStringExtra(KEY_PACKAGE_PATH)
if (!installPackagePath.isNullOrEmpty()) {
val pendingSessionInfo = XapkInstaller.getPendingSessionInfo(installPackagePath)
pendingSessionInfo?.updateStatus(status)
}
}
}

View File

@ -9,6 +9,7 @@ import com.gh.download.DownloadManager
import com.gh.gamecenter.common.utils.debugOnly
import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.throwExceptionInDebug
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SentryHelper
import com.gh.gamecenter.xapk.XApkUnZipper
import com.gh.gamecenter.xapk.core.XApkFile
@ -59,9 +60,7 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
private val mDownloadEntityMap = Collections.synchronizedMap(HashMap<String, DownloadEntity>())
private val mInstallingPath = Collections.synchronizedList(mutableListOf<String>())
private val mPendingSessionIdMap = Collections.synchronizedMap(HashMap<String, Int>())
private val mPendingSessionInfoMap = HashMap<String, XapkPendingSessionInfo>()
// 按并行解压
@JvmStatic
@ -99,7 +98,11 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
val downloadEntity = mDownloadEntityMap[apk.file.path] ?: return
downloadEntity.meta[XAPK_UNZIP_PERCENT] = String.format("%.2f", progress * 100)
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.UNZIPPING.name
NDataChanger.notifyDataChanged(downloadEntity)
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
}
debugOnly {
Utils.log("unzip", "onProgress->$progress")
}
@ -110,43 +113,40 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.SUCCESS.name
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压成功")
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压成功")
}
debugOnly {
Utils.log("unzip", "onSuccess->${downloadEntity.path}")
}
if (!mInstallingPath.contains(downloadEntity.path)) {
mInstallingPath.add(downloadEntity.path)
}
NDataChanger.notifyDataChanged(downloadEntity)
XapkInstallerLooper.add(downloadEntity.path, installer)
XapkInstallerLooper.install(mContext)
installer.install(mContext)
}
override fun onError(apk: XApkFile, exception: Throwable) {
val downloadEntity = mDownloadEntityMap[apk.file.path] ?: return
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.FAILURE.name
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
// 仅官网渠道上报 XAPK 异常信息
if (HaloApp.getInstance().channel == "GH_206") {
SentryHelper.onEvent(
"XAPK_UNZIP_ERROR",
"gameName", downloadEntity.name,
"errorDigest", exception.localizedMessage
)
AppExecutor.ioExecutor.execute {
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
// 仅官网渠道上报 XAPK 异常信息
if (HaloApp.getInstance().channel == "GH_206") {
SentryHelper.onEvent(
"XAPK_UNZIP_ERROR",
"gameName", downloadEntity.name,
"errorDigest", exception.localizedMessage
)
}
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压失败")
}
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压失败")
debugOnly {
Utils.log("unzip", "onFailure->$exception")
}
@ -156,8 +156,10 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
val downloadEntity = mDownloadEntityMap.remove(apk.file.path) ?: return
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "0.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.CANCEL.name
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
}
}
override fun onNext(apk: XApkFile, fileName: String) {
@ -166,11 +168,9 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
}
}
fun isInstalling(packagePath: String): Boolean = mInstallingPath.contains(packagePath)
fun getPendingSessionInfo(packagePath: String): XapkPendingSessionInfo? = mPendingSessionInfoMap[packagePath]
fun onPendingUserAction(packagePath: String, sessionId: Int) {
mPendingSessionIdMap[packagePath] = sessionId
}
fun isInstalling(packagePath: String): Boolean = mPendingSessionInfoMap.containsKey(packagePath)
/**
* 通知XAPK安装完成
@ -178,41 +178,32 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
fun onInstalled(packagePath: String) {
val downloadEntity = mDownloadEntityMap.remove(packagePath) ?: return
mPendingSessionIdMap.remove(packagePath)
mInstallingPath.remove(packagePath)
mPendingSessionInfoMap.remove(packagePath)
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.INSTALLED.name
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk安装成功")
XapkInstallerLooper.remove(downloadEntity.path)
XapkInstallerLooper.install(mContext)
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk安装成功")
}
}
fun onInstallCanceled(packagePath: String) {
val downloadEntity = mDownloadEntityMap.remove(packagePath) ?: return
mPendingSessionIdMap.remove(packagePath)
mInstallingPath.remove(packagePath)
mPendingSessionInfoMap.remove(packagePath)
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "0.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.CANCEL.name
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk安装取消")
XapkInstallerLooper.remove(downloadEntity.path)
XapkInstallerLooper.install(mContext)
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk安装取消")
}
}
/**
@ -220,29 +211,46 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
* 1. 用户触碰安装弹窗(原生Android系统)区域外导致安装取消
*/
fun updateCurrentInstallStatus() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || mPendingSessionIdMap.isEmpty()) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || mPendingSessionInfoMap.isEmpty()) {
return
}
val installer = mContext.packageManager.packageInstaller
val updateList = mutableListOf<XapkPendingSessionInfo>()
for (pendingSessionEntry in mPendingSessionIdMap) {
val sessionInfo = installer.getSessionInfo(pendingSessionEntry.value)
for (pendingSessionInfoEntry in mPendingSessionInfoMap) {
// 1. 用户点击了取消按钮时sessionInfo为空
// 2. 用户点击了确定按钮时sessionInfo的progress大于0.8
if (sessionInfo == null || sessionInfo.progress > 0.8F) {
continue
val pendingSessionInfo = pendingSessionInfoEntry.value
if (pendingSessionInfo.getStatus() == XapkPendingSessionInfo.STATUS_PENDING_USER_ACTION) {// 用户触摸安装弹窗外部区域取消安装后,更新安装状态
val installer = mContext.packageManager.packageInstaller
val sessionId = pendingSessionInfo.sessionId
if (sessionId != -1) {
val sessionInfo = installer.getSessionInfo(sessionId)
// 表示用户点击了安装弹窗外部区域
if (sessionInfo != null && sessionInfo.progress <= 0.8F) {
AppExecutor.ioExecutor.execute {
installer.abandonSession(sessionInfo.sessionId)
}
pendingSessionInfo.updateStatus(XapkPendingSessionInfo.STATUS_INSTALL_CANCELED)
}
}
}
installer.abandonSession(sessionInfo.sessionId)
val installStatus = pendingSessionInfo.getStatus()
if (installStatus == XapkPendingSessionInfo.STATUS_INSTALL_CANCELED
|| installStatus == XapkPendingSessionInfo.STATUS_INSTALL_SUCCESS
) {
updateList.add(pendingSessionInfo)
}
}
val downloadEntity = mDownloadEntityMap[pendingSessionEntry.key] ?: return
if (!PackageUtils.isInstalled(mContext, downloadEntity.packageName)) {
onInstallCanceled(downloadEntity.path)
} else {
for (pendingSessionInfo in updateList) {
val downloadEntity = mDownloadEntityMap[pendingSessionInfo.path] ?: continue
val installStatus = pendingSessionInfo.getStatus()
if (installStatus == XapkPendingSessionInfo.STATUS_INSTALL_SUCCESS) {
onInstalled(downloadEntity.path)
} else if (installStatus == XapkPendingSessionInfo.STATUS_INSTALL_CANCELED) {
onInstallCanceled(downloadEntity.path)
}
}
}
@ -268,9 +276,15 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
private val xApkFile: XApkFile,
private val sessionId: Int,
) : IPackageInstaller {
override fun install(context: Context) {
val downloadEntity = mDownloadEntityMap[xApkFile.file.path] ?: return
PackageInstaller.installMultiple(context, downloadEntity.path, sessionId)
val applicationContext = context.applicationContext
mPendingSessionInfoMap[downloadEntity.path] = XapkPendingSessionInfo(downloadEntity.path, sessionId)
AppExecutor.ioExecutor.execute {// 有可能卡顿造成anr
NDataChanger.notifyDataChanged(downloadEntity)
PackageInstaller.installMultiple(applicationContext, downloadEntity.path, sessionId)
}
}
}
@ -278,6 +292,7 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
private val xApkFile: XApkFile,
private val file: File
) : IPackageInstaller {
override fun install(context: Context) {
val downloadEntity = mDownloadEntityMap[xApkFile.file.path] ?: return
PackageInstaller.install(
@ -288,42 +303,6 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
)
}
}
/**
* XAPK安装每次只能执行一个安装流程因此添加一个安装队列
*/
private object XapkInstallerLooper {
private val packagePathList = mutableListOf<String>()
private val installerList = mutableListOf<IPackageInstaller>()
fun add(packagePath: String, installer: IPackageInstaller) {
if (packagePathList.contains(packagePath)) {
return
}
packagePathList.add(packagePath)
installerList.add(installer)
}
fun install(context: Context) {
if (installerList.isEmpty()) {
return
}
installerList.first().install(context)
}
fun remove(packagePath: String) {
if (!packagePathList.contains(packagePath)) {
return
}
val index = packagePathList.indexOf(packagePath)
if (index != -1) {
packagePathList.removeAt(index)
installerList.removeAt(index)
}
}
}
}
enum class XapkUnzipStatus(status: String) {

View File

@ -0,0 +1,21 @@
package com.gh.common.xapk
class XapkPendingSessionInfo(
val path: String,
val sessionId: Int = -1
) {
companion object {
const val STATUS_INIT = -1
const val STATUS_PENDING_USER_ACTION = 0
const val STATUS_INSTALL_SUCCESS = 1
const val STATUS_INSTALL_CANCELED = 2
}
private var status = STATUS_INIT
internal fun updateStatus(status: Int) {
this.status = status
}
fun getStatus(): Int = status
}

View File

@ -111,8 +111,7 @@ object PackageObserver {
runOnIoThread { FileUtils.deleteFile(mDownloadEntity.path) }
}
if (mDownloadEntity.format == Constants.XAPK_FORMAT
|| mDownloadEntity.format == Constants.XAPK_APKS_FORMAT) {
if (mDownloadEntity.format == Constants.XAPK_FORMAT) {
XapkInstaller.onInstalled(mDownloadEntity.path)
}

View File

@ -198,7 +198,6 @@ public class MainActivity extends BaseActivity {
protected void onCreate(Bundle savedInstanceState) {
showAd = getIntent().getBooleanExtra(SHOW_AD, false) && savedInstanceState == null;
HaloApp.getInstance().initFresco();
HaloApp.getInstance().isAlreadyUpAndRunning = true;
super.onCreate(savedInstanceState);

View File

@ -297,19 +297,7 @@ class SplashScreenActivity : BaseActivity() {
private fun doFlavorInit() {
HaloApp.getInstance().flavorProvider.init(HaloApp.getInstance(), this, PkgHelper.getActivateRatio())
val whiteListChannel = arrayListOf(
"GH_206",
"KS-GHZS-KY1",
"KS-GHZS-MC1",
"GDT_GHZS_MC1",
"T11-GH-APPDY-ZC01",
"T7-GH-APPDY-KY03",
"T8-GH-APPUX-KY04",
"T1-GHZS-MC01",
"T4-GHZS-MC03"
)
if (whiteListChannel.contains(HaloApp.getInstance().channel) || PackageFlavorHelper.IS_TEST_FLAVOR) {
if (HaloApp.getInstance().channel == "GH_206" || PackageFlavorHelper.IS_TEST_FLAVOR) {
SensorsBridge.init(HaloApp.getInstance(), HaloApp.getInstance().channel)
}
}

View File

@ -12,10 +12,6 @@ import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import com.airbnb.lottie.LottieAnimationView;
import com.gh.common.chain.AutoSwitchAssistantInstallHandler;
import com.gh.common.chain.UnsupportedFeatureHandler;
import com.gh.common.util.PackageLauncher;
import com.gh.gamecenter.common.base.GlobalActivityManager;
import com.gh.common.chain.BrowserInstallHandler;
import com.gh.common.chain.CertificationHandler;
import com.gh.common.chain.ChainBuilder;
@ -26,15 +22,13 @@ import com.gh.common.chain.DownloadDialogHelperHandler;
import com.gh.common.chain.GamePermissionHandler;
import com.gh.common.chain.OverseaDownloadHandler;
import com.gh.common.chain.PackageCheckHandler;
import com.gh.common.chain.UnsupportedFeatureHandler;
import com.gh.common.chain.UpdateNewSimulatorHandler;
import com.gh.common.chain.ValidateVSpaceHandler;
import com.gh.common.chain.VersionNumberHandler;
import com.gh.common.constant.Config;
import com.gh.common.dialog.DeviceRemindDialog;
import com.gh.common.dialog.GameOffServiceDialogFragment;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
import com.gh.common.filter.RegionSetting;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.history.HistoryHelper;
@ -42,34 +36,38 @@ import com.gh.common.simulator.NewSimulatorGameManager;
import com.gh.common.simulator.SimulatorDownloadManager;
import com.gh.common.simulator.SimulatorGameManager;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.xapk.XapkInstaller;
import com.gh.common.xapk.XapkUnzipStatus;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.DataLogUtils;
import com.gh.common.util.DetailDownloadUtils;
import com.gh.gamecenter.common.utils.DialogHelper;
import com.gh.common.util.DialogUtils;
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.LogUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageLauncher;
import com.gh.common.util.PackageUtils;
import com.gh.gamecenter.common.utils.PermissionHelper;
import com.gh.common.util.ReservationHelper;
import com.gh.gamecenter.feature.view.DownloadButton;
import com.gh.common.xapk.XapkInstaller;
import com.gh.common.xapk.XapkUnzipStatus;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.core.utils.StringUtils;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.common.utils.DataLogUtils;
import com.gh.gamecenter.common.utils.DialogHelper;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.PermissionHelper;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
import com.gh.gamecenter.core.utils.StringUtils;
import com.gh.gamecenter.eventbus.EBScroll;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
import com.gh.gamecenter.feature.view.DownloadButton;
import com.gh.gamecenter.gamedetail.GameDetailFragment;
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
import com.gh.gamecenter.teenagermode.TeenagerModeActivity;
@ -227,7 +225,6 @@ public class DetailViewHolder {
}
case PLUGIN:
ChainBuilder builder = new ChainBuilder();
builder.addHandler(new AutoSwitchAssistantInstallHandler());
builder.addHandler(new UnsupportedFeatureHandler());
builder.addHandler(new UpdateNewSimulatorHandler());
builder.addHandler(new GamePermissionHandler());

View File

@ -137,8 +137,7 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi
}
}
adapter.getUrlMap().put(PackageUtils.getPackageNameByPath(HaloApp.getInstance().getApplication(),
downloadEntity.getPath()), downloadEntity.getUrl());
adapter.getUrlMap().put(downloadEntity.getPackageName(), downloadEntity.getUrl());
// 用户焦点在下载管理页面时有任务完成,直接把所有下载完成的任务标记为已读
DownloadManager.getInstance().markDownloadedTaskAsRead();

View File

@ -773,7 +773,18 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
}
// 这里的 selectedPosition 指的是应该被高亮显示的 position
val selectedPosition = (position + positionOffset).roundToInt()
val selectedPosition = try {
(position + positionOffset).roundToInt()
} catch (e: IllegalArgumentException) {
// roundToInt() 方法有时候会报 Cannot round NaN value. 错误
// https://sentry.shanqu.cc/organizations/lightgame/issues/301377/?project=22
SentryHelper.onEvent(
"HOME_NAN_POSITION",
"value",
"$position+$positionOffset=(${position + positionOffset})"
)
position
}
val positionOffsetOnRealSelectedPosition = if (positionOffset >= 0.5) {
positionOffset - 1
} else {
@ -797,8 +808,8 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
// positionOffset 小于零,表示 indicator 当前位置处于选中的 tab 的左边
val indicatorOnLeft = positionOffset < 0F
val selectedTabBinding = mTabBindingList[selectedPosition]
val selectedTabImageStyle = mTabImageStyleList[selectedPosition]
val selectedTabBinding = mTabBindingList.safelyGetInRelease(selectedPosition) ?: return
val selectedTabImageStyle = mTabImageStyleList.safelyGetInRelease(selectedPosition) ?: return
// 前一个 tab、当前选中的 tab、后一个 tab 的显示比例
val preScaleRatio = 1 + abs(positionOffset) / 4

View File

@ -35,6 +35,7 @@ class GameCollectionHotListAdapter(
private val mPath: String,
private val mBasicExposureSource: List<ExposureSource>
) : ListAdapter<GameCollectionListItemData>(context), IExposable {
private val mCoverWidth = (DisplayUtils.getScreenWidth() - 40F.dip2px()) / 2
override fun getItemViewType(position: Int): Int {
return if (position == itemCount - 1) ItemViewType.ITEM_FOOTER else ItemViewType.ITEM_BODY
}
@ -94,7 +95,7 @@ class GameCollectionHotListAdapter(
stampIv.setBackgroundResource(if (entity?.stamp == "official") R.drawable.label_game_collection_official else R.drawable.label_game_collection_special_choice)
titleTv.text = entity?.title
userTv.text = entity?.user?.name
coverImage.setTag(ImageUtils.TAG_TARGET_WIDTH, DisplayUtils.getScreenWidth() - 40F.dip2px())
coverImage.setTag(ImageUtils.TAG_TARGET_WIDTH, mCoverWidth)
ImageUtils.display(coverImage, entity?.cover)
ImageUtils.display(userIv, entity?.user?.icon)

View File

@ -55,6 +55,7 @@ class GameCollectionSquareAdapter(
private val mRefreshCallback: () -> Unit
) :
ListAdapter<GameCollectionListItemData>(context), IExposable {
private val mPosterWidth = DisplayUtils.getScreenWidth() - 32F.dip2px()
override fun setListData(updateData: MutableList<GameCollectionListItemData>?) {
if (updateData == null) {
@ -409,7 +410,7 @@ class GameCollectionSquareAdapter(
}
}
class GameCollectionSquareItemViewHolder(val binding: GameCollectionSquareItemBinding) :
inner class GameCollectionSquareItemViewHolder(val binding: GameCollectionSquareItemBinding) :
RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n")
fun bindGameCollection(
@ -421,6 +422,7 @@ class GameCollectionSquareAdapter(
) {
binding.run {
val context = root.context
poster.setTag(ImageUtils.TAG_TARGET_WIDTH, mPosterWidth)
display(poster, gamesCollectionEntity.cover)
display(userIv, gamesCollectionEntity.user?.icon)
titleTv.text = gamesCollectionEntity.title

View File

@ -30,6 +30,7 @@ class HomeGameCollectionAdapter(
private val mBlockName: String = ""
) :
BaseRecyclerAdapter<HomeGameCollectionAdapter.HomeGameCollectionCardViewHolder>(context) {
private val mPosterWidth = DisplayUtils.getScreenWidth() - 50F.dip2px()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
HomeGameCollectionCardViewHolder(HomeGameCollectionItemCell(mContext).apply { inflate() })
@ -69,7 +70,8 @@ class HomeGameCollectionAdapter(
}
}
class HomeGameCollectionCardViewHolder(val cell: HomeGameCollectionItemCell) : BaseRecyclerViewHolder<Any>(cell) {
inner class HomeGameCollectionCardViewHolder(val cell: HomeGameCollectionItemCell) :
BaseRecyclerViewHolder<Any>(cell) {
fun bindGameCollectionCard(
binding: HomeGameCollectionCardItemBinding,
itemData: GameCollectionListItemData,
@ -81,9 +83,9 @@ class HomeGameCollectionAdapter(
binding.run {
val context = root.context
val gamesCollectionEntity = itemData.gameCollectionItem
root.layoutParams.width = DisplayUtils.getScreenWidth() - 50F.dip2px()
root.layoutParams.width = mPosterWidth
if (gamesCollectionEntity != null) {
poster.setTag(ImageUtils.TAG_TARGET_WIDTH, DisplayUtils.getScreenWidth() - 50F.dip2px())
poster.setTag(ImageUtils.TAG_TARGET_WIDTH, mPosterWidth)
ImageUtils.display(poster, gamesCollectionEntity.cover)
ImageUtils.display(userIv, gamesCollectionEntity.user?.icon)
titleTv.text = gamesCollectionEntity.title

View File

@ -23,6 +23,8 @@ import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
class GameBigImageViewHolder(val binding: ItemGameServerTestBigImageBinding) :
BaseRecyclerViewHolder<Any>(binding.root) {
private val mGameImageWidth = DisplayUtils.getScreenWidth() - 32F.dip2px()
fun bindAttachGame(
holder: GameBigImageViewHolder,
gameEntity: GameEntity,
@ -32,7 +34,7 @@ class GameBigImageViewHolder(val binding: ItemGameServerTestBigImageBinding) :
) {
holder.bindGameInfo(gameEntity, adapter, exposureEvent, entrance)
holder.binding.gameImage.goneIf(gameEntity.topVideo != null || gameEntity.homeSetting.image.isEmpty()) {
binding.gameImage.setTag(ImageUtils.TAG_TARGET_WIDTH, DisplayUtils.getScreenWidth() - 32F.dip2px())
binding.gameImage.setTag(ImageUtils.TAG_TARGET_WIDTH, mGameImageWidth)
ImageUtils.display(binding.gameImage, gameEntity.homeSetting.image)
val hierarchy = binding.gameImage.hierarchy
try {

View File

@ -102,6 +102,7 @@ class GameServerTestV2ListFragment :
}
override fun initSkeletonScreen() {
if (mBinding?.skeleton == null) return
mSkeletonScreen = Skeleton.bind(mBinding?.skeleton)
.shimmer(true)
.angle(Constants.SHIMMER_ANGLE)

View File

@ -150,7 +150,7 @@ object VArchiveHelper {
if (isSuccess) {
val vGameEntity = VHelper.getVGameSnapshot(packageName = packageName)
runOnIoThread {
val fileMd5 = MD5Utils.calculateMD5(mLatestArchiveFile)
val fileMd5 = MD5Utils.calculateMD5(mLatestArchiveFile) ?: return@runOnIoThread
val vArchiveEntity = VArchiveEntity(
id = fileMd5,
gameId = vGameEntity?.downloadEntity?.gameId ?: "",

View File

@ -160,6 +160,9 @@ object VHelper {
if (it.type == EBPackage.TYPE_INSTALLED) {
SensorsBridge.trackEvent("HaloFunInstallDone", "space_schema_type", if (isVSpace32) "32位" else "64位")
if (isVSpace32) {
SensorsBridge.trackEvent("HaloFunExpandInstallDone")
}
if (skip64VSpaceInstalled) return@PackageChangeListener
@ -959,11 +962,21 @@ object VHelper {
location: String? = null) {
Utils.log(LOG_TAG, "检测是需要安装还是启动 ${downloadEntity.gameId}")
if (downloadEntity.name.isNullOrEmpty()) {
SentryHelper.onEvent(
"V_GAME_DOWNLOAD_ENTITY_NAME_EMPTY",
"game_id",
downloadEntity.gameId,
"location",
location
)
}
installOrLaunch(
context,
downloadEntity.packageName,
downloadEntity.gameId,
downloadEntity.name,
downloadEntity.name ?: "",
downloadEntity.getGameCategory(),
downloadEntity.getMetaExtra(KEY_BIT),
location
@ -1343,7 +1356,6 @@ object VHelper {
VSpace32DialogFragment.showDownloadDialog(
context,
getVSpaceDownloadEntity(false),
autoDownload = true,
gameId = gameId,
gameName = gameName
)

View File

@ -46,6 +46,7 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
private val mBinding by lazy { DialogVspace32Binding.inflate(layoutInflater) }
private var mIsLogInstallShow = false
private var mIsLogAutoInstallClick = false
private var mIsClickDownloadThisTime = false // 是否本次弹出Dialog点击的下载按钮
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
if (downloadEntity.url == mDownloadUrl && isAdded) {
@ -146,6 +147,8 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
downloadType
).toJson()
mIsClickDownloadThisTime = true
AppExecutor.uiExecutor.executeWithDelay({
DownloadManager.getInstance().cancel(mDownloadUrl)
DownloadManager.getInstance().add(downloadEntity)
@ -165,7 +168,7 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
// 上面监听安装包名变化的 LiveData 监听有可能被冲掉了
// 手动再检查一下安装状态,避免出现已安装但是没有 dismiss 弹窗的问题
if (PackageUtils.isInstalled(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)) {
if (PackageUtils.isInstalledFromAllPackage(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)) {
dismissAllowingStateLoss()
}
}
@ -221,7 +224,7 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
val isVSpace32DownloadOnly =
downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.VSPACE_32_DOWNLOAD_ONLY
val isAutoInstall = SPUtils.getBoolean(Constants.SP_AUTO_INSTALL, true)
if (!isVSpace32DownloadOnly && isAutoInstall && !mIsLogAutoInstallClick) {
if (!isVSpace32DownloadOnly && isAutoInstall && !mIsLogAutoInstallClick && mIsClickDownloadThisTime) {
NewFlatLogUtils.logHaloFunEvent("halo_fun_32_install_tip_dialog_click")
SensorsBridge.trackEvent("HaloFunExpandInstallButtonClick")
mIsLogAutoInstallClick = true
@ -260,15 +263,11 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
companion object {
const val KEY_APP_ENTITY_32 = "app_entity_32"
const val KEY_AUTO_DOWNLOAD = "auto_download"
const val KEY_IS_UPDATE = "is_update"
@JvmStatic
fun showDownloadDialog(
context: Context?,
appEntity32: AppEntity,
autoDownload: Boolean = false,
isUpdate: Boolean = false,
gameId: String = "",
gameName: String = ""
) {
@ -291,8 +290,6 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
putParcelable(KEY_APP_ENTITY_32, appEntity32)
putString(EntranceConsts.KEY_GAME_ID, gameId)
putString(EntranceConsts.KEY_GAME_NAME, gameName)
putBoolean(KEY_AUTO_DOWNLOAD, autoDownload)
putBoolean(KEY_IS_UPDATE, isUpdate)
}
}
downloadDialog.show(
@ -301,24 +298,6 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
)
}
@JvmStatic
fun showDownloadDialog(
context: Context?,
appEntity32: AppEntity,
gameEntity: GameEntity?,
autoDownload: Boolean = false,
isUpdate: Boolean = false
) {
showDownloadDialog(
context,
appEntity32,
autoDownload,
isUpdate,
gameEntity?.id ?: "",
gameEntity?.name ?: ""
)
}
private fun hasDialogDisplayedInCurrentActivity(fragmentActivity: FragmentActivity): Boolean {
val fragments: List<Fragment> = fragmentActivity.supportFragmentManager.fragments
fragments.forEach { fragment ->

View File

@ -39,6 +39,13 @@ import com.lightgame.download.DownloadStatus.*
import com.lightgame.utils.AppManager
import java.io.File
/**
* 1. 单独的 64 位组件的下载和更新使用本 VSpaceDialogFragment
* 2. 已经安装了 64 位组件,后续操作所调起的 32 位组件的首次下载使用亦 VSpace32DialogFragment
* 3. 64 位组件已安装且 64 位组件无需更新时32 位组件需要更新时,使用本 VSpaceDialogFragment
* 4. 64 位组件已安装且 6432 位都需要更新时64 位更新使用本 VSpaceDialogFragment
* 同时下载64位组件和32位组件但是32位在64位安装完成之前不触发安装 32 位安装使用跳转 VSpaceUpdate32DialogFragment 进行
*/
class VSpaceDialogFragment : BaseDraggableDialogFragment() {
private var mAppEntity64: AppEntity? = null
@ -52,6 +59,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
private val mBinding by lazy { DialogVspaceBinding.inflate(layoutInflater) }
private var mIsLogInstallShow = false
private var mIsLogAutoInstallClick = false
private var mIsClickDownloadThisTime = false // 是否本次弹出Dialog点击的下载按钮
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
if (((mAppEntity64 != null && downloadEntity.url == mDownloadUrl64) || (mAppEntity64 == null && downloadEntity.url == mDownloadUrl32)) && isAdded) {
@ -92,13 +100,8 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
val mViewModel = viewModelProvider<VSpaceDialogViewModel>()
mViewModel.packageLiveData.observe(this) {
if (it.packageName == VHelper.DEFAULT_VSPACE_PACKAGENAME) {
if (mIsUpdate) showVSpace32UpdateDialogIfNeeded() else showVSpace32DownloadDialogIfNeeded()
dismissAllowingStateLoss()
}
if (it.packageName == VHelper.VSPACE_32BIT_PACKAGENAME) {
dismissAllowingStateLoss()
}
show32BitRelatedDialogIfNeeded()
dismissDialogIfInstalled()
}
mBinding.downloadBtn.text = "下载畅玩助手服务组件"
@ -157,6 +160,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
DataCollectionUtils.uploadDownload(HaloApp.getInstance(), downloadEntity32, "开始")
}
mIsClickDownloadThisTime = true
AppExecutor.uiExecutor.executeWithDelay({
if (downloadEntity64 != null) {
DownloadManager.getInstance().cancel(mDownloadUrl64)
@ -204,13 +208,42 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
super.onStart()
DownloadManager.getInstance().addObserver(mDataWatcher)
// 上面监听安装包名变化的 LiveData 监听有可能被冲掉了
// 手动再检查一下安装状态,避免出现已安装但是没有 dismiss 弹窗的问题
if (PackageUtils.isInstalled(requireContext(), VHelper.DEFAULT_VSPACE_PACKAGENAME)) {
if (mIsUpdate) showVSpace32UpdateDialogIfNeeded() else showVSpace32DownloadDialogIfNeeded()
dismissAllowingStateLoss()
show32BitRelatedDialogIfNeeded()
// 检查安装状态,避免出现已安装但是没有 dismiss 弹窗的问题
dismissDialogIfInstalled()
}
// 弹下载/更新 32 位组件,前提是 64 位组件已经安装并安装了指定的版本
private fun show32BitRelatedDialogIfNeeded() {
if (PackageUtils.isInstalledFromAllPackage(requireContext(), VHelper.DEFAULT_VSPACE_PACKAGENAME)
&& mAppEntity64?.version == PackageUtils.getVersionNameByPackageName(VHelper.DEFAULT_VSPACE_PACKAGENAME)) {
// 该游戏需要 32 位组件,且后台配置的 32 位组件不为空
if (mBit == "32" && mAppEntity32 != null && !mAppEntity32?.url.isNullOrEmpty()) {
if (mIsUpdate) {
showVSpace32UpdateDialog()
} else {
showVSpace32DownloadDialogIfNeeded()
}
}
}
if (PackageUtils.isInstalled(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)) {
}
/**
* dismiss 当前 VSpaceDialogFragment (如果满足入参条件的话)
*/
private fun dismissDialogIfInstalled() {
// 需要下载的 64 位组件是否与已安装的 64 位组件版本一致
val is64BitVersionMatched =
mAppEntity64 == null
|| mAppEntity64?.version == PackageUtils.getVersionNameByPackageName(VHelper.DEFAULT_VSPACE_PACKAGENAME)
// 需要下载的 32 位组件是否与已安装的 32 位组件版本一致
val is32BitVersionMatched =
(mAppEntity32 == null || mBit != "32")
|| mAppEntity32?.version == PackageUtils.getVersionNameByPackageName(VHelper.VSPACE_32BIT_PACKAGENAME)
if (is64BitVersionMatched && is32BitVersionMatched) {
dismissAllowingStateLoss()
}
}
@ -218,7 +251,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
private fun showVSpace32DownloadDialogIfNeeded() {
val is32VSpaceInstalled =
PackageUtils.isInstalledFromAllPackage(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)
if (!is32VSpaceInstalled && mBit == "32" && mAppEntity32 != null && !mAppEntity32?.url.isNullOrEmpty()) {
if (!is32VSpaceInstalled) {
VSpace32DialogFragment.showDownloadDialog(
requireContext(),
mAppEntity32!!,
@ -228,15 +261,13 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
}
}
private fun showVSpace32UpdateDialogIfNeeded() {
if (mBit == "32" && mAppEntity32 != null && !mAppEntity32?.url.isNullOrEmpty()) {
VSpaceUpdate32DialogFragment.showDownloadDialog(
requireContext(),
mAppEntity32!!,
gameId = mGameId,
gameName = mGameName
)
}
private fun showVSpace32UpdateDialog() {
VSpaceUpdate32DialogFragment.showDownloadDialog(
requireContext(),
mAppEntity32!!,
gameId = mGameId,
gameName = mGameName
)
}
override fun onStop() {
@ -277,6 +308,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
DownloadManager.getInstance().resume(downloadEntity, false)
}
}
done -> {
downloadBtn.setText(R.string.install)
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
@ -288,7 +320,11 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
mIsLogInstallShow = true
}
if (SPUtils.getBoolean(Constants.SP_AUTO_INSTALL, true) && !mIsLogAutoInstallClick) {
if (SPUtils.getBoolean(
Constants.SP_AUTO_INSTALL,
true
) && !mIsLogAutoInstallClick && mIsClickDownloadThisTime
) {
SensorsBridge.trackEvent("HaloFunInstallButtonClick", "space_schema_type", vSpaceType)
mIsLogAutoInstallClick = true
}
@ -316,6 +352,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
DownloadManager.getInstance().resume(downloadEntity, true)
}
}
else -> {
// do nothing
}
@ -370,7 +407,6 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
)
}
val downloadDialog = VSpaceDialogFragment().apply {
arguments = Bundle().apply {
if (appEntity64 != null) putParcelable(KEY_APP_ENTITY_64, appEntity64)
@ -388,6 +424,14 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
)
}
/**
* 显示下载弹窗
* @param appEntity64 需要下载的 64 位组件实体,不为空即代表需要下载
* @param appEntity32 需要下载的 32 位组件实体,不为空即代表需要下载
* @param gameEntity 游戏相关的实体
* @param autoDownload 是否需要显示弹窗即进行下载
* @param isUpdate 是否为更新
*/
@JvmStatic
fun showDownloadDialog(
context: Context?,

View File

@ -141,7 +141,8 @@ class VSpaceUpdate32DialogFragment : BaseDialogFragment() {
// 上面监听安装包名变化的 LiveData 监听有可能被冲掉了
// 手动再检查一下安装状态,避免出现已安装但是没有 dismiss 弹窗的问题
if (PackageUtils.isInstalled(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)) {
if (PackageUtils.isInstalledFromAllPackage(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)
&& mAppEntity?.version == PackageUtils.getVersionNameByPackageName(VHelper.VSPACE_32BIT_PACKAGENAME)) {
dismissAllowingStateLoss()
}
}

View File

@ -227,12 +227,12 @@ public class HaloApp extends MultiDexApplication {
PlayerFactory.setPlayManager(Exo2PlayerManager.class);
CacheFactory.setCacheManager(ExoPlayerCacheManager.class);
initFresco();
AppExecutor.getIoExecutor().execute(() -> {
initDataHelper();
ExtensionsKt.doOnMainProcessOnly(this, () -> Tracker.init(this));
initFresco();
deviceRamSize = DeviceUtils.getTotalRamSizeOfDevice(this);
mChannel = mFlavorProvider.getChannelStr(this);

View File

@ -7,9 +7,11 @@ import android.text.TextUtils
import com.gh.gamecenter.BuildConfig
import com.bytedance.hume.readapk.HumeSDK
import com.gh.gamecenter.TeaHelper
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import java.io.File
@ -58,6 +60,11 @@ class FlavorProviderImp : IFlavorProvider {
override fun logCoreEvent() {
logEvent("game_addiction")
if (BuildConfig.ACTIVATE_REPORTING_RATIO == 1) {
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast("关键行为 game_addiction")
}, 500)
}
}
private fun amILucky(percentage: Int = 100): Boolean {

View File

@ -7,8 +7,8 @@ ext {
targetSdkVersion = 28
// application info (每个大版本之间的 versionCode 增加 20)
versionCode = 910
versionName = "5.28.0"
versionCode = 912
versionName = "5.28.2"
applicationId = "com.gh.gamecenter"
// AndroidX

View File

@ -2,6 +2,7 @@ package com.gh.gamecenter.xapk.io
import android.content.Context
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.Session
import android.content.pm.PackageInstaller.SessionParams
import android.content.pm.PackageManager
import android.os.Build
@ -35,9 +36,6 @@ class SplitApksOutput(
.packageInstaller
// 创建安装会话并获取返回会话ID
val sessionId = installer.createSession(it)
.also { sessionId ->
SessionPool.put(installer, sessionId)
}
// 开启安装会话
val session = installer.openSession(sessionId)
try {
@ -59,24 +57,4 @@ class SplitApksOutput(
} else {
throw ApkOutputUnsupportedSplitApksException()
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private object SessionPool {
private val sessionIdList = mutableListOf<Int>()
fun put(installer: PackageInstaller, sessionId: Int) {
sessionIdList.removeAll {
installer.getSessionInfo(it) == null
}
sessionIdList.add(sessionId)
installer.mySessions.forEach {
if (!sessionIdList.contains(it.sessionId)) {
installer.abandonSession(it.sessionId)
}
}
}
}
}

View File

@ -93,14 +93,14 @@ fi
# 是否选择了 sdk 类型
if [ "${sdk_platform}" != "" ]; then
if [ "${activate_reporting_ratio}" == "" ]; then
activate_reporting_ratio="100"
fi
# 调整上报比例
sed -i "s/int ACTIVATE_REPORTING_RATIO = 100/int ACTIVATE_REPORTING_RATIO = ${activate_reporting_ratio}/g" app/build.gradle
# 头条包
if [ "${sdk_platform}" == "toutiao" ]; then
if [ "${activate_reporting_ratio}" == "" ]; then
activate_reporting_ratio="100"
fi
# 调整上报比例
sed -i "s/int ACTIVATE_REPORTING_RATIO = 100/int ACTIVATE_REPORTING_RATIO = ${activate_reporting_ratio}/g" app/build.gradle
if [ "${sdk_version}" == "5.3.0" ]; then
sed -i "s/bytedanceApplog = \"6.14.3\"/bytedanceApplog = \"${sdk_version}\"/g" dependencies.gradle
rm app/src/tea/java/com/gh/gamecenter/TeaHelper.kt