Compare commits
80 Commits
feat/vacor
...
legacy-rel
| Author | SHA1 | Date | |
|---|---|---|---|
| 1040f5ff4d | |||
| 97be320529 | |||
| 59cde4e2bf | |||
| cc0c7c7fae | |||
| 9e9ce6a84f | |||
| 7d0b500ff9 | |||
| 425456b263 | |||
| f6abab9a2d | |||
| d194f969e4 | |||
| 95f66344fb | |||
| 570e2fa9bc | |||
| 9e07080043 | |||
| e10a329159 | |||
| b3bc7b43f7 | |||
| 811d42457c | |||
| ac0b819ea9 | |||
| d931fb5940 | |||
| cea62b55e2 | |||
| ff6cdb1ba3 | |||
| b6e531fa96 | |||
| e7a37df690 | |||
| 239b056abb | |||
| 315be3797c | |||
| bdcca58770 | |||
| 644b93ab02 | |||
| 1ee0f292ba | |||
| f609637f0b | |||
| 9d10add8eb | |||
| f5a39f982e | |||
| 1a063bb0c1 | |||
| 86340d603f | |||
| 0731cc1fde | |||
| 86dfee2ff9 | |||
| edf82952ce | |||
| 4412d159bb | |||
| e119b7fecd | |||
| 3fe7c8252e | |||
| 36ebab77ee | |||
| e84db01984 | |||
| ae605d4a55 | |||
| 882bf4b551 | |||
| 968164af55 | |||
| 0119e6f123 | |||
| 7093552259 | |||
| 2be52d21ee | |||
| cb093cc3f0 | |||
| 3cbdd94189 | |||
| 11013319bf | |||
| aa954b3af9 | |||
| 93f279a384 | |||
| 4e54833cc9 | |||
| f95862da8b | |||
| 1515df34b5 | |||
| 8a8ef40dc1 | |||
| b6194fed26 | |||
| 02752f6c81 | |||
| b33d367dfd | |||
| d5046ab431 | |||
| a53168c9bc | |||
| 3cbc8c2f74 | |||
| 7398b83004 | |||
| 8013426ded | |||
| b86d85b15f | |||
| 5a73afbab3 | |||
| e19ee25839 | |||
| 61bf39e95f | |||
| ef82ae2378 | |||
| 2dcccc22a8 | |||
| cb0e77d204 | |||
| a6ea178609 | |||
| 6a62f08891 | |||
| ddb48481d2 | |||
| 48a55a6b31 | |||
| 50fcb0c3ea | |||
| e97722b6fb | |||
| 2163b2ff9e | |||
| b9558e2732 | |||
| e9139c66e1 | |||
| f492d2ea97 | |||
| 46955685bb |
@ -72,6 +72,7 @@ android_build:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6644
|
||||
|
||||
# 代码检查
|
||||
sonarqube_analysis:
|
||||
@ -156,4 +157,5 @@ oss-upload&send-email:
|
||||
- /usr/local/bin/python /ci-android-mail-jira-comment.py
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- release
|
||||
- feat/GHZSCY-6644
|
||||
@ -32,11 +32,43 @@ class ExternalGameUsage : ITestCase {
|
||||
it.titleTv.text = context.getString(R.string.title_install_external_game)
|
||||
it.iconIv.setImageResource(R.drawable.ic_personal_my_game)
|
||||
it.root.setOnClickListener {
|
||||
context.startActivity(
|
||||
InstallExternalGameActivity.getIntent(context)
|
||||
.apply { flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK })
|
||||
VHelper.connectService {
|
||||
context.startActivity(
|
||||
InstallExternalGameActivity.getIntent(context)
|
||||
.apply { flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun addInstallPluginButton(viewParent: ViewGroup) {
|
||||
buttonTemplate(viewParent, R.id.install_plugin) {
|
||||
it.titleTv.text = "安装64位插件"
|
||||
it.root.setOnClickListener {
|
||||
val file = File("/data/local/tmp/gh-plugins/artifacts.zip")
|
||||
if (file.exists()) {
|
||||
Utils.log(VHelper.LOG_TAG, "有本地更新文件: 64位插件")
|
||||
// TODO: 补充debug插件更新
|
||||
ToastUtils.showToast("暂未实现debug功能")
|
||||
} else {
|
||||
ToastUtils.showToast("data/local/tmp没有push文件")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun addInstallPlugin32Button(viewParent: ViewGroup) {
|
||||
buttonTemplate(viewParent, R.id.install_plugin_32) {
|
||||
it.titleTv.text = "安装32位插件"
|
||||
it.root.setOnClickListener {
|
||||
val file = File("/data/local/tmp/gh-plugins/artifacts32.zip")
|
||||
if (file.exists()) {
|
||||
// TODO: 补充debug插件更新
|
||||
ToastUtils.showToast("暂未实现debug功能")
|
||||
} else {
|
||||
ToastUtils.showToast("data/local/tmp没有push文件")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,7 @@
|
||||
package com.gh.vspace.installexternalgames
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Dialog
|
||||
import android.content.ComponentName
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.gamecenter.R
|
||||
@ -45,19 +40,6 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
|
||||
private lateinit var dialog: Dialog
|
||||
|
||||
|
||||
private val requestPermissionLauncher = registerForActivityResult<String, Boolean>(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { result ->
|
||||
if (result == true) {
|
||||
// grant
|
||||
mViewModel.scanPaths()
|
||||
} else {
|
||||
// not grant
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setNavigationTitle(getString(com.gh.gamecenter.R.string.title_install_external_game))
|
||||
@ -74,30 +56,11 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
mViewModel.scanPaths()
|
||||
|
||||
|
||||
requestStoragePermission()
|
||||
}
|
||||
|
||||
private fun requestStoragePermission() {
|
||||
when {
|
||||
ContextCompat.checkSelfPermission(
|
||||
requireContext(),
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED -> {
|
||||
mViewModel.scanPaths()
|
||||
}
|
||||
|
||||
shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE) -> {
|
||||
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
|
||||
else -> {
|
||||
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun initView() {
|
||||
dialog = DialogUtils.showWaitDialog(requireContext(), "")
|
||||
mBinding.externalGamesList.let {
|
||||
@ -131,11 +94,9 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
OnItemClickListener.ClickType.CLICK_INSTALL -> {
|
||||
install(externalGameUiState)
|
||||
}
|
||||
|
||||
OnItemClickListener.ClickType.CLICK_UNINSTALL -> {
|
||||
uninstall(externalGameUiState)
|
||||
}
|
||||
|
||||
OnItemClickListener.ClickType.CLICK_START -> {
|
||||
start(externalGameUiState)
|
||||
}
|
||||
@ -143,8 +104,9 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
}
|
||||
|
||||
private fun install(externalGameUiState: ExternalGameUiState) {
|
||||
val bit =
|
||||
externalGameUiState.externalGameEntity.cpuAbi.let { if (it.size == 1 && it.contains("armeabi-v7a")) "32" else "64" }
|
||||
|
||||
VHelper.disableLaunchGameAfterInstallation()
|
||||
VHelper.install(requireContext(), DownloadEntity().apply {
|
||||
externalGameUiState.externalGameEntity.apply {
|
||||
packageName = apkPackageName
|
||||
@ -152,12 +114,20 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
}
|
||||
}, true)
|
||||
|
||||
VHelper.newCwValidateVspaceBeforeAction(
|
||||
requireContext(),null,
|
||||
) {
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
if (VHelper.showDialogIfVSpaceIsNeeded(
|
||||
requireContext(),
|
||||
"",
|
||||
externalGameUiState.externalGameEntity.appName,
|
||||
"",
|
||||
bit = bit
|
||||
)
|
||||
) return
|
||||
dialog.show()
|
||||
externalGameUiState.externalGameEntity.let {
|
||||
val intent = VirtualAppManager.getInstallIntent(context, it.apkPath, it.apkPackageName)
|
||||
requireActivity().startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun uninstall(externalGameUiState: ExternalGameUiState) {
|
||||
@ -188,12 +158,6 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
com.gh.gamecenter.BuildConfig.VA_VERSION_NAME,
|
||||
HaloApp.getInstance().oaid
|
||||
)
|
||||
intent.setComponent(
|
||||
ComponentName(
|
||||
com.gh.gamecenter.BuildConfig.APPLICATION_ID,
|
||||
VirtualAppManager.AIDL_SERVER_REMOTE_GUIDE_ACTIVITY
|
||||
)
|
||||
)
|
||||
requireActivity().startActivity(intent)
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<item name="install_game_from_external" type="id" />
|
||||
<item name="install_plugin" type="id" />
|
||||
<item name="install_plugin_32" type="id" />
|
||||
</resources>
|
||||
@ -0,0 +1,16 @@
|
||||
package com.gh.common.prioritychain
|
||||
|
||||
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
|
||||
|
||||
class VideoHandler(priority: Int, val scrollCalculatorHelper: ScrollCalculatorHelper): PriorityChainHandler(priority) {
|
||||
|
||||
init {
|
||||
updateStatus(STATUS_VALID)
|
||||
}
|
||||
|
||||
override fun onProcess(): Boolean {
|
||||
scrollCalculatorHelper.enableAndPlayIfValid()
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,12 +2,15 @@ package com.gh.common.provider
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.gamecenter.common.avoidcallback.Callback
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.core.provider.IEntranceUtilsProvider
|
||||
import com.lightgame.utils.AppManager
|
||||
|
||||
@Route(path = RouteConsts.provider.entranceUtils, name = "EntranceUtils暴露服务")
|
||||
class EntranceUtilsProviderImpl : IEntranceUtilsProvider {
|
||||
@ -20,11 +23,16 @@ class EntranceUtilsProviderImpl : IEntranceUtilsProvider {
|
||||
}
|
||||
|
||||
override fun jumpActivityWithCallback(context: Context, bundle: Bundle, callback: () -> Unit) {
|
||||
EntranceUtils.jumpActivity(context, null, bundle, object : Callback {
|
||||
override fun onActivityResult(resultCode: Int, data: Intent?) {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
if (context is FragmentActivity && !context.supportFragmentManager.isDestroyed) {
|
||||
EntranceUtils.jumpActivity(context, null, bundle, object : Callback {
|
||||
override fun onActivityResult(resultCode: Int, data: Intent?) {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
EntranceUtils.jumpActivity(AppManager.getInstance().currentActivity(), bundle)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun init(context: Context?) {
|
||||
|
||||
@ -37,10 +37,10 @@ import com.gh.gamecenter.core.utils.*
|
||||
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.minigame.MiniGameItemHelper
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
|
||||
import com.gh.gamecenter.teenagermode.TeenagerModeActivity
|
||||
import com.gh.vspace.VHelper
|
||||
import com.lightgame.download.DownloadConfig
|
||||
@ -697,7 +697,7 @@ object DownloadItemUtils {
|
||||
// 为 downloadButton 添加游戏实体,供点击的时候上报用
|
||||
downloadBtn.putObject(gameEntity)
|
||||
|
||||
val gamePermissionDialogFragment = (context as AppCompatActivity).supportFragmentManager.findFragmentByTag(
|
||||
val gamePermissionDialogFragment = (context as? AppCompatActivity)?.supportFragmentManager?.findFragmentByTag(
|
||||
GamePermissionDialogFragment::class.java.name
|
||||
) as GamePermissionDialogFragment?
|
||||
gamePermissionDialogFragment?.dismissAllowingStateLoss()
|
||||
|
||||
@ -105,9 +105,14 @@ public class EntranceUtils {
|
||||
//TODO:添加FLAG_ACTIVITY_NEW_TASK会导致一跳转页面callback就被调用
|
||||
//intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent1.putExtras(bundle);
|
||||
if (context instanceof AppCompatActivity) {
|
||||
AvoidOnResultManager.Companion.getInstance((AppCompatActivity) context)
|
||||
.startForResult(intent1, callback);
|
||||
} else {
|
||||
// 不要回调,正常跳转
|
||||
context.startActivity(intent1);
|
||||
}
|
||||
|
||||
AvoidOnResultManager.Companion.getInstance((AppCompatActivity) context)
|
||||
.startForResult(intent1, callback);
|
||||
}
|
||||
} else {
|
||||
// 应用未在运行
|
||||
|
||||
@ -7,6 +7,7 @@ import com.gh.gamecenter.common.utils.toObject
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.SubjectEntity
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
@ -111,6 +112,14 @@ object GameSubstituteRepositoryHelper {
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否已安装该游戏 id
|
||||
if (PackagesManager.getInstalledDataByGameId(game.id) != null) {
|
||||
// 将该位置的游戏标记为需要替换
|
||||
positionOfGameToBeReplacedList.add(index)
|
||||
thisPositionNeedToBeReplaced = true
|
||||
break
|
||||
}
|
||||
|
||||
// 若此游戏所包含的 apk 没有已安装,那么再检查是否已安装有预设相关包名
|
||||
if (!thisPositionNeedToBeReplaced) {
|
||||
var relatedPackageList = arrayListOf<String>()
|
||||
|
||||
@ -308,7 +308,7 @@ object GameUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否以畅玩游戏的形式来处理
|
||||
* 是否默认以畅玩游戏的形式来处理
|
||||
*/
|
||||
@JvmStatic
|
||||
fun shouldPerformAsVGame(gameEntity: GameEntity): Boolean {
|
||||
|
||||
@ -57,6 +57,10 @@ object HomeBottomBarHelper {
|
||||
return BottomTab(name = "我的光环", jsCode = animationCode, iconSelector = R.drawable.selector_ic_user, link = LinkEntity(type = TYPE_MY_HALO))
|
||||
}
|
||||
|
||||
fun isDefaultHomeBottomTabDataExist(): Boolean {
|
||||
return SPUtils.getString(KEY_HOME_BOTTOM_TAB).isNotEmpty()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDefaultHomeBottomTabData(): List<BottomTab> {
|
||||
try {
|
||||
|
||||
@ -90,7 +90,7 @@ object PackageChangeHelper : DefaultLifecycleObserver {
|
||||
pendingPackageTriple = null
|
||||
pendingGhId = null
|
||||
|
||||
PackageRepository.addInstalledGame(packageName)
|
||||
PackageRepository.addInstalledGame(PackageRepository.packageFilterManager, packageName)
|
||||
|
||||
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
|
||||
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
|
||||
|
||||
@ -81,23 +81,28 @@ object PackageHelper {
|
||||
|
||||
// 评论黑名单包名列表,避免用户安装了 Xposed Installer 这样的工具,也能在包含该安装包的游戏详情页评论
|
||||
private var _commentPackageNameBlackList = arrayListOf<String>()
|
||||
val commentPackageNameBlackList: ArrayList<String> = _commentPackageNameBlackList
|
||||
val commentPackageNameBlackList: ArrayList<String>
|
||||
get() = _commentPackageNameBlackList
|
||||
|
||||
// 关闭下载的包列表
|
||||
private var _downloadPackageNameBlackList = arrayListOf<String>()
|
||||
val downloadPackageNameBlackList: ArrayList<String> = _downloadPackageNameBlackList
|
||||
val downloadPackageNameBlackList: ArrayList<String>
|
||||
get() = _downloadPackageNameBlackList
|
||||
|
||||
// 本地已安装的包去掉关闭下载的包后的列表
|
||||
private var _validLocalPackageNameSet = hashSetOf<String>()
|
||||
val validLocalPackageNameSet: HashSet<String> = _validLocalPackageNameSet
|
||||
val validLocalPackageNameSet: HashSet<String>
|
||||
get() = _validLocalPackageNameSet
|
||||
|
||||
// 游戏包名匹配列表
|
||||
private var _relatedPackageList = arrayListOf<SettingsEntity.GameWithPackages>()
|
||||
val relatedPackageList: ArrayList<SettingsEntity.GameWithPackages> = _relatedPackageList
|
||||
val relatedPackageList: ArrayList<SettingsEntity.GameWithPackages>
|
||||
get() = _relatedPackageList
|
||||
|
||||
// 接口控制的已安装应用列表获取开关状态 (UI 显示)
|
||||
private var _installedPackageApiSwitchStatusLiveData = MutableLiveData<Boolean>()
|
||||
val installedPackageApiSwitchStatusLiveData: LiveData<Boolean> = _installedPackageApiSwitchStatusLiveData
|
||||
val installedPackageApiSwitchStatusLiveData: LiveData<Boolean>
|
||||
get() = _installedPackageApiSwitchStatusLiveData
|
||||
|
||||
// 本地已安装包的列表
|
||||
var localPackageNameSet = hashSetOf<String>()
|
||||
@ -541,6 +546,7 @@ object PackageHelper {
|
||||
Utils.log(TAG, "addInstalledButMissingPackages 需要请求接口获取的包数量为 ${installedPackageNameSet.size}")
|
||||
|
||||
PackageRepository.addInstalledGames(
|
||||
packageFilterManager = PackageRepository.packageFilterManager,
|
||||
pkgNameList = ArrayList(installedPackageNameSet),
|
||||
updateInstallStatus = true
|
||||
)
|
||||
|
||||
@ -14,6 +14,7 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.PowerManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AndroidException;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -222,8 +223,19 @@ public class PackageUtils {
|
||||
if (metaDate != null) {
|
||||
return metaDate.get(name);
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
// e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
if (e instanceof AndroidException) {
|
||||
// 有些设备会出现 DeadSystemException
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"GET_META_DATA_ERROR",
|
||||
"packageName",
|
||||
packageName,
|
||||
"exception_digest",
|
||||
e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -627,8 +639,19 @@ public class PackageUtils {
|
||||
try {
|
||||
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName;
|
||||
} catch (NameNotFoundException e) {
|
||||
// do nothing
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
if (e instanceof AndroidException) {
|
||||
// 有些设备会出现 DeadSystemException
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"GET_VERSION_NAME_ERROR",
|
||||
"packageName",
|
||||
packageName,
|
||||
"exception_digest",
|
||||
e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -640,8 +663,18 @@ public class PackageUtils {
|
||||
try {
|
||||
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionCode;
|
||||
} catch (NameNotFoundException e) {
|
||||
// do nothing
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (e instanceof AndroidException) {
|
||||
// 有些设备会出现 DeadSystemException
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"GET_VERSION_CODE_ERROR",
|
||||
"packageName",
|
||||
packageName,
|
||||
"exception_digest",
|
||||
e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -654,8 +687,18 @@ public class PackageUtils {
|
||||
try {
|
||||
PackageManager packageManager = context.getApplicationContext().getPackageManager();
|
||||
return packageManager.getApplicationIcon(packageName);
|
||||
} catch (NameNotFoundException e) {
|
||||
// do nothing
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (e instanceof AndroidException) {
|
||||
// 有些设备会出现 DeadSystemException
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"GET_ICON_ERROR",
|
||||
"packageName",
|
||||
packageName,
|
||||
"exception_digest",
|
||||
e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -706,8 +749,19 @@ public class PackageUtils {
|
||||
jsonObject.put("version", packageInfo.versionName);
|
||||
}
|
||||
return jsonObject;
|
||||
} catch (JSONException | NameNotFoundException e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (e instanceof AndroidException) {
|
||||
// 有些设备会出现 DeadSystemException
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"GET_APP_BASIC_INFO_BY_PACKAGE_NAME",
|
||||
"packageName",
|
||||
packageName,
|
||||
"exception_digest",
|
||||
e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,8 +59,8 @@ class GameDetailActivity : DownloadToolbarActivity() {
|
||||
}
|
||||
|
||||
override fun getBusinessId(): Pair<String, String> {
|
||||
val fragment = targetFragment as GameDetailFragment
|
||||
return if (fragment.arguments != null) {
|
||||
val fragment = targetFragment as? GameDetailFragment?
|
||||
return if (fragment?.arguments != null) {
|
||||
Pair(fragment.requireArguments().getString(EntranceConsts.KEY_GAMEID) ?: "", "")
|
||||
} else {
|
||||
super.getBusinessId()
|
||||
|
||||
@ -161,6 +161,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
|
||||
val showOnFailed = downloadManagerAd?.displayRule?.onFailedAction == "show"
|
||||
if ((showThirdPartyAd && thirdPartyAd != null) || (!showThirdPartyAd && thirdPartyAd != null && ownerAd == null)) {
|
||||
initThirdPartyAd(thirdPartyAd) { isSuccess ->
|
||||
if (!isAdded) return@initThirdPartyAd
|
||||
mBinding.maskView.goneIf(!isSuccess)
|
||||
if (!isSuccess && ownerAd != null && showOnFailed) {
|
||||
mSlideInterval = ownerAd.adSource?.sliderInterval ?: -1
|
||||
@ -193,7 +194,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
|
||||
}
|
||||
|
||||
private fun initOwnerAd(adConfig: AdConfig) {
|
||||
if (adConfig.id.isEmpty()) return
|
||||
if (!isAdded || adConfig.id.isEmpty()) return
|
||||
mAdGameViewModel = viewModelProvider(AdGameViewModel.Factory(adConfig))
|
||||
initAdGameBanner(adConfig)
|
||||
mBinding.closeAdIv.setOnClickListener {
|
||||
@ -227,6 +228,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
|
||||
adConfig.displayRule.onFailedAction == "show" && adConfig.thirdPartyAd != null) {
|
||||
// 自有广告游戏为空时,显示第三方广告
|
||||
initThirdPartyAd(adConfig.thirdPartyAd) { isSuccess ->
|
||||
if (!isAdded) return@initThirdPartyAd
|
||||
mBinding.maskView.goneIf(!isSuccess)
|
||||
if (isSuccess) {
|
||||
SPUtils.setLong(Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME, System.currentTimeMillis())
|
||||
|
||||
@ -2,8 +2,8 @@ package com.gh.gamecenter.game.columncollection.detail
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.gh.gamecenter.common.base.activity.ToolBarActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.activity.ToolBarActivity
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.updateStatusBarColor
|
||||
|
||||
@ -34,8 +34,8 @@ class ColumnCollectionDetailActivity : ToolBarActivity() {
|
||||
}
|
||||
|
||||
override fun getBusinessId(): Pair<String, String> {
|
||||
val fragment = targetFragment as ColumnCollectionDetailFragment
|
||||
return if (fragment.arguments != null) {
|
||||
val fragment = targetFragment as? ColumnCollectionDetailFragment?
|
||||
return if (fragment?.arguments != null) {
|
||||
Pair(fragment.requireArguments().getString(EntranceConsts.KEY_COLLECTION_ID) ?: "", "")
|
||||
} else {
|
||||
super.getBusinessId()
|
||||
|
||||
@ -36,8 +36,8 @@ class CommonCollectionDetailActivity : ToolBarActivity() {
|
||||
}
|
||||
|
||||
override fun getBusinessId(): Pair<String, String> {
|
||||
val fragment = targetFragment as CommonCollectionDetailFragment
|
||||
return if (fragment.arguments != null) {
|
||||
val fragment = targetFragment as? CommonCollectionDetailFragment?
|
||||
return if (fragment?.arguments != null) {
|
||||
Pair(
|
||||
fragment.requireArguments().getString(EntranceConsts.KEY_COLLECTION_ID) ?: "",
|
||||
fragment.requireArguments().getString(EntranceConsts.KEY_BLOCK_ID) ?: ""
|
||||
|
||||
@ -36,8 +36,8 @@ class CustomCommonCollectionDetailActivity : ToolBarActivity() {
|
||||
}
|
||||
|
||||
override fun getBusinessId(): Pair<String, String> {
|
||||
val fragment = targetFragment as CustomCommonCollectionDetailFragment
|
||||
return if (fragment.arguments != null) {
|
||||
val fragment = targetFragment as? CustomCommonCollectionDetailFragment?
|
||||
return if (fragment?.arguments != null) {
|
||||
Pair(
|
||||
fragment.requireArguments().getString(EntranceConsts.KEY_COLLECTION_ID) ?: "",
|
||||
fragment.requireArguments().getString(EntranceConsts.KEY_BLOCK_ID) ?: ""
|
||||
|
||||
@ -182,7 +182,9 @@ class AddGamesDialogFragment : BaseDialogFragment() {
|
||||
return super.onBack()
|
||||
}
|
||||
|
||||
private fun showGuidePopupWindow(): PopupWindow {
|
||||
private fun showGuidePopupWindow(): PopupWindow? {
|
||||
if (!isAdded) return null
|
||||
|
||||
val guideBinding = LayoutGameCollectionAddGamesGuideBinding.inflate(layoutInflater)
|
||||
val popupWindow = BugFixedPopupWindow(
|
||||
guideBinding.root,
|
||||
|
||||
@ -7,8 +7,8 @@ import android.view.View
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.activity.ToolBarActivity
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
|
||||
/**
|
||||
* 游戏单详情
|
||||
@ -30,8 +30,8 @@ class GameCollectionDetailActivity : ToolBarActivity() {
|
||||
}
|
||||
|
||||
override fun getBusinessId(): Pair<String, String> {
|
||||
val fragment = targetFragment as GameCollectionDetailFragment
|
||||
return if (fragment.arguments != null) {
|
||||
val fragment = targetFragment as? GameCollectionDetailFragment?
|
||||
return if (fragment?.arguments != null) {
|
||||
Pair(fragment.requireArguments().getString(EntranceConsts.KEY_GAME_COLLECTION_ID) ?: "", "")
|
||||
} else {
|
||||
super.getBusinessId()
|
||||
|
||||
@ -149,8 +149,6 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
|
||||
|
||||
private var mShowConcernOnMenu = false
|
||||
|
||||
private var mSpecialDownloadDetailFragmentIsShowing = false
|
||||
|
||||
private val mFragmentsList = ArrayList<Fragment>()
|
||||
private val mTabTitleList = ArrayList<String>()
|
||||
private val mTabTypeList = ArrayList<String>() // tab 类型的列表,用于确定某个类型的 tab 在第几个位置
|
||||
@ -167,7 +165,7 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
|
||||
|| downloadEntity.status == DownloadStatus.redirected
|
||||
) {
|
||||
// 特殊下载弹窗
|
||||
if (isSpecialDownloadDialogAvailable() && !mSpecialDownloadDetailFragmentIsShowing) {
|
||||
if (isSpecialDownloadDialogAvailable(downloadEntity) && !isSpecialDownloadDetailFragmentIsShowing()) {
|
||||
updateSpecialDownloadDialogIcon(true)
|
||||
|
||||
if (downloadEntity.status == DownloadStatus.add) {
|
||||
@ -868,8 +866,10 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
|
||||
|
||||
showConcernIconAtBottomBarIfAvailable()
|
||||
|
||||
if (isSpecialDownloadDialogAvailable()
|
||||
&& DownloadManager.getInstance().getDownloadEntitySnapshot(mGameEntity) != null) {
|
||||
val downloadEntitySnapshot = DownloadManager.getInstance().getDownloadEntitySnapshot(mGameEntity)
|
||||
|
||||
if (isSpecialDownloadDialogAvailable(downloadEntitySnapshot)
|
||||
&& downloadEntitySnapshot != null) {
|
||||
updateSpecialDownloadDialogIcon(true)
|
||||
}
|
||||
|
||||
@ -2562,12 +2562,15 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
|
||||
* 2. 未获取到游戏详情数据
|
||||
* 3. 当前游戏 APK 不为 1 个
|
||||
* 4. 当前游戏类型不为畅玩
|
||||
* 5. 当前游戏不是双下载时使用本地下载进行下载
|
||||
*/
|
||||
private fun isSpecialDownloadDialogAvailable(): Boolean {
|
||||
private fun isSpecialDownloadDialogAvailable(downloadEntity: DownloadEntity? = null): Boolean {
|
||||
if (Config.getNewApiSettingsEntity()?.install?.questionTip?.linkEntity == null) return false
|
||||
if (mNewGameDetailEntity == null || mGameEntity == null) return false
|
||||
if (mGameEntity?.getApk()?.size != 1) return false
|
||||
if (GameUtils.shouldPerformAsVGame(mGameEntity!!)) return false
|
||||
if (downloadEntity?.asVGame() == true) return false
|
||||
if (downloadEntity?.isSimulatorGame() == true) return false
|
||||
if (downloadEntity?.isLocalDownloadInDualDownloadMode() == true) return false
|
||||
|
||||
return true
|
||||
}
|
||||
@ -2585,7 +2588,6 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
|
||||
if (fragment == null) {
|
||||
if (!visibilityViewModel.specialDownloadVisibleLiveData.hasObservers()) {
|
||||
visibilityViewModel.specialDownloadVisibleLiveData.observe(viewLifecycleOwner) {
|
||||
mSpecialDownloadDetailFragmentIsShowing = it
|
||||
updateSpecialDownloadDialogIcon(visible = !it)
|
||||
}
|
||||
}
|
||||
@ -2601,6 +2603,10 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSpecialDownloadDetailFragmentIsShowing(): Boolean {
|
||||
return childFragmentManager.findFragmentByTag(TAG_SPECIAL_DOWNLOAD_DIALOG) != null
|
||||
}
|
||||
|
||||
override fun scrollToTop() {
|
||||
val fragment = mFragmentsList.safelyGetInRelease(mBodyBinding.gamedetailVp.currentItem)
|
||||
if (fragment is IScrollable && fragment.isAdded) {
|
||||
|
||||
@ -394,7 +394,7 @@ class SpecialDownloadDialogFragment : BaseDraggableDialogFragment() {
|
||||
SensorsBridge.trackDownloadComponentsContentClick(
|
||||
gameId = gameEntity.id,
|
||||
gameName = gameEntity.name ?: "unknown",
|
||||
gameSchemeType = gameEntity.gameBitChinese,
|
||||
gameSchemaType = gameEntity.gameBitChinese,
|
||||
downloadStatus = gameEntity.downloadStatusChinese,
|
||||
gameType = gameEntity.categoryChinese,
|
||||
downloadType = if (asVGame) "畅玩下载" else "本地下载",
|
||||
@ -405,7 +405,7 @@ class SpecialDownloadDialogFragment : BaseDraggableDialogFragment() {
|
||||
SensorsBridge.trackDownloadComponentsShow(
|
||||
gameId = gameEntity.id,
|
||||
gameName = gameEntity.name ?: "unknown",
|
||||
gameSchemeType = gameEntity.gameBitChinese,
|
||||
gameSchemaType = gameEntity.gameBitChinese,
|
||||
downloadStatus = gameEntity.downloadStatusChinese,
|
||||
gameType = gameEntity.categoryChinese,
|
||||
downloadType = if (asVGame) "畅玩下载" else "本地下载",
|
||||
|
||||
@ -17,6 +17,7 @@ import com.gh.common.iinterface.ISuperiorChain
|
||||
import com.gh.common.prioritychain.CustomFloatingWindowHandler
|
||||
import com.gh.common.prioritychain.PriorityChain
|
||||
import com.gh.common.prioritychain.PullDownPushHandler
|
||||
import com.gh.common.prioritychain.VideoHandler
|
||||
import com.gh.common.util.DefaultSearchHintHelper
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.DirectUtils
|
||||
@ -468,9 +469,9 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
|
||||
|
||||
binding = FragmentCustomBinding.bind(mCachedView)
|
||||
|
||||
buildPriorityChain()
|
||||
scrollCalculatorHelper = ScrollCalculatorHelper(binding.gameList, R.id.autoVideoView, 0, false)
|
||||
|
||||
scrollCalculatorHelper = ScrollCalculatorHelper(binding.gameList, R.id.autoVideoView, 0)
|
||||
buildPriorityChain()
|
||||
|
||||
adapter = CustomPageAdapter(
|
||||
viewModel,
|
||||
@ -512,9 +513,11 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
|
||||
|
||||
private fun buildPriorityChain() {
|
||||
val floatingWindowHandler = CustomFloatingWindowHandler(23)
|
||||
val videoHandler = VideoHandler(24, scrollCalculatorHelper)
|
||||
|
||||
priorityChain.addHandler(pullDownPushHandler)
|
||||
priorityChain.addHandler(floatingWindowHandler)
|
||||
priorityChain.addHandler(videoHandler)
|
||||
(parentFragment as? BaseTabWrapperFragment)?.addTabGuideHandlerIfExists(priorityChain)
|
||||
|
||||
viewModel.floatingWindows.observe(viewLifecycleOwner, EventObserver {
|
||||
|
||||
@ -5,7 +5,6 @@ import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.forEach
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
@ -15,13 +14,28 @@ import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.video.detail.CustomManager
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
class ScrollCalculatorHelper(val mListRv: RecyclerView, private val mPlayId: Int, private val mRangeTop: Int) {
|
||||
class ScrollCalculatorHelper(
|
||||
val mListRv: RecyclerView,
|
||||
private val mPlayId: Int,
|
||||
private val mRangeTop: Int,
|
||||
private var isEnabled: Boolean = true
|
||||
) {
|
||||
|
||||
private var mFirstVisible = -1
|
||||
private var mLastVisible = 0
|
||||
private var mRunnable: PlayRunnable? = null
|
||||
private val mPlayHandler = Handler(Looper.getMainLooper())
|
||||
var currentPlayer: AutomaticVideoView? = null
|
||||
|
||||
fun enableAndPlayIfValid() {
|
||||
isEnabled = true
|
||||
|
||||
if (mListRv.isAttachedToWindow
|
||||
&& mListRv.scrollState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
playVideo(mListRv)
|
||||
}
|
||||
}
|
||||
|
||||
fun onScrollStateChanged(scrollState: Int) {
|
||||
if (scrollState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
playVideo(mListRv)
|
||||
@ -80,7 +94,7 @@ class ScrollCalculatorHelper(val mListRv: RecyclerView, private val mPlayId: Int
|
||||
}
|
||||
|
||||
private fun playVideo(view: RecyclerView?) {
|
||||
if (view == null) return
|
||||
if (view == null || !view.isAttachedToWindow || !isEnabled) return
|
||||
val layoutManager = view.layoutManager
|
||||
var gsyBaseVideoPlayer: AutomaticVideoView
|
||||
for (i in mFirstVisible until mLastVisible + 1) {
|
||||
|
||||
@ -13,7 +13,7 @@ object HeadUpDisplayLogHelper {
|
||||
source = source,
|
||||
downloadType = if (downloadEntity.asVGame()) "畅玩下载" else "本地下载",
|
||||
downloadStatus = downloadEntity.getMetaExtra(Constants.DOWNLOAD_STATUS_IN_CHINESE),
|
||||
gameSchemeType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
gameSchemaType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
gameType = downloadEntity.getMetaExtra(Constants.GAME_CATEGORY_IN_CHINESE),
|
||||
gameId = downloadEntity.gameId,
|
||||
gameName = downloadEntity.name
|
||||
@ -25,7 +25,7 @@ object HeadUpDisplayLogHelper {
|
||||
source = source,
|
||||
downloadType = if (downloadEntity.asVGame()) "畅玩下载" else "本地下载",
|
||||
downloadStatus = downloadEntity.getMetaExtra(Constants.DOWNLOAD_STATUS_IN_CHINESE),
|
||||
gameSchemeType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
gameSchemaType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
gameType = downloadEntity.getMetaExtra(Constants.GAME_CATEGORY_IN_CHINESE),
|
||||
gameId = downloadEntity.gameId,
|
||||
gameName = downloadEntity.name
|
||||
@ -36,7 +36,7 @@ object HeadUpDisplayLogHelper {
|
||||
SensorsBridge.trackAutomaticInstallationPromptBarShow(
|
||||
downloadType = if (downloadEntity.asVGame()) "畅玩下载" else "本地下载",
|
||||
downloadStatus = downloadEntity.getMetaExtra(Constants.DOWNLOAD_STATUS_IN_CHINESE),
|
||||
gameSchemeType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
gameSchemaType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
gameType = downloadEntity.getMetaExtra(Constants.GAME_CATEGORY_IN_CHINESE),
|
||||
gameId = downloadEntity.gameId,
|
||||
gameName = downloadEntity.name
|
||||
@ -47,7 +47,7 @@ object HeadUpDisplayLogHelper {
|
||||
SensorsBridge.trackAutomaticInstallationPromptBarClick(
|
||||
downloadType = if (downloadEntity.asVGame()) "畅玩下载" else "本地下载",
|
||||
downloadStatus = downloadEntity.getMetaExtra(Constants.DOWNLOAD_STATUS_IN_CHINESE),
|
||||
gameSchemeType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
gameSchemaType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
gameType = downloadEntity.getMetaExtra(Constants.GAME_CATEGORY_IN_CHINESE),
|
||||
gameId = downloadEntity.gameId,
|
||||
gameName = downloadEntity.name
|
||||
|
||||
@ -130,6 +130,24 @@ object PackagesManager {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据游戏 ID 获取已安装的信息
|
||||
*
|
||||
* @param gameId 游戏 Id
|
||||
* @return 如果为空:未安装
|
||||
*/
|
||||
fun getInstalledDataByGameId(gameId: String?): GameInstall? {
|
||||
if (TextUtils.isEmpty(gameId)) {
|
||||
return null
|
||||
}
|
||||
for (gameInstall in mInstalledList) {
|
||||
if (gameInstall.id == gameId) {
|
||||
return gameInstall
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断包名是否可以更新
|
||||
|
||||
@ -11,11 +11,9 @@ import com.gh.gamecenter.room.AppDatabase
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
object PackageFilterManager {
|
||||
class PackageFilterManager {
|
||||
|
||||
private var mPackageKey = "" // 用于下次获取包名-游戏信息的 key
|
||||
private val mPendingPackageNameSet by lazy { hashSetOf<String>() } // 因遇到异常而等待下次操作更新的包名列表
|
||||
private val mValidPackageNameSet by lazy { hashSetOf<String>() } // 已被收录的游戏包名列表
|
||||
|
||||
val packageKey: String
|
||||
get() = mPackageKey
|
||||
@ -34,7 +32,7 @@ object PackageFilterManager {
|
||||
) {
|
||||
if (appendOnly) {
|
||||
// 添加因为异常而没能正常更新的包名列表
|
||||
packageList.addAll(mPendingPackageNameSet)
|
||||
packageList.addAll(PackageRepository.mPendingPackageNameSet)
|
||||
}
|
||||
|
||||
RetrofitManager.getInstance()
|
||||
@ -44,12 +42,12 @@ object PackageFilterManager {
|
||||
.subscribe(object : BiResponse<PackageFilter>() {
|
||||
override fun onSuccess(data: PackageFilter) {
|
||||
mPackageKey = data.key
|
||||
mPendingPackageNameSet.clear()
|
||||
PackageRepository.mPendingPackageNameSet.clear()
|
||||
|
||||
val partialPackageList = arrayListOf<String>()
|
||||
|
||||
if (!appendOnly) {
|
||||
mValidPackageNameSet.clear()
|
||||
PackageRepository.mValidPackageNameSet.clear()
|
||||
tryWithDefaultCatch {
|
||||
AppDatabase.getInstance().packageFilterDao().deleteAllPackageName()
|
||||
}
|
||||
@ -63,13 +61,13 @@ object PackageFilterManager {
|
||||
}
|
||||
|
||||
partialPackageList.add(packageName)
|
||||
mValidPackageNameSet.add(packageName)
|
||||
PackageRepository.mValidPackageNameSet.add(packageName)
|
||||
}
|
||||
|
||||
if (appendOnly) {
|
||||
callbackClosure?.invoke(ArrayList(partialPackageList))
|
||||
} else {
|
||||
callbackClosure?.invoke(ArrayList(mValidPackageNameSet))
|
||||
callbackClosure?.invoke(ArrayList(PackageRepository.mValidPackageNameSet))
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +75,7 @@ object PackageFilterManager {
|
||||
super.onFailure(exception)
|
||||
|
||||
if (appendOnly) {
|
||||
mPendingPackageNameSet.addAll(packageList)
|
||||
PackageRepository.mPendingPackageNameSet.addAll(packageList)
|
||||
} else {
|
||||
if (exception is retrofit2.HttpException && exception.code() == 403) {
|
||||
// 403 代表 key 过期,需要重新获取
|
||||
@ -91,28 +89,13 @@ object PackageFilterManager {
|
||||
for (packageEntity in packageEntityList) {
|
||||
// 依然为已安装状态才加入到有效包名列表中
|
||||
if (PackageUtils.isInstalled(HaloApp.getInstance(), packageEntity.packageName)) {
|
||||
mValidPackageNameSet.add(packageEntity.packageName)
|
||||
PackageRepository.mValidPackageNameSet.add(packageEntity.packageName)
|
||||
}
|
||||
}
|
||||
|
||||
callbackClosure?.invoke(ArrayList(mValidPackageNameSet))
|
||||
callbackClosure?.invoke(ArrayList(PackageRepository.mValidPackageNameSet))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 该包名是否有效 (即是否已被光环收录)
|
||||
*/
|
||||
fun isPackageValid(packageName: String): Boolean {
|
||||
return mValidPackageNameSet.contains(packageName)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在因为接口异常而导致没有查询收录情况的包名列表
|
||||
*/
|
||||
fun hasPendingPackage(): Boolean {
|
||||
return mPendingPackageNameSet.isEmpty()
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,7 +6,6 @@ import android.text.TextUtils
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.common.filter.RegionSettingHelper
|
||||
import com.gh.gamecenter.feature.utils.ApkActiveUtils
|
||||
import com.gh.common.util.GameUtils
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.gamecenter.R
|
||||
@ -16,19 +15,29 @@ import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.ObservableUtil
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.secondOrNull
|
||||
import com.gh.gamecenter.common.utils.toArrayList
|
||||
import com.gh.gamecenter.common.utils.tryCatchInRelease
|
||||
import com.gh.gamecenter.core.runOnIoThread
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.entity.AppEntity
|
||||
import com.gh.gamecenter.entity.GameUpdateEntity
|
||||
import com.gh.gamecenter.entity.PackageGame
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.GameInstall
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.gh.gamecenter.feature.utils.ApkActiveUtils
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.gh.gamecenter.packagehelper.PackageRepository.gameInstalled
|
||||
import com.gh.gamecenter.packagehelper.PackageRepository.gameUpdate
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.vspace.VHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.SingleObserver
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.json.JSONException
|
||||
@ -74,6 +83,10 @@ object PackageRepository {
|
||||
fun changeRecentVaPlayed() {
|
||||
_recentVaPlayedChanged.postValue(Unit)
|
||||
}
|
||||
val packageFilterManager = PackageFilterManager()
|
||||
var mPendingPackageNameSet = hashSetOf<String>() // 因遇到异常而等待下次操作更新的包名列表
|
||||
var mValidPackageNameSet = hashSetOf<String>() // 已被收录的游戏包名列表
|
||||
|
||||
|
||||
/**
|
||||
* 预留方法,如果想手动初始化可以调用
|
||||
@ -89,18 +102,51 @@ object PackageRepository {
|
||||
if (gameUpdate.isNotEmpty()) gameUpdate.clear()
|
||||
if (mInstalledPkgSet.isNotEmpty()) mInstalledPkgSet.clear()
|
||||
|
||||
val list = PackageUtils.getAllPackageName(mApplication)
|
||||
Single.zip<Result<Any?>, Result<Any?>, Result<Any?>>(
|
||||
Single.create { emitter ->
|
||||
val list = PackageUtils.getAllPackageName(mApplication)
|
||||
uploadAppList()
|
||||
initFilterPackage(list) { filteredList ->
|
||||
emitter.onSuccess(Result.success(null))
|
||||
|
||||
uploadAppList()
|
||||
mInstalledPkgSet.addAll(filteredList)
|
||||
notifyInstallPkgData()
|
||||
loadInstalledGameDigestAndNotifyData(packageFilterManager.packageKey, filteredList)
|
||||
}
|
||||
|
||||
initFilterPackage(list) { filteredList ->
|
||||
mIsInitialisingData = false
|
||||
|
||||
mInstalledPkgSet.addAll(filteredList)
|
||||
notifyInstallPkgData()
|
||||
},
|
||||
Single.create { emitter ->
|
||||
// 畅玩游戏更新
|
||||
var allGames = VHelper.getAllVGameSnapshots()
|
||||
if (allGames.isEmpty()) {
|
||||
VHelper.refreshVGameSnapshot()
|
||||
allGames = VHelper.getAllVGameSnapshots()
|
||||
}
|
||||
val allGamePkgNames = allGames.map { it.packageName }.toArrayList()
|
||||
if (allGamePkgNames.isNotEmpty()) {
|
||||
val packageFilterManager = PackageFilterManager()
|
||||
updateFilterPackage(packageFilterManager, allGamePkgNames) {
|
||||
emitter.onSuccess(Result.success(null))
|
||||
loadInstalledGameDigestAndNotifyData(
|
||||
packageKey = packageFilterManager.packageKey,
|
||||
filteredList = allGamePkgNames,
|
||||
isVGame = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
) { t1, t2 -> Result.success(null) }.subscribe(object : SingleObserver<Result<Any?>> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
|
||||
loadInstalledGameDigestAndNotifyData(filteredList)
|
||||
}
|
||||
override fun onSuccess(t: Result<Any?>) {
|
||||
mIsInitialisingData = false
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
}
|
||||
})
|
||||
|
||||
loadGhzsUpdate()
|
||||
}
|
||||
@ -113,18 +159,15 @@ object PackageRepository {
|
||||
list: MutableList<String>,
|
||||
callbackClosure: ((list: ArrayList<String>) -> Unit)? = null
|
||||
) {
|
||||
PackageFilterManager.updateFilterPackages(list, false) {
|
||||
callbackClosure?.invoke(it)
|
||||
}
|
||||
packageFilterManager.updateFilterPackages(list, false, callbackClosure)
|
||||
}
|
||||
|
||||
private fun updateFilterPackage(
|
||||
packageFilterManager: PackageFilterManager,
|
||||
list: MutableList<String>,
|
||||
callbackClosure: ((list: ArrayList<String>) -> Unit)? = null
|
||||
) {
|
||||
PackageFilterManager.updateFilterPackages(list, true) {
|
||||
callbackClosure?.invoke(it)
|
||||
}
|
||||
packageFilterManager.updateFilterPackages(list, true, callbackClosure)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,7 +178,8 @@ object PackageRepository {
|
||||
PackageUtils.getGhVersionName(),
|
||||
PackageUtils.getGhVersionCode(),
|
||||
HaloApp.getInstance().channel,
|
||||
Build.VERSION.SDK_INT)
|
||||
Build.VERSION.SDK_INT
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Response<AppEntity>() {
|
||||
@ -208,6 +252,7 @@ object PackageRepository {
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
private fun loadInstalledGameDigestAndNotifyData(
|
||||
packageKey: String,
|
||||
filteredList: ArrayList<String>,
|
||||
isVGame: Boolean = false,
|
||||
updateInstallStatus: Boolean = false
|
||||
@ -222,7 +267,7 @@ object PackageRepository {
|
||||
}, Any())
|
||||
|
||||
while (++page <= maxPageCount) {
|
||||
var observable = mNewApi.getPackageGames(PackageFilterManager.packageKey, page, PAGE_SIZE)
|
||||
var observable = mNewApi.getPackageGames(packageKey, page, PAGE_SIZE)
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
observable.subscribe(object : BiResponse<List<PackageGame>>() {
|
||||
@ -238,7 +283,8 @@ object PackageRepository {
|
||||
}
|
||||
|
||||
for (game in validGames) {
|
||||
val shouldNotifyChanges = validateGameAndPostChanges(gh_id, game, pkgName, isVGame, updateInstallStatus)
|
||||
val shouldNotifyChanges =
|
||||
validateGameAndPostChanges(gh_id, game, pkgName, isVGame, updateInstallStatus)
|
||||
if (!isNotifyUpdate && shouldNotifyChanges) {
|
||||
isNotifyUpdate = true
|
||||
}
|
||||
@ -259,11 +305,13 @@ object PackageRepository {
|
||||
/**
|
||||
* 验证游戏并且更新数据
|
||||
*/
|
||||
private fun validateGameAndPostChanges(ghId: Any?,
|
||||
game: GameEntity,
|
||||
pkgName: String,
|
||||
isVGame: Boolean,
|
||||
updateInstallStatus: Boolean): Boolean {
|
||||
private fun validateGameAndPostChanges(
|
||||
ghId: Any?,
|
||||
game: GameEntity,
|
||||
pkgName: String,
|
||||
isVGame: Boolean,
|
||||
updateInstallStatus: Boolean
|
||||
): Boolean {
|
||||
if (ghId == null || ghId == game.id) {
|
||||
gameInstalled.add(GameInstall.transformGameInstall(game, pkgName, isVGame))
|
||||
mInstalledGameList.add(game)
|
||||
@ -272,7 +320,8 @@ object PackageRepository {
|
||||
addCurrentlyInstalledVersionIfValid(game)
|
||||
|
||||
if (updateInstallStatus) {
|
||||
EventBus.getDefault().post(EBPackage(EBPackage.TYPE_INSTALLED, pkgName, game.getApk().firstOrNull()?.version))
|
||||
EventBus.getDefault()
|
||||
.post(EBPackage(EBPackage.TYPE_INSTALLED, pkgName, game.getApk().firstOrNull()?.version))
|
||||
}
|
||||
|
||||
if (isCanUpdate || isCanPluggable) {
|
||||
@ -356,7 +405,8 @@ object PackageRepository {
|
||||
) {
|
||||
// 使用了镜像的游戏;插件化关闭的游戏;无需插件化
|
||||
if (game.shouldUseMirrorInfo()
|
||||
|| apk.plugin == "close") {
|
||||
|| apk.plugin == "close"
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -416,8 +466,11 @@ object PackageRepository {
|
||||
* @param pkgName 已安装的游戏包名
|
||||
* @param cachedGameEntity 缓存的游戏实体,若存在免去再请求接口的过程
|
||||
*/
|
||||
fun addInstalledGame(pkgName: String,
|
||||
cachedGameEntity: GameEntity? = null) {
|
||||
fun addInstalledGame(
|
||||
packageFilterManager: PackageFilterManager,
|
||||
pkgName: String,
|
||||
cachedGameEntity: GameEntity? = null
|
||||
) {
|
||||
mInstalledPkgSet.add(pkgName)
|
||||
notifyInstallPkgData()
|
||||
|
||||
@ -428,7 +481,8 @@ object PackageRepository {
|
||||
game = cachedGameEntity,
|
||||
pkgName = pkgName,
|
||||
isVGame = false,
|
||||
updateInstallStatus = false)
|
||||
updateInstallStatus = false
|
||||
)
|
||||
|
||||
if (containsUpdate) {
|
||||
notifyGameUpdateData()
|
||||
@ -436,8 +490,9 @@ object PackageRepository {
|
||||
} else {
|
||||
val list = arrayListOf(pkgName)
|
||||
|
||||
updateFilterPackage(list) {
|
||||
updateFilterPackage(packageFilterManager, list) {
|
||||
loadInstalledGameDigestAndNotifyData(
|
||||
packageKey = packageFilterManager.packageKey,
|
||||
filteredList = list,
|
||||
updateInstallStatus = false
|
||||
)
|
||||
@ -453,9 +508,11 @@ object PackageRepository {
|
||||
* @param isVGame 是否为畅玩游戏
|
||||
* @param updateInstallStatus 是否更新安装状态
|
||||
*/
|
||||
fun addInstalledGames(pkgNameList: ArrayList<String>,
|
||||
isVGame: Boolean = false,
|
||||
updateInstallStatus: Boolean = false,
|
||||
fun addInstalledGames(
|
||||
packageFilterManager: PackageFilterManager,
|
||||
pkgNameList: ArrayList<String>,
|
||||
isVGame: Boolean = false,
|
||||
updateInstallStatus: Boolean = false,
|
||||
) {
|
||||
// 畅玩游戏不添加至本地的已安装包名列表中
|
||||
if (!isVGame) {
|
||||
@ -465,8 +522,9 @@ object PackageRepository {
|
||||
}
|
||||
notifyInstallPkgData()
|
||||
|
||||
updateFilterPackage(pkgNameList) {
|
||||
updateFilterPackage(packageFilterManager, pkgNameList) {
|
||||
loadInstalledGameDigestAndNotifyData(
|
||||
packageKey = packageFilterManager.packageKey,
|
||||
filteredList = pkgNameList,
|
||||
isVGame = isVGame,
|
||||
updateInstallStatus = updateInstallStatus
|
||||
@ -526,6 +584,13 @@ object PackageRepository {
|
||||
changeRecentVaPlayed()
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在因为接口异常而导致没有查询收录情况的包名列表
|
||||
*/
|
||||
fun hasPendingPackage(): Boolean {
|
||||
return mPendingPackageNameSet.isEmpty()
|
||||
}
|
||||
|
||||
private fun notifyGameInstallData() {
|
||||
PackagesManager.initGameInstall(ArrayList(gameInstalled))
|
||||
gameInstalledLiveData.postValue(ArrayList(gameInstalled))
|
||||
|
||||
@ -63,7 +63,13 @@ class PackageViewModel(
|
||||
* @param cachedGameEntity 缓存的游戏实体
|
||||
*/
|
||||
fun addInstalledGame(pkgName: String?, cachedGameEntity: GameEntity? = null) {
|
||||
if (!TextUtils.isEmpty(pkgName)) mRepository.addInstalledGame(pkgName!!, cachedGameEntity)
|
||||
if (!TextUtils.isEmpty(pkgName)) {
|
||||
mRepository.addInstalledGame(
|
||||
mRepository.packageFilterManager,
|
||||
pkgName!!,
|
||||
cachedGameEntity
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,9 +87,7 @@ class PackageViewModel(
|
||||
// 未同意获取已安装应用权限时不进行数据初始化
|
||||
if (!PackageHelper.isGetInstalledPackagesAgreed()) return
|
||||
|
||||
if (mRepository.gameInstalled.size == 0
|
||||
|| PackageFilterManager.hasPendingPackage()
|
||||
) {
|
||||
if (mRepository.gameInstalled.size == 0 || mRepository.hasPendingPackage()) {
|
||||
PackageHelper.initPackageRelatedData();
|
||||
}
|
||||
}
|
||||
|
||||
@ -699,6 +699,8 @@ class HaloPersonalFragment : BaseLazyFragment() {
|
||||
} catch (e: Exception) {
|
||||
} as? ITestCase)?.apply {
|
||||
addInstallExternalGameButton(mStubBinding.otherItems)
|
||||
addInstallPluginButton(mStubBinding.otherItems)
|
||||
addInstallPlugin32Button(mStubBinding.otherItems)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,11 +16,12 @@ import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.databinding.PieceBottomTabBinding
|
||||
import com.gh.gamecenter.entity.BottomTab
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper
|
||||
|
||||
/**
|
||||
* 底部Tab 基类
|
||||
*/
|
||||
abstract class BaseBottomTabFragment<T: ViewBinding>: ToolbarFragment() {
|
||||
abstract class BaseBottomTabFragment<T : ViewBinding> : ToolbarFragment() {
|
||||
|
||||
protected var mViewPager: ViewPager2? = null
|
||||
protected var mBottomTabContainer: LinearLayout? = null
|
||||
@ -44,6 +45,7 @@ abstract class BaseBottomTabFragment<T: ViewBinding>: ToolbarFragment() {
|
||||
protected fun initBottomTab(bottomTabList: List<BottomTab>) {
|
||||
mBottomTabBindingList.clear()
|
||||
mBottomTabContainer?.run {
|
||||
visibility = View.VISIBLE
|
||||
removeAllViews()
|
||||
bottomTabList.forEachIndexed { index, bottomTab ->
|
||||
addView(
|
||||
@ -61,6 +63,13 @@ abstract class BaseBottomTabFragment<T: ViewBinding>: ToolbarFragment() {
|
||||
.apply {
|
||||
tabTv.text = bottomTab.name
|
||||
if (!TextUtils.isEmpty(bottomTab.jsCode)) {
|
||||
tabLottie.setFailureListener {
|
||||
SentryHelper.onEvent(
|
||||
SENTRY_ID_BOTTOM_TAB_LOTTIE_LOAD_FAILED,
|
||||
BOTTOM_TAB_ID, bottomTab.id,
|
||||
BOTTOM_TAB_NAME, bottomTab.name
|
||||
)
|
||||
}
|
||||
tabLottie.setAnimationFromJson(bottomTab.jsCode, bottomTab.id + bottomTab.name)
|
||||
}
|
||||
if (bottomTab.iconSelector != 0) {
|
||||
@ -122,6 +131,13 @@ abstract class BaseBottomTabFragment<T: ViewBinding>: ToolbarFragment() {
|
||||
protected open fun onPageSelected(position: Int) {
|
||||
checkIndex(position)
|
||||
}
|
||||
|
||||
protected open fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
protected open fun onPageScrollStateChanged(state: Int) {}
|
||||
|
||||
companion object {
|
||||
private const val SENTRY_ID_BOTTOM_TAB_LOTTIE_LOAD_FAILED = "bottom_tab_lottie_load_failed"
|
||||
private const val BOTTOM_TAB_ID = "bottom_tab_id"
|
||||
private const val BOTTOM_TAB_NAME = "bottom_tab_name"
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,8 @@ import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.text.color
|
||||
import androidx.core.view.doOnNextLayout
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
import com.ethanhua.skeleton.SkeletonScreen
|
||||
import com.gh.common.iinterface.ISuperiorChain
|
||||
import com.gh.common.prioritychain.BottomTabGuideHandler
|
||||
import com.gh.common.prioritychain.GlobalPriorityChainHelper
|
||||
@ -48,6 +50,8 @@ class MainWrapperFragment : BaseBottomTabFragment<PieceBottomTabBinding>(), OnBa
|
||||
private var mBottomTabGuideHandler: BottomTabGuideHandler? = null
|
||||
private var mBottomTabGuidePopupWindow: PopupWindow? = null
|
||||
|
||||
private var mSkeletonScreen: SkeletonScreen? = null
|
||||
|
||||
override fun getLayoutId(): Int = 0
|
||||
override fun getInflatedLayout(): View = mBinding.root
|
||||
override fun provideAdapter(): FragmentStateAdapter = mAdapter
|
||||
@ -63,10 +67,13 @@ class MainWrapperFragment : BaseBottomTabFragment<PieceBottomTabBinding>(), OnBa
|
||||
super.onCreate(savedInstanceState)
|
||||
DisplayUtils.transparentStatusBar(requireActivity())
|
||||
|
||||
initSkeleton()
|
||||
|
||||
mBinding.viewShadow.visibility = if (mIsDarkModeOn) View.GONE else View.VISIBLE
|
||||
buildPriorityChain()
|
||||
|
||||
mViewModel?.bottomTabListLiveData?.observe(this) {
|
||||
mSkeletonScreen?.hide()
|
||||
mBottomTabList.clear()
|
||||
mBottomTabList.addAll(it)
|
||||
mViewPager?.offscreenPageLimit = it.size
|
||||
@ -84,6 +91,18 @@ class MainWrapperFragment : BaseBottomTabFragment<PieceBottomTabBinding>(), OnBa
|
||||
mPriorityChain.addHandler(mBottomTabGuideHandler!!)
|
||||
}
|
||||
|
||||
private fun initSkeleton() {
|
||||
mSkeletonScreen = Skeleton.bind(mBinding.skeleton)
|
||||
.shimmer(true)
|
||||
.angle(Constants.SHIMMER_ANGLE)
|
||||
.color(R.color.ui_skeleton_highlight)
|
||||
.duration(Constants.SHIMMER_DURATION)
|
||||
.maskWidth(Constants.MASK_WIDTH)
|
||||
.gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
|
||||
.load(R.layout.fragment_main_skeleton)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun showBottomTabGuideIfExists() {
|
||||
val guidePosition = mBottomTabList.indexOfFirst { it.guide != null }
|
||||
if (guidePosition != -1) {
|
||||
|
||||
@ -3,10 +3,10 @@ package com.gh.gamecenter.wrapper
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.common.util.HomeBottomBarHelper
|
||||
import com.gh.common.util.HomeBottomBarHelper.isDefaultHomeBottomTabDataExist
|
||||
import com.gh.common.util.ViewPagerFragmentHelper
|
||||
import com.gh.gamecenter.common.entity.LaunchRedirect
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.core.utils.GsonUtils
|
||||
import com.gh.gamecenter.core.utils.SingletonHolder
|
||||
import com.gh.gamecenter.entity.BottomTab
|
||||
@ -17,6 +17,7 @@ import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
@ -134,7 +135,13 @@ class MainWrapperRepository {
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun getDataUnion() {
|
||||
processBottomTabData(emptyList())
|
||||
// 若历史 tab 数据存在,优先使用作为占位
|
||||
if (isDefaultHomeBottomTabDataExist()) {
|
||||
processBottomTabData(emptyList())
|
||||
} else {
|
||||
// 若 timeout 后数据未加载完成,则即便还没回调 onFailure 也生成两个底部 tab
|
||||
emitDefaultTabDataAfterTimeout()
|
||||
}
|
||||
mNewApi.dataUnion
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : BiResponse<DataUnionEntity>() {
|
||||
@ -232,6 +239,15 @@ class MainWrapperRepository {
|
||||
multiTabNavLiveData.postValue(multiTabNav)
|
||||
}
|
||||
|
||||
private fun emitDefaultTabDataAfterTimeout() {
|
||||
CoroutineScope(SupervisorJob()).launch {
|
||||
delay(3000)
|
||||
if (!mMainDataIsLoaded) {
|
||||
processBottomTabData(emptyList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object : SingletonHolder<MainWrapperRepository>({ MainWrapperRepository() })
|
||||
}
|
||||
|
||||
|
||||
@ -58,6 +58,7 @@ import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.exposure.time.TimeUtil
|
||||
import com.gh.gamecenter.feature.game.GameItemViewHolder
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper
|
||||
import com.gh.gamecenter.gamecollection.square.GameCollectionSquareFragment
|
||||
import com.gh.gamecenter.home.custom.CustomPageFragment
|
||||
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
|
||||
@ -89,7 +90,18 @@ import kotlin.math.roundToInt
|
||||
* @see Style
|
||||
*/
|
||||
class SearchToolbarTabWrapperFragment : BaseTabWrapperFragment(), ISearchToolbarTab, ISmartRefresh, ISuperiorChain {
|
||||
private val mBinding by lazy { FragmentSearchToolbarTabWrapperBinding.inflate(layoutInflater) }
|
||||
private val mBinding by lazy {
|
||||
try {
|
||||
FragmentSearchToolbarTabWrapperBinding.inflate(layoutInflater)
|
||||
} catch (e: Exception) {
|
||||
SentryHelper.onEvent("VIEW_BINDING_BIND_ERROR",
|
||||
"digest", e.localizedMessage,
|
||||
"gid", HaloApp.getInstance().gid
|
||||
)
|
||||
// 玄学,重试一次,该闪退闪退
|
||||
FragmentSearchToolbarTabWrapperBinding.inflate(layoutInflater)
|
||||
}
|
||||
}
|
||||
private val mViewModel: SearchToolbarTabWrapperViewModel by lazy {
|
||||
viewModelProviderFromParent(
|
||||
SearchToolbarTabWrapperViewModel.Factory(mMultiTabNavId, mNoTabLinkEntity?.link ?: ""),
|
||||
|
||||
@ -14,9 +14,11 @@ import android.text.TextUtils;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import com.blankj.utilcode.util.ThreadUtils;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager;
|
||||
import com.gh.gamecenter.core.AppExecutor;
|
||||
import com.gh.ndownload.suspendwindow.NDownloadDrawOverlayPermissionWindowController;
|
||||
import com.gh.ndownload.suspendwindow.NDownloadSuspendWindowController;
|
||||
import com.gh.ndownload.suspendwindow.utils.NDownloadSuspendWindowHelper;
|
||||
@ -282,6 +284,14 @@ public class NDownloadService extends Service {
|
||||
}
|
||||
|
||||
private void showDownloadSuspendWindowIfNeeded(DownloadEntity entry) {
|
||||
if (ThreadUtils.isMainThread()) {
|
||||
showDownloadSuspendWindowIfNeededInner(entry);
|
||||
} else {
|
||||
AppExecutor.getUiExecutor().execute(() -> showDownloadSuspendWindowIfNeededInner(entry));
|
||||
}
|
||||
}
|
||||
|
||||
private void showDownloadSuspendWindowIfNeededInner(DownloadEntity entry) {
|
||||
if (!NDownloadSuspendWindowHelper.shouldSkipDownloadEntity(getApplicationContext(), entry)) {
|
||||
if (NDownloadSuspendWindowHelper.canDrawOverLayer(getApplicationContext())) {// 已开启悬浮窗权限,直接显示悬浮窗
|
||||
showDownloadSuspendWindow();
|
||||
|
||||
@ -4,6 +4,7 @@ import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.app.Application.ActivityLifecycleCallbacks
|
||||
import android.os.Bundle
|
||||
import androidx.core.view.ViewCompat
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.asVGame
|
||||
@ -45,7 +46,9 @@ class NDownloadDrawOverlayPermissionWindowController(val application: Applicatio
|
||||
}
|
||||
|
||||
fun show(activity: Activity) {
|
||||
if (isStarted) return
|
||||
val decorView = activity.window.decorView
|
||||
val isAttachedToWindow = ViewCompat.isAttachedToWindow(decorView)
|
||||
if (isStarted || !isAttachedToWindow) return
|
||||
isStarted = true
|
||||
currentActivityRef = WeakReference(activity)
|
||||
onAttachToUi(activity)
|
||||
@ -124,10 +127,10 @@ class NDownloadDrawOverlayPermissionWindowController(val application: Applicatio
|
||||
SensorsBridge.trackDownloadSuspendedWindowGuideShow(
|
||||
gameId = downloadEntity.gameId,
|
||||
gameName = downloadEntity.name,
|
||||
gameSchemeType = if(downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
gameSchemaType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
gameType = downloadEntity.categoryChinese,
|
||||
downloadStatus = downloadEntity.getMetaExtra(Constants.DOWNLOAD_STATUS_IN_CHINESE),
|
||||
downloadType = if(downloadEntity.asVGame()) "畅玩下载" else "本地下载"
|
||||
downloadType = if (downloadEntity.asVGame()) "畅玩下载" else "本地下载"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ import org.greenrobot.eventbus.ThreadMode
|
||||
* 下载悬浮窗-控制器
|
||||
*/
|
||||
class NDownloadSuspendWindowController(private val application: Application) :
|
||||
NDownloadSuspendIconLayout.OnDragListener, Application.ActivityLifecycleCallbacks,
|
||||
NDownloadSuspendIconLayout.OnDragCallback, Application.ActivityLifecycleCallbacks,
|
||||
PackageInstaller.OnInstallListener, NDownloadSuspendIconView.OnIconClickListener {
|
||||
|
||||
private var isStarted = false
|
||||
@ -75,22 +75,24 @@ class NDownloadSuspendWindowController(private val application: Application) :
|
||||
|
||||
downloadCount = 0
|
||||
currentDownloadEntity = null
|
||||
onDetachFromUi()
|
||||
NDataChanger.deleteObserver(downloadObserver)
|
||||
PackageInstaller.unregisterOnInstallListener(this)
|
||||
EventBus.getDefault().unregister(this)
|
||||
application.unregisterActivityLifecycleCallbacks(this)
|
||||
onDetachFromUi()
|
||||
isStarted = false
|
||||
}
|
||||
|
||||
private fun onAttachToUi() {
|
||||
closeWindow.attach()
|
||||
iconWindow.attach()
|
||||
iconWindow.setOnDragListener(this)
|
||||
iconWindow.setOnDragCallback(this)
|
||||
iconWindow.setOnIconClickListener(this)
|
||||
}
|
||||
|
||||
private fun onDetachFromUi() {
|
||||
iconWindow.setOnDragCallback(null)
|
||||
iconWindow.setOnIconClickListener(null)
|
||||
closeWindow.detach()
|
||||
iconWindow.detach()
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.asVGame
|
||||
import com.gh.gamecenter.common.utils.getExtension
|
||||
import com.gh.gamecenter.common.utils.isLocalDownloadInDualDownloadMode
|
||||
import com.gh.gamecenter.common.utils.isSimulatorDownload
|
||||
import com.gh.gamecenter.common.utils.isSimulatorGame
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
@ -184,6 +185,7 @@ object NDownloadSuspendWindowHelper {
|
||||
|| downloadEntity.isPluggable
|
||||
|| downloadEntity.isSimulatorDownload()
|
||||
|| downloadEntity.isSimulatorGame()
|
||||
|| downloadEntity.isLocalDownloadInDualDownloadMode()
|
||||
|
||||
@JvmStatic
|
||||
fun isDrawOverlayPermissionWindowShown(): Boolean =
|
||||
|
||||
@ -26,7 +26,7 @@ class NDownloadSuspendIconLayout @JvmOverloads constructor(
|
||||
ViewConfiguration.get(context).scaledTouchSlop
|
||||
}
|
||||
|
||||
private var onDragListener: OnDragListener? = null
|
||||
private var onDragCallback: OnDragCallback? = null
|
||||
|
||||
val icon = NDownloadSuspendIconView(context).also {
|
||||
it.clipChildren = false
|
||||
@ -39,12 +39,12 @@ class NDownloadSuspendIconLayout @JvmOverloads constructor(
|
||||
addView(it, LayoutParams(size, size))
|
||||
}
|
||||
|
||||
fun setOnDragListener(onDragListener: OnDragListener) {
|
||||
this.onDragListener = onDragListener
|
||||
fun setOnDragCallback(onDragCallback: OnDragCallback?) {
|
||||
this.onDragCallback = onDragCallback
|
||||
}
|
||||
|
||||
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
||||
val onDragListener = this.onDragListener
|
||||
val onDragCallback = this.onDragCallback
|
||||
?: return super.onInterceptTouchEvent(ev)
|
||||
|
||||
if (ev.action == MotionEvent.ACTION_DOWN) {
|
||||
@ -66,7 +66,7 @@ class NDownloadSuspendIconLayout @JvmOverloads constructor(
|
||||
val dragging = xDiff > touchSlop || yDiff > touchSlop
|
||||
if (dragging) {
|
||||
isDragging = true
|
||||
onDragListener.onDragStart(this)
|
||||
onDragCallback.onDragStart(this)
|
||||
return true
|
||||
}
|
||||
return super.onInterceptTouchEvent(ev)
|
||||
@ -81,7 +81,7 @@ class NDownloadSuspendIconLayout @JvmOverloads constructor(
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(ev: MotionEvent): Boolean {
|
||||
val onDragListener = this.onDragListener
|
||||
val onDragListener = this.onDragCallback
|
||||
?: return super.onInterceptTouchEvent(ev)
|
||||
|
||||
when(ev.action) {
|
||||
@ -93,7 +93,7 @@ class NDownloadSuspendIconLayout @JvmOverloads constructor(
|
||||
return super.onTouchEvent(ev)
|
||||
}
|
||||
|
||||
interface OnDragListener {
|
||||
interface OnDragCallback {
|
||||
|
||||
fun onDragStart(v: View)
|
||||
|
||||
|
||||
@ -109,7 +109,7 @@ class NDownloadSuspendIconView @JvmOverloads constructor(
|
||||
addView(it, layoutParams)
|
||||
}
|
||||
|
||||
fun setOnIconClickListener(listener: OnIconClickListener) {
|
||||
fun setOnIconClickListener(listener: OnIconClickListener?) {
|
||||
this.onIconClickListener = listener
|
||||
}
|
||||
|
||||
|
||||
@ -56,6 +56,13 @@ class NDownloadSuspendCloseWindow(context: Context, suspend: Boolean = true) :
|
||||
it.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
popupAnimator.removeListener(hiddenListener)
|
||||
popupAnimator.removeListener(shownListener)
|
||||
popupAnimator.cancel()
|
||||
root.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: NDownloadSuspendCloseLayout) {
|
||||
view.apply {
|
||||
popupAnimator.addUpdateListener { value ->
|
||||
|
||||
@ -19,7 +19,7 @@ import com.gh.ndownload.suspendwindow.view.NDownloadSuspendIconView
|
||||
*/
|
||||
class NDownloadSuspendIconWindow(context: Context, suspend: Boolean = true, private val draggable: Boolean = true) :
|
||||
NDownloadSuspendWindow<NDownloadSuspendIconLayout>(context, suspend),
|
||||
NDownloadSuspendIconLayout.OnDragListener {
|
||||
NDownloadSuspendIconLayout.OnDragCallback {
|
||||
|
||||
companion object {
|
||||
private const val TYPE_DRAGGING = 0
|
||||
@ -40,7 +40,7 @@ class NDownloadSuspendIconWindow(context: Context, suspend: Boolean = true, priv
|
||||
/**
|
||||
* 图标拖动回调事件
|
||||
*/
|
||||
private var onDragListener: NDownloadSuspendIconLayout.OnDragListener? = null
|
||||
private var onDragCallback: NDownloadSuspendIconLayout.OnDragCallback? = null
|
||||
|
||||
/**
|
||||
* 手指松开拖动的悬浮图标时,自动吸附到屏幕侧边的动画
|
||||
@ -67,20 +67,30 @@ class NDownloadSuspendIconWindow(context: Context, suspend: Boolean = true, priv
|
||||
get() = root.getLocationOnScreen(screenLocation)
|
||||
.let { screenLocation[1] - layoutParams.y }
|
||||
|
||||
fun setOnDragListener(onDragListener: NDownloadSuspendIconLayout.OnDragListener?) {
|
||||
this.onDragListener = onDragListener
|
||||
fun setOnDragCallback(onDragCallback: NDownloadSuspendIconLayout.OnDragCallback?) {
|
||||
this.onDragCallback = onDragCallback
|
||||
}
|
||||
|
||||
override fun detach() {
|
||||
super.detach()
|
||||
root.removeCallbacks(initRunnable)
|
||||
override fun onAttach() {
|
||||
if (draggable) {
|
||||
root.post(initRunnable)
|
||||
root.setOnDragCallback(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
if (draggable) {
|
||||
root.removeCallbacks(initRunnable)
|
||||
root.setOnDragCallback(null)
|
||||
}
|
||||
edgeAnimator.removeAllUpdateListeners()
|
||||
edgeAnimator.removeAllListeners()
|
||||
edgeAnimator.cancel()
|
||||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
override fun onCreateView(context: Context): NDownloadSuspendIconLayout =
|
||||
NDownloadSuspendIconLayout(context).also {
|
||||
if (draggable) it.setOnDragListener(this)
|
||||
it.clipChildren = false
|
||||
it.clipToPadding = false
|
||||
}
|
||||
@ -96,7 +106,6 @@ class NDownloadSuspendIconWindow(context: Context, suspend: Boolean = true, priv
|
||||
override fun onViewCreated(view: NDownloadSuspendIconLayout) {
|
||||
super.onViewCreated(view)
|
||||
view.setBackgroundResource(R.drawable.shape_download_suspend_icon_idle_right)
|
||||
if (draggable) view.post(initRunnable)
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(configuration: Configuration) {
|
||||
@ -135,7 +144,7 @@ class NDownloadSuspendIconWindow(context: Context, suspend: Boolean = true, priv
|
||||
root.icon.setDownloadIconUrl(url)
|
||||
}
|
||||
|
||||
fun setOnIconClickListener(listener: NDownloadSuspendIconView.OnIconClickListener) {
|
||||
fun setOnIconClickListener(listener: NDownloadSuspendIconView.OnIconClickListener?) {
|
||||
root.icon.setOnIconClickListener(listener)
|
||||
}
|
||||
|
||||
@ -203,16 +212,16 @@ class NDownloadSuspendIconWindow(context: Context, suspend: Boolean = true, priv
|
||||
|
||||
override fun onDragStart(v: View) {
|
||||
setIconLayoutStyleByType(TYPE_DRAGGING)
|
||||
onDragListener?.onDragStart(v)
|
||||
onDragCallback?.onDragStart(v)
|
||||
}
|
||||
|
||||
override fun onDragMove(v: View, x: Float, y: Float) {
|
||||
moveToPosition(v, x, y)
|
||||
onDragListener?.onDragMove(v, x, y)
|
||||
onDragCallback?.onDragMove(v, x, y)
|
||||
}
|
||||
|
||||
override fun onDragEnd(v: View, x: Float, y: Float) {
|
||||
animateToEdge(v, x, y)
|
||||
onDragListener?.onDragEnd(v, x, y)
|
||||
onDragCallback?.onDragEnd(v, x, y)
|
||||
}
|
||||
}
|
||||
@ -46,22 +46,35 @@ abstract class NDownloadSuspendWindow<T : View>(
|
||||
onViewCreated(it)
|
||||
}
|
||||
|
||||
open fun attach() {
|
||||
fun attach() {
|
||||
if (!isAttached) {
|
||||
_isAttached = true
|
||||
windowManager.addView(root, layoutParams)
|
||||
context.registerComponentCallbacks(this)
|
||||
try {
|
||||
_isAttached = true
|
||||
windowManager.addView(root, layoutParams)
|
||||
context.registerComponentCallbacks(this)
|
||||
onAttach()
|
||||
} catch (e: Throwable) {
|
||||
// 处理“Unable to add window android.view.ViewRootImpl$W@7bc9502 -- permission denied for window type 2038”的异常
|
||||
// 目前Sentry上仅Z10型号的手机报这个错误(Android 8.1.0),这里明明已经授予了SYSTEM_ALERT_WINDOW权限,但是就是会抛异常= =,只能暴力捕获处理了。。。
|
||||
// 相关异常的链接:https://sentry.shanqu.cc/organizations/lightgame/issues/407275/?project=22
|
||||
_isAttached = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun detach() {
|
||||
fun detach() {
|
||||
if (isAttached) {
|
||||
_isAttached = false
|
||||
onDetach()
|
||||
context.unregisterComponentCallbacks(this)
|
||||
windowManager.removeView(root)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun onAttach() = Unit
|
||||
|
||||
protected open fun onDetach() = Unit
|
||||
|
||||
protected open fun onViewCreated(view: T) = Unit
|
||||
|
||||
override fun onConfigurationChanged(configuration: Configuration) = Unit
|
||||
|
||||
@ -8,4 +8,6 @@ public interface ITestCase {
|
||||
|
||||
void addInstallExternalGameButton(@NonNull ViewGroup viewParent);
|
||||
|
||||
void addInstallPluginButton(@NonNull ViewGroup viewParent);
|
||||
void addInstallPlugin32Button(@NonNull ViewGroup viewParent);
|
||||
}
|
||||
|
||||
@ -56,6 +56,7 @@ import com.gh.gamecenter.history.HistoryActivity
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.gh.gamecenter.mygame.MyGameActivity
|
||||
import com.gh.gamecenter.packagehelper.PackageFilterManager
|
||||
import com.gh.gamecenter.packagehelper.PackageRepository
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
@ -1997,7 +1998,7 @@ object VHelper {
|
||||
validInstalledPackageList.add(packageName)
|
||||
}
|
||||
}
|
||||
PackageRepository.addInstalledGames(validInstalledPackageList, true)
|
||||
PackageRepository.addInstalledGames(PackageFilterManager(), validInstalledPackageList, true)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2277,6 +2278,13 @@ object VHelper {
|
||||
val token = UserManager.getInstance().token
|
||||
val userName = UserManager.getInstance().userInfoEntity?.name
|
||||
val userAvatar = UserManager.getInstance().userInfoEntity?.icon
|
||||
|
||||
if (token == null) {
|
||||
SentryHelper.onEvent("LAUNCH_SUCCESS_BUT_TOKEN_EMPTY", "gid", HaloApp.getInstance().gid)
|
||||
Utils.log(LOG_TAG, "登录成功,但 token 为空")
|
||||
return@runOnIoThread
|
||||
}
|
||||
|
||||
Utils.log(
|
||||
LOG_TAG,
|
||||
"登录成功,插入用户信息:token=${token},userName=${userName}, uri=${va.getUriAuthorizationString()}"
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 554 B |
6
app/src/main/res/drawable/bg_skeleton_radius_40.xml
Normal file
6
app/src/main/res/drawable/bg_skeleton_radius_40.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="20dp" />
|
||||
<solid android:color="@color/ui_skeleton_frame" />
|
||||
</shape>
|
||||
@ -142,7 +142,14 @@
|
||||
android:focusable="true"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/skeleton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</com.gh.gamecenter.common.view.MaterializedConstraintLayout>
|
||||
316
app/src/main/res/layout/fragment_main_skeleton.xml
Normal file
316
app/src/main/res/layout/fragment_main_skeleton.xml
Normal file
@ -0,0 +1,316 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@id/b"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.gh.gamecenter.common.view.StatusBarView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp">
|
||||
|
||||
<View
|
||||
android:id="@+id/sb"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/bg_skeleton_radius_40"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/ic1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/ic1"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/ic2"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/ic2"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="@drawable/bg_skeleton_radius_4"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="28dp"
|
||||
android:gravity="bottom"
|
||||
android:paddingTop="8dp">
|
||||
|
||||
<View
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="29dp"
|
||||
android:layout_marginTop="7dp"
|
||||
android:src="@drawable/ic_home_tab_indicator_skeleton" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<View
|
||||
android:id="@+id/square"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="140dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="@drawable/bg_skeleton_radius_10"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/rect1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/rect1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="66dp"
|
||||
android:background="@drawable/bg_skeleton_radius_10"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/square"
|
||||
app:layout_constraintTop_toTopOf="@id/square" />
|
||||
|
||||
<View
|
||||
android:id="@+id/rect2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="66dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/bg_skeleton_radius_10"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="@id/rect1"
|
||||
app:layout_constraintTop_toBottomOf="@id/rect1" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="87dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="18dp"
|
||||
android:paddingVertical="16dp">
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_skeleton_radius_8" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="26dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_skeleton_radius_8" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="26dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_skeleton_radius_8" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="26dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_skeleton_radius_8" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="26dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_skeleton_radius_8" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="18dp">
|
||||
|
||||
<View
|
||||
android:layout_width="54dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="53dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include layout="@layout/fragment_main_skeleton_item_simple_game" />
|
||||
|
||||
<include layout="@layout/fragment_main_skeleton_item_simple_game" />
|
||||
|
||||
<include layout="@layout/fragment_main_skeleton_item_simple_game" />
|
||||
|
||||
<include layout="@layout/fragment_main_skeleton_item_simple_game" />
|
||||
|
||||
<include layout="@layout/fragment_main_skeleton_item_simple_game" />
|
||||
|
||||
<include layout="@layout/fragment_main_skeleton_item_simple_game" />
|
||||
|
||||
<include layout="@layout/fragment_main_skeleton_item_simple_game" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/fragment_main_skeleton_item_game" />
|
||||
|
||||
<include layout="@layout/fragment_main_skeleton_item_game" />
|
||||
|
||||
<include layout="@layout/fragment_main_skeleton_item_game" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/b"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="54dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
layout="@layout/fragment_main_skeleton_item_bottom_tab"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<include
|
||||
layout="@layout/fragment_main_skeleton_item_bottom_tab"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<include
|
||||
layout="@layout/fragment_main_skeleton_item_bottom_tab"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<include
|
||||
layout="@layout/fragment_main_skeleton_item_bottom_tab"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<include
|
||||
layout="@layout/fragment_main_skeleton_item_bottom_tab"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
|
||||
<View
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="10dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
47
app/src/main/res/layout/fragment_main_skeleton_item_game.xml
Normal file
47
app/src/main/res/layout/fragment_main_skeleton_item_game.xml
Normal file
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<View
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:background="@drawable/bg_skeleton_radius_14" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="72dp"
|
||||
android:layout_height="16dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="160dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="@drawable/bg_skeleton_radius_999" />
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="11dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="44dp"
|
||||
android:layout_height="11dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4"/>
|
||||
|
||||
<View
|
||||
android:layout_width="5dp"
|
||||
android:layout_height="5dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@drawable/bg_skeleton_radius_40"/>
|
||||
|
||||
<View
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:background="@drawable/bg_skeleton_radius_14" />
|
||||
|
||||
<View
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/bg_skeleton_radius_4" />
|
||||
|
||||
<View
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:background="@drawable/bg_skeleton_radius_40" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@ -17,8 +17,8 @@ buildscript {
|
||||
password("u9gZYH4MQEwLLQZK")
|
||||
}
|
||||
}
|
||||
maven { url 'https://jitpack.io' }
|
||||
maven { url "https://maven.google.com" }
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -41,7 +41,8 @@ allprojects {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url 'https://jitpack.io' }
|
||||
maven { url 'https://maven.aliyun.com/repository/public' }
|
||||
maven { url 'https://maven.aliyun.com/repository/central'}
|
||||
maven { url 'https://maven.aliyun.com/nexus/content/repositories/releases/' }
|
||||
maven { url 'https://artifact.bytedance.com/repository/Volcengine/'}
|
||||
maven { url 'https://artifact.bytedance.com/repository/pangle' }
|
||||
@ -53,6 +54,7 @@ allprojects {
|
||||
// 配置HMS Core SDK的Maven仓地址。
|
||||
maven { url 'https://developer.huawei.com/repo/' }
|
||||
maven { url 'https://developer.hihonor.com/repo' }
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
task clean(type: Delete) {
|
||||
|
||||
@ -7,8 +7,8 @@ ext {
|
||||
targetSdkVersion = 30
|
||||
|
||||
// application info (每个大版本之间的 versionCode 增加 20)
|
||||
versionCode = 1110
|
||||
versionName = "5.38.0"
|
||||
versionCode = 1095
|
||||
versionName = "5.37.5"
|
||||
applicationId = "com.gh.gamecenter"
|
||||
applicationIdGat = "com.gh.gamecenter.intl"
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
ext {
|
||||
vaCompileSdkVersion = 33
|
||||
vaCompileSdkVersion = 34
|
||||
vaMinSdkVersion = 21
|
||||
vaTargetSdkVersion = 28
|
||||
}
|
||||
|
||||
@ -323,14 +323,11 @@ class HelpAndFeedbackFragment : BaseLazyFragment() {
|
||||
mPopupWindow = null
|
||||
}
|
||||
}
|
||||
popupWindow.width = mBinding.helpCenterTv.width
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.isFocusable = true
|
||||
popupWindow.animationStyle = 0
|
||||
popupWindow.showAsDropDown(mBinding.helpCenterTv, 0, 0)
|
||||
binding.root.layoutParams = (binding.root.layoutParams as MarginLayoutParams).apply {
|
||||
leftMargin = 16F.dip2px()
|
||||
rightMargin = 16F.dip2px()
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleHighlightedView(targetView: View, highlightIt: Boolean) {
|
||||
|
||||
@ -4,7 +4,6 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.gh.gamecenter.common.utils.safelyGetInRelease
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
|
||||
/**
|
||||
* 支持diff刷新的FragmentStateAdapter
|
||||
@ -64,7 +63,7 @@ abstract class BaseDiffFragmentStateAdapter<T>(fragment: Fragment) : FragmentSta
|
||||
abstract fun createFragment(data: T?, position: Int): Fragment?
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
if (mDataList.size < position) {
|
||||
if (mDataList.size <= position) {
|
||||
return 0L
|
||||
}
|
||||
return mDataList[position].hashCode().toLong()
|
||||
|
||||
@ -14,11 +14,11 @@ import android.view.ViewGroup
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.databinding.DialogAlertDefaultBinding
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.provider.IAppProvider
|
||||
import com.lightgame.dialog.BaseDialogFragment
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
class ManageExternalStoragePermissionDialogFragment : BaseDialogFragment() {
|
||||
|
||||
@ -26,7 +26,7 @@ object SensorsBridge {
|
||||
private const val KEY_LAST_PAGE_BUSINESS_ID = "last_page_business_id"
|
||||
private const val KEY_DOWNLOAD_STATUS = "download_status"
|
||||
private const val KEY_DOWNLOAD_TYPE = "download_type"
|
||||
private const val KEY_GAME_SCHEME_TYPE = "game_scheme_type"
|
||||
private const val KEY_GAME_SCHEMA_TYPE = "game_schema_type"
|
||||
private const val KEY_GAME_TYPE = "game_type"
|
||||
const val KEY_POSITION = "position"
|
||||
const val KEY_TAB_CONTENT = "tab_content"
|
||||
@ -4070,7 +4070,7 @@ object SensorsBridge {
|
||||
* 触发时机:当下载悬浮窗引导图展示时触发上报
|
||||
* @param gameId 游戏ID
|
||||
* @param gameName 游戏名称
|
||||
* @param gameSchemeType 游戏架构类型:64位/32位
|
||||
* @param gameSchemaType 游戏架构类型:64位/32位
|
||||
* @param downloadStatus 游戏下载状态
|
||||
* @param gameType 游戏的类型:单机、网游等
|
||||
* @param downloadType 实际下载方式:本地下载/畅玩下载
|
||||
@ -4079,7 +4079,7 @@ object SensorsBridge {
|
||||
fun trackDownloadSuspendedWindowGuideShow(
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameSchemeType: String,
|
||||
gameSchemaType: String,
|
||||
downloadStatus: String,
|
||||
gameType: String,
|
||||
downloadType: String
|
||||
@ -4087,7 +4087,7 @@ object SensorsBridge {
|
||||
val json = json {
|
||||
KEY_GAME_ID to gameId
|
||||
KEY_GAME_NAME to gameName
|
||||
KEY_GAME_SCHEME_TYPE to gameSchemeType
|
||||
KEY_GAME_SCHEMA_TYPE to gameSchemaType
|
||||
KEY_DOWNLOAD_STATUS to downloadStatus
|
||||
KEY_GAME_TYPE to gameType
|
||||
KEY_DOWNLOAD_TYPE to downloadType
|
||||
@ -4126,7 +4126,7 @@ object SensorsBridge {
|
||||
* @param source 来源:游戏下载\重启APP
|
||||
* @param downloadType 所上报游戏的实际下载方式:本地下载/畅玩下载
|
||||
* @param downloadStatus 所上报游戏下载状态
|
||||
* @param gameSchemeType 所上报游戏架构类型:64位/32位
|
||||
* @param gameSchemaType 所上报游戏架构类型:64位/32位
|
||||
* @param gameType 游戏的类型:单机、网游等
|
||||
* @param gameId 游戏ID
|
||||
* @param gameName 游戏名称
|
||||
@ -4135,7 +4135,7 @@ object SensorsBridge {
|
||||
source: String,
|
||||
downloadType: String,
|
||||
downloadStatus: String,
|
||||
gameSchemeType: String,
|
||||
gameSchemaType: String,
|
||||
gameType: String,
|
||||
gameId: String,
|
||||
gameName: String
|
||||
@ -4144,7 +4144,7 @@ object SensorsBridge {
|
||||
KEY_SOURCE to source
|
||||
KEY_DOWNLOAD_TYPE to downloadType
|
||||
KEY_DOWNLOAD_STATUS to downloadStatus
|
||||
KEY_GAME_SCHEME_TYPE to gameSchemeType
|
||||
KEY_GAME_SCHEMA_TYPE to gameSchemaType
|
||||
KEY_GAME_TYPE to gameType
|
||||
KEY_GAME_ID to gameId
|
||||
KEY_GAME_NAME to gameName
|
||||
@ -4159,7 +4159,7 @@ object SensorsBridge {
|
||||
* @param source 来源:游戏下载\重启APP
|
||||
* @param downloadType 所上报游戏的实际下载方式:本地下载/畅玩下载
|
||||
* @param downloadStatus 所上报游戏下载状态
|
||||
* @param gameSchemeType 所上报游戏架构类型:64位/32位
|
||||
* @param gameSchemaType 所上报游戏架构类型:64位/32位
|
||||
* @param gameType 游戏的类型:单机、网游等
|
||||
* @param gameId 游戏ID
|
||||
* @param gameName 游戏名称
|
||||
@ -4168,7 +4168,7 @@ object SensorsBridge {
|
||||
source: String,
|
||||
downloadType: String,
|
||||
downloadStatus: String,
|
||||
gameSchemeType: String,
|
||||
gameSchemaType: String,
|
||||
gameType: String,
|
||||
gameId: String,
|
||||
gameName: String
|
||||
@ -4177,7 +4177,7 @@ object SensorsBridge {
|
||||
KEY_SOURCE to source
|
||||
KEY_DOWNLOAD_TYPE to downloadType
|
||||
KEY_DOWNLOAD_STATUS to downloadStatus
|
||||
KEY_GAME_SCHEME_TYPE to gameSchemeType
|
||||
KEY_GAME_SCHEMA_TYPE to gameSchemaType
|
||||
KEY_GAME_TYPE to gameType
|
||||
KEY_GAME_ID to gameId
|
||||
KEY_GAME_NAME to gameName
|
||||
@ -4191,7 +4191,7 @@ object SensorsBridge {
|
||||
* 触发时机:触发自动下载提示条展示时上报
|
||||
* @param downloadType 所上报游戏的实际下载方式:本地下载/畅玩下载
|
||||
* @param downloadStatus 所上报游戏下载状态
|
||||
* @param gameSchemeType 所上报游戏架构类型:64位/32位
|
||||
* @param gameSchemaType 所上报游戏架构类型:64位/32位
|
||||
* @param gameType 游戏的类型:单机、网游等
|
||||
* @param gameId 游戏ID
|
||||
* @param gameName 游戏名称
|
||||
@ -4199,7 +4199,7 @@ object SensorsBridge {
|
||||
fun trackAutomaticInstallationPromptBarShow(
|
||||
downloadType: String,
|
||||
downloadStatus: String,
|
||||
gameSchemeType: String,
|
||||
gameSchemaType: String,
|
||||
gameType: String,
|
||||
gameId: String,
|
||||
gameName: String
|
||||
@ -4207,7 +4207,7 @@ object SensorsBridge {
|
||||
val json = json {
|
||||
KEY_DOWNLOAD_TYPE to downloadType
|
||||
KEY_DOWNLOAD_STATUS to downloadStatus
|
||||
KEY_GAME_SCHEME_TYPE to gameSchemeType
|
||||
KEY_GAME_SCHEMA_TYPE to gameSchemaType
|
||||
KEY_GAME_TYPE to gameType
|
||||
KEY_GAME_ID to gameId
|
||||
KEY_GAME_NAME to gameName
|
||||
@ -4221,7 +4221,7 @@ object SensorsBridge {
|
||||
* 触发时机:触发自动下载提示条点击时上报
|
||||
* @param downloadType 所上报游戏的实际下载方式:本地下载/畅玩下载
|
||||
* @param downloadStatus 所上报游戏下载状态
|
||||
* @param gameSchemeType 所上报游戏架构类型:64位/32位
|
||||
* @param gameSchemaType 所上报游戏架构类型:64位/32位
|
||||
* @param gameType 游戏的类型:单机、网游等
|
||||
* @param gameId 游戏ID
|
||||
* @param gameName 游戏名称
|
||||
@ -4229,7 +4229,7 @@ object SensorsBridge {
|
||||
fun trackAutomaticInstallationPromptBarClick(
|
||||
downloadType: String,
|
||||
downloadStatus: String,
|
||||
gameSchemeType: String,
|
||||
gameSchemaType: String,
|
||||
gameType: String,
|
||||
gameId: String,
|
||||
gameName: String
|
||||
@ -4237,7 +4237,7 @@ object SensorsBridge {
|
||||
val json = json {
|
||||
KEY_DOWNLOAD_TYPE to downloadType
|
||||
KEY_DOWNLOAD_STATUS to downloadStatus
|
||||
KEY_GAME_SCHEME_TYPE to gameSchemeType
|
||||
KEY_GAME_SCHEMA_TYPE to gameSchemaType
|
||||
KEY_GAME_TYPE to gameType
|
||||
KEY_GAME_ID to gameId
|
||||
KEY_GAME_NAME to gameName
|
||||
@ -4251,7 +4251,7 @@ object SensorsBridge {
|
||||
* 触发时机:下载组件展示时上报
|
||||
* @param gameId 游戏ID
|
||||
* @param gameName 游戏名称
|
||||
* @param gameSchemeType 游戏架构类型:64位/32位
|
||||
* @param gameSchemaType 游戏架构类型:64位/32位
|
||||
* @param downloadStatus 所上报游戏下载状态
|
||||
* @param gameType 游戏的类型:单机、网游等
|
||||
* @param downloadType 所上报游戏的实际下载方式:本地下载/畅玩下载
|
||||
@ -4259,7 +4259,7 @@ object SensorsBridge {
|
||||
fun trackDownloadComponentsShow(
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameSchemeType: String,
|
||||
gameSchemaType: String,
|
||||
downloadStatus: String,
|
||||
gameType: String,
|
||||
downloadType: String,
|
||||
@ -4267,7 +4267,7 @@ object SensorsBridge {
|
||||
val json = json {
|
||||
KEY_GAME_ID to gameId
|
||||
KEY_GAME_NAME to gameName
|
||||
KEY_GAME_SCHEME_TYPE to gameSchemeType
|
||||
KEY_GAME_SCHEMA_TYPE to gameSchemaType
|
||||
KEY_DOWNLOAD_STATUS to downloadStatus
|
||||
KEY_GAME_TYPE to gameType
|
||||
KEY_DOWNLOAD_TYPE to downloadType
|
||||
@ -4281,7 +4281,7 @@ object SensorsBridge {
|
||||
* 触发时机:下载组件点击时上报
|
||||
* @param gameId 游戏ID
|
||||
* @param gameName 游戏名称
|
||||
* @param gameSchemeType 游戏架构类型:64位/32位
|
||||
* @param gameSchemaType 游戏架构类型:64位/32位
|
||||
* @param downloadStatus 所上报游戏下载状态
|
||||
* @param gameType 游戏的类型:单机、网游等
|
||||
* @param downloadType 所上报游戏的实际下载方式:本地下载/畅玩下载
|
||||
@ -4291,7 +4291,7 @@ object SensorsBridge {
|
||||
fun trackDownloadComponentsContentClick(
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameSchemeType: String,
|
||||
gameSchemaType: String,
|
||||
downloadStatus: String,
|
||||
gameType: String,
|
||||
downloadType: String,
|
||||
@ -4301,7 +4301,7 @@ object SensorsBridge {
|
||||
val json = json {
|
||||
KEY_GAME_ID to gameId
|
||||
KEY_GAME_NAME to gameName
|
||||
KEY_GAME_SCHEME_TYPE to gameSchemeType
|
||||
KEY_GAME_SCHEMA_TYPE to gameSchemaType
|
||||
KEY_DOWNLOAD_STATUS to downloadStatus
|
||||
KEY_GAME_TYPE to gameType
|
||||
KEY_DOWNLOAD_TYPE to downloadType
|
||||
|
||||
@ -6,6 +6,8 @@ import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ProcessUtil {
|
||||
@ -20,13 +22,25 @@ public class ProcessUtil {
|
||||
return currentProcessName;
|
||||
}
|
||||
|
||||
//1)通过Application的API获取当前进程名
|
||||
//0)通过反射 ActivityThread 获取实例再获取当前进程名
|
||||
currentProcessName = getCurrentProcessNameByActivityThreadInstance();
|
||||
if (!TextUtils.isEmpty(currentProcessName)) {
|
||||
return currentProcessName;
|
||||
}
|
||||
|
||||
//1)通过 CMD 获取当前进程名
|
||||
currentProcessName = getCurrentProcessNameByCMD(android.os.Process.myPid());
|
||||
if (!TextUtils.isEmpty(currentProcessName)) {
|
||||
return currentProcessName;
|
||||
}
|
||||
|
||||
//2)通过 Application 的 API 获取当前进程名
|
||||
currentProcessName = getCurrentProcessNameByApplication();
|
||||
if (!TextUtils.isEmpty(currentProcessName)) {
|
||||
return currentProcessName;
|
||||
}
|
||||
|
||||
//2)通过反射ActivityThread获取当前进程名
|
||||
//3)通过反射 ActivityThread 获取当前进程名
|
||||
currentProcessName = getCurrentProcessNameByActivityThread();
|
||||
if (!TextUtils.isEmpty(currentProcessName)) {
|
||||
return currentProcessName;
|
||||
@ -38,7 +52,7 @@ public class ProcessUtil {
|
||||
/**
|
||||
* 通过Application新的API获取进程名,无需反射,无需IPC,效率最高。
|
||||
*/
|
||||
public static String getCurrentProcessNameByApplication() {
|
||||
private static String getCurrentProcessNameByApplication() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
return Application.getProcessName();
|
||||
}
|
||||
@ -48,7 +62,7 @@ public class ProcessUtil {
|
||||
/**
|
||||
* 通过反射ActivityThread获取进程名,避免了ipc
|
||||
*/
|
||||
public static String getCurrentProcessNameByActivityThread() {
|
||||
private static String getCurrentProcessNameByActivityThread() {
|
||||
String processName = null;
|
||||
try {
|
||||
final Method declaredMethod = Class.forName("android.app.ActivityThread", false, Application.class.getClassLoader())
|
||||
@ -64,4 +78,52 @@ public class ProcessUtil {
|
||||
return processName;
|
||||
}
|
||||
|
||||
private static String getCurrentProcessNameByActivityThreadInstance() {
|
||||
try {
|
||||
// Get ActivityThread class
|
||||
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread",false, Application.class.getClassLoader());
|
||||
|
||||
// Get the current ActivityThread instance
|
||||
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
|
||||
currentActivityThreadMethod.setAccessible(true);
|
||||
Object activityThread = currentActivityThreadMethod.invoke(null);
|
||||
|
||||
// Get the getProcessName method
|
||||
Method getProcessNameMethod = activityThreadClass.getDeclaredMethod("getProcessName");
|
||||
getProcessNameMethod.setAccessible(true);
|
||||
|
||||
// Call the getProcessName method
|
||||
return (String) getProcessNameMethod.invoke(activityThread);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getCurrentProcessNameByCMD(int pid) {
|
||||
//get from /proc/PID/cmdline
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
br = new BufferedReader(new FileReader("/proc/" + pid + "/cmdline"));
|
||||
String processName = br.readLine();
|
||||
if (!TextUtils.isEmpty(processName)) {
|
||||
processName = processName.trim();
|
||||
if (!TextUtils.isEmpty(processName)) {
|
||||
return processName; //OK
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (br != null) {
|
||||
br.close();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
//failed
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -62,16 +62,14 @@ class AboutFragment : ToolbarFragment() {
|
||||
ARouter.getInstance().build(RouteConsts.provider.updateManager).navigation() as? IUpdateManagerProvider
|
||||
updateManager?.checkUpdate(requireActivity(), true) // 检查更新
|
||||
|
||||
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
|
||||
var clickCount = 0
|
||||
mBinding.aboutGhIcon.setOnClickListener {
|
||||
if (clickCount == 5) {
|
||||
mBinding.aboutGhIcon.setOnClickListener(null)
|
||||
mBinding.deviceContent.visibility = View.VISIBLE
|
||||
mBinding.deviceContent.text.toString().copyTextAndToast("复制成功!")
|
||||
} else {
|
||||
clickCount++
|
||||
}
|
||||
var clickCount = 0
|
||||
mBinding.aboutGhIcon.setOnClickListener {
|
||||
if (clickCount == 5) {
|
||||
mBinding.aboutGhIcon.setOnClickListener(null)
|
||||
mBinding.deviceContent.visibility = View.VISIBLE
|
||||
mBinding.deviceContent.text.toString().copyTextAndToast("复制成功!")
|
||||
} else {
|
||||
clickCount++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -131,6 +131,7 @@ class ComposeAboutActivity : ComposeBaseActivity() {
|
||||
}
|
||||
},
|
||||
onPress = {
|
||||
if (deviceContent.isNotEmpty()) return@detectTapGestures
|
||||
if (clickCount == 5) {
|
||||
val sb = StringBuilder()
|
||||
val meta = MetaUtil.getMeta()
|
||||
|
||||
@ -49,6 +49,18 @@ android {
|
||||
publish {
|
||||
dimension "env"
|
||||
}
|
||||
tea {
|
||||
dimension "env"
|
||||
}
|
||||
kuaishou {
|
||||
dimension "env"
|
||||
}
|
||||
gdt {
|
||||
dimension "env"
|
||||
}
|
||||
sm {
|
||||
dimension "env"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,15 +3,9 @@ package com.gh.gamecenter.va
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.core.iinterface.IApplication
|
||||
import com.gh.gamecenter.core.provider.IAppProvider
|
||||
import com.gh.gamecenter.core.provider.ISentryProvider
|
||||
import com.google.auto.service.AutoService
|
||||
import com.lg.vspace.common.CommonApp
|
||||
import com.lody.virtual.client.core.VirtualCore
|
||||
import com.lody.virtual.client.core.VirtualCore.VirtualInitializer
|
||||
|
||||
@AutoService(IApplication::class)
|
||||
class HaloApp : IApplication {
|
||||
@ -23,20 +17,6 @@ class HaloApp : IApplication {
|
||||
}
|
||||
|
||||
override fun onCreate(application: Application) {
|
||||
VirtualCore.get().initialize(object : VirtualInitializer() {
|
||||
override fun onServerProcess() {
|
||||
(ARouter.getInstance().build(RouteConsts.provider.app)
|
||||
.navigation() as? IAppProvider)?.let { appProvider ->
|
||||
(ARouter.getInstance().build(RouteConsts.provider.sentry).navigation() as? ISentryProvider)?.init(
|
||||
application,
|
||||
appProvider.getChannel(),
|
||||
appProvider.getFlavor(),
|
||||
appProvider.getAppVersion()
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
commonApp.onCreate(application)
|
||||
}
|
||||
|
||||
|
||||
2
vasdk
2
vasdk
Submodule vasdk updated: e64cec2695...ff118306e4
Reference in New Issue
Block a user