Compare commits

..

4 Commits

Author SHA1 Message Date
552f29b8e1 refactor: sync vasdk 2024-07-02 17:55:25 +08:00
f6c8bdf2d5 chore: 修改为debug打包 2024-07-01 16:35:18 +08:00
beee85fe15 chore: 版本更新至 5.36.4 2024-07-01 15:43:18 +08:00
d77545f242 feat: merge va 2024-07-01 15:40:34 +08:00
1044 changed files with 21431 additions and 26814 deletions

View File

@ -72,7 +72,7 @@ android_build:
only:
- dev
- release
- feat/GHZSCY-6578
- feature-GHZS-5816
# 代码检查
sonarqube_analysis:
@ -128,9 +128,6 @@ oss-upload&send-email:
- sysadm-devops
stage: oss-upload&send-email
image: hub.shanqu.cc/devops/android-apk-oss-upload:latest
id_tokens:
VAULT_ID_TOKEN:
aud: https://vault.shanqu.cc
variables:
GIT_STRATEGY: none
VAULT_ADDR: https://vault.shanqu.cc # 固定值
@ -149,7 +146,6 @@ oss-upload&send-email:
artifacts: true
script:
### 绑定上传参数 ###
- export OSS_PATH="release/dev/${CI_PROJECT_NAME}/$(date "+%Y/%m/%d")"
### 开启上传 ###
- /usr/local/bin/python /upload.py
@ -158,4 +154,4 @@ oss-upload&send-email:
only:
- dev
- release
- feat/GHZSCY-6578
- feature-GHZS-5816

View File

@ -44,4 +44,5 @@
### 混淆配置
* 本项目使用了微信的 [AndResGuard](https://github.com/shwenzhang/AndResGuard) 作为资源混淆压缩方案,新增需要使用 `getIdentifier` 获取的资源文件时需要添加至白名单
* 本项目默认使用 R8 作为混淆工具,往 proguard-rules.txt 添加 proguard 新配置项时请检查可用性(如语法等)

View File

@ -3,6 +3,7 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' // kotlin
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
apply plugin: 'AndResGuard'
import groovy.xml.XmlUtil
@ -105,8 +106,6 @@ android {
buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\""
buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\""
buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\""
// 一体包的32位畅玩游戏助手包名
buildConfigField "String", "EXT_PACKAGE_NAME", "\"${rootProject.ext.EXT_PACKAGE_NAME}\""
}
// gradle 2.2以上默认同时启用v1和v2优先用于Android N
@ -217,9 +216,6 @@ android {
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${DEV_QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${DEV_CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "VA_VERSION_NAME", "\"${rootProject.ext.VA_VERSION}-debug\""
manifestPlaceholders.put("VA_VERSION_NAME", "${rootProject.ext.VA_VERSION}-debug")
}
// publish 发布时候使用的 flavor接口仅包含正式环境
@ -233,9 +229,6 @@ android {
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "VA_VERSION_NAME", "\"${rootProject.ext.VA_VERSION}\""
manifestPlaceholders.put("VA_VERSION_NAME", "${rootProject.ext.VA_VERSION}")
}
tea {
@ -249,10 +242,7 @@ android {
buildConfigField "String", "DEV_CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "VA_VERSION_NAME", "\"${rootProject.ext.VA_VERSION}\""
manifestPlaceholders.put("APPLOG_SCHEME", "rangersapplog.byAx6uYt".toLowerCase())
manifestPlaceholders.put("VA_VERSION_NAME", "${rootProject.ext.VA_VERSION}")
}
kuaishou {
@ -265,9 +255,6 @@ android {
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "VA_VERSION_NAME", "\"${rootProject.ext.VA_VERSION}\""
manifestPlaceholders.put("VA_VERSION_NAME", "${rootProject.ext.VA_VERSION}")
}
gdt {
@ -280,9 +267,6 @@ android {
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "VA_VERSION_NAME", "\"${rootProject.ext.VA_VERSION}\""
manifestPlaceholders.put("VA_VERSION_NAME", "${rootProject.ext.VA_VERSION}")
}
sm {
@ -295,9 +279,6 @@ android {
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "VA_VERSION_NAME", "\"${rootProject.ext.VA_VERSION}\""
manifestPlaceholders.put("VA_VERSION_NAME", "${rootProject.ext.VA_VERSION}")
}
// 港澳台
@ -335,6 +316,7 @@ dependencies {
kuaishouImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/kuaishou/libs')
gdtImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/gdt/libs')
smImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/sm/libs')
testImplementation 'junit:junit:4.12'
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakcanary}"
debugImplementation "com.squareup.leakcanary:leakcanary-android-process:${leakcanary}"
@ -388,7 +370,7 @@ dependencies {
implementation "com.lg:easyfloat:${easyFloat}"
implementation("com.lg:apksig:${apksig}") {
implementation ("com.lg:apksig:${apksig}") {
exclude group: 'com.google.protobuf'
}
@ -401,96 +383,64 @@ dependencies {
kapt "com.alibaba:arouter-compiler:$arouterVersion"
implementation project(':ndownload')
implementation project(':vspace-bridge:vspace')
implementation(project(':feature:xapk-installer'))
implementation project(':vspace-bridge')
implementation(project(':module_common')) {
implementation (project(':module_common')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_login')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_core_feature')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_setting')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':module_setting_compose')) {
// exclude group: 'androidx.swiperefreshlayout'
// }
if (!gradle.ext.excludeOptionalModules || gradle.ext.enablePkg) {
implementation(project(':feature:pkg'))
// implementation(project(':module_setting_compose')) {
// exclude group: 'androidx.swiperefreshlayout'
// }
implementation(project(':module_core_feature')) {
exclude group: 'androidx.swiperefreshlayout'
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableFeedback) {
implementation(project(':feature:new_feedback')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':module_feedback')) {
// exclude group: 'androidx.swiperefreshlayout'
// }
implementation(project(':feature:new_feedback',)) {
exclude group: 'androidx.swiperefreshlayout'
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableMessage) {
implementation(project(':module_message')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_sensors_data')) {
exclude group: 'androidx.swiperefreshlayout'
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableOaid) {
implementation(project(':feature:oaid'))
implementation(project(':module_message')) {
exclude group: 'androidx.swiperefreshlayout'
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableFloatingWindow) {
implementation(project(':feature:floating-window'))
implementation(project(':feature:pkg'))
implementation(project(':feature:oaid'))
implementation(project(':feature:floating-window'))
implementation(project(':feature:csj_ad'))
// implementation(project(':feature:beizi_startup_ad'))
implementation(project(':feature:xapk-installer'))
implementation(project(':feature:qq_game')) {
exclude group: 'androidx.swiperefreshlayout'
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableSensorData) {
implementation(project(':module_sensors_data')) {
exclude group: 'androidx.swiperefreshlayout'
}
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableCsjAd) {
implementation(project(':feature:csj_ad'))
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableQQGame) {
implementation(project(':feature:qq_game')) {
exclude group: 'androidx.swiperefreshlayout'
}
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enablePush) {
def pushProperty = findProperty('BUILD_PUSH_TYPE')
// 根据BUILD_PUSH_TYPE决定使用哪个推送SDK目前默认使用极光推送
def pushProject = (pushProperty == null || pushProperty == 'jg')
? project(':feature:jg_push') : project(':feature:acloud_push')
implementation(pushProject) {
exclude group: 'androidx.swiperefreshlayout'
}
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableSentry) {
implementation(project(':feature:sentry'))
}
implementation(project(':feature:media_select'))
implementation(project(":module_va_api"))
implementation(project(":va-archive-common"))
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableVa) {
implementation(project(":module_va_impl"))
}
debugImplementation "com.bytedance.tools.codelocator:codelocator-core:2.0.3"
internalImplementation(project(':module_internal_test'))
debugImplementation 'com.bytedance.android:shadowhook:1.0.9'
debugImplementation 'io.github.shiqos:wytrace:1.0.1'
def pushProperty = findProperty('BUILD_PUSH_TYPE')
// 根据BUILD_PUSH_TYPE决定使用哪个推送SDK目前默认使用极光推送
def pushProject = (pushProperty == null || pushProperty == 'jg')
? project(':feature:jg_push') : project(':feature:acloud_push')
implementation(pushProject) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(":va-lib"))
implementation(project(':va-main')) {
exclude group: 'androidx.swiperefreshlayout'
}
debugImplementation "com.bytedance.tools.codelocator:codelocator-core:2.0.3"
compileOnly project(":va-core")
compileOnly project(":va-plugin-host-lib")
implementation project(":va-plugin-host")
implementation project(":va-archive")
}
File propFile = file('sign.properties')
@ -550,6 +500,122 @@ if (propFile.exists()) {
// }.each { t -> t.dependsOn generateMetaJson }
//}
andResGuard {
mappingFile = null
use7zip = true
useSign = true
// 打开这个开关会keep住所有资源的原始路径只混淆资源的名字
keepRoot = false
// 设置这个值会把arsc name列混淆成相同的名字减少string常量池的大小
fixedResName = "arg"
// 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源
mergeDuplicatedRes = true
whiteList = [
"R.xml.jpush*",
"R.drawable.jpush*",
"R.layout.jpush*",
"R.layout.push*",
"R.string.jg*",
"R.style.MyDialogStyle",
"R.style.JPushTheme",
"R.drawable.icon",
"R.drawable.ic_bar_back",
"R.drawable.toolbar_search_icon",
"R.drawable.bg_notification_answer_style_1",
"R.drawable.bg_notification_answer_style_2",
"R.drawable.bg_notification_article_style_1",
"R.drawable.bg_notification_article_style_2",
"R.drawable.bg_notification_feedback_style_1",
"R.drawable.bg_notification_feedback_style_2",
"R.drawable.bg_notification_gift_style_1",
"R.drawable.bg_notification_gift_style_2",
"R.drawable.bg_notification_login_style_1",
"R.drawable.bg_notification_login_style_2",
"R.drawable.bg_notification_question_style_1",
"R.drawable.bg_notification_question_style_2",
"R.drawable.bg_notification_rating_style_1",
"R.drawable.bg_notification_rating_style_2",
"R.drawable.bg_notification_reserve_game_style_1",
"R.drawable.bg_notification_reserve_game_style_2",
"R.drawable.bg_notification_video_style_1",
"R.drawable.bg_notification_video_style_2",
"R.drawable.ic_recommend_activity",
"R.drawable.ic_recommend_discount",
"R.drawable.ic_recommend_function",
"R.drawable.ic_recommend_gift",
"R.drawable.ic_recommend_role",
"R.drawable.download_button_normal_style",
"R.drawable.ic_selector_selected",
"R.drawable.ic_selector_default",
"R.id.download_speed",
"R.id.download_percentage",
"R.id.comment",
"R.id.vote",
"R.id.watermark_hint",
"R.id.watermark_sb",
"R.id.bottomShareIv",
"R.id.bottomShareTv",
"R.id.recommendStarPref",
"R.id.recommendStar",
"R.id.iv_vmode_badge",
"R.id.tv_vmode",
"R.id.iv_vmode",
"R.drawable.help_search_delete",
"R.drawable.suggest_type_normal",
"R.drawable.suggest_type_crash",
"R.drawable.suggest_type_game_question",
"R.drawable.suggest_type_game_collect",
"R.drawable.suggest_type_function_suggest",
"R.drawable.suggest_type_article_collect",
"R.drawable.suggest_type_copyright",
"R.drawable.news_comment_detail_read",
"R.drawable.news_comment_detail_comment",
"R.drawable.news_comment_detail_share",
"R.drawable.ic_libao",
"R.drawable.ic_link",
"R.drawable.concern_message_icon",
"R.drawable.reuse_blank_hint",
"R.drawable.ic_concern",
"R.drawable.concern_down",
"R.drawable.concern_up",
"R.drawable.ic_libao_more",
"R.drawable.ic_libao_delete",
"R.drawable.ic_dialog_close",
"R.drawable.occupy2",
"R.drawable.kc_checkbox_unselect",
"R.drawable.kc_checkbox_select",
"R.drawable.ic_type_unselect",
"R.drawable.ic_type_selected",
"R.drawable.suggest_add_pic_icon",
"R.drawable.icon_pic_add",
"R.drawable.ask_search_input_delete",
"R.drawable.suggest_pic_delete",
"R.id.cardIv",
"R.id.cardMask",
"R.id.cardGradientMask",
"R.id.gameIconIv",
"R.id.titleContainer",
"R.id.v_login_background",
"R.id.tv_login_tips",
"R.id.tv_login",
"R.id.v_code_background",
"R.id.tv_code_tips",
"R.id.tv_code",
"R.id.tv_copy",
"R.id.v_indicator_background",
"R.id.v_indicator"
]
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
]
sevenzip {
artifact = 'io.github.leon406:SevenZip:1.2.22.5'
}
}
project.afterEvaluate {
def variants = null
try {

View File

@ -1,6 +1,7 @@
package com.gh.vspace
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -9,7 +10,11 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.LayoutPersonalOtherItemBinding
import com.gh.vspace.installexternalgames.InstallExternalGameActivity
import com.lg.vspace.VaApp
import com.lg.vspace.plugin.host.PluginHelper
import com.lightgame.utils.Utils
import com.lightgame.utils.toast.ToastHelper
import com.lody.virtual.client.core.VirtualCore
import java.io.File
@Keep
@ -32,11 +37,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文件")
}
}
}
}
}

View File

@ -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) {
@ -185,15 +155,9 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
HaloApp.getInstance().channel,
"",
"",
com.gh.gamecenter.BuildConfig.VA_VERSION_NAME,
com.lg.core.BuildConfig.VERSION_NAME,
HaloApp.getInstance().oaid
)
intent.setComponent(
ComponentName(
com.gh.gamecenter.BuildConfig.APPLICATION_ID,
VirtualAppManager.AIDL_SERVER_REMOTE_GUIDE_ACTIVITY
)
)
requireActivity().startActivity(intent)
}

View File

@ -2,7 +2,6 @@
<resources>
<string name="title_install_external_game">從SD卡安裝</string>
<string name="text_install">安裝</string>
<string name="text_update">更新</string>
<string name="text_uninstall">卸載</string>
<string name="text_start">啟動</string>
</resources>

View File

@ -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>

View File

@ -9,17 +9,15 @@
<queries>
<package android:name="com.lg.vspace" />
<package android:name="com.gh.gamecenter.addon" />
</queries>
<!-- 华为/荣耀角标 -->
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE " />
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE "/>
<uses-permission android:name="com.hihonor.android.launcher.permission.CHANGE_BADGE" />
<!-- vivo角标 -->
<uses-permission android:name="com.vivo.notification.permission.BADGE_ICON" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<!-- 允许应用程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />
@ -41,7 +39,7 @@
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- 应用安装相关 -->
<uses-permission android:name="com.android.permission.GET_INSTALLED_APPS" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- 前台服务权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
@ -56,9 +54,6 @@
<!-- 如果有视频相关的广告且使用textureView播放请务必添加否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 悬浮窗 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-sdk tools:overrideLibrary="
com.shuyu.gsyvideoplayer,
com.shuyu.gsyvideoplayer.lib,
@ -120,10 +115,7 @@
com.lg.plugin.constant,
com.bytedance.tools.codelocator,
org.chickenhook.restrictionbypass,
com.lody.virtual.sandhook,
com.lg.vspace.common,
com.lg.vspace.archive.common,
com.wy.lib.wytrace" />
com.lody.virtual.sandhook,com.lg.vspace.common" />
<!-- 去掉 SDK 一些流氓权限 -->
<uses-permission
@ -185,8 +177,6 @@
android:name="io.sentry.breadcrumbs.system-events"
android:value="false" />
<meta-data android:name="module_version" android:value="${VA_VERSION_NAME}" />
<service android:name="com.gh.ndownload.NDownloadService" />
<activity
@ -311,6 +301,10 @@
android:name="com.gh.gamecenter.CleanApkActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SelectUserIconActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.CommentDetailActivity"
android:screenOrientation="portrait"
@ -335,6 +329,14 @@
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden" />
<activity
android:name=".category.CategoryDirectoryActivity"
android:screenOrientation="portrait" />
<activity
android:name=".category.CategoryListActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.UserInfoActivity"
android:screenOrientation="portrait" />
@ -456,6 +458,9 @@
android:name="com.gh.gamecenter.video.game.GameVideoActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.editor.LocalMediaActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.servers.GameServersActivity"
@ -488,6 +493,9 @@
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait"
android:theme="@style/TransparentStatusBarAndNavigationBar" />
<activity
android:name=".gamedetail.myrating.MyRatingActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity"
@ -553,6 +561,14 @@
android:name=".simulatorgame.SimulatorManagementActivity"
android:screenOrientation="portrait" />
<activity
android:name=".catalog.CatalogActivity"
android:screenOrientation="portrait" />
<activity
android:name=".catalog.NewCatalogListActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.search.ForumOrUserSearchActivity"
android:screenOrientation="portrait" />
@ -573,6 +589,10 @@
android:name=".personal.DeliveryInfoActivity"
android:screenOrientation="portrait" />
<activity
android:name=".qa.editor.PreviewVideoActivity"
android:screenOrientation="portrait" />
<activity
android:name=".qa.video.publish.VideoPublishActivity"
android:screenOrientation="portrait" />
@ -787,6 +807,7 @@
<activity
android:name=".forum.home.follow.FollowDynamicActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Transparent" />
<activity
@ -851,8 +872,6 @@
<service android:name="com.gh.gamecenter.install.InstallService" />
<service android:name="com.gh.download.suspendwindow.DownloadSuspendWindowService" />
<receiver
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
android:exported="false">

File diff suppressed because one or more lines are too long

View File

@ -28,6 +28,7 @@ import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.provider.IBeiziAdProvider
import com.gh.gamecenter.core.provider.ICsjAdProvider
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.SPUtils
@ -45,11 +46,14 @@ import io.reactivex.schedulers.Schedulers
*
* 由它来分发功能实现到具体的实现
*
* 以开屏广告为例,有种实现1. 自有的广告实现 2. 穿山甲的开屏广告实现
* 以最复杂的开屏广告为例,有种实现1. 自有的广告实现 2. 穿山甲的开屏广告实现 3. Beizi 的开屏广告实现
*
* 由于两个广告 SDK 有可能在一次启动中都被使用,所以会根据获取到的广告配置 config 来决定是否需要出是很好两个 SDK
*/
object AdDelegateHelper {
private var mCsjAdImpl: ICsjAdProvider? = null
private var mBeiziAdImpl: IBeiziAdProvider? = null
private val mAdConfigList: ArrayList<AdConfig> by lazy { arrayListOf() }
@ -61,10 +65,8 @@ object AdDelegateHelper {
val vGameLaunchAd: AdConfig?
get() = mVGameLaunchAd
val splashAdDisplayInterval: Int
get() = mSplashAd?.ownerAd?.startAd?.displayInterval ?: 3
private const val AD_SDK_CSJ = "穿山甲"
private const val AD_SDK_BEIZI = "倍孜"
const val AD_TYPE_SDK = "third_party_ads" // 第三方 SDK 广告
const val AD_TYPE_OWNER = "owner_ads" // 自有广告
@ -78,6 +80,13 @@ object AdDelegateHelper {
var gameSearchKeyword = ""
fun initAdSdk(context: Context) {
// 初始化 Beizi
if (mBeiziAdImpl == null) {
mBeiziAdImpl =
ARouter.getInstance().build(RouteConsts.provider.beiziAd).navigation() as? IBeiziAdProvider
mBeiziAdImpl?.initSDK(context)
}
// 初始化穿山甲
if (mCsjAdImpl == null) {
mCsjAdImpl =
@ -184,7 +193,7 @@ object AdDelegateHelper {
/**
* 热启动是否需要显示开屏广告(目前只展示第三方广告)
*/
private fun shouldShowStartUpAdWhenHotLaunch() = (mCsjAdImpl != null)
private fun shouldShowStartUpAdWhenHotLaunch() = (mCsjAdImpl != null || mBeiziAdImpl != null)
&& mSplashAd?.displayRule?.hotStartSplashAd?.type == AD_TYPE_SDK
&& mSplashAd?.hotStartThirdPartyAd != null
@ -227,7 +236,18 @@ object AdDelegateHelper {
/**
* 是否大于开屏广告展示间隔时长
*/
private fun isMatchStartUpAdDisplayRule(): Boolean = isMatchAdDisplayRule(mSplashAd, Constants.SP_LAST_SPLASH_AD_SHOW_TIME)
private fun isMatchStartUpAdDisplayRule(): Boolean {
mSplashAd?.displayRule?.run {
if (adDisplayInterval > 0) {
val lastShowTime = SPUtils.getLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, 0L)
val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60
return durationInMinutes > adDisplayInterval
} else {
return true
}
}
return true
}
/**
* 是否大于广告管理展示间隔时长
@ -281,7 +301,6 @@ object AdDelegateHelper {
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
sdkStartAdContainer: ViewGroup,
sdkJumpBtn: TextView,
adsViewGroup: FrameLayout,
handler: BaseActivity.BaseHandler,
isHotLaunch: Boolean,
@ -303,7 +322,6 @@ object AdDelegateHelper {
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
sdkJumpBtn,
adsViewGroup,
handler,
isHotLaunch,
@ -321,7 +339,6 @@ object AdDelegateHelper {
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
sdkJumpBtn,
adsViewGroup,
handler,
isHotLaunch,
@ -345,7 +362,6 @@ object AdDelegateHelper {
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
sdkStartAdContainer: ViewGroup,
sdkJumpBtn: TextView,
adsViewGroup: FrameLayout,
handler: BaseActivity.BaseHandler,
isHotLaunch: Boolean,
@ -367,7 +383,6 @@ object AdDelegateHelper {
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
sdkJumpBtn,
adsViewGroup,
handler,
isHotLaunch,
@ -393,18 +408,20 @@ object AdDelegateHelper {
((mSplashAd?.displayRule?.timeout ?: 3.5F) * 1000).toInt()
}
if (thirdPartyAd.sourceName == AD_SDK_CSJ) {
if (thirdPartyAd.sourceName == AD_SDK_BEIZI) {
sdkStartAdContainer.visibility = View.VISIBLE
requestBeiziSplashAd(sdkStartAdContainer, adsViewGroup, adViewWidthInPx, adViewHeightInPx, timeout.toLong(), sdkSplashCallback)
} else if (thirdPartyAd.sourceName == AD_SDK_CSJ) {
sdkStartAdContainer.visibility = View.VISIBLE
requestCsjSplashAd(
activity,
thirdPartyAd.slotId,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
sdkStartAdContainer,
sdkJumpBtn,
timeout,
isHotLaunch,
sdkSplashCallback
)
}
@ -415,70 +432,50 @@ object AdDelegateHelper {
*/
private fun requestCsjSplashAd(
activity: Activity,
slotId: String,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
adViewWidthInDp: Float,
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
sdkJumpBtn: TextView,
timeout: Int,
isHotLaunch: Boolean,
callback: (isSuccess: Boolean) -> Unit,
) {
val thirdPartyAd = if (isHotLaunch) mSplashAd?.hotStartThirdPartyAd else mSplashAd?.thirdPartyAd
if (mCsjAdImpl == null || thirdPartyAd == null) {
if (mCsjAdImpl == null) {
callback.invoke(false)
} else {
sdkJumpBtn.setOnClickListener {
callback.invoke(true)
if (activity is BaseActivity) {
activity.baseHandler.removeMessages(MainActivity.COUNTDOWN_SDK_AD)
}
}
val onAdShowAction = {
sdkJumpBtn.visibility = View.VISIBLE
if (activity is BaseActivity) {
activity.baseHandler.sendEmptyMessageDelayed(MainActivity.COUNTDOWN_SDK_AD, 1000)
}
SensorsBridge.trackEvent("ThirdPartyAdShow",
"ad_source", thirdPartyAd.sourceName,
"ad_id", thirdPartyAd.slotId,
"ad_format", mSplashAd?.typeChinese ?: "",
"ad_placement", "光环启动",
"launch_type", if (isHotLaunch) "热启动" else "冷启动",
"ad_space_id", mSplashAd?.id ?: "",
"ad_space_name", mSplashAd?.name ?: ""
)
}
val onAdClickAction = {
callback.invoke(true)
SensorsBridge.trackEvent("ThirdPartyAdClick",
"ad_source", thirdPartyAd.sourceName,
"ad_id", thirdPartyAd.slotId,
"ad_format", mSplashAd?.typeChinese ?: "",
"ad_placement", "光环启动",
"launch_type", if (isHotLaunch) "热启动" else "冷启动",
"ad_space_id", mSplashAd?.id ?: "",
"ad_space_name", mSplashAd?.name ?: ""
)
}
mCsjAdImpl?.requestSplashAd(
activity,
thirdPartyAd.slotId,
slotId,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
timeout,
onAdShowAction,
onAdClickAction,
callback,
)
}
}
/**
* 获取 Beizi 的开屏广告
*/
private fun requestBeiziSplashAd(
startAdContainer: View,
adsFl: FrameLayout,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
timeout: Long,
callback: (isSuccess: Boolean) -> Unit,
) {
if (mBeiziAdImpl == null) {
callback.invoke(false)
} else {
mBeiziAdImpl?.requestSplashAd(startAdContainer, adsFl, adViewWidthInPx, adViewHeightInPx, timeout, callback)
}
}
/**
* 显示自有的开屏广告
*/
@ -490,7 +487,6 @@ object AdDelegateHelper {
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
sdkStartAdContainer: ViewGroup,
sdkJumpBtn: TextView,
adsViewGroup: FrameLayout,
handler: BaseActivity.BaseHandler,
isHotLaunch: Boolean,
@ -508,7 +504,6 @@ object AdDelegateHelper {
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
sdkJumpBtn,
adsViewGroup,
handler,
isHotLaunch,
@ -561,15 +556,12 @@ object AdDelegateHelper {
handler: BaseActivity.BaseHandler,
hideCallback: () -> Unit
) {
val jumpBtn = startAdContainer.findViewById<TextView>(R.id.jumpBtn)
val jumpBtn: View = startAdContainer.findViewById(R.id.jumpBtn)
val jumpDetailBtn: TextView = startAdContainer.findViewById(R.id.jumpDetailBtn)
val adImage: SimpleDraweeView = startAdContainer.findViewById(R.id.adImage)
val adVideo = startAdContainer.findViewById<SplashAdVideoView>(R.id.ad_video)
val icpContainer: View? = startAdContainer.findViewById(R.id.startAdIcpContainer)
startAdContainer.visibility = View.VISIBLE
icpContainer?.visibility = View.VISIBLE
jumpBtn.text = startAdContainer.context.getString(R.string.splash_jump, splashAdDisplayInterval)
jumpDetailBtn.text = ad.desc
jumpDetailBtn.setDrawableEnd(
AppCompatResources.getDrawable(
@ -577,16 +569,7 @@ object AdDelegateHelper {
R.drawable.ic_startup_ad_arrow
), null, null
)
adImage.visibleIf(true)
ImageUtils.display(adImage, ad.img)
if (ad.isImageType) {
adVideo.visibleIf(false)
} else {
adVideo.visibleIf(true)
adVideo.startPlay(ad.video.url)
}
startAdContainer.setOnClickListener {
// 拦截点击事件传递
}
@ -656,11 +639,9 @@ object AdDelegateHelper {
slotId: String,
adContainerView: ViewGroup,
expressViewWidth: Float,
onAdShowAction: () -> Unit,
onAdClickAction: () -> Unit,
callback: (isSuccess: Boolean) -> Unit,
) {
mCsjAdImpl?.requestFlowAd(fragment, adContainerView, slotId, expressViewWidth, onAdShowAction, onAdClickAction, callback)
mCsjAdImpl?.requestFlowAd(fragment, adContainerView, slotId, expressViewWidth, callback)
}
/**
@ -671,8 +652,6 @@ object AdDelegateHelper {
containerView: ViewGroup,
ad: AdConfig.ThirdPartyAd,
expressViewWidthInDp: Float,
onAdShowAction: () -> Unit,
onAdClickAction: () -> Unit,
callback: (isSuccess: Boolean) -> Unit
) {
@ -695,28 +674,6 @@ object AdDelegateHelper {
slotId,
expressViewWidthInDp,
expressViewHeightInDp,
onAdShowAction,
onAdClickAction,
callback
)
}
/**
* 获取第三方 全屏/插屏 广告
*/
fun requestFullScreenAd(
fragment: Fragment,
ad: AdConfig.ThirdPartyAd,
onAdShowAction: () -> Unit,
onAdClickAction: () -> Unit,
callback: (isSuccess: Boolean) -> Unit
) {
val slotId = ad.slotId
mCsjAdImpl?.requestFullScreenAd(
fragment,
slotId,
onAdShowAction,
onAdClickAction,
callback
)
}
@ -725,6 +682,7 @@ object AdDelegateHelper {
* 取消开屏广告
*/
fun cancelSplashAd(context: Context) {
mBeiziAdImpl?.cancelSplashAd(context)
mCsjAdImpl?.cancelSplashAd(context)
}

View File

@ -3,105 +3,42 @@ package com.gh.ad
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.view.ViewStub
import androidx.fragment.app.Fragment
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.provider.ILaunchAd
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.AdConfig
import com.lg.vspace.ui.launcher.ILaunchAd
@Route(path = RouteConsts.provider.vaAd, name = "畅玩启动页广告")
class LaunchAdImpl : ILaunchAd {
override fun init(context: Context?) {
}
override fun requestAd(fragment: Fragment, container: ViewGroup, maskView: View, topViewStub: ViewStub, bottomViewStub: ViewStub, adClickAction: () -> Unit): View {
override fun requestAd(fragment: Fragment, container: ViewGroup, maskView: View) {
if (AdDelegateHelper.shouldShowHelperLaunchAd()) {
val launchAd = AdDelegateHelper.vGameLaunchAd
val showThirdPartyAd = launchAd?.displayRule?.adSource == AdDelegateHelper.AD_TYPE_SDK
val thirdPartyAd = launchAd?.thirdPartyAd
if (showThirdPartyAd && thirdPartyAd != null) {
val onAdShowAction = {
SensorsBridge.trackEvent("ThirdPartyAdShow",
"ad_source", thirdPartyAd.sourceName,
"ad_id", thirdPartyAd.slotId,
"ad_format", launchAd.typeChinese,
"ad_placement", AD_PLACEMENT,
"ad_space_id", launchAd.id,
"ad_space_name", launchAd.name
)
}
val onAdClickAction = {
SensorsBridge.trackEvent("ThirdPartyAdClick",
"ad_source", thirdPartyAd.sourceName,
"ad_id", thirdPartyAd.slotId,
"ad_format", launchAd.typeChinese,
"ad_placement", AD_PLACEMENT,
"ad_space_id", launchAd.id,
"ad_space_name", launchAd.name
)
adClickAction.invoke()
}
if (launchAd.type == AdConfig.TYPE_BANNER) {
requestBannerAd(fragment, container, maskView, thirdPartyAd, onAdShowAction, onAdClickAction)
return topViewStub.inflate()
} else if (launchAd.type == AdConfig.TYPE_INTERSTITIAL) {
requestFullScreenAd(fragment, thirdPartyAd, onAdShowAction, onAdClickAction)
return bottomViewStub.inflate()
AdDelegateHelper.requestThirdPartyBannerAd(
fragment,
container,
thirdPartyAd,
DisplayUtils.getScreenWidthInDp(fragment.requireActivity()),
) { isSuccess ->
maskView.goneIf(!isSuccess)
if (isSuccess) {
SPUtils.setLong(Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME, System.currentTimeMillis())
}
}
}
}
return bottomViewStub.inflate()
}
private fun requestBannerAd(
fragment: Fragment,
container: ViewGroup,
maskView: View,
thirdPartyAd: AdConfig.ThirdPartyAd,
onAdShowAction: () -> Unit,
onAdClickAction: () -> Unit,
) {
AdDelegateHelper.requestThirdPartyBannerAd(
fragment,
container,
thirdPartyAd,
DisplayUtils.getScreenWidthInDp(fragment.requireActivity()),
onAdShowAction,
onAdClickAction
) { isSuccess ->
maskView.goneIf(!isSuccess)
if (isSuccess) {
SPUtils.setLong(Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME, System.currentTimeMillis())
}
}
}
private fun requestFullScreenAd(
fragment: Fragment,
thirdPartyAd: AdConfig.ThirdPartyAd,
onAdShowAction: () -> Unit,
onAdClickAction: () -> Unit
) {
AdDelegateHelper.requestFullScreenAd(
fragment,
thirdPartyAd,
onAdShowAction,
onAdClickAction
) { isSuccess ->
if (isSuccess) {
SPUtils.setLong(Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME, System.currentTimeMillis())
}
}
}
companion object {
private const val AD_PLACEMENT = "畅玩启动"
}
}

View File

@ -1,78 +0,0 @@
package com.gh.ad
import android.app.Activity
import android.content.Context
import android.util.AttributeSet
import android.view.WindowManager
import com.gh.gamecenter.R
import com.gh.gamecenter.video.detail.CustomManager
import com.shuyu.gsyvideoplayer.utils.GSYVideoType
import com.shuyu.gsyvideoplayer.utils.GSYVideoType.SCREEN_TYPE_FULL
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
import com.shuyu.gsyvideoplayer.video.base.GSYVideoViewBridge
class SplashAdVideoView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) :
StandardGSYVideoPlayer(context, attrs) {
fun startPlay(url: String) {
GSYVideoType.setShowType(SCREEN_TYPE_FULL)
GSYVideoType.setRenderType(GSYVideoType.SUFRACE)
CustomManager.getCustomManager(getKey()).isNeedMute = true
setUp(url, true, "")
setNeedAutoAdaptation(false)
startPlayLogic()
}
override fun getGSYVideoManager(): GSYVideoViewBridge {
CustomManager.getCustomManager(getKey()).initContext(context.applicationContext)
return CustomManager.getCustomManager(getKey())
}
private fun getKey() = "splash_ad"
/**
* 覆盖父类方法,防止在是视频 Preparing 阶段封面图被隐藏,导致白屏
*/
override fun changeUiToPreparingShow() = Unit
override fun getLayoutId(): Int {
return R.layout.layout_splash_ad_video
}
override fun onAutoCompletion() {
setStateAndUi(CURRENT_STATE_AUTO_COMPLETE);
mSaveChangeViewTIme = 0
mCurrentPosition = 0
if (!mIfCurrentIsFullscreen) {
getGSYVideoManager().setLastListener(null)
}
mAudioManager.abandonAudioFocus(onAudioFocusChangeListener);
if (mContext is Activity) {
try {
(mContext as Activity).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} catch (e: Exception) {
e.printStackTrace()
}
}
releaseNetWorkState()
if (mVideoAllCallBack != null && isCurrentMediaListener()) {
mVideoAllCallBack.onAutoComplete(mOriginUrl, mTitle, this)
}
mHadPlay = false
}
fun clearAll() {
GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_DEFAULT)
GSYVideoType.setRenderType(GSYVideoType.TEXTURE)
release()
CustomManager.removeManager(getKey())
}
}

View File

@ -21,8 +21,6 @@ import com.gh.common.view.RichEditor
import com.gh.gamecenter.CropImageActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.entity.LocalVideoEntity
import com.gh.gamecenter.feature.selector.LocalMediaActivity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnIoThread
@ -32,7 +30,6 @@ import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.qa.editor.*
import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.feature.entity.ArticleEntity
import com.gh.gamecenter.feature.selector.ChooseType
import com.gh.gamecenter.qa.entity.EditorInsertEntity
import com.gh.gamecenter.video.poster.PosterEditActivity
import com.gh.gamecenter.video.upload.UploadManager
@ -505,7 +502,7 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
startActivityForResult(
LocalMediaActivity.getIntent(
this@BaseRichEditorActivity,
ChooseType.VIDEO,
LocalMediaActivity.ChooseType.VIDEO,
maxChooseCount,
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
), INSERT_MEDIA_VIDEO_CODE
@ -534,7 +531,7 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
val maxChooseCount = if (imageCount + 10 <= MAX_IMAGE_COUNT) 10 else MAX_IMAGE_COUNT - imageCount
val intent = LocalMediaActivity.getIntent(
this@BaseRichEditorActivity,
ChooseType.IMAGE,
LocalMediaActivity.ChooseType.IMAGE,
maxChooseCount,
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
)

View File

@ -20,7 +20,7 @@ import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.ForumDetailEntity
import com.gh.gamecenter.common.entity.LocalVideoEntity
import com.gh.gamecenter.entity.LocalVideoEntity
import com.gh.gamecenter.entity.QuoteCountEntity
import com.gh.gamecenter.qa.BbsType
import com.gh.gamecenter.retrofit.RetrofitManager
@ -39,6 +39,8 @@ import retrofit2.HttpException
import java.io.File
import java.io.FileOutputStream
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.collections.LinkedHashMap
import kotlin.collections.set

View File

@ -16,18 +16,18 @@ import com.gh.gamecenter.SplashScreenActivity
import com.gh.gamecenter.authorization.AuthorizationActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.provider.IHelpAndFeedbackProvider
import com.gh.gamecenter.common.utils.PackageFlavorHelper
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.feedback.view.suggest.SuggestionActivity
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.gamecenter.va.VCore
import com.gh.gamecenter.login.utils.QuickLoginHelper
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lg.vspace.ui.launcher.LaunchActivity
// TODO移动到对应的模块
class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
private var isFromBackgroundToForeground = false // 是否后台回到前台
private var activityCount = 0
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
// do nothing
@ -35,31 +35,28 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
override fun onActivityStarted(activity: Activity) {
GlobalActivityManager.currentActivity = activity
GlobalActivityManager.activityCount ++
if (GlobalActivityManager.activityCount == 1 && isFromBackgroundToForeground) {
activityCount ++
if (activityCount == 1 && isFromBackgroundToForeground) {
if (AdDelegateHelper.shouldShowStartUpAd(true)
&& !HaloApp.getInstance().isDisableSplashAdTemporarily
&& !HaloApp.getInstance().isSkippingThirdParty
&& activity !is SplashScreenActivity
&& activity !is SkipActivity
&& activity !is AuthorizationActivity
&& activity !is SplashAdActivity
&& !isSuggestionActivity(activity)
&& activity !is SuggestionActivity
) {
activity.startActivity(SplashAdActivity.getIntent(activity))
}
isFromBackgroundToForeground = false
}
if (GlobalActivityManager.activityCount == 1) {
if (activityCount == 1) {
// 清除桌面角标
if (activity !is SplashScreenActivity && activity !is AuthorizationActivity) {
val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
pushProvider?.cleanBadgeNumber(activity.applicationContext)
}
}
if (QuickLoginHelper.isLoginAuthPage(activity)) {
QuickLoginHelper.addCustomViewToLoginAuthPage(activity)
}
}
override fun onActivityResumed(activity: Activity) {
@ -91,7 +88,7 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
if (activity is AppCompatActivity
&& !VCore.getInstance().isLaunchActivity(activity)
&& activity !is LaunchActivity
&& activity !is LoginActivity
&& activity !is SplashScreenActivity
&& activity !is SkipActivity
@ -111,8 +108,8 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
override fun onActivityStopped(activity: Activity) {
GlobalActivityManager.activityCount --
isFromBackgroundToForeground = GlobalActivityManager.activityCount <= 0
activityCount --
isFromBackgroundToForeground = activityCount <= 0
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
@ -120,16 +117,7 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
override fun onActivityDestroyed(activity: Activity) {
if (QuickLoginHelper.isLoginAuthPage(activity)) {
QuickLoginHelper.release()
}
}
private fun isSuggestionActivity(activity: Activity): Boolean {
val helpAndFeedbackProvider =
ARouter.getInstance().build(RouteConsts.provider.helpAndFeedback)
.navigation() as? IHelpAndFeedbackProvider
return helpAndFeedbackProvider?.isSuggestionActivity(activity) ?: false
// do nothing
}
}

View File

@ -49,7 +49,6 @@ import com.gh.gamecenter.login.user.LoginTag
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserRepository
import com.gh.gamecenter.login.utils.LoginHelper
import com.gh.gamecenter.login.utils.QuickLoginHelper
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
import com.gh.gamecenter.setting.SettingBridge
@ -139,12 +138,12 @@ class DefaultJsApi(
@JavascriptInterface
fun login(msg: Any) {
if (NetworkUtils.isQuickLoginEnabled(context)) {
QuickLoginHelper.startLogin(context, "浏览器")
} else {
// if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
// QuickLoginHelper.startLogin(context, "浏览器")
// } else {
val intent = LoginActivity.getIntent(context, "浏览器")
context.startActivity(intent)
}
// }
}
@JavascriptInterface

View File

@ -268,6 +268,10 @@ object DefaultUrlHandler {
directToGameVideo(context, id, entrance, "")
}
EntranceConsts.HOST_CATEGORY -> {
val title = uri.getQueryParameter("title")
DirectUtils.directCategoryDirectory(context, id, title ?: "", entrance, "")
}
EntranceConsts.HOST_COLUMN_COLLECTION -> {
val name = uri.getQueryParameter("name")
DirectUtils.directToColumnCollection(context, id, -1, entrance, name ?: "")

View File

@ -6,8 +6,8 @@ class DownloadChainBuilder {
private var processEndCallback: ((asVGame: Boolean, Any?) -> Unit)? = null
fun setProcessEndCallback(gameId: String, callback: (asVGame: Boolean, Any?) -> Unit): DownloadChainBuilder {
processEndCallback = VaPluginDownloadWrapper(gameId = gameId, callback = callback) // 其他需要添加行为的装饰者可以一直包装A(B(C(callback))), 执行顺序 A->B->C->callback
fun setProcessEndCallback(callback: (asVGame: Boolean, Any?) -> Unit): DownloadChainBuilder {
processEndCallback = callback
return this
}

View File

@ -1,12 +0,0 @@
package com.gh.common.chain
import com.gh.vspace.VHelper
class VaPluginDownloadWrapper(val gameId: String, val callback: (Boolean, Any?) -> Unit) : (Boolean, Any?) -> Unit {
override fun invoke(asVGame: Boolean, any: Any?) {
callback.invoke(asVGame, any)
if (asVGame) {
VHelper.initVaPlugin(gameId)
}
}
}

View File

@ -7,7 +7,6 @@ import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.gh.common.util.PackageHelper;
@ -21,7 +20,6 @@ import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.common.utils.DarkModeUtils;
import com.gh.gamecenter.common.utils.EnvHelper;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.UrlFilterUtils;
@ -47,9 +45,9 @@ import org.json.JSONObject;
import java.io.IOException;
import java.util.Locale;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
@ -80,10 +78,10 @@ public class Config {
private static NewApiSettingsEntity.NightMode mNightModeSetting;
private static SimulatorEntity mNewSimulatorEntity;
private static VSetting mVSetting;
private volatile static VNewSetting mVNewSetting;
private static VNewSetting mVNewSetting;
private static AppEntity mNew32UpdateEntity;
private static BehaviorSubject<VNewSetting> vNewSettingSubject = BehaviorSubject.create();
public static BehaviorSubject<VNewSetting> vNewSettingSubject = BehaviorSubject.create();
private static GameGuidePopupEntity mGameGuidePopupEntity;
private static SharedPreferences mDefaultSharedPreferences;
@ -214,16 +212,6 @@ public class Config {
return mVNewSetting;
}
@NonNull
public static Observable<VNewSetting> getVNewSettingObservable() {
if (mVNewSetting != null) {
return Observable.just(mVNewSetting);
} else {
return vNewSettingSubject.hide();
}
}
@Nullable
public static AppEntity getNew32UpdateEntity() {
return mNew32UpdateEntity;
@ -237,6 +225,7 @@ public class Config {
RetrofitManager.getInstance()
.getVApi().getSettings(BuildConfig.VERSION_NAME, Build.VERSION.SDK_INT)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<VSetting>() {
@Override
public void onSuccess(VSetting data) {
@ -269,6 +258,7 @@ public class Config {
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<AppEntity>() {
@Override
public void onSuccess(AppEntity data) {
@ -300,6 +290,7 @@ public class Config {
RetrofitManager.getInstance()
.getApi().getSettings(PackageUtils.getGhVersionName(), channel)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<SettingsEntity>() {
@Override
public void onResponse(SettingsEntity response) {
@ -312,7 +303,7 @@ public class Config {
edit.apply();
if (!SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) {
AppExecutor.getUiExecutor().execute(() -> EventBus.getDefault().post(new EBReuse("Refresh")));
EventBus.getDefault().post(new EBReuse("Refresh"));
}
}
});
@ -320,6 +311,7 @@ public class Config {
RetrofitManager.getInstance()
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<NewSettingsEntity>() {
@Override
public void onSuccess(NewSettingsEntity data) {
@ -334,6 +326,7 @@ public class Config {
RetrofitManager.getInstance()
.getApi().getGameGuidePopup(Build.MANUFACTURER, Build.VERSION.RELEASE, Build.MODEL, channel, BuildConfig.VERSION_NAME)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<GameGuidePopupEntity>() {
@Override
public void onSuccess(GameGuidePopupEntity data) {
@ -345,6 +338,7 @@ public class Config {
if (manufacturer.equals("OPPO") || manufacturer.equals("VIVO")) {
RetrofitManager.getInstance().getNewApi().getBrowserHintUrl(manufacturer)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<ResponseBody>() {
@Override
public void onSuccess(ResponseBody data) {
@ -375,6 +369,7 @@ public class Config {
RetrofitManager.getInstance()
.getNewApi().getNewSettings(PackageUtils.getGhVersionName(), channel, filterString)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<NewApiSettingsEntity>() {
@Override
public void onSuccess(NewApiSettingsEntity data) {
@ -383,7 +378,7 @@ public class Config {
mNewSimulatorEntity = data.getSimulator();
if (HaloApp.getInstance().isNewForThisVersion && mNightModeSetting != null && mNightModeSetting.getInstall()) {
DarkModeUtils.INSTANCE.updateFollowSystemDarkModeToSp(true);
AppExecutor.getUiExecutor().execute(DarkModeUtils.INSTANCE::initDarkMode);
DarkModeUtils.INSTANCE.initDarkMode();
}
SPUtils.setString(Constants.SP_NEW_API_SETTINGS, GsonUtils.toJson(data));
@ -401,7 +396,7 @@ public class Config {
// 更新包名监听是否开启
if (mNewApiSettingsEntity.isPackageObserveEnable()) {
AppExecutor.getUiExecutor().execute(() -> observePackageChange(mNewApiSettingsEntity.getPackageObserveActions()));
observePackageChange(mNewApiSettingsEntity.getPackageObserveActions());
}
}
});

View File

@ -172,7 +172,7 @@ public class BindingAdapters {
builder.addHandler(new OverseaDownloadHandler());
builder.addHandler(new CheckDownloadHandler());
builder.setProcessEndCallback(gameEntity.getId(), (asVGame, isSubscribe) -> {
builder.setProcessEndCallback((asVGame, isSubscribe) -> {
download(v.getContext(),
progressBar,
gameEntity,
@ -197,7 +197,7 @@ public class BindingAdapters {
builder.addHandler(new GamePermissionHandler());
builder.addHandler(new VersionNumberHandler());
builder.setProcessEndCallback(gameEntity.getId(), (asVGame, isSubscribe) -> {
builder.setProcessEndCallback((asVGame, isSubscribe) -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,

View File

@ -158,7 +158,7 @@ class InstallPermissionDialogFragment : BaseDialogFragment() {
}
if (isXapk) {
val xapkUnzipVersions = Config.getSettings()?.permissionPopupAppliedVersions?.xapkUnzip
if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false || XapkInstaller.systemHasFlaw) {
if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
callBack?.invoke(false)
return
}

View File

@ -1,6 +1,5 @@
package com.gh.gamecenter.common.dialog
package com.gh.common.dialog
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Build
@ -12,18 +11,14 @@ import android.view.LayoutInflater
import android.view.View
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 androidx.appcompat.app.AppCompatActivity
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() {
class ManagerAllFilesPermissionDialogFragment : BaseDialogFragment() {
private val mBinding by lazy { DialogAlertDefaultBinding.inflate(layoutInflater) }
private var mCallBack: ((Boolean) -> Unit)? = null
private var mCallBack: (() -> Unit)? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return mBinding.root
@ -37,8 +32,6 @@ class ManageExternalStoragePermissionDialogFragment : BaseDialogFragment() {
contentTv.text = "需要所有文件访问权限,请打开权限设置页面"
confirmTv.setOnClickListener {
val appProvider = ARouter.getInstance().build(RouteConsts.provider.app).navigation() as? IAppProvider?
appProvider?.setDisableSplashAdTemporarily(true)
val intent = Intent().apply {
action = Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
data = Uri.fromParts("package", requireContext().packageName, null)
@ -46,24 +39,15 @@ class ManageExternalStoragePermissionDialogFragment : BaseDialogFragment() {
requireActivity().startActivityForResult(intent, REQUEST_CODE)
}
cancelTv.setOnClickListener {
mCallBack?.invoke(false)
dismissAllowingStateLoss()
}
}
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
AppExecutor.uiExecutor.executeWithDelay({
val appProvider = ARouter.getInstance().build(RouteConsts.provider.app).navigation() as? IAppProvider?
appProvider?.setDisableSplashAdTemporarily(false)
}, 100)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE && Environment.isExternalStorageManager()) {
mCallBack?.invoke(true)
mCallBack?.invoke()
dismissAllowingStateLoss()
}
}
@ -72,12 +56,12 @@ class ManageExternalStoragePermissionDialogFragment : BaseDialogFragment() {
const val REQUEST_CODE = 1000
@JvmStatic
fun show(activity: FragmentActivity, callback: (Boolean) -> Unit) {
ManageExternalStoragePermissionDialogFragment().apply {
fun show(activity: AppCompatActivity, callback: () -> Unit) {
ManagerAllFilesPermissionDialogFragment().apply {
mCallBack = callback
}.show(
activity.supportFragmentManager,
ManageExternalStoragePermissionDialogFragment::class.java.name
ManagerAllFilesPermissionDialogFragment::class.java.name
)
}
}

View File

@ -60,7 +60,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private val mDuration = 3000
private var mDisposable: Disposable? = null
private var mAdapter: PackageCheckAdapter? = null
private var mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
private var mAllInstalledPackages = PackageHelper.getInstalledPackages(HaloApp.getInstance().application, 0)
var gameEntity: GameEntity? = null
var callBack: ConfirmListener? = null
@ -326,7 +326,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
override fun onResume() {
super.onResume()
mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
mAllInstalledPackages = PackageHelper.getInstalledPackages(HaloApp.getInstance().application, 0)
gameEntity?.packageDialog?.let {
if (isAllPackageInstalled(mAllInstalledPackages, it)) {
callBack?.onConfirm()
@ -364,7 +364,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
mAllInstalledPackages = PackageHelper.getInstalledPackages(HaloApp.getInstance().application, 0)
mAdapter?.notifyDataSetChanged()
}
}
@ -417,7 +417,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
return
}
val allInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
val allInstalledPackages = PackageHelper.getInstalledPackages(HaloApp.getInstance().application, 0)
if (isAllPackageInstalled(allInstalledPackages, packageDialogEntity)) {
callBack.onConfirm()
return
@ -454,12 +454,12 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
}
private fun checkDetectionsInstalled(
allInstalledPackages: List<String>,
allInstalledPackages: List<PackageInfo>,
packages: ArrayList<String>
): Boolean {
var isPackagesInstalled = false
packages.forEach { packageName ->
val isInstalled = allInstalledPackages.find { it == packageName } != null
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
if (isInstalled) {
isPackagesInstalled = true
return@forEach
@ -470,7 +470,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
fun isAllPackageInstalled(
allInstalledPackages: List<String>,
allInstalledPackages: List<PackageInfo>,
packageDialogEntity: PackageDialogEntity
): Boolean {
var isAllInstalled = true

View File

@ -6,16 +6,16 @@ import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.fromHtml
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.view.FixLinearLayoutManager
import com.gh.gamecenter.databinding.DialogReserveBinding
import com.gh.gamecenter.databinding.DialogReserveItemBinding
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.mygame.MyGameActivity
import com.lightgame.adapter.BaseRecyclerAdapter
@ -43,7 +43,7 @@ class ReserveDialog : BaseDialogFragment() {
View.VISIBLE
} else View.GONE
binding.more.setOnClickListener {
val intent = MyGameActivity.getIntentWithConfig(requireContext(), MyGameActivity.RESERVATION_INDEX)
val intent = MyGameActivity.getIntentWithConfig(requireContext(), 2)
startActivity(intent)
dismissAllowingStateLoss()
}

View File

@ -1,13 +1,13 @@
package com.gh.common.prioritychain
import android.app.Activity
import android.os.Handler
import android.view.Gravity
import android.view.LayoutInflater
import android.widget.FrameLayout
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.DisplayUtils
@ -19,7 +19,7 @@ import com.gh.gamecenter.wrapper.MainWrapperViewModel
class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priority) {
private var mActivity: Activity? = null
private var mHandler: Handler? = null
private var mBaseHandler: BaseFragment.BaseHandler? = null
private var mGameList: List<GameEntity>? = null
private var mViewModel: MainWrapperViewModel? = null
@ -28,13 +28,13 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
*/
fun doPreProcess(
activity: Activity,
handler: Handler,
baseHandler: BaseFragment.BaseHandler,
gameEntityList: List<GameEntity>?,
viewModel: MainWrapperViewModel
) {
mActivity = activity
mGameList = gameEntityList
mHandler = handler
mBaseHandler = baseHandler
mViewModel = viewModel
if (getStatus() == STATUS_PENDING) {
@ -59,7 +59,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
val accelerateSet =
HashSet(SPUtils.getStringSet(Constants.SP_ACCELERATE_NOTIFICATION_POP_UP_SET))
if (!mGameList.isNullOrEmpty() && !accelerateSet.contains(mGameList!![0].messageId)) {
showAccelerateNotificationPopupWindow(mActivity!!, mViewModel, mHandler, mGameList!![0]) {
showAccelerateNotificationPopupWindow(mActivity!!, mViewModel, mBaseHandler, mGameList!![0]) {
processNext()
}
accelerateSet.add(mGameList!![0].messageId)
@ -82,7 +82,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
fun showAccelerateNotificationPopupWindow(
activity: Activity,
viewModel: MainWrapperViewModel?,
handler: Handler?,
baseHandler: BaseFragment.BaseHandler?,
gameEntity: GameEntity?,
dismissCallback: (() -> Unit)?
) {
@ -131,7 +131,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
setOnDismissListener {
dismissCallback?.invoke()
}
handler?.postDelayed({ dismiss() }, 5000)
baseHandler?.postDelayed({ dismiss() }, 5000)
}
}
}

View File

@ -1,169 +0,0 @@
package com.gh.common.prioritychain
import android.app.Activity
import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.PopupBottomTabGuideBinding
import com.gh.gamecenter.entity.BottomTab
class BottomTabGuideHandler(priority: Int): PriorityChainHandler(priority) {
private var mActivity: Activity? = null
private var mHandler: Handler? = null
private var mViewPager: ViewGroup? = null
private var mGuide: BottomTab.Guide? = null
private var mTriangleTransX = 0F
private var mGuideTransX = 0F
private var mRestWidth = 0F
private var mIsCenterPosition = false
private var mIsRightPosition = false
private var mPopupWindow: PopupWindow? = null
fun doPreProcess(
shouldShow: Boolean,
activity: Activity? = null,
handler: Handler? = null,
viewPager: ViewGroup? = null,
guide: BottomTab.Guide? = null,
triangleTransX: Float = 0F,
guideTransX: Float = 0F,
restWidth: Float = 0F,
isCenterPosition: Boolean = false,
isRightPosition: Boolean = false
) {
mActivity = activity
mHandler = handler
mViewPager = viewPager
mGuide = guide
mTriangleTransX = triangleTransX
mGuideTransX = guideTransX
mRestWidth = restWidth
mIsCenterPosition = isCenterPosition
mIsRightPosition = isRightPosition
if (getStatus() == STATUS_PENDING) {
if (shouldShow) {
updateStatus(STATUS_VALID)
process()
} else {
processNext()
}
} else {
if (shouldShow) {
updateStatus(STATUS_VALID)
} else {
updateStatus(STATUS_INVALID)
}
}
}
override fun onProcess(): Boolean {
when (getStatus()) {
STATUS_VALID -> {
if (mGuide == null || mActivity == null || mViewPager == null) {
processNext()
return false
}
val guideSet = HashSet(SPUtils.getStringSet(Constants.SP_BOTTOM_TAB_GUIDE_SET))
if (!guideSet.contains(mGuide?.bottomTabId + mGuide?.text)) {
mPopupWindow = showBottomTabPopupWindow(
mActivity!!,
mHandler,
mViewPager!!,
mGuide!!,
mTriangleTransX,
mGuideTransX,
mRestWidth,
mIsCenterPosition,
mIsRightPosition
) {
processNext()
}
guideSet.add(mGuide?.bottomTabId + mGuide?.text)
SPUtils.setStringSet(Constants.SP_BOTTOM_TAB_GUIDE_SET, guideSet)
return true
} else {
processNext()
}
}
STATUS_INVALID -> {
processNext()
}
}
return false
}
fun dismiss() {
if (mPopupWindow?.isShowing == true) {
mPopupWindow?.dismiss()
}
}
companion object {
const val KEY_BOTTOM_TAB_GUIDE_AUTO_DISMISS = 100
private const val AUTO_DISMISS_DELAY_TIME = 5000L
fun showBottomTabPopupWindow(
activity: Activity,
handler: Handler?,
viewPager: ViewGroup,
guide: BottomTab.Guide,
triangleTransX: Float,
guideTransX: Float,
restWidth: Float,
isCenterPosition: Boolean,
isRightPosition: Boolean,
dismissCallback: (() -> Unit)?
): PopupWindow {
val binding = PopupBottomTabGuideBinding.inflate(LayoutInflater.from(activity))
binding.guideTv.text = guide.text
binding.guideTriangleIv.translationX = triangleTransX
binding.guideTv.translationX = guideTransX
binding.guideIconIv.translationX = guideTransX
binding.guideTv.updateLayoutParams<ConstraintLayout.LayoutParams> {
horizontalBias = if (isCenterPosition) 0.5F else if (isRightPosition) 1F else 0F
}
val popupWindow = BugFixedPopupWindow(
binding.root,
ConstraintLayout.LayoutParams.MATCH_PARENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
)
popupWindow.contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val measureWidth = popupWindow.contentView.measuredWidth
val measureHeight = popupWindow.contentView.measuredHeight
if (measureWidth > restWidth) {
binding.guideTv.translationX = 0F
binding.guideIconIv.translationX = 0F
}
return popupWindow.apply {
isFocusable = false
isOutsideTouchable = false
animationStyle = R.style.popup_window_ease_in_and_out_anim_style
setOnDismissListener {
dismissCallback?.invoke()
}
handler?.post {
if (!activity.isFinishing) {
showAsDropDown(viewPager, 0, 8F.dip2px() - measureHeight)
}
handler.sendEmptyMessageDelayed(KEY_BOTTOM_TAB_GUIDE_AUTO_DISMISS, AUTO_DISMISS_DELAY_TIME)
}
}
}
}
}

View File

@ -1,52 +0,0 @@
package com.gh.common.prioritychain
import android.content.Context
import android.view.LayoutInflater
import android.widget.FrameLayout
import com.airbnb.lottie.LottieAnimationView
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.LayoutCommunityHomeVideoGuideBinding
class CommunityHomeGuideHandler(
priority: Int,
private val context: Context,
private val decorView: FrameLayout?,
private val videoLottie: LottieAnimationView?
) : PriorityChainHandler(priority) {
init {
updateStatus(STATUS_VALID)
}
override fun onProcess(): Boolean {
return if (SPUtils.getBoolean(Constants.SP_SHOW_COMMUNITY_HOME_VIDEO_GUIDE, true)) {
showHomeVideoGuide(context, decorView, videoLottie)
processNext()
true
} else {
processNext()
false
}
}
companion object {
fun showHomeVideoGuide(context: Context, decorView: FrameLayout?, videoLottie: LottieAnimationView?) {
val guideLayoutBinding = LayoutCommunityHomeVideoGuideBinding.inflate(
LayoutInflater.from(context),
decorView,
true
)
guideLayoutBinding.root.setOnClickListener { view ->
decorView?.removeView(view)
SPUtils.setBoolean(Constants.SP_SHOW_COMMUNITY_HOME_VIDEO_GUIDE, false)
videoLottie?.playAnimation()
SPUtils.setLong(
Constants.SP_COMMUNITY_HOME_VIDEO_LOTTIE_LAST_PLAY_TIME,
System.currentTimeMillis()
)
}
}
}
}

View File

@ -2,7 +2,7 @@ package com.gh.common.prioritychain
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.feature.entity.FloatingWindowEntity
import com.gh.gamecenter.floatingwindow.FloatingWindowEntity
import com.gh.gamecenter.livedata.Event
class CustomFloatingWindowHandler(priority: Int) : PriorityChainHandler(priority) {
@ -60,7 +60,7 @@ class CustomFloatingWindowHandler(priority: Int) : PriorityChainHandler(priority
when (getStatus()) {
STATUS_VALID -> {
_showFloatingAction.value = Event(data)
return true
processNext()
// floatingWindowProvider.showFloatingWindowOnly(
// mFragment!!,
// mRecyclerView!!,
@ -79,9 +79,4 @@ class CustomFloatingWindowHandler(priority: Int) : PriorityChainHandler(priority
return false
}
fun dismiss() {
if (getStatus() == STATUS_HANDLING || getStatus() == STATUS_VALID) {
processNext()
}
}
}

View File

@ -18,8 +18,6 @@ import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.DialogEntity
import com.gh.gamecenter.feature.entity.WelcomeDialogEntity
import com.gh.gamecenter.hud.PendingInstallHUDHandler
import com.gh.gamecenter.hud.ResumeDownloadHudHandler
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
@ -59,8 +57,6 @@ object GlobalPriorityChainHelper : ISuperiorChain {
val notificationPermissionDialogHandler = NotificationPermissionDialogHandler(0)
val reserveDialogHandler = ReserveDialogHandler(1)
val welcomeDialogHandler = WelcomeDialogHandler(2)
val pendingInstallHandler = PendingInstallHUDHandler(3)
val resumeDownloadHandler = ResumeDownloadHudHandler(4)
mainChain.addHandler(launchRedirectHandler)
mainChain.addHandler(updateDialogHandler)
@ -68,8 +64,6 @@ object GlobalPriorityChainHelper : ISuperiorChain {
mainChain.addHandler(welcomeDialogHandler)
mainChain.addHandler(reserveDialogHandler)
mainChain.addHandler(notificationPermissionDialogHandler)
mainChain.addHandler(pendingInstallHandler)
mainChain.addHandler(resumeDownloadHandler)
launchRedirectHandler.doPreProcess()
updateDialogHandler.doPreProcess()

View File

@ -1,297 +0,0 @@
package com.gh.common.prioritychain
import android.app.Activity
import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.widget.PopupWindow
import androidx.constraintlayout.widget.ConstraintLayout
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.common.view.NoDefaultMinWidthTabLayout
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.PopupMultiTabGuideBinding
import com.gh.gamecenter.entity.BottomTab
import com.gh.gamecenter.wrapper.BaseTabWrapperFragment
import com.gh.gamecenter.wrapper.MainWrapperFragment
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.TabView
class MultiTabGuideHandler(priority: Int): PriorityChainHandler(priority) {
private var mActivity: Activity? = null
private var mHandler: Handler? = null
private var mGuide: BottomTab.Guide? = null
private var mTabLayout: TabLayout? = null
private var mTabView: TabView? = null
private var mIsSingleLineTab = false
private var mMainWrapperFragment: MainWrapperFragment? = null
private var mTabWrapperFragment: BaseTabWrapperFragment? = null
fun doPreProcess(
shouldShow: Boolean,
activity: Activity? = null,
handler: Handler? = null,
guide: BottomTab.Guide? = null,
tabLayout: TabLayout? = null,
tabView: TabLayout.TabView? = null,
isSingleLineTab: Boolean = false,
mainWrapperFragment: MainWrapperFragment? = null,
tabWrapperFragment: BaseTabWrapperFragment? = null
) {
mActivity = activity
mHandler = handler
mGuide = guide
mTabLayout = tabLayout
mTabView = tabView
mIsSingleLineTab = isSingleLineTab
mMainWrapperFragment = mainWrapperFragment
mTabWrapperFragment = tabWrapperFragment
if (getStatus() == STATUS_PENDING) {
if (shouldShow) {
updateStatus(STATUS_VALID)
process()
} else {
processNext()
}
} else {
if (shouldShow) {
updateStatus(STATUS_VALID)
} else {
updateStatus(STATUS_INVALID)
}
}
}
override fun onProcess(): Boolean {
when (getStatus()) {
STATUS_VALID -> {
if (mGuide == null || mActivity == null || mTabView == null || mTabLayout == null) {
processNext()
return false
}
return showMultiTabGuide(
true,
mActivity!!,
mHandler,
mGuide!!,
mTabLayout!!,
mTabView!!,
mIsSingleLineTab,
mMainWrapperFragment,
mTabWrapperFragment
) {
processNext()
}
}
STATUS_INVALID -> {
processNext()
}
}
return false
}
companion object {
private const val TAB_GUIDE_TRIANGLE_OFFSET_DP = 5F
private const val TAB_GUIDE_START_TRIANGLE_OFFSET_DP = 12F
private const val TAB_GUIDE_RIGHT_SIDE_ICON_RIGHT_RESERVED_OFFSET_DP = 51F + TAB_GUIDE_TRIANGLE_OFFSET_DP // 光宝在文案右侧时预留引导到屏幕右侧的距离
private const val TAB_GUIDE_RIGHT_SIDE_ICON_LEFT_RESERVED_OFFSET_DP = TAB_GUIDE_START_TRIANGLE_OFFSET_DP + TAB_GUIDE_TRIANGLE_OFFSET_DP // 光宝在文案作侧时预留引导到屏幕右侧的距离
fun showMultiTabGuide(
isImmediately: Boolean,
activity: Activity,
handler: Handler?,
guide: BottomTab.Guide,
tabLayout: TabLayout,
tabView: TabView,
isSingleLineTab: Boolean = false,
mainWrapperFragment: MainWrapperFragment? = null,
tabWrapperFragment: BaseTabWrapperFragment? = null,
dismissCallback: (() -> Unit)? = null
): Boolean {
val guideSet = HashSet(SPUtils.getStringSet(Constants.SP_MULTI_TAB_NAV_GUIDE_SET))
val hasShownGuide = guideSet.contains(guide.multiTabId + guide.text)
val isCurrentBottomTab = mainWrapperFragment == null || guide.bottomTabId == mainWrapperFragment.currentTab?.id
if (!hasShownGuide && isCurrentBottomTab) {
val screenWidth = DisplayUtils.getScreenWidth(activity)
val outLocation = IntArray(2)
tabView.getLocationOnScreen(outLocation)
val tabViewCenterPosX = outLocation.first() + tabView.width / 2F
val iconLeftMaxPosX = if (isSingleLineTab) tabLayout.width else tabLayout.width - TAB_GUIDE_RIGHT_SIDE_ICON_LEFT_RESERVED_OFFSET_DP.dip2px()
val iconRightMaxPosX = if (isSingleLineTab) tabLayout.width else tabLayout.width - TAB_GUIDE_RIGHT_SIDE_ICON_RIGHT_RESERVED_OFFSET_DP.dip2px()
val isIconLeftValid = tabViewCenterPosX <= iconLeftMaxPosX
val isIconRightValid = tabViewCenterPosX <= iconRightMaxPosX
val isTabViewShowOnScreen = tabViewCenterPosX > 0 && (isIconLeftValid || isIconRightValid)
val isTabLayoutScrollStateIdle = (tabLayout as? NoDefaultMinWidthTabLayout)?.isScrollStateIdle == true
if (isTabViewShowOnScreen && isTabLayoutScrollStateIdle) {
val trianglePosX = tabViewCenterPosX - TAB_GUIDE_TRIANGLE_OFFSET_DP.dip2px()
val guideStartPosX = trianglePosX - TAB_GUIDE_START_TRIANGLE_OFFSET_DP.dip2px()
val xoff = tabView.width / 2 - TAB_GUIDE_START_TRIANGLE_OFFSET_DP.dip2px() - TAB_GUIDE_TRIANGLE_OFFSET_DP.dip2px()
val restGuideWidth = screenWidth - guideStartPosX
showMultiTabPopupWindow(
activity,
handler,
guide,
tabView,
xoff,
screenWidth,
restGuideWidth,
isIconRightValid,
dismissCallback
)
guideSet.add(guide.multiTabId + guide.text)
SPUtils.setStringSet(Constants.SP_MULTI_TAB_NAV_GUIDE_SET, guideSet)
return true
} else if (isImmediately) {
(tabLayout as? NoDefaultMinWidthTabLayout)?.let {
it.onScrollListener = object :
NoDefaultMinWidthTabLayout.OnScrollListener() {
override fun onScrollStateChanged(view: NoDefaultMinWidthTabLayout, scrollState: Int) {
if (scrollState == SCROLL_STATE_IDLE) {
showMultiTabGuideIfTabViewShow(
activity,
handler,
guide,
it,
tabView,
isSingleLineTab,
mainWrapperFragment
)
}
}
}
}
}
} else if (isImmediately && !isCurrentBottomTab) {
tabWrapperFragment?.setResumeAndPauseListener {
if (it) {
handler?.post {
(tabLayout as? NoDefaultMinWidthTabLayout)?.let { tl ->
showMultiTabGuideIfBottomTabShow(
activity,
handler,
guide,
tl,
tabView,
isSingleLineTab,
mainWrapperFragment,
tabWrapperFragment
)
}
}
}
}
}
dismissCallback?.invoke()
return false
}
fun showMultiTabGuideIfTabViewShow(
activity: Activity,
handler: Handler?,
guide: BottomTab.Guide,
tabLayout: NoDefaultMinWidthTabLayout,
tabView: TabView,
isSingleLineTab: Boolean = false,
mainWrapperFragment: MainWrapperFragment?
) {
if (showMultiTabGuide(
false,
activity,
handler,
guide,
tabLayout,
tabView,
isSingleLineTab,
mainWrapperFragment
)
) {
tabLayout.onScrollListener = null
}
}
fun showMultiTabGuideIfBottomTabShow(
activity: Activity,
handler: Handler?,
guide: BottomTab.Guide,
tabLayout: NoDefaultMinWidthTabLayout,
tabView: TabView,
isSingleLineTab: Boolean = false,
mainWrapperFragment: MainWrapperFragment?,
tabWrapperFragment: BaseTabWrapperFragment?
) {
if (showMultiTabGuide(
false,
activity,
handler,
guide,
tabLayout,
tabView,
isSingleLineTab,
mainWrapperFragment,
tabWrapperFragment
)
) {
tabWrapperFragment?.setResumeAndPauseListener(null)
}
}
fun showMultiTabPopupWindow(
activity: Activity,
handler: Handler?,
guide: BottomTab.Guide,
tabView: TabView,
xoff: Int,
screenWidth: Int,
restGuideWidth: Float,
isIconRight: Boolean,
dismissCallback: (() -> Unit)?
): PopupWindow {
val binding = PopupMultiTabGuideBinding.inflate(LayoutInflater.from(activity))
binding.guideTv.text = guide.text
binding.guideTriangleIv.translationX = 12F.dip2px().toFloat()
binding.guideTv.setPadding(if (isIconRight) 8F.dip2px() else 52F.dip2px(), 0, if (isIconRight) 52F.dip2px() else 8F.dip2px(), 0)
binding.guideIconIv.goneIf(!isIconRight)
binding.guideIconFlipIv.goneIf(isIconRight)
val popupWindow = BugFixedPopupWindow(
binding.root,
ConstraintLayout.LayoutParams.WRAP_CONTENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
)
popupWindow.contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val measureWidth = popupWindow.contentView.measuredWidth
if (measureWidth >= screenWidth) {
popupWindow.width = screenWidth
binding.guideTriangleIv.translationX += screenWidth - restGuideWidth
} else if (measureWidth > restGuideWidth) {
binding.guideTriangleIv.translationX += measureWidth - restGuideWidth
}
return popupWindow.apply {
isTouchable = false
isFocusable = false
isOutsideTouchable = true
animationStyle = R.style.popup_window_ease_in_and_out_anim_style
setOnDismissListener {
dismissCallback?.invoke()
}
handler?.post {
if (!activity.isFinishing) {
showAsDropDown(tabView, xoff, (-25F).dip2px())
}
}
}
}
}
}

View File

@ -1,16 +0,0 @@
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
}
}

View File

@ -7,8 +7,8 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IAppProvider
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.va.VCore
import com.halo.assistant.HaloApp
import com.va.host.HostUtils
@Route(path = RouteConsts.provider.app, name = "Application暴露服务")
class AppProviderImpl : IAppProvider {
@ -84,13 +84,9 @@ class AppProviderImpl : IAppProvider {
return HaloApp.getInstance().isBrandNewInstall
}
override fun setDisableSplashAdTemporarily(isDisable: Boolean) {
HaloApp.getInstance().isDisableSplashAdTemporarily = isDisable
override fun setSkippingThirdParty(isSkippingThirdParty: Boolean) {
HaloApp.getInstance().isSkippingThirdParty = isSkippingThirdParty
}
override fun getPluginVersion(): String = VCore.getInstance().getPluginVersion()
override fun initImageLoaderIfNeeded() {
HaloApp.getInstance().initFresco()
}
override fun getPluginVersion(): String = HostUtils.getPluginVersion()
}

View File

@ -17,7 +17,7 @@ import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.toArrayList
import com.gh.gamecenter.core.provider.IConcernArticleUtilsProvider
import com.gh.gamecenter.databinding.RecyclerGameArticleBinding
import com.gh.gamecenter.R
import com.gh.gamecenter.message.R
@Route(path = RouteConsts.provider.concernContentUtils, name = "ConcernContentUtils暴露服务")
class ConcernArticleUtilsProviderImpl : IConcernArticleUtilsProvider {

View File

@ -100,10 +100,6 @@ class ConfigProviderImpl : IConfigProvider {
return Config.getNightModeSetting()?.setting ?: false
}
override fun isJiguangSwitch(): Boolean {
return Config.getNewApiSettingsEntity()?.jiguangSwitch ?: false
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -1,16 +1,11 @@
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 {
@ -22,19 +17,6 @@ class EntranceUtilsProviderImpl : IEntranceUtilsProvider {
EntranceUtils.saveShortcut(activityName, bundle)
}
override fun jumpActivityWithCallback(context: Context, bundle: Bundle, callback: () -> Unit) {
if (context is FragmentActivity && !context.supportFragmentManager.isDestroyed) {
EntranceUtils.jumpActivityCompat(context, bundle, null, object : Callback {
override fun onActivityResult(resultCode: Int, data: Intent?) {
callback()
}
})
} else {
EntranceUtils.jumpActivityCompat(AppManager.getInstance().currentActivity(), bundle)
}
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -1,23 +0,0 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IMiniGameRecentlyPlayedProvider
import com.gh.gamecenter.minigame.MiniGameRecentlyPlayUseCase
@Route(path = RouteConsts.provider.miniGameRecentPlayed, name = "MiniGameRecentlyPlayed暴露服务")
class MiniGameRecentlyPlayedProviderImpl : IMiniGameRecentlyPlayedProvider {
override fun clearMiniGameRecentlyPlayed(gameType: String) {
MiniGameRecentlyPlayUseCase.clearRecentlyPlayedMiniGameList(gameType)
}
override fun refreshQQMiniRecentPlayed() {
MiniGameRecentlyPlayUseCase.loadRecentlyPlayedMiniGameList(Constants.QQ_MINI_GAME)
}
override fun init(context: Context?) {
// no implement
}
}

View File

@ -24,7 +24,7 @@ class PackageUtilsProviderImpl : IPackageUtilsProvider {
}
override fun getInstalledPackages(context: Context, flag: Int): List<PackageInfo> {
return PackageHelper.getInstalledPackageInfoList(context, flag)
return PackageHelper.getInstalledPackages(context, flag)
}
override fun getApkSignatureByPackageName(context: Context, packageName: String): Array<String> {

View File

@ -19,12 +19,12 @@ import com.gh.gamecenter.databinding.DialogArchiveLoadingBinding
import com.gh.gamecenter.entity.ArchiveEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.va.VCore
import com.gh.vspace.VArchiveHelper
import com.gh.vspace.VHelper
import com.gh.vspace.VHelper.is32
import com.lg.download.DownloadError
import com.lg.download.DownloadStatus
import com.lody.virtual.client.core.VirtualCore
import io.reactivex.schedulers.Schedulers
import org.greenrobot.eventbus.EventBus
import splitties.systemservices.layoutInflater
@ -273,7 +273,7 @@ object ArchiveDownloadButtonHelper {
R.string.archive_apply.toResString(),
R.string.cancel.toResString(),
{
if(gameEntity.is32() && VHelper.isInnerInstalled(packageName) && !VCore.getInstance().isExtPackageInstalled()) {
if(gameEntity.is32() && VHelper.isInnerInstalled(packageName) && !VirtualCore.get().isExtPackageInstalled) {
// 32位的游戏 并且 32位畅玩没有安装 并且 一体化
VHelper.newCwValidateVspaceBeforeAction(context, gameEntity) {}
} else {

View File

@ -1,21 +1,14 @@
package com.gh.common.util;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.NetworkUtils;
import com.gh.gamecenter.core.utils.CurrentActivityHolder;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.login.utils.QuickLoginHelper;
import com.gh.gamecenter.login.view.LoginActivity;
import com.gh.gamecenter.login.user.UserManager;
import com.lightgame.utils.Utils;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
/**
* Created by khy on 28/06/17.
@ -29,15 +22,15 @@ public class CheckLoginUtils {
LogUtils.login("dialog", null, entrance);
LogUtils.login("activity", null, entrance);
if (NetworkUtils.isQuickLoginEnabled(context)) {
startQuickLogin(context, entrance, null);
} else {
// 有可能App未启动
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(context, bundle);
}
// if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
// startQuickLogin(context, entrance);
// } else {
// 有可能App未启动
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(context, bundle);
// }
} else {
if (listener != null) {
listener.onLogin();
@ -45,16 +38,16 @@ public class CheckLoginUtils {
}
}
private static void startQuickLogin(Context context, String entrance, Function0<Unit> callback) {
// 需要确保传入的 context 不为 application
if (!(context instanceof Activity)) {
context = CurrentActivityHolder.getCurrentActivity();
}
if (context != null) {
QuickLoginHelper.startLogin(context, entrance, callback);
}
}
// private static void startQuickLogin(Context context, String entrance) {
// // 需要确保传入的 context 不为 application
// if (!(context instanceof Activity)) {
// context = CurrentActivityHolder.getCurrentActivity();
// }
//
// if (context != null) {
// QuickLoginHelper.startLogin(context, entrance);
// }
// }
public static void checkLogin(final Context context, Bundle nextToBundle, boolean isTriggerNextStep, String entrance, OnLoginListener listener) {
if (!isLogin()) {
@ -62,25 +55,15 @@ public class CheckLoginUtils {
LogUtils.login("dialog", null, entrance);
LogUtils.login("activity", null, entrance);
if (NetworkUtils.isQuickLoginEnabled(context)) {
startQuickLogin(context, entrance, () -> {
if (isTriggerNextStep && listener != null && isLogin()) {
listener.onLogin();
}
return null;
});
} else {
// 有可能App未启动
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivityCompat(context, bundle, nextToBundle, (resultCode, data) -> {
if (isTriggerNextStep && listener != null && isLogin()) {
listener.onLogin();
}
});
}
// 有可能App未启动
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(context, nextToBundle, bundle, (resultCode, data) -> {
if (isTriggerNextStep && listener != null && isLogin()) {
listener.onLogin();
}
});
} else {
if (listener != null) {
listener.onLogin();

View File

@ -9,18 +9,17 @@ import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import com.alibaba.android.arouter.launcher.ARouter;
import com.gh.ad.AdDelegateHelper;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.base.GlobalActivityManager;
import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.RouteConsts;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.provider.ISentryProvider;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.feature.utils.SentryHelper;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.login.entity.IdCardEntity;
import com.gh.gamecenter.login.entity.UserInfoEntity;
import com.gh.gamecenter.provider.GhContentProvider;
@ -32,6 +31,9 @@ import com.lightgame.config.CommonDebug;
import com.lightgame.utils.Utils;
import io.reactivex.schedulers.Schedulers;
import io.sentry.Sentry;
import io.sentry.android.core.SentryAndroid;
import kotlin.Pair;
/**
* Created by LGT on 2016/6/15.
@ -55,10 +57,50 @@ public class DataUtils {
}
private static void initSentry(Context context, String channel) {
ISentryProvider sentryProvider = (ISentryProvider) ARouter.getInstance().build(RouteConsts.provider.sentry).navigation();
if (sentryProvider != null) {
sentryProvider.init(context, channel, BuildConfig.FLAVOR, BuildConfig.VERSION_NAME);
}
SentryAndroid.init(context, options -> {
// Sentry 疯狂报 ANR (很大一部分还是莫名奇妙的 ANR)严重影响到其它闪退日志的收集
// 这里将它局限到只有官网渠道的包才统计 ANR
if ("GH_206".equals(channel) || "GH_BETA".equals(channel) || com.gh.gamecenter.common.BuildConfig.BUILD_TIME != 0) {
options.setAnrEnabled(true);
options.setAnrTimeoutIntervalMillis(6000);
} else {
options.setAnrEnabled(false);
}
options.setDebug(BuildConfig.DEBUG);
options.setEnableAutoSessionTracking(true);
options.setEnvironment(BuildConfig.FLAVOR);
options.setEnableSystemEventBreadcrumbs(false);
options.setDsn("https://6b1caf0d17c1408e8680f3f73ff80bd0@sentry.shanqu.cc/22");
options.setBeforeSend((event, hint) -> {
if (BuildConfig.DEBUG) {
return null;
} else {
return event;
}
});
options.setBeforeBreadcrumb(((breadcrumb, hint) -> {
if ("ui.lifecycle".equals(breadcrumb.getCategory()) && "started".equals(breadcrumb.getData("state")) && GlobalActivityManager.INSTANCE.getCurrentActivity() instanceof BaseActivity) {
Pair<String, String> businessId = ((BaseActivity) GlobalActivityManager.INSTANCE.getCurrentActivity()).getBusinessId();
if (businessId != null) {
breadcrumb.setData("businessId1", businessId.component1());
breadcrumb.setData("businessId2", businessId.component2());
}
}
return breadcrumb;
}));
});
Sentry.configureScope(scope -> {
if (com.gh.gamecenter.common.BuildConfig.BUILD_TIME != 0L) {
scope.setTag("alias", "内测版" + BuildConfig.VERSION_NAME);
} else {
scope.setTag("alias", "正式版" + BuildConfig.VERSION_NAME);
scope.setTag("channel", channel);
}
});
}
public static void getGid() {

View File

@ -5,6 +5,7 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.common.filter.RegionSetting;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.repository.ReservationRepository;
@ -18,7 +19,6 @@ import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.SpeedUtils;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.PluginLocation;
import com.gh.gamecenter.feature.view.DownloadButton;
@ -48,6 +48,11 @@ public class DetailDownloadUtils {
GameEntity gameEntity = viewHolder.getGameEntity();
String downloadAddWord = gameEntity.getDownloadAddWord();
// 隐藏下载按钮上的畅玩文案
if (viewHolder.getOverlayTv() != null) {
viewHolder.getOverlayTv().setVisibility(View.GONE);
}
// 多版本下载箭头
if (viewHolder.getMultiVersionDownloadTv() != null) {
viewHolder.getMultiVersionDownloadTv().setVisibility(View.GONE);
@ -112,6 +117,17 @@ public class DetailDownloadUtils {
}
}
// 更新默认的下载按钮
updateWithSingleApk(
gameEntity,
viewHolder,
viewHolder.getDownloadPb(),
downloadAddWord,
showVGame,
showDualDownloadButton,
downloadEntity
);
if (showDualDownloadButton) {
// 双下载按钮时更新占位的下载按钮
updateWithSingleApk(
@ -124,17 +140,6 @@ public class DetailDownloadUtils {
downloadEntity
);
}
// 更新默认的下载按钮
updateWithSingleApk(
gameEntity,
viewHolder,
viewHolder.getDownloadPb(),
downloadAddWord,
showVGame,
showDualDownloadButton,
downloadEntity
);
} else {
// 游戏包含多 APK 的情况
viewHolder.getMultiVersionDownloadTv().setText("选择下载你的版本" + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord));
@ -187,53 +192,49 @@ public class DetailDownloadUtils {
Context context = viewHolder.getContext();
TextView overlayTv = viewHolder.getOverlayTv();
boolean containsAddWord = !TextUtils.isEmpty(downloadAddWord); // 是否存在下载补充文案
// 根据游戏实体获取下载按钮文案
String rawBtnText = GameUtils.getDownloadBtnText(context, gameEntity, false, showAsVGame, PluginLocation.only_game);
String status = GameUtils.getDownloadBtnText(context, gameEntity, false, showAsVGame, PluginLocation.only_game);
if (showAsVGame) {
// 显示为畅玩游戏
if (context.getString(R.string.launch).equals(rawBtnText)) {
if (context.getString(R.string.launch).equals(status)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
} else {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
}
String decoratedBtnText;
// 双下载按钮时,显示特殊样式
String btnText;
if (showDualDownloadButton
&& (context.getString(R.string.launch).equals(rawBtnText) || context.getString(R.string.install).equals(rawBtnText) || context.getString(R.string.smooth).equals(rawBtnText) || context.getString(R.string.update).equals(rawBtnText))) {
if (context.getString(R.string.smooth).equals(rawBtnText)) {
decoratedBtnText = context.getString(R.string.download_v);
} else if (context.getString(R.string.update).equals(rawBtnText)) {
decoratedBtnText = context.getString(R.string.update_v);
&& (context.getString(R.string.launch).equals(status) || context.getString(R.string.install).equals(status) || context.getString(R.string.smooth).equals(status) || context.getString(R.string.update).equals(status))) {
if (context.getString(R.string.smooth).equals(status)) {
btnText = context.getString(R.string.download_v);
} else if (context.getString(R.string.update).equals(status)) {
btnText = context.getString(R.string.update_v);
} else {
decoratedBtnText = context.getString(R.string.launch_v);
btnText = context.getString(R.string.launch_v);
}
if (overlayTv != null && downloadButton.getVisibility() != View.GONE) {
overlayTv.setVisibility(View.VISIBLE);
overlayTv.setText(decoratedBtnText);
overlayTv.setText(btnText);
downloadButton.setText("");
}
} else {
decoratedBtnText = rawBtnText + (containsAddWord? "" : downloadAddWord) + getWrappedDownloadSizeText(viewHolder);
btnText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : downloadAddWord) + getDownloadSizeText(viewHolder);
if (overlayTv != null && downloadButton.getVisibility() != View.GONE) {
if (context.getString(R.string.launch).equals(rawBtnText)
|| context.getString(R.string.install).equals(rawBtnText)) {
if (context.getString(R.string.launch).equals(status)
|| context.getString(R.string.install).equals(status)) {
overlayTv.setVisibility(View.VISIBLE);
overlayTv.setText("启动(畅玩)");
} else {
overlayTv.setVisibility(View.GONE);
downloadButton.setText(decoratedBtnText);
downloadButton.setText(btnText);
}
} else {
if (overlayTv != null) {
overlayTv.setVisibility(View.GONE);
}
downloadButton.setText(decoratedBtnText);
downloadButton.setText(btnText);
}
}
@ -246,11 +247,11 @@ public class DetailDownloadUtils {
}
} else {
// 非畅玩,显示为普通游戏
if (context.getString(R.string.pluggable).equals(rawBtnText)) {
if (context.getString(R.string.pluggable).equals(status)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.PLUGIN);
} else if (context.getString(R.string.launch).equals(rawBtnText)) {
} else if (context.getString(R.string.launch).equals(status)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
} else if (context.getString(R.string.install).equals(rawBtnText)) {
} else if (context.getString(R.string.install).equals(status)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_NORMAL);
} else {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
@ -270,78 +271,48 @@ public class DetailDownloadUtils {
}
}
String decoratedBtnText;
String localBtnText;
boolean useAlternativeTextStyle = false; // 是否使用带图标的文案,仅不包含补充文案时使用且
// 更新下载按钮文案
String btnText;
String extraBtnText;
if (viewHolder.isNewsDetail()) {
decoratedBtnText = rawBtnText;
localBtnText = rawBtnText;
} else if (context.getString(R.string.pluggable).equals(rawBtnText)) {
decoratedBtnText = "升级" + (!containsAddWord ? "" : "" + downloadAddWord) + getWrappedDownloadSizeText(viewHolder);
localBtnText = "升级" + (!containsAddWord ? "" : "" + downloadAddWord);
} else if (context.getString(R.string.launch).equals(rawBtnText)) {
decoratedBtnText = rawBtnText + (!containsAddWord ? "" : "-" + downloadAddWord);
localBtnText = context.getString(R.string.launch_local);
} else if (context.getString(R.string.attempt).equals(rawBtnText)) {
decoratedBtnText = context.getString(R.string.attempt);
localBtnText = rawBtnText;
btnText = status;
extraBtnText = status;
} else if (context.getString(R.string.pluggable).equals(status)) {
btnText = "升级" + (TextUtils.isEmpty(downloadAddWord) ? "" : "" + downloadAddWord) + getDownloadSizeText(viewHolder);
extraBtnText = "升级" + (TextUtils.isEmpty(downloadAddWord) ? "" : "" + downloadAddWord);
} else if (context.getString(R.string.launch).equals(status)) {
btnText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord);
extraBtnText = context.getString(R.string.launch_local);
} else if (context.getString(R.string.attempt).equals(status)) {
btnText = status + getDownloadSizeText(viewHolder);
extraBtnText = status;
if (showDualDownloadButton
&& viewHolder.getLocalDownloadContainer() != null
&& viewHolder.getLocalDownloadContainer().getVisibility() == View.VISIBLE) {
viewHolder.getLocalDownloadSizeTv().setVisibility(View.VISIBLE);
} else if (viewHolder.getOverlayTv() != null) {
useAlternativeTextStyle = true;
}
} else if (context.getString(R.string.install).equals(rawBtnText)) {
decoratedBtnText = context.getString(R.string.install);
localBtnText = context.getString(R.string.install_local);
} else if (context.getString(R.string.update).equals(rawBtnText)) {
decoratedBtnText = context.getString(R.string.update);
localBtnText = context.getString(R.string.update_local);
} else if (context.getString(R.string.install).equals(status)) {
btnText = context.getString(R.string.install);
extraBtnText = context.getString(R.string.install_local);
} else if (context.getString(R.string.update).equals(status)) {
btnText = context.getString(R.string.update);
extraBtnText = context.getString(R.string.update_local);
if (showDualDownloadButton
&& viewHolder.getLocalDownloadContainer() != null
&& viewHolder.getLocalDownloadContainer().getVisibility() == View.VISIBLE) {
viewHolder.getLocalDownloadSizeTv().setVisibility(View.VISIBLE);
}
} else {
if (containsAddWord) {
decoratedBtnText = rawBtnText + downloadAddWord + getWrappedDownloadSizeText(viewHolder);
} else {
decoratedBtnText = rawBtnText;
}
localBtnText = context.getString(R.string.download_local);
btnText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : downloadAddWord) + getDownloadSizeText(viewHolder);
extraBtnText = context.getString(R.string.download_local);
if (showDualDownloadButton
&& viewHolder.getLocalDownloadContainer() != null
&& viewHolder.getLocalDownloadContainer().getVisibility() == View.VISIBLE) {
viewHolder.getLocalDownloadSizeTv().setVisibility(View.VISIBLE);
} else if (viewHolder.getOverlayTv() != null && !containsAddWord) {
useAlternativeTextStyle = true;
}
}
if (useAlternativeTextStyle) {
downloadButton.setText("");
viewHolder.getOverlayTv().setText(decoratedBtnText);
viewHolder.getOverlayTv().setVisibility(View.VISIBLE);
viewHolder.getOverlayTv().setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_special_download, 0, 0, 0);
if (viewHolder.getExtraOverlayTv() != null) {
viewHolder.getExtraOverlayTv().setVisibility(View.VISIBLE);
viewHolder.getExtraOverlayTv().setText(gameEntity.getApk().get(0).getSize());
}
} else {
if (viewHolder.getOverlayTv() != null && !showDualDownloadButton) {
viewHolder.getOverlayTv().setVisibility(View.GONE);
if (viewHolder.getExtraOverlayTv() != null) {
viewHolder.getExtraOverlayTv().setVisibility(View.GONE);
}
}
downloadButton.setText(decoratedBtnText);
}
downloadButton.setText(btnText);
if (viewHolder.getLocalDownloadTitleTv() != null) {
viewHolder.getLocalDownloadTitleTv().setText(localBtnText);
viewHolder.getLocalDownloadTitleTv().setText(extraBtnText);
}
}
@ -378,13 +349,10 @@ public class DetailDownloadUtils {
if (overlayTv != null
&& downloadEntity.getStatus() != DownloadStatus.done) {
overlayTv.setVisibility(View.GONE);
if (viewHolder.getExtraOverlayTv() != null) {
viewHolder.getExtraOverlayTv().setVisibility(View.GONE);
}
}
if (showAsVGame) {
updateVStyleDownloadButton(viewHolder, downloadButton, downloadEntity, rawBtnText);
updateVStyleDownloadButton(viewHolder, downloadButton, downloadEntity, status);
} else {
updateDefaultStyleDownloadButton(context, viewHolder, downloadButton, gameEntity, downloadEntity);
}
@ -473,7 +441,7 @@ public class DetailDownloadUtils {
return false;
}
private static String getWrappedDownloadSizeText(DetailViewHolder viewHolder) {
private static String getDownloadSizeText(DetailViewHolder viewHolder) {
return String.format("%s", viewHolder.getGameEntity().getApk().isEmpty() ? "" : viewHolder.getGameEntity().getApk().get(0).getSize());
}
@ -484,7 +452,7 @@ public class DetailDownloadUtils {
switch (downloadEntity.getStatus()) {
case redirected:
case downloading:
downloadButton.setText(SpeedUtils.getSpeed(downloadEntity.getSpeed()));
downloadButton.setText("游戏加载中 " + downloadEntity.getPercent() + "%");
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_NORMAL);
break;
case waiting:
@ -498,13 +466,11 @@ public class DetailDownloadUtils {
case diskisfull:
case diskioerror:
case pause:
String pausedText = viewHolder.getContext().getString(R.string.paused);
downloadButton.setText(getValidProgress(downloadEntity) + "% " + pausedText);
downloadButton.setText("继续加载 " + downloadEntity.getPercent() + "%");
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_NORMAL);
break;
case done:
String updateText = viewHolder.getContext().getString(R.string.update);
if (!status.contains(updateText)) {
if (!status.contains("更新")) {
if (VHelper.isInstalled(downloadEntity.getPackageName())) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
} else {
@ -544,9 +510,8 @@ public class DetailDownloadUtils {
case diskisfull:
case diskioerror:
case overflow:
String pausedText = context.getString(R.string.paused);
String downloadingText = SpeedUtils.getSpeed(downloadEntity.getSpeed());
String resumeText = getValidProgress(downloadEntity) + "% " + pausedText;
String downloadingText = "游戏加载中 " + downloadEntity.getPercent() + "%";
String resumeText = "继续加载 " + downloadEntity.getPercent() + "%";
downloadButton.setText((downloadEntity.getStatus() == DownloadStatus.downloading || downloadEntity.getStatus() == DownloadStatus.redirected) ? downloadingText : resumeText);
if (downloadEntity.isPluggable() && PackagesManager.isInstalled(downloadEntity.getPackageName())) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN);
@ -596,10 +561,6 @@ public class DetailDownloadUtils {
}
}
public static int getValidProgress(DownloadEntity downloadEntity) {
return (int) Math.ceil(downloadEntity.getPercent());
}
private static boolean handleDownloadButtonAsXapk(DownloadEntity downloadEntity, DownloadButton downloadButton) {
String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);

View File

@ -10,7 +10,6 @@ import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureManager.log
@ -19,6 +18,8 @@ import com.gh.common.util.EntranceUtils.jumpActivity
import com.gh.common.util.EntranceUtils.jumpActivityCompat
import com.gh.gamecenter.*
import com.gh.gamecenter.amway.AmwayActivity
import com.gh.gamecenter.catalog.CatalogActivity
import com.gh.gamecenter.category.CategoryDirectoryActivity
import com.gh.gamecenter.category2.CategoryV2Activity
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.base.activity.BaseActivity_TabLayout
@ -149,12 +150,14 @@ object DirectUtils {
"qqqun",
"tag",
"all_community_article",
"category",
"block",
"column_collection",
"server",
"top_game_comment",
"wechat_bind",
"video",
"catalog",
"category_v2",
"common_collection",
"game_list",
@ -281,6 +284,10 @@ object DirectUtils {
)
)
"category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!)
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
"category_v2" -> directCategoryV2(
context,
linkEntity.link!!,
@ -348,7 +355,7 @@ object DirectUtils {
"qa", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
"qa_list" -> directToHelpAndFeedback(context, bundleOf(KEY_ENTRANCE to entrance))
"qa_list" -> directToHelpAndFeedback(context)
"qa_collection", "Q&A合集" -> directToQaCollection(
context, linkEntity.text
@ -473,7 +480,6 @@ object DirectUtils {
"column_test_v2" -> context.startActivity(
GameServerTestV2Activity.getIntent(
context,
linkEntity.link ?: "none",
entrance,
exposureEvent
)
@ -917,16 +923,12 @@ object DirectUtils {
qaContentId: String? = "",
isPlugin: Boolean = false,
isSmoothGame: Boolean = false,
gameId: String? = "",
gameName: String? = "",
entrance: String? = null
) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putBoolean(KEY_PLUGIN, isPlugin)
bundle.putBoolean(KEY_SMOOTH_GAME, isSmoothGame)
bundle.putString(KEY_GAME_ID, gameId)
bundle.putString(KEY_GAME_NAME, gameName)
if (isPlugin) {
bundle.putString(KEY_HIDE_SUGGEST_HINT, "【插件问题】")
}
@ -1415,6 +1417,47 @@ object DirectUtils {
}
}
/**
* 跳转分类
*/
@JvmStatic
fun directCategoryDirectory(
context: Context,
categoryId: String,
categoryTitle: String,
entrance: String? = null,
path: String? = ""
) {
if (categoryId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, CategoryDirectoryActivity::class.java.name)
bundle.putString(KEY_CATEGORY_ID, categoryId)
bundle.putString(KEY_CATEGORY_TITLE, categoryTitle)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_PATH, path)
jumpActivity(context, bundle)
}
/**
* 跳转新分类
*/
@JvmStatic
fun directCatalog(
context: Context,
catalogId: String,
catalogTitle: String,
entrance: String? = null,
path: String? = "",
) {
if (catalogId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, CatalogActivity::class.java.name)
bundle.putString(KEY_CATALOG_ID, catalogId)
bundle.putString(KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
jumpActivity(context, bundle)
}
/**
* 跳转新分类2.0
*/
@ -1974,9 +2017,9 @@ object DirectUtils {
val qGameProvider = ARouter
.getInstance()
.build(RouteConsts.provider.qGame)
.navigation() as? IQGameProvider
qGameProvider?.setLoginInfo(activity, userId, userName, userToken)
qGameProvider?.launchGame(activity, qqAppId) { _, _ ->
.navigation() as IQGameProvider
qGameProvider.setLoginInfo(activity, userId, userName, userToken)
qGameProvider.launchGame(activity, qqAppId) { _, _ ->
MiniGameRecentlyPlayUseCase.submitRecentPlayedQGame(qqAppId, userId)
}
}

View File

@ -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()
@ -910,7 +910,7 @@ object DownloadItemUtils {
addHandler(CheckStoragePermissionHandler())
addHandler(VersionNumberHandler())
}
.setProcessEndCallback(gameEntity.id) { _, _ ->
.setProcessEndCallback { _, _ ->
DownloadDialog.showDownloadDialog(view.context, gameEntity, traceEvent, entrance, location)
}
.buildHandlerChain()
@ -953,7 +953,7 @@ object DownloadItemUtils {
addHandler(LandPageAddressHandler())
addHandler(CheckDownloadHandler())
}
.setProcessEndCallback(gameEntity.id) { asVGame, isSubscribe ->
.setProcessEndCallback { asVGame, isSubscribe ->
download(context, gameEntity, downloadBtn, entrance, location, asVGame, isSubscribe as Boolean, traceEvent)
}
.buildHandlerChain()
@ -972,7 +972,7 @@ object DownloadItemUtils {
addHandler(OverseaDownloadHandler())
addHandler(CheckDownloadHandler())
}
.setProcessEndCallback(gameEntity.id) { asVGame, isSubscribe ->
.setProcessEndCallback { asVGame, isSubscribe ->
download(context, gameEntity, downloadBtn, entrance, location, asVGame, isSubscribe as Boolean, traceEvent)
}
.buildHandlerChain()
@ -991,7 +991,7 @@ object DownloadItemUtils {
addHandler(ValidateVSpaceHandler())
addHandler(CheckDownloadHandler())
}
.setProcessEndCallback(gameEntity.id) { asVGame, isSubscribe ->
.setProcessEndCallback { asVGame, isSubscribe ->
download(context, gameEntity, downloadBtn, entrance, location, asVGame, isSubscribe as Boolean, traceEvent)
}
.buildHandlerChain()
@ -1004,7 +1004,7 @@ object DownloadItemUtils {
addHandler(DownloadDialogHelperHandler())
addHandler(CheckDownloadHandler())
}
.setProcessEndCallback(gameEntity.id) { _, isSubscribe ->
.setProcessEndCallback { _, isSubscribe ->
plugin(context, gameEntity, downloadBtn, entrance, location, isSubscribe as Boolean, traceEvent)
}
.buildHandlerChain()
@ -1089,7 +1089,7 @@ object DownloadItemUtils {
DownloadChainBuilder()
.apply {
addHandler(LandPageAddressHandler())
}.setProcessEndCallback(gameEntity.id) { asVGame, _ ->
}.setProcessEndCallback { asVGame, _ ->
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk) {
DialogUtils.checkDownload(
context,
@ -1162,11 +1162,7 @@ object DownloadItemUtils {
isSubscribe,
traceEvent
)
if (asVGame) {
ToastUtils.toast(gameEntity.name + "已加入加载队列")
} else {
ToastUtils.toast(gameEntity.name + "已加入下载队列")
}
ToastUtils.toast(gameEntity.name + "已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({

View File

@ -69,13 +69,11 @@ object DownloadObserver {
DownloadDataHelper.uploadDownloadEvent(downloadEntity)
}
val status = downloadEntity.status
if (DownloadStatus.hijack == status) {
if (DownloadStatus.hijack == downloadEntity.status) {
// 链接被劫持
processHijack(downloadEntity)
return
} else if (DownloadStatus.notfound == status) {
} else if (DownloadStatus.notfound == downloadEntity.status) {
// 404 Not Found
// 删除任务
downloadEntity.status = DownloadStatus.cancel
@ -129,9 +127,10 @@ object DownloadObserver {
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
return
} else if (DownloadStatus.neterror == status
|| DownloadStatus.diskioerror == status
|| DownloadStatus.timeout == status
} else if (DownloadStatus.neterror == downloadEntity.status
|| DownloadStatus.timeout == downloadEntity.status
|| DownloadStatus.diskioerror == downloadEntity.status
|| DownloadStatus.diskisfull == downloadEntity.status
) {
if (mRetryableHashMap[downloadEntity.url] == true
&& NetworkUtils.isWifiConnected(HaloApp.getInstance().application)
@ -140,7 +139,9 @@ object DownloadObserver {
mRetryableHashMap[downloadEntity.url] = false
Utils.log(TAG, "下载重试->" + downloadEntity.toJson())
} else {
if (DownloadStatus.diskioerror == status) {
if (DownloadStatus.diskisfull == downloadEntity.status) {
ToastUtils.toast("磁盘已满,请清理空间后重试下载")
} else if (DownloadStatus.diskioerror == downloadEntity.status) {
ToastUtils.toast("磁盘 IO 异常,请稍后重试")
} else {
ToastUtils.toast("网络不稳定,下载任务已暂停")
@ -149,21 +150,17 @@ object DownloadObserver {
DataLogUtils.uploadNeterrorLog(mApplication, downloadEntity)
Utils.log(TAG, "下载自动暂停->" + downloadEntity.toJson())
}
} else if (DownloadStatus.diskisfull == status) {
ToastUtils.toast("磁盘已满,请清理空间后重试下载")
downloadManager.pause(downloadEntity.url)
} else if (DownloadStatus.redirected == status) {
} else if (DownloadStatus.redirected == downloadEntity.status) {
Utils.log(TAG, "重定向完毕")
DownloadDataHelper.uploadRedirectEvent(downloadEntity)
} else if (DownloadStatus.unqualified == status) {
} else if (DownloadStatus.unqualified == downloadEntity.status) {
// 未成年
RealNameHelper.showRealNameUnqualifiedDialog(downloadEntity)
// 删除任务
downloadEntity.status = DownloadStatus.cancel
downloadManager.cancel(downloadEntity.url)
} else if (DownloadStatus.unavailable == status) {
} else if (DownloadStatus.unavailable == downloadEntity.status) {
// 未接入防沉迷系统
val currentActivity = AppManager.getInstance().currentActivity()
@ -182,7 +179,7 @@ object DownloadObserver {
// 删除任务
downloadEntity.status = DownloadStatus.cancel
downloadManager.cancel(downloadEntity.url)
} else if (DownloadStatus.isCertificating == status) {
} else if (DownloadStatus.isCertificating == downloadEntity.status) {
// 未接入防沉迷系统
val currentActivity = AppManager.getInstance().currentActivity()
@ -210,21 +207,21 @@ object DownloadObserver {
// 删除任务
downloadEntity.status = DownloadStatus.cancel
downloadManager.cancel(downloadEntity.url)
} else if (DownloadStatus.uncertificated == status) {
} else if (DownloadStatus.uncertificated == downloadEntity.status) {
// 未实名
RealNameHelper.showRealNameUncertificatedDialog(downloadEntity)
// 删除任务
downloadEntity.status = DownloadStatus.cancel
downloadManager.cancel(downloadEntity.url)
} else if (DownloadStatus.banned == status) {
} else if (DownloadStatus.banned == downloadEntity.status) {
ToastUtils.showToast("网络异常")
// 删除任务
downloadEntity.status = DownloadStatus.cancel
downloadManager.cancel(downloadEntity.url)
}
if (DownloadStatus.done == status) {
if (DownloadStatus.done == downloadEntity.status) {
if (mDoneDebouncePair?.first != downloadEntity.url) {
mDoneDebouncePair = Pair(downloadEntity.url, System.currentTimeMillis())
performDownloadCompleteAction(downloadEntity, downloadManager)
@ -244,7 +241,7 @@ object DownloadObserver {
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
// 如果已下载大小发生变化,表示成功恢复下载,则重置重试标记
if (status == DownloadStatus.downloading) {
if (downloadEntity.status == DownloadStatus.downloading) {
mRetryableHashMap[downloadEntity.url] = true
}
}
@ -502,7 +499,7 @@ object DownloadObserver {
"game_name", downloadEntity.name,
"game_id", downloadEntity.gameId,
"game_type", downloadEntity.categoryChinese,
"game_schema_type", if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
"game_schema_type", if (downloadEntity.getMetaExtra(VHelper.KEY_BIT) == "32") "32位" else "64位",
*kvs
)
} else if (downloadEntity.gameId == Constants.HALO_FUN_GAME_ID) {
@ -537,7 +534,7 @@ object DownloadObserver {
"game_name", downloadEntity.meta[Constants.GAME_NAME] ?: "",
"game_type", downloadEntity.meta[Constants.GAME_CATEGORY_IN_CHINESE] ?: "",
"game_label", downloadEntity.tags.joinToString(","),
"game_schema_type", if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
"game_schema_type", if (downloadEntity.getMetaExtra(VHelper.KEY_BIT) == "32") "32位" else "64位",
"page_name", getCurrentPageEntity().pageName,
"page_id", getCurrentPageEntity().pageId,
"page_business_id", getCurrentPageEntity().pageBusinessId,

View File

@ -27,6 +27,7 @@ import com.gh.gamecenter.core.utils.ClassUtils;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.SPUtils;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.AppManager;
import com.lightgame.utils.Utils;
import org.json.JSONException;
@ -37,18 +38,7 @@ import java.util.Set;
public class EntranceUtils {
public static void jumpActivity(Context context, Bundle bundle) {
jumpActivityCompat(context, bundle, null, null);
}
public static void jumpActivityCompat(Context context, Bundle bundle) {
jumpActivityCompat(context, bundle, null,null);
}
public static void jumpActivityCompat(Context context,
Bundle bundle,
@Nullable Bundle nextToBundle,
@Nullable Callback callback) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
if (HaloApp.getInstance().isRunningForeground || HaloApp.getInstance().isAlreadyUpAndRunning) {
@ -58,18 +48,6 @@ public class EntranceUtils {
if (clazz == null) clazz = MainActivity.class;
if (ToolbarFragment.class.isAssignableFrom(clazz)) { // 兼容ToolbarFragment
ToolBarActivity.startFragmentNewTask(context, (Class<? extends ToolbarFragment>) clazz, bundle);
} else if (callback != null ) {
Intent intent1 = new Intent(context, clazz);
//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);
}
} else {
Intent intent1 = new Intent(context, clazz);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@ -80,6 +58,57 @@ public class EntranceUtils {
intent1.putExtras(bundle);
context.startActivity(intent1);
}
} else {
// 应用未在运行
context.startActivity(SplashScreenActivity.getSplashScreenIntent(context, bundle));
}
}
public static void jumpActivity(Context context, Bundle bundle) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
if (AppManager.getInstance().findActivity(MainActivity.class) != null) {
// 应用正在运行前台或后台且MainActivity在栈中
String to = bundle.getString(KEY_TO);
Class<?> clazz = ClassUtils.forName(to);
if (clazz == null) clazz = MainActivity.class;
if (ToolbarFragment.class.isAssignableFrom(clazz)) { // 兼容ToolbarFragment
ToolBarActivity.startFragmentNewTask(context, (Class<? extends ToolbarFragment>) clazz, bundle);
} else {
Intent intent1 = new Intent(context, clazz);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 如果 activity 名称有 singleton 的就添加 reorder_to_front 标签 (有点粗暴有点蠢,但暂时就先这样吧 :C )
if (clazz.getSimpleName().toLowerCase().contains("singleton")) {
intent1.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
}
intent1.putExtras(bundle);
context.startActivity(intent1);
}
} else {
// 应用未在运行
context.startActivity(SplashScreenActivity.getSplashScreenIntent(context, bundle));
}
}
public static void jumpActivity(Context context, Bundle nextToBundle, Bundle bundle, Callback callback) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
if (AppManager.getInstance().findActivity(MainActivity.class) != null) {
// 应用正在运行前台或后台且MainActivity在栈中
String to = bundle.getString(KEY_TO);
Class<?> clazz = ClassUtils.forName(to);
if (clazz == null) clazz = MainActivity.class;
if (ToolbarFragment.class.isAssignableFrom(clazz)) { // 兼容ToolbarFragment
ToolBarActivity.startFragmentNewTask(context, (Class<? extends ToolbarFragment>) clazz, bundle);
} else {
Intent intent1 = new Intent(context, clazz);
//TODO:添加FLAG_ACTIVITY_NEW_TASK会导致一跳转页面callback就被调用
//intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent1.putExtras(bundle);
AvoidOnResultManager.Companion.getInstance((AppCompatActivity) context)
.startForResult(intent1, callback);
}
} else {
// 应用未在运行
if (nextToBundle != null) {

View File

@ -7,7 +7,6 @@ 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
@ -112,14 +111,6 @@ object GameSubstituteRepositoryHelper {
}
}
// 检查是否已安装该游戏 id
if (PackagesManager.getInstalledDataByGameId(game.id) != null) {
// 将该位置的游戏标记为需要替换
positionOfGameToBeReplacedList.add(index)
thisPositionNeedToBeReplaced = true
break
}
// 若此游戏所包含的 apk 没有已安装,那么再检查是否已安装有预设相关包名
if (!thisPositionNeedToBeReplaced) {
var relatedPackageList = arrayListOf<String>()

View File

@ -308,7 +308,7 @@ object GameUtils {
}
/**
* 是否默认以畅玩游戏的形式来处理
* 是否以畅玩游戏的形式来处理
*/
@JvmStatic
fun shouldPerformAsVGame(gameEntity: GameEntity): Boolean {

View File

@ -49,8 +49,13 @@ public class InstallUtils {
@Override
public void handleMessage(Message msg) {
if (msg.what == INSTALL_WHAT && packageManager != null) {
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
ArrayList<String> list = new ArrayList<>(packageNameList);
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
list.add(packageInfo.packageName);
}
}
if (installMap != null && installMap.size() != 0) {
ArrayList<String> keys = new ArrayList<>();
for (String packageName : installMap.keySet()) {

View File

@ -768,10 +768,10 @@ public class LibaoUtils {
}
public static boolean isAppInstalled(Context context, String packageName) {
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
if (packageNameList != null) {
for (int i = 0; i < packageNameList.size(); i++) {
String pn = packageNameList.get(i);
List<PackageInfo> pinfo = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
if (pn.equals(packageName)) {
return true;
}

View File

@ -734,6 +734,18 @@ public class LogUtils {
LoghubUtils.log(object, LOG_STORE_EVENT, false);
}
public static void logNewCatalogAppearanceEvent(String entrance, String key) {
logCatalogEvent("access_to_classification", entrance, key, -1, -1, -1, -1);
}
public static void logSubCatalogClickEvent(String entrance, String key, int seq1) {
logCatalogEvent("click_first_classification", entrance, key, seq1, -1, -1, -1);
}
public static void logSubCatalogContentClickEvent(String entrance, String key, int seq1, int seq2) {
logCatalogEvent("click_secondary_classification", entrance, key, seq1, seq2, -1, -1);
}
public static void logSpecialCatalogContentClickEvent(String entrance, String key, int seq1, int seqContent) {
logCatalogEvent("click_content", entrance, key, seq1, -1, seqContent, -1);
}

View File

@ -30,9 +30,6 @@ object NewFlatLogUtils {
private const val EVENT_LOGIN_FROM_GHZS_SHOW = "halo_fun_login_from_ghzs_show"
private const val EVENT_LOGIN_FROM_GHZS_CLICK = "halo_fun_login_from_ghzs_click"
private const val EVENT_INSTALLED_LAUNCH_DIALOG_SHOW = "halo_fun_installed_launch_dialog_show"
private const val EVENT_INSTALLED_LAUNCH_DIALOG_CLICK = "halo_fun_installed_launch_dialog_click"
private fun log(jsonObject: JSONObject, logStore: String = "event", uploadImmediately: Boolean = false) {
Utils.log("NewFlatLogUtils", jsonObject.toString(4))
LoghubUtils.log(jsonObject, logStore, uploadImmediately, true)
@ -553,8 +550,6 @@ object NewFlatLogUtils {
// 搜索-点击搜索榜单内容
@JvmStatic
fun logSearchClickRankDetail(
key: String,
rankType: String,
rankName: String,
rankSequence: String,
linkId: String,
@ -563,8 +558,6 @@ object NewFlatLogUtils {
) {
val json = json {
KEY_EVENT to "search_click_rank_detail"
"key" to key
"rank_type" to rankType
"rank_name" to rankName
"rank_sequence" to rankSequence
"link_id" to linkId
@ -2695,73 +2688,4 @@ object NewFlatLogUtils {
parseAndPutMeta()(this)
}.let(::log)
}
fun logHaloFunInstalledLaunchDialogShow() {
json {
KEY_EVENT to EVENT_INSTALLED_LAUNCH_DIALOG_SHOW
parseAndPutMeta()(this)
}.let(::log)
}
fun logHaloFunInstalledLaunchDialogClick(
gameId: String,
gameName: String,
buttonType: String
) {
json {
KEY_EVENT to EVENT_INSTALLED_LAUNCH_DIALOG_CLICK
"game_id" to gameId
"game_name" to gameName
"button_type" to buttonType
parseAndPutMeta()(this)
}.let(::log)
}
// 用户访问分流器
fun logByPassBrowsing(
source: String,
bypassName: String,
bypassId: String,
branchId: String,
branchName: String,
inProcessTime: Int,
bypassVisitTime: Int,
linkType: String,
linkId: String,
linkText: String,
bypassStatus: Int
) {
json {
KEY_EVENT to "BypassBrowsing"
"source" to source
"bypass_name" to bypassName
"bypass_id" to bypassId
"branch_id" to branchId
"branch_name" to branchName
"inprocess_time" to inProcessTime
"bypass_visit_time" to bypassVisitTime
"link_type" to linkType
"link_id" to linkId
"link_text" to linkText
"bypass_status" to bypassStatus
parseAndPutMeta()(this)
}.let(::log)
}
// 分流失败
fun logFailByPass(
source: String,
bypassName: String,
bypassId: String,
defeatedReason: String
) {
json {
KEY_EVENT to "FailBypass"
"source" to source
"bypass_name" to bypassName
"bypass_id" to bypassId
"defeated_reason" to defeatedReason
parseAndPutMeta()(this)
}.let(::log)
}
}

View File

@ -4,18 +4,12 @@ import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.gh.download.DownloadManager
import com.gh.download.PackageObserver
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.hud.HeadUpDisplayHelper
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.R
import com.gh.gamecenter.hud.HeadUpDisplayLogHelper
import com.lightgame.utils.Utils
import org.greenrobot.eventbus.EventBus
@ -28,10 +22,8 @@ object PackageChangeHelper : DefaultLifecycleObserver {
private const val UPDATE_PENDING = 3
// <包名pending 类型,应用版本> Triple
private var pendingPackageTriple: Triple<String, Int, String>? = null
private var pendingGhId: String? = null
private var pendingHUDShowed: Boolean = false
private var pendingPackagePair: Triple<String, Int, String>? = null
private var pendingGhId: String ? = null
/**
* 添加一个等待中,待确定是否已成功安装的应用
@ -41,9 +33,7 @@ object PackageChangeHelper : DefaultLifecycleObserver {
if (installData == null) {
Utils.log(TAG, "添加了: $packageName 包名等待安装成功")
pendingHUDShowed = false
pendingPackageTriple = Triple(packageName, INSTALL_PENDING, "")
pendingPackagePair = Triple(packageName, INSTALL_PENDING, "")
} else {
Utils.log(TAG, "添加了: $packageName 包名等待安装更新成功")
@ -54,58 +44,44 @@ object PackageChangeHelper : DefaultLifecycleObserver {
pendingGhId = ghId.toString()
}
pendingHUDShowed = false
pendingPackageTriple = Triple(packageName, UPDATE_PENDING, installData.version)
pendingPackagePair = Triple(packageName, UPDATE_PENDING, installData.version)
}
}
fun isInstallPendingPackage(packageName: String): Boolean {
return pendingPackageTriple?.first == packageName
}
/**
* 添加一个等待中,待确定是否已成功卸载的应用
*/
fun addUninstallPendingPackage(packageName: String) {
Utils.log(TAG, "添加了: $packageName 包名等待卸载成功")
pendingPackageTriple = Triple(packageName, UNINSTALL_PENDING, "")
pendingPackagePair = Triple(packageName, UNINSTALL_PENDING, "")
}
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
if (pendingPackageTriple != null) {
val packageName = pendingPackageTriple?.first ?: return
val isInstallPending = pendingPackageTriple?.second == INSTALL_PENDING
val isUninstallPending = pendingPackageTriple?.second == UNINSTALL_PENDING
val isUpdatePending = pendingPackageTriple?.second == UPDATE_PENDING
if (pendingPackagePair != null) {
val packageName = pendingPackagePair?.first ?: return
val isInstallPending = pendingPackagePair?.second == INSTALL_PENDING
val isUninstallPending = pendingPackagePair?.second == UNINSTALL_PENDING
val isUpdatePending = pendingPackagePair?.second == UPDATE_PENDING
val pendingVersion = pendingPackageTriple?.third ?: ""
val pendingVersion = pendingPackagePair?.third ?: ""
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
val isInstalled = installedVersionName != null
if (isInstallPending) {
if (isInstalled) {
pendingPackageTriple = null
pendingGhId = null
if (isInstallPending && isInstalled) {
pendingPackagePair = null
pendingGhId = null
PackageRepository.addInstalledGame(PackageRepository.packageFilterManager, packageName)
PackageRepository.addInstalledGame(packageName)
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
performInstallSuccessAction(packageName)
} else {
// 任务不存在了,将等待更新安装结果的 triple 置为 null
if (DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) == null) {
pendingPackageTriple = null
} else {
showHUDIfNeeded(packageName)
}
}
performInstallSuccessAction(packageName)
} else if (isUninstallPending && !isInstalled) {
pendingPackageTriple = null
pendingPackagePair = null
pendingGhId = null
// 从额外的包名白名单移除,下次启动时不再查询此包的安装情况
@ -119,19 +95,12 @@ object PackageChangeHelper : DefaultLifecycleObserver {
!pendingGhId.isNullOrEmpty() && pendingGhId != PackageUtils.getGhId(packageName).toString()
}
pendingPackageTriple = null
pendingPackagePair = null
pendingGhId = null
if (isUpdateValid) {
performUninstallSuccessAction(packageName)
performInstallSuccessAction(packageName)
} else {
// 任务不存在了,将等待更新安装结果的 triple 置为 null
if (DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) == null) {
pendingPackageTriple = null
} else {
showHUDIfNeeded(packageName)
}
}
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
@ -140,27 +109,6 @@ object PackageChangeHelper : DefaultLifecycleObserver {
}
}
private fun showHUDIfNeeded(packageName: String) {
if (pendingHUDShowed) return
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) ?: return
val activity = CurrentActivityHolder.getCurrentActivity() ?: return
if (activity is DownloadManagerActivity) return
pendingHUDShowed = true
HeadUpDisplayHelper.showHUD(activity,
downloadEntity.icon ?: "",
activity.getString(R.string.hud_has_pending_install_game),
activity.getString(R.string.hud_head_to_download_manager),
showingCallback = {
HeadUpDisplayLogHelper.trackInstallationShow(downloadEntity, "游戏下载")
},
clickedCallback = {
DirectUtils.directToDownloadManager(activity, "HUD")
HeadUpDisplayLogHelper.trackInstallationClick(downloadEntity, "游戏下载")
})
}
/**
* 对外暴露的方法,用于添加一个安装成功的应用
* @param packageName 包名
@ -186,11 +134,9 @@ object PackageChangeHelper : DefaultLifecycleObserver {
* @param cachedGameEntity 缓存的 GameEntity用于快速更新状态
* @param withLog 是否需要记录日志
*/
private fun performInstallSuccessAction(
packageName: String,
cachedGameEntity: GameEntity? = null,
withLog: Boolean = true
) {
private fun performInstallSuccessAction(packageName: String,
cachedGameEntity: GameEntity? = null,
withLog: Boolean = true) {
Utils.log(TAG, "安装了: $packageName 包名的程序")
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName)
val gameId = if (downloadEntity != null && downloadEntity.gameId != null) downloadEntity.gameId else ""

View File

@ -2,11 +2,11 @@ package com.gh.common.util
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PermissionInfo
import android.os.Build
import android.os.Process
import android.provider.Settings
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LiveData
@ -24,7 +24,6 @@ import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.WhitePackageListEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.feature.utils.SentryHelper
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.retrofit.RetrofitManager
@ -43,14 +42,11 @@ object PackageHelper {
private const val SP_GET_INSTALLED_PACKAGES_AGREED = "get_installed_packages_agreed" // 用户是否同意使用已安装应用列表 API
private const val SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API =
"get_installed_packages_by_alternative_api" // 是否使用另类方式获取已安装应用列表
private const val SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API = "get_installed_packages_by_alternative_api" // 是否使用另类方式获取已安装应用列表
private const val SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE =
"user_used_get_installed_api_switch_package" // 用户是否使用过含有已安装应用列表获取开关的包
private const val SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE = "user_used_get_installed_api_switch_package" // 用户是否使用过含有已安装应用列表获取开关的包
private const val SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST =
"additional_whitelist_package_name_list" // 额外的白名单包名列表 (曾经更正为已安装的包名列表)
private const val SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST = "additional_whitelist_package_name_list" // 额外的白名单包名列表 (曾经更正为已安装的包名列表)
private const val UNKNOWN = -1
private const val UNSUPPORTED = 0
@ -60,8 +56,7 @@ object PackageHelper {
private const val DISABLED = 3
private var lastSuccessfullyGetInstalledPackagesTimeMills = 0L
private var cachedInstalledPackageInfoList: List<PackageInfo> = arrayListOf() // 缓存的已安装应用列表
private var cachedInstalledPackageNameList: List<String> = arrayListOf() // 缓存的已安装应用包名列表
private var cachedInstalledPackagesList: List<PackageInfo> = arrayListOf()
private var additionalWhiteListPackageNameSet: HashSet<String> = hashSetOf()
private var isGetInstalledPackagesAgreed = false // 用户是否已经同意使用已安装应用列表
@ -74,35 +69,25 @@ object PackageHelper {
private val packageExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_PACKAGE_THREAD")) }
private var uploadUIDGapLog = true
// 光环运行的环境是否为默认的 UID (0)
private val isRunningOnDefaultUid by lazy { Process.myUid() / 100000 == 0 }
// 评论黑名单包名列表,避免用户安装了 Xposed Installer 这样的工具,也能在包含该安装包的游戏详情页评论
private var _commentPackageNameBlackList = arrayListOf<String>()
val commentPackageNameBlackList: ArrayList<String>
get() = _commentPackageNameBlackList
val commentPackageNameBlackList: ArrayList<String> = _commentPackageNameBlackList
// 关闭下载的包列表
private var _downloadPackageNameBlackList = arrayListOf<String>()
val downloadPackageNameBlackList: ArrayList<String>
get() = _downloadPackageNameBlackList
val downloadPackageNameBlackList: ArrayList<String> = _downloadPackageNameBlackList
// 本地已安装的包去掉关闭下载的包后的列表
private var _validLocalPackageNameSet = hashSetOf<String>()
val validLocalPackageNameSet: HashSet<String>
get() = _validLocalPackageNameSet
val validLocalPackageNameSet: HashSet<String> = _validLocalPackageNameSet
// 游戏包名匹配列表
private var _relatedPackageList = arrayListOf<SettingsEntity.GameWithPackages>()
val relatedPackageList: ArrayList<SettingsEntity.GameWithPackages>
get() = _relatedPackageList
val relatedPackageList: ArrayList<SettingsEntity.GameWithPackages> = _relatedPackageList
// 接口控制的已安装应用列表获取开关状态 (UI 显示)
private var _installedPackageApiSwitchStatusLiveData = MutableLiveData<Boolean>()
val installedPackageApiSwitchStatusLiveData: LiveData<Boolean>
get() = _installedPackageApiSwitchStatusLiveData
val installedPackageApiSwitchStatusLiveData: LiveData<Boolean> = _installedPackageApiSwitchStatusLiveData
// 本地已安装包的列表
var localPackageNameSet = hashSetOf<String>()
@ -120,22 +105,17 @@ object PackageHelper {
* 用于覆盖安装首次启动时的检查 https://jira.shanqu.cc/browse/GHZSCY-5694
*/
fun checkIfGetInstalledApiSwitchShouldBeIgnored(context: Context) {
val userHasUsedGetInstalledApiSwitchPackage =
SPUtils.getBoolean(SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE, false)
val userHasUsedGetInstalledApiSwitchPackage = SPUtils.getBoolean(SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE, false)
if (!userHasUsedGetInstalledApiSwitchPackage) {
val isSupportGetInstalledAppsPermission = isSupportGetInstalledAppsPermission(context)
if (!isSupportGetInstalledAppsPermission) {
if (isRunningOnDefaultUid) {
// 设备不支持动态管理获取已安装应用列表,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
}
// 设备不支持动态管理获取已安装应用列表,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
onGetInstalledPackagesAgreed()
} else if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
if (isRunningOnDefaultUid) {
// 设备支持动态管理获取已安装应用列表但已经授权,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
}
// 设备支持动态管理获取已安装应用列表但已经授权,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
onGetInstalledPackagesAgreed()
}
@ -202,10 +182,12 @@ object PackageHelper {
private fun getAllPackageName(context: Context): HashSet<String> {
val set = HashSet<String>()
return try {
val packageNameList = getInstalledPackageNameList(context, 0)
for (packageName in packageNameList) {
if (context.packageName != packageName) {
set.add(packageName)
val packageInfos = getInstalledPackages(context, 0)
for (packageInfo in packageInfos) {
if (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0) {
if (context.packageName != packageInfo.packageName) {
set.add(packageInfo.packageName)
}
}
}
set
@ -258,8 +240,7 @@ object PackageHelper {
if (isEnabled) {
Utils.log(TAG, "开启获取已安装应用列表限制")
additionalWhiteListPackageNameSet =
SPUtils.getString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST).toObject() ?: hashSetOf()
additionalWhiteListPackageNameSet = SPUtils.getString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST).toObject() ?: hashSetOf()
Utils.log(TAG, "额外的白名单为 $additionalWhiteListPackageNameSet")
@ -271,10 +252,8 @@ object PackageHelper {
isGetInstalledPackagesAgreedRequired = DISABLED
if (isRunningOnDefaultUid) {
// 启用另类获取已安装应用列表的 API
updateUseAlternativeWayToGetInstalledPackages()
}
// 启用另类获取已安装应用列表的 API
updateUseAlternativeWayToGetInstalledPackages()
onGetInstalledPackagesAgreed()
}
@ -290,12 +269,12 @@ object PackageHelper {
}
/**
* 用户是否已经使用另类方式获取已安装应用列表
* 用户是否已经允许了调用获取已安装应用列表接口
* 优先用内存的值,没有再从 SP 中获取并更新
*/
private fun isUseAlternativeWayToGetInstalledPackages(): Boolean {
return useAlternativeWayToGetInstalledPackages
|| (SPUtils.getBoolean(SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API)
.also { useAlternativeWayToGetInstalledPackages = it })
|| (SPUtils.getBoolean(SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API).also { useAlternativeWayToGetInstalledPackages = it })
}
private fun updateUseAlternativeWayToGetInstalledPackages() {
@ -311,37 +290,20 @@ object PackageHelper {
/**
* 获取已安装应用列表
*/
fun getInstalledPackageInfoList(context: Context?, flags: Int): List<PackageInfo> {
return getInstalledListInternal(context, flags, false).first
}
/**
* 获取已安装应用包名列表
*/
fun getInstalledPackageNameList(context: Context?, flags: Int): List<String> {
return getInstalledListInternal(context, flags, true).second
}
private fun getInstalledListInternal(context: Context?,
flags: Int,
packageNameOnly: Boolean): Pair<List<PackageInfo>, List<String>> {
Utils.log(TAG, "即将获取已安装应用列表,仅获取包名 $packageNameOnly")
fun getInstalledPackages(context: Context?, flags: Int): List<PackageInfo> {
Utils.log(TAG, "即将获取已安装应用列表")
// 用户未同意使用已安装应用列表 API返回空列表
if (!isGetInstalledPackagesAgreed()) {
Utils.log(TAG, "用户未同意使用已安装应用列表 API返回空列表")
return Pair(cachedInstalledPackageInfoList, cachedInstalledPackageNameList)
return cachedInstalledPackagesList
}
// 简单 debounce 过于频繁的获取已安装应用列表调用
if (System.currentTimeMillis() - lastSuccessfullyGetInstalledPackagesTimeMills < 20 * 1000) {
// 时间间隔合适且对应的列表不为空,直接返回对应的缓存列表数据
if ((packageNameOnly && cachedInstalledPackageNameList.isNotEmpty())
|| (!packageNameOnly && cachedInstalledPackageInfoList.isNotEmpty())
) {
Utils.log(TAG, "使用了缓存的已安装应用列表")
return Pair(cachedInstalledPackageInfoList, cachedInstalledPackageNameList)
}
if (System.currentTimeMillis() - lastSuccessfullyGetInstalledPackagesTimeMills < 20 * 1000
&& cachedInstalledPackagesList.isNotEmpty()) {
Utils.log(TAG, "使用了缓存的已安装应用列表")
return cachedInstalledPackagesList
}
var shouldGetNewInstalledPackagedList = false
@ -363,17 +325,12 @@ object PackageHelper {
if (shouldGetNewInstalledPackagedList) {
lastSuccessfullyGetInstalledPackagesTimeMills = System.currentTimeMillis()
cachedInstalledPackagesList = getInstalledPackagesInternal(context, flags)
if (packageNameOnly) {
cachedInstalledPackageNameList = getInstalledPackageNameListInternal(context, flags)
Utils.log(TAG, "获取已安装应用列表成功,数量为 ${cachedInstalledPackageNameList.size}")
} else {
cachedInstalledPackageInfoList = getInstalledPackageInfoListInternal(context, flags)
Utils.log(TAG, "获取已安装应用列表成功,数量为 ${cachedInstalledPackageInfoList.size}")
}
Utils.log(TAG, "获取已安装应用列表成功,数量为 ${cachedInstalledPackagesList.size}")
}
return Pair(cachedInstalledPackageInfoList, cachedInstalledPackageNameList)
return cachedInstalledPackagesList
}
/**
@ -546,7 +503,6 @@ object PackageHelper {
Utils.log(TAG, "addInstalledButMissingPackages 需要请求接口获取的包数量为 ${installedPackageNameSet.size}")
PackageRepository.addInstalledGames(
packageFilterManager = PackageRepository.packageFilterManager,
pkgNameList = ArrayList(installedPackageNameSet),
updateInstallStatus = true
)
@ -564,10 +520,7 @@ object PackageHelper {
additionalWhiteListPackageNameSet.remove(packageName)
}
Utils.log(
TAG,
"updateAdditionalWhiteListPackageName 更新额外的白名单包名列表 $isAdd $packageName ,结果是 $isUpdated"
)
Utils.log(TAG, "updateAdditionalWhiteListPackageName 更新额外的白名单包名列表 $isAdd $packageName ,结果是 $isUpdated")
if (isUpdated) {
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toJson())
@ -588,25 +541,17 @@ object PackageHelper {
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
if (PackagesManager.isInstalled(packageName)
&& installedVersionName == null
) {
&& installedVersionName == null) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName != null
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
) {
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)) {
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
}
}
Utils.log(
TAG,
"refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(TAG, "refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}")
Utils.log(TAG, "refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}")
runOnUiThread {
if (uninstalledButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
@ -615,10 +560,7 @@ object PackageHelper {
additionalWhiteListPackageNameSet.remove(packageName)
}
SPUtils.setString(
SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST,
additionalWhiteListPackageNameSet.toString()
)
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toString())
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
@ -666,18 +608,9 @@ object PackageHelper {
}
}
Utils.log(
TAG,
"refreshWrongInstallStatus 需要更新已安装状态的包数量为 ${installedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(TAG, "refreshWrongInstallStatus 需要更新已安装状态的包数量为 ${installedButKeepingWrongStatusPackageNameSet.size}")
Utils.log(TAG, "refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}")
Utils.log(TAG, "refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}")
runOnUiThread {
if (installedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
@ -686,10 +619,7 @@ object PackageHelper {
additionalWhiteListPackageNameSet.add(packageName)
}
SPUtils.setString(
SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST,
additionalWhiteListPackageNameSet.toString()
)
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toString())
}
if (uninstalledButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
@ -698,10 +628,7 @@ object PackageHelper {
additionalWhiteListPackageNameSet.remove(packageName)
}
SPUtils.setString(
SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST,
additionalWhiteListPackageNameSet.toString()
)
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toString())
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
@ -713,7 +640,7 @@ object PackageHelper {
}
}
private fun getInstalledPackageInfoListInternal(
private fun getInstalledPackagesInternal(
context: Context,
flags: Int
): List<PackageInfo> {
@ -726,26 +653,6 @@ object PackageHelper {
}
}
private fun getInstalledPackageNameListInternal(
context: Context,
flags: Int
): List<String> {
if (isUseAlternativeWayToGetInstalledPackages()) {
Utils.log(TAG, "调用另类系统 API 获取已安装应用包名列表")
return getInstalledPackageNameByAlternative(context)
} else {
Utils.log(TAG, "调用默认系统 API 获取已安装应用包名列表")
val packageInfoList = getInstalledPackageByDefault(context, flags)
val packageList = arrayListOf<String>()
for (packageInfo in packageInfoList) {
if (context.packageName != packageInfo.packageName) {
packageList.add(packageInfo.packageName)
}
}
return packageList
}
}
private fun getInstalledPackageByDefault(context: Context, flags: Int): List<PackageInfo> {
val pm = context.packageManager
try {
@ -789,39 +696,4 @@ object PackageHelper {
return packageList
}
private fun getInstalledPackageNameByAlternative(context: Context): ArrayList<String> {
val packageManager = context.getPackageManager()
val packageList = arrayListOf<String>()
var packagesArray: Array<String>? = null
var uid = android.os.Process.FIRST_APPLICATION_UID
var lastValidUid = 0
while (uid <= android.os.Process.LAST_APPLICATION_UID) {
try {
packagesArray = packageManager.getPackagesForUid(uid)
if (packagesArray != null && packagesArray.isNotEmpty()) {
lastValidUid = uid
for (packageName in packagesArray) {
packageList.add(packageName)
}
}
} catch (securityException: SecurityException) {
securityException.printStackTrace()
}
uid++
}
if (HaloApp.getInstance().isNewForThisVersion && uploadUIDGapLog) {
// 仅应用该版本第一次启动的第一次方法调用上报日志
uploadUIDGapLog = false
val uidGap = (android.os.Process.LAST_APPLICATION_UID - lastValidUid) / 100 * 100
SentryHelper.onEvent("UID_GAP", "gap", uidGap.toString())
}
return packageList
}
}

View File

@ -22,15 +22,12 @@ import com.gh.gamecenter.install.InstallService
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
import java.io.File
// TODO 将弹窗改成以责任链模式来处理
object PackageInstaller {
private val listeners = mutableListOf<OnInstallListener>()
/**
* 为了兼容java代码
*/
@ -61,7 +58,7 @@ object PackageInstaller {
val isDownloadAsVGame = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.VGAME
|| downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.DUAL_DOWNLOAD_VGAME
val currentActivity = AppManager.getInstance().currentActivity() ?: return
val currentActivity = CurrentActivityHolder.getCurrentActivity() ?: return
if (!ignoreAsVGame && isDownloadAsVGame) {
VHelper.install(currentActivity, downloadEntity)
@ -129,7 +126,6 @@ object PackageInstaller {
installWithPureModeHandled(
context,
pkgPath,
downloadEntity?.packageName,
downloadEntity?.gameId ?: "unknown",
downloadEntity?.name ?: "unknown",
downloadEntity?.categoryChinese ?: "unknown"
@ -169,20 +165,19 @@ object PackageInstaller {
private fun installWithPureModeHandled(
context: Context,
pkgPath: String,
pkgName: String?,
gameId: String,
gameName: String,
gameType: String,
) {
PureModeHelper.handlePureModeIfNeeded(context, gameId, gameName, gameType) {
install(context, pkgPath, pkgName)
install(context, pkgPath)
}
}
/**
* 最终执行安装的方法
*/
private fun install(context: Context, pkgPath: String, pkgName: String?) {
private fun install(context: Context, pkgPath: String) {
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU && Build.MANUFACTURER.lowercase().contains("xiaomi")) {
@ -193,13 +188,10 @@ object PackageInstaller {
val installIntent = getInstallIntent(context, pkgPath)
context.startActivity(installIntent)
dispatchOnInstallListener(pkgPath, pkgName)
}
fun installMultiple(
context: Context,
pkgName: String,
pkgPath: String,
sessionId: Int = -1
) {
@ -222,24 +214,6 @@ object PackageInstaller {
val pendingIntent = PendingIntent.getActivity(context, sessionId, intent, flags)
// 提交数据流并执行安装
session.commit(pendingIntent.intentSender)
dispatchOnInstallListener(pkgName, pkgPath)
}
fun registerOnInstallListener(listener: OnInstallListener) {
if (!listeners.contains(listener)) {
listeners.add(listener)
}
}
fun unregisterOnInstallListener(listener: OnInstallListener) {
listeners.remove(listener)
}
private fun dispatchOnInstallListener(pkgPath: String, pkgName: String?) {
for (listener in listeners) {
listener.onInstalling(pkgName, pkgPath)
}
}
/**
@ -331,8 +305,4 @@ object PackageInstaller {
return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis())
}
interface OnInstallListener {
fun onInstalling(packageName: String?, packagePath: String)
}
}

View File

@ -14,7 +14,6 @@ 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;
@ -29,10 +28,10 @@ import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.core.utils.MD5Utils;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.feature.utils.SentryHelper;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.vspace.VHelper;
import com.gh.vspace.db.VGameEntity;
@ -223,19 +222,8 @@ public class PackageUtils {
if (metaDate != null) {
return metaDate.get(name);
}
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_META_DATA_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
} catch (NameNotFoundException e) {
// e.printStackTrace();
}
return null;
}
@ -639,19 +627,8 @@ public class PackageUtils {
try {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName;
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_VERSION_NAME_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
} catch (NameNotFoundException e) {
// do nothing
}
return null;
}
@ -663,18 +640,8 @@ public class PackageUtils {
try {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionCode;
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_VERSION_CODE_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
} catch (NameNotFoundException e) {
// do nothing
}
return 0;
}
@ -687,49 +654,71 @@ public class PackageUtils {
try {
PackageManager packageManager = context.getApplicationContext().getPackageManager();
return packageManager.getApplicationIcon(packageName);
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_ICON_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
} catch (NameNotFoundException e) {
// do nothing
}
return null;
}
/*
* 获取所有已安装的软件的包名(包括系统应用
* 获取所有已安装的软件的包名、版本(非系统应用)
*/
public static ArrayList<String> getAllPackageName(Context context) {
ArrayList<String> list = new ArrayList<>();
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
for (String packageName : packageNameList) {
if (!context.getPackageName().equals(packageName)) {
list.add(packageName);
List<PackageInfo> packageInfos = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
if (!context.getPackageName().equals(packageInfo.packageName)) {
list.add(packageInfo.packageName);
}
}
}
return list;
}
public static ArrayList<String> getAllPackageNameIncludeGh(Context context) {
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
return new ArrayList<>(packageNameList);
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
list.add(packageInfo.packageName);
}
}
return list;
}
/*
* 获取所有已安装的软件的包名(包括系统应用)
*/
public static ArrayList<String> getAllPackageNameIncludeSystemApps(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
list.add(packageInfo.packageName);
}
return list;
}
public static JSONArray getAppList(Context context) {
JSONArray jsonArray = new JSONArray();
try {
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
for (String packageName : packageNameList) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("package", packageName);
jsonArray.put(jsonObject);
PackageManager pm = context.getPackageManager();
List<PackageInfo> packageInfos = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
JSONObject jsonObject = new JSONObject();
// 这里的 pm.getApplicationLabel 有极小机率会返回 null 值 (明明方法标示了返回值 nonnull
// Attempt to invoke interface method 'java.lang.String java.lang.CharSequence.toString()' on a null object reference
// 所以要是为空就 continue忽略掉它
if (pm.getApplicationLabel(packageInfo.applicationInfo) == null) {
continue;
}
jsonObject.put("name", pm.getApplicationLabel(packageInfo.applicationInfo).toString());
jsonObject.put("package", packageInfo.packageName);
jsonObject.put("version", packageInfo.versionName);
jsonArray.put(jsonObject);
}
}
} catch (JSONException e) {
e.printStackTrace();
@ -749,19 +738,8 @@ public class PackageUtils {
jsonObject.put("version", packageInfo.versionName);
}
return jsonObject;
} catch (Exception e) {
} catch (JSONException | NameNotFoundException 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;
}
}

View File

@ -3,12 +3,12 @@ package com.gh.common.util
import android.annotation.SuppressLint
import com.gh.gamecenter.common.entity.SignatureEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.schedulers.Schedulers
/**
* 存储光环网游使用的签名
@ -24,7 +24,7 @@ object SignatureRepository {
RetrofitManager.getInstance()
.newApi
.ghSignature
.subscribeOn(Schedulers.io())
.compose(singleToMain())
.subscribe(object : BiResponse<ArrayList<SignatureEntity>>() {
override fun onSuccess(data: ArrayList<SignatureEntity>) {
signDigestList = ArrayList()

View File

@ -2,16 +2,15 @@ package com.gh.common.util
import android.os.Bundle
import androidx.fragment.app.Fragment
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.iinterface.ISuperiorChain
import com.gh.gamecenter.amway.AmwayFragment
import com.gh.gamecenter.category2.CategoryV2Fragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.provider.IHelpAndFeedbackProvider
import com.gh.gamecenter.discovery.DiscoveryFragment
import com.gh.gamecenter.entity.SubjectData
import com.gh.gamecenter.feedback.view.help.HelpAndFeedbackFragment
import com.gh.gamecenter.feedback.view.qa.HelpContainerFragment
import com.gh.gamecenter.forum.detail.ForumDetailFragment
import com.gh.gamecenter.forum.home.CommunityHomeFragment
import com.gh.gamecenter.fragment.ReloadFragment
@ -82,7 +81,6 @@ object ViewPagerFragmentHelper {
const val TYPE_TOOLKIT = "toolkit" // 工具箱
fun createFragment(parentFragment: Fragment?, bundle: Bundle, linkEntity: LinkEntity, isTabWrapper: Boolean): Fragment {
val superiorChain = if (parentFragment is ISuperiorChain) parentFragment else null
return when (linkEntity.type) {
// 游戏详情页
TYPE_GAME -> {
@ -91,12 +89,11 @@ object ViewPagerFragmentHelper {
}
// 我的光环
TYPE_MY_HALO -> {
val superiorChain = if (parentFragment is ISuperiorChain) parentFragment else null
HaloPersonalFragment().setSuperiorChain(superiorChain).with(bundle)
}
// 社区首页
TYPE_COMMUNITY_HOME -> {
CommunityHomeFragment().setSuperiorChain(superiorChain).with(bundle)
}
TYPE_COMMUNITY_HOME -> CommunityHomeFragment().with(bundle)
// 视频信息流
TYPE_VIDEO_STREAM -> {
bundle.putBoolean(EntranceConsts.KEY_IS_HOME_VIDEO, true)
@ -128,15 +125,7 @@ object ViewPagerFragmentHelper {
}
// 帮助与反馈
TYPE_FEEDBACK -> {
val helpAndFeedbackProvider =
ARouter.getInstance().build(RouteConsts.provider.helpAndFeedback)
.navigation() as? IHelpAndFeedbackProvider
if (helpAndFeedbackProvider != null) {
helpAndFeedbackProvider.getHelpAndFeedbackFragment().with(bundle)
} else {
// 纯粹是占位用的 fragment
AmwayFragment().with(bundle)
}
HelpAndFeedbackFragment().with(bundle)
}
// 帖子
TYPE_COMMUNITY_ARTICLE -> {
@ -150,11 +139,11 @@ object ViewPagerFragmentHelper {
NewQuestionDetailFragment().with(bundle)
}
// 其他原来带Toolbar的Fragment
else -> createToolbarWrapperFragment(parentFragment, bundle, linkEntity, isTabWrapper)
else -> createToolbarWrapperFragment(bundle, linkEntity, isTabWrapper)
}
}
private fun createToolbarWrapperFragment(parentFragment: Fragment?, bundle: Bundle, entity: LinkEntity, isTabWrapper: Boolean): Fragment {
private fun createToolbarWrapperFragment(bundle: Bundle, entity: LinkEntity, isTabWrapper: Boolean): Fragment {
var className = ReloadFragment::class.java.name
when (entity.type) {
@ -192,8 +181,6 @@ object ViewPagerFragmentHelper {
// 新游开测
TYPE_COLUMN_TEST -> {
className = GameServerTestV2Fragment::class.java.name
bundle.putString(EntranceConsts.KEY_ID, entity.link)
bundle.putString(EntranceConsts.KEY_NAME, entity.text)
}
// 分类2.0
TYPE_CATEGORY_V2 -> {
@ -246,15 +233,9 @@ object ViewPagerFragmentHelper {
}
// QA
TYPE_QA -> {
val helpAndFeedbackProvider =
ARouter.getInstance().build(RouteConsts.provider.helpAndFeedback)
.navigation() as? IHelpAndFeedbackProvider
helpAndFeedbackProvider?.let {
className = it.getHelpContainerFragmentClass()
bundle.putString(EntranceConsts.KEY_QA_ID, entity.link)
bundle.putString(EntranceConsts.KEY_NAVIGATION_TITLE, entity.text)
}
className = HelpContainerFragment::class.java.name
bundle.putString(EntranceConsts.KEY_QA_ID, entity.link)
bundle.putString(EntranceConsts.KEY_NAVIGATION_TITLE, entity.text)
}
// 资讯中心
TYPE_ARTICLE_CENTER -> {

View File

@ -31,7 +31,7 @@ class CustomExoPlayerCacheManager : ICacheManager {
mediaPlayer.setDataSource(context, Uri.parse(url), header)
}
override fun clearCache(context: Context, cachePath: File?, url: String) {
override fun clearCache(context: Context, cachePath: File, url: String) {
ExoSourceManager.clearCache(context, cachePath, url)
}

View File

@ -156,8 +156,8 @@ class CustomIjkExo2MediaPlayer : AbstractMediaPlayer(), Player.EventListener, An
override fun setDataSource(context: Context?, uri: Uri) {
dataSource = uri.toString()
mediaSource = exoHelper?.getMediaSource(dataSource, isPreview, isCache, isLooping, cacheDir, overrideExtension)
// mediaSource = DefaultMediaSourceFactory(context!!).createMediaSource(MediaItem.fromUri(uri))
// mediaSource = exoHelper?.getMediaSource(dataSource, isPreview, isCache, isLooping, cacheDir, overrideExtension)
mediaSource = DefaultMediaSourceFactory(context!!).createMediaSource(MediaItem.fromUri(uri))
}
override fun setDataSource(fd: FileDescriptor?) {
@ -265,9 +265,7 @@ class CustomIjkExo2MediaPlayer : AbstractMediaPlayer(), Player.EventListener, An
internalPlayer?.release()
internalPlayer = null
// exoHelper?.release() 调用的是 ExoSourceManager 的 release 方法,会废弃掉全局唯一的 SimpleCache 实例
// 导致其他地方使用 SimpleCache 时会出现异常,无法正常播放
// exoHelper?.release()
exoHelper?.release()
surface = null
dataSource = null

View File

@ -0,0 +1,331 @@
package com.gh.common.view
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.setDrawableEnd
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.visibleIf
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.google.android.flexbox.FlexboxLayout
class CatalogFilterView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
private var mTypeTv: TextView
private var mCatalogTv: TextView
private var mSizeTv: TextView
private var mTypeContainer: View
private var mCatalogContainer: View
private var mSizeContainer: View
private var mTypeFilterArray = ArrayList<SortType>()
private var mCatalogFilterArray = ArrayList<CatalogEntity.SubCatalogEntity>()
private var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
private var mOnCatalogFilterSetupListener: OnCatalogFilterSetupListener? = null
private var mTypePopupWindow: PopupWindow? = null
private var mCatalogPopupWindow: PopupWindow? = null
private var mSizePopupWindow: PopupWindow? = null
init {
View.inflate(context, R.layout.layout_catalog_filter, this)
mTypeTv = findViewById(R.id.type_tv)
mCatalogTv = findViewById(R.id.catalog_tv)
mSizeTv = findViewById(R.id.size_tv)
mTypeContainer = findViewById(R.id.container_type)
mCatalogContainer = findViewById(R.id.container_catalog)
mSizeContainer = findViewById(R.id.container_size)
mTypeContainer.setOnClickListener {
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
}
mCatalogContainer.setOnClickListener {
showSelectCatalogPopupWindow(this, mCatalogTv, mCatalogTv.text.toString())
}
mSizeContainer.setOnClickListener {
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
}
}
fun setTypeList(switch: CatalogEntity.CatalogSwitch) {
switch.run {
if ("on" == hotSort) mTypeFilterArray.add(SortType.RECOMMENDED)
if ("on" == newSort) mTypeFilterArray.add(SortType.NEWEST)
if ("on" == starSort) mTypeFilterArray.add(SortType.RATING)
}
if (mTypeFilterArray.isNotEmpty()) mTypeTv.text = mTypeFilterArray[0].value
}
fun setCatalogList(subCatalogList: List<CatalogEntity.SubCatalogEntity>, initCatalogName: String) {
mCatalogFilterArray = ArrayList(subCatalogList)
mCatalogTv.text = initCatalogName
}
fun setOnConfigSetupListener(onCatalogFilterSetupListener: OnCatalogFilterSetupListener) {
mOnCatalogFilterSetupListener = onCatalogFilterSetupListener
}
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
if (highlightIt) {
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
targetTextView.setTextColor(Color.WHITE)
} else {
targetTextView.background = null
targetTextView.setTextColor(R.color.text_757575.toColor(context))
}
}
private fun showSelectTypePopupWindow(containerView: View, typeTv: TextView, typeText: String) {
typeTv.setTextColor(R.color.text_theme.toColor(context))
typeTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
val inflater = LayoutInflater.from(typeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
).apply { mTypePopupWindow = this }
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (type in mTypeFilterArray) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = typeTv.context.resources.displayMetrics.widthPixels / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
tv.text = type.value
toggleHighlightedTextView(tv, typeText == type.value)
tv.tag = type.value
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
typeTv.text = type.value
mOnCatalogFilterSetupListener?.onSetupSortType(type)
}
}
popupWindow.setOnDismissListener {
typeTv.setTextColor(R.color.text_757575.toColor(context))
typeTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
mTypePopupWindow = null
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun showSelectCatalogPopupWindow(containerView: View, catalogTv: TextView, catalogText: String) {
catalogTv.setTextColor(R.color.text_theme.toColor(context))
catalogTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
val inflater = LayoutInflater.from(catalogTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
).apply { mCatalogPopupWindow = this }
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (entity in mCatalogFilterArray) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = catalogTv.context.resources.displayMetrics.widthPixels / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
val iv = item.findViewById<ImageView>(R.id.recommend_iv)
tv.text = entity.name
iv.visibleIf(entity.recommended)
toggleHighlightedTextView(tv, catalogText == entity.name)
tv.tag = entity.name
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
catalogTv.text = entity.name
mOnCatalogFilterSetupListener?.onSetupSortCatalog(entity)
}
}
popupWindow.setOnDismissListener {
catalogTv.setTextColor(R.color.text_757575.toColor(context))
catalogTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
mCatalogPopupWindow = null
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun showSelectSizePopupWindow(containerView: View, sizeTv: TextView, sizeText: String) {
sizeTv.setTextColor(R.color.text_theme.toColor(context))
sizeTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
val inflater = LayoutInflater.from(sizeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
).apply { mSizePopupWindow = this }
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
sizeFilterArray = if (sizeFilterArray == null) {
getDefaultSizeFilterArray()
} else {
sizeFilterArray?.apply {
if (firstOrNull()?.text != "全部大小") {
add(0, SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
}
}
}
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (size in sizeFilterArray!!) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = sizeTv.context.resources.displayMetrics.widthPixels / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
tv.text = size.text
toggleHighlightedTextView(tv, sizeText == size.text)
tv.tag = size.text
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
sizeTv.text = size.text
mOnCatalogFilterSetupListener?.onSetupSortSize(size)
}
}
popupWindow.setOnDismissListener {
sizeTv.setTextColor(R.color.text_757575.toColor(context))
sizeTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
mSizePopupWindow = null
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
return arrayListOf<SubjectSettingEntity.Size>().apply {
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下"))
add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M"))
add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M"))
add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G"))
add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上"))
}
}
fun setRootBackgroundColor(@ColorInt color: Int) {
findViewById<View>(R.id.config_controller).setBackgroundColor(color)
}
fun setItemTextColor(@ColorInt color: Int) {
mTypeTv.setTextColor(color)
mCatalogTv.setTextColor(color)
mSizeTv.setTextColor(color)
}
fun updatePopupWindow() {
when {
mTypePopupWindow != null && mTypePopupWindow!!.isShowing -> {
mTypePopupWindow?.dismiss()
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
}
mCatalogPopupWindow != null && mCatalogPopupWindow!!.isShowing -> {
mCatalogPopupWindow?.dismiss()
showSelectCatalogPopupWindow(this, mCatalogTv, mCatalogTv.text.toString())
}
mSizePopupWindow != null && mSizePopupWindow!!.isShowing -> {
mSizePopupWindow?.dismiss()
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
}
}
}
interface OnCatalogFilterSetupListener {
fun onSetupSortSize(sortSize: SubjectSettingEntity.Size)
fun onSetupSortType(sortType: SortType)
fun onSetupSortCatalog(sortCatalog: CatalogEntity.SubCatalogEntity)
}
enum class SortType(val value: String) {
RECOMMENDED("热门推荐"),
NEWEST("最新上线"),
RATING("最高评分")
}
}

View File

@ -1,18 +0,0 @@
package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.FrameLayout
import androidx.constraintlayout.widget.ConstraintLayout
class InterceptTouchContainView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : FrameLayout(context, attrs, defStyleAttr) {
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
return true
}
}

View File

@ -1,65 +0,0 @@
package com.gh.common.view
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.children
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.visibleIf
/**
* 单游戏卡片标签样式专用
* 根据宽度展示标签个数,最多展示三个标签
*/
class SingleCardTagContainerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
) : LinearLayout(context, attrs) {
private val childViews = arrayListOf<TextView>()
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
children.forEach {
// 父容器不限制子View的宽度
it.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec)
}
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
// 如果有显示不完整的标签,直接隐藏
children.forEach {
it.visibleIf(it.right <= width)
}
}
fun setData(tags: List<String>) {
removeAllViews()
tags.forEachIndexed { index, tag ->
if (index < 3) {
// 缓存子View 避免频繁创建新View
val tvTag = childViews.getOrNull(index) ?: TextView(context).also { childViews.add(it) }
if (index == 0) {
tvTag.text = tag
} else {
tvTag.text = "$DELIMITER$tag"
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
tvTag.setTextAppearance(R.style.TextCaption2)
} else {
tvTag.setTextAppearance(context, R.style.TextCaption2)
}
tvTag.setTextColor(R.color.text_tertiary.toColor(context))
addView(tvTag)
}
}
}
companion object {
private const val DELIMITER = "·"
}
}

View File

@ -0,0 +1,64 @@
package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import com.gh.gamecenter.R
import com.gh.gamecenter.category.CategoryListActivity
import com.gh.gamecenter.entity.CategoryEntity
class SubCategoryView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
LinearLayout(context, attrs, defStyleAttr) {
var leftTv: TextView
var centerTv: TextView
var rightTv: TextView
var leftDivider: View
var rightDivider: View
var primeCategory: CategoryEntity? = null
var categoryTitle: String? = ""
init {
View.inflate(context, R.layout.layout_sub_category, this)
leftTv = findViewById(R.id.tv_left_sub_category)
centerTv = findViewById(R.id.tv_center_sub_category)
rightTv = findViewById(R.id.tv_right_sub_category)
leftDivider = findViewById(R.id.divider_left)
rightDivider = findViewById(R.id.divider_right)
}
fun setLeftCategory(category: CategoryEntity) {
setCategory(leftTv, category)
}
fun setCenterCategory(category: CategoryEntity) {
setCategory(centerTv, category)
leftDivider.visibility = View.VISIBLE
}
fun setRightCategory(category: CategoryEntity) {
setCategory(rightTv, category)
rightDivider.visibility = View.VISIBLE
}
private fun setCategory(tv: TextView, category: CategoryEntity) {
tv.text = category.name
tv.setOnClickListener {
tv.context.startActivity(
CategoryListActivity.getIntent(
tv.context,
categoryTitle!!,
primeCategory!!,
category.name!!
)
)
}
}
}

View File

@ -207,7 +207,7 @@ object XapkDialogHelper {
SuggestType.GAME,
null,
hint,
SimpleGameEntity(downloadEntity.gameId, downloadEntity.name, downloadEntity.icon?: "")
SimpleGameEntity(downloadEntity.gameId, downloadEntity.name, downloadEntity.icon)
)
NewFlatLogUtils.logXApkUnzipFailedDialogClick(
"提交反馈",

View File

@ -6,7 +6,10 @@ import android.content.Intent
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.constant.Config
import com.gh.common.dialog.ManagerAllFilesPermissionDialogFragment
import com.gh.common.util.*
import com.gh.common.util.DirectUtils
import com.gh.common.util.DownloadNotificationHelper
import com.gh.common.util.PackageInstaller
@ -16,17 +19,15 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.SentryHelper
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.feature.utils.SentryHelper
import com.gh.gamecenter.xapk.XApkUnZipper
import com.gh.gamecenter.xapk.core.XApkFile
import com.gh.gamecenter.xapk.core.XApkUnZipCallback
import com.gh.gamecenter.xapk.core.XApkUnZipEntry
import com.gh.gamecenter.xapk.core.XApkUnZipOutputFactory
import com.gh.gamecenter.xapk.io.NonSplitApksOutput
import com.gh.gamecenter.xapk.io.OBBFileOutput
import com.gh.gamecenter.xapk.io.SplitApksOutput
import com.gh.gamecenter.xapk.io.XApkFileOutput
import com.gh.gamecenter.xapk.io.*
import com.gh.gamecenter.xapk.pi.IPackageInstaller
import com.gh.ndownload.NDataChanger
import com.halo.assistant.HaloApp
@ -47,6 +48,8 @@ import java.util.*
@SuppressLint("StaticFieldLeak")
object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
private const val XAPK_PACKAGE_PATH_TAG = "xapk_package_path"
const val XAPK_EXTENSION_NAME = "xapk"
// 通过解压过程存放于 DownloadEntity meta
@ -56,21 +59,12 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
const val XAPK_DATA_EXTENSION_NAME = "obb"
const val PACKAGE_EXTENSION_NAME = "apk"
// 系统是否有 obb 访问漏洞
val systemHasFlaw by lazy {
val systemMatched = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
val rootPath = Environment.getExternalStorageDirectory().path
val fileListMatched = File(rootPath, "Android").list().contentEquals(File(rootPath, "\u200bAndroid").list())
systemMatched && fileListMatched
}
private const val GUIDE_TYPE_MIUI_OPTIMIZATION = "miui_optimization"
private const val MIUI_OPTIMIZATION_WARNING_DIALOG_ENTRANCE = "MIUI优化关闭提示弹窗"
private var mContext = HaloApp.getInstance().application.applicationContext
private val mXApkUnZipper = XApkUnZipper(this, useFlawToUnzip = systemHasFlaw)
private val mXApkUnZipper = XApkUnZipper(this)
.also {
it.registerCallback(this)
}
@ -120,7 +114,7 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
return
}
PermissionHelper.checkManageAllFilesOrStoragePermissionBeforeAction(context) {
if (checkPermission(downloadEntity, showUnzipToast)) {
DownloadManager.getInstance().getDownloadEntitySnapshot(downloadEntity.url, downloadEntity.gameId)
?.let {
unzipXapkFile(it)
@ -135,6 +129,23 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
}
}
private fun checkPermission(downloadEntity: DownloadEntity, showUnzipToast: Boolean = false): Boolean {
// 安卓11以上系统需要开启所有文件访问权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& !Environment.isExternalStorageManager()) {
CurrentActivityHolder.getCurrentActivity()?.let {
ManagerAllFilesPermissionDialogFragment.show(it as AppCompatActivity) {
unzipXapkFile(downloadEntity)
if (showUnzipToast) {
Utils.toast(mContext, "解压过程请勿退出光环助手!")
}
}
}
return false
}
return true
}
private fun unzipXapkFile(downloadEntity: DownloadEntity) {
mXApkUnZipper.unzip(
XApkUnZipEntry(
@ -351,7 +362,7 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
mPendingSessionInfoMap[downloadEntity.path] = XapkPendingSessionInfo(downloadEntity.path, sessionId)
AppExecutor.ioExecutor.execute {// 有可能卡顿造成anr
PackageInstaller.installMultiple(applicationContext, downloadEntity.packageName, downloadEntity.path, sessionId)
PackageInstaller.installMultiple(applicationContext, downloadEntity.path, sessionId)
NDataChanger.notifyDataChanged(downloadEntity)
}
}

View File

@ -20,7 +20,6 @@ import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.core.GHThreadFactory;
import com.gh.gamecenter.feature.entity.TagStyleEntity;
import com.gh.gamecenter.feature.entity.CustomPageTrackData;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
@ -41,6 +40,7 @@ import com.gh.gamecenter.common.utils.NetworkUtils;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.download.DownloadedGameIdAndPackageNameDao;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.entity.HomePluggableFilterEntity;
@ -48,7 +48,6 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.PluginLocation;
import com.gh.gamecenter.feature.utils.SentryHelper;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.gamecenter.packagehelper.PackageRepository;
@ -77,8 +76,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class DownloadManager implements DownloadStatusListener {
@ -105,9 +102,6 @@ public class DownloadManager implements DownloadStatusListener {
private final Set<String> mUpdateMarks;
private final ExecutorService packageExecutor
= Executors.newSingleThreadExecutor(new GHThreadFactory("GH_DOWNLOAD_MANAGER_THREAD"));
@Override
public void onTaskCancelled(DownloadEntity entity) {
EBDownloadStatus status = new EBDownloadStatus("delete", entity.getName(),
@ -298,7 +292,7 @@ public class DownloadManager implements DownloadStatusListener {
// 下载模拟器游戏配置文件,地址是 "模拟器游戏类型根目录/cheat/"
if (!TextUtils.isEmpty(gameEntity.getSimulatorGameConfig())) {
String configFilePath = SimulatorGameManager.getPathByType(gameEntity.getSimulatorType()) + "/cheat/" + apkEntity.getPackageName() + ".ini";
getInstance().packageExecutor.execute(() -> {
AppExecutor.getIoExecutor().execute(() -> {
FileUtils.downloadFile(gameEntity.getSimulatorGameConfig(), configFilePath);
});
}
@ -356,10 +350,9 @@ public class DownloadManager implements DownloadStatusListener {
ExtensionsKt.addMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE, Constants.VGAME);
ExtensionsKt.addMetaExtra(downloadEntity, DownloadConfig.KEY_PROGRESS_CALLBACK_INTERVAL, "200");
ExtensionsKt.addMetaExtra(downloadEntity, VHelper.KEY_REQUIRED_G_APPS, gameEntity.getGAppsSwitch());
ExtensionsKt.addMetaExtra(downloadEntity, VHelper.KEY_BIT, apkEntity.getBit());
}
ExtensionsKt.addMetaExtra(downloadEntity, Constants.KEY_BIT, apkEntity.getBit());
// 记录是否为双下载按钮模式
if (isDualDownloadTypeEnabled) {
if (asVGame) {
@ -542,7 +535,6 @@ public class DownloadManager implements DownloadStatusListener {
checkDownloadEntryRecordValidate(url);
if (isDownloadCompleted(url)) {
downloadEntity.setStatus(DownloadStatus.done);
mDownloadDao.newOrUpdate(downloadEntity);
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
} else if (!isTaskDownloading(url)) {
DownloadEntity daoEntity = mDownloadDao.get(downloadEntity.getUrl());
@ -657,7 +649,7 @@ public class DownloadManager implements DownloadStatusListener {
* @return 下载任务快照列表
*/
@NonNull
public ArrayList<DownloadEntity> getAllDownloadEntitySnapshots() {
private ArrayList<DownloadEntity> getAllDownloadEntitySnapshots() {
return mDownloadDao.getAllSnapshots();
}
@ -913,7 +905,7 @@ public class DownloadManager implements DownloadStatusListener {
DownloadEntity entry = mDownloadDao.getSnapshot(url);
DownloadDataSimpleHelper.INSTANCE.removeDownloadSimpleEntity(url);
if (entry != null) {
getInstance().packageExecutor.execute(() -> {
AppExecutor.getIoExecutor().execute(() -> {
NDownloadBridge.INSTANCE.cancel(url);
mDownloadDao.delete(url);
@ -955,6 +947,7 @@ public class DownloadManager implements DownloadStatusListener {
// 改任务队列的状态
NDataChanger.INSTANCE.getDownloadingTaskUrlSet().remove(entry.getUrl());
NDataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl());
if (!cancelSilently) {
NDataChanger.INSTANCE.notifyDataChanged(entry);
onTaskCancelled(entry);
@ -967,9 +960,9 @@ public class DownloadManager implements DownloadStatusListener {
* 暂停所有正在下载的任务
*/
public void pauseAll() {
synchronized (NDataChanger.INSTANCE.getDownloadingTaskUrlSet()) {
for (String url : NDataChanger.INSTANCE.getDownloadingTaskUrlSet()) {
pause(url);
synchronized (NDataChanger.INSTANCE.getDownloadEntries()) {
for (DownloadEntity entity : NDataChanger.INSTANCE.getDownloadEntries().values()) {
pause(entity.getUrl());
}
}
Utils.log(DownloadManager.class.getSimpleName(), "pause all");
@ -980,7 +973,7 @@ public class DownloadManager implements DownloadStatusListener {
*/
public void pause(String url) {
checkDownloadEntryRecordValidate(url);
DownloadEntity entry = getDownloadEntitySnapshot(url);
DownloadEntity entry = NDataChanger.INSTANCE.getDownloadEntries().get(url);
if (entry != null) {
startDownloadService(entry, DownloadStatus.pause);
put(url, System.currentTimeMillis());
@ -996,21 +989,19 @@ public class DownloadManager implements DownloadStatusListener {
* 3.检查是否显示下载通知栏
*/
public void initDownloadService() {
packageExecutor.execute(() -> {
final Set<String> urlSet = NDataChanger.INSTANCE.getDownloadingTaskUrlSet();
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
if (!urlSet.contains(downloadEntity.getUrl())
&& (downloadEntity.getStatus().equals(DownloadStatus.downloading)
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
downloadEntity.setStatus(DownloadStatus.subscribe);
mDownloadDao.newOrUpdate(downloadEntity);
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
}
final Set<String> urlSet = NDataChanger.INSTANCE.getDownloadingTaskUrlSet();
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
if (!urlSet.contains(downloadEntity.getUrl())
&& (downloadEntity.getStatus().equals(DownloadStatus.downloading)
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
downloadEntity.setStatus(DownloadStatus.subscribe);
mDownloadDao.newOrUpdate(downloadEntity);
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
}
}
startDownloadService();
checkAndRetryDownload(true);
});
startDownloadService();
checkAndRetryDownload();
}
/**
@ -1101,15 +1092,13 @@ public class DownloadManager implements DownloadStatusListener {
/**
* 检查并尝试重试下载
*/
public void checkAndRetryDownload(boolean includePausedTask) {
public void checkAndRetryDownload() {
if (!NetworkUtils.isWifiConnected(mContext)) return;
for (DownloadEntity downloadEntity : DownloadManager.getInstance().getAllDownloadEntityExcludeDoneTask()) {
if (DownloadStatus.neterror.equals(downloadEntity.getStatus())
|| DownloadStatus.timeout.equals(downloadEntity.getStatus())
|| DownloadStatus.subscribe.equals(downloadEntity.getStatus())
|| (includePausedTask && DownloadStatus.pause.equals(downloadEntity.getStatus()))
) {
|| DownloadStatus.subscribe.equals(downloadEntity.getStatus())) {
DownloadManager.getInstance().put(downloadEntity.getUrl(), System.currentTimeMillis());
Message msg = Message.obtain();
msg.what = DownloadConfig.CONTINUE_DOWNLOAD_AUTO_TASK;
@ -1214,7 +1203,7 @@ public class DownloadManager implements DownloadStatusListener {
* 标记下载已完成的任务为已读 (用于下载管理页入口的 toolbar 红点显示)
*/
public void markDownloadedTaskAsRead() {
getInstance().packageExecutor.execute(() -> {
AppExecutor.getIoExecutor().execute(() -> {
boolean markHasChanged = false;
List<DownloadEntity> all = getAllDownloadEntityExcludeSilentTask();
@ -1254,7 +1243,7 @@ public class DownloadManager implements DownloadStatusListener {
* 更改下载中任务的已读状态(用于下载页及外部toolbar)
*/
private void markDownloadingTaskAsReadOrUnread(boolean isRead) {
getInstance().packageExecutor.execute(() -> {
AppExecutor.getIoExecutor().execute(() -> {
boolean markHasChanged = false;
List<DownloadEntity> all = getAllDownloadEntityExcludeSilentTask();
@ -1285,7 +1274,7 @@ public class DownloadManager implements DownloadStatusListener {
* 标记可用更新为已读 (用于下载管理页入口的 toolbar 红点显示)
*/
public void markUpdatableTaskAsRead() {
getInstance().packageExecutor.execute(() -> {
AppExecutor.getIoExecutor().execute(() -> {
boolean markHasChanged = false;
ArrayList<GameUpdateEntity> updates = PackageRepository.INSTANCE.getGameUpdate();
@ -1384,7 +1373,7 @@ public class DownloadManager implements DownloadStatusListener {
* 手动触发下载 LiveData 变更
*/
public void notifyDownloadLiveDataChanged() {
getInstance().packageExecutor.execute(() -> mDownloadEntityListLiveData.postValue(getAllDownloadEntity()));
AppExecutor.getIoExecutor().execute(() -> mDownloadEntityListLiveData.postValue(getAllDownloadEntity()));
}
/**

View File

@ -4,12 +4,10 @@ import android.content.Context
import android.graphics.drawable.GradientDrawable
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.callback.OnViewClickListener
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.feature.entity.GameEntity
@ -102,16 +100,7 @@ class DownloadDialogAdapter(
DirectUtils.directToQa(mContext, data.linkText, data.linkId)
}
"qa_collection" -> {
DirectUtils.directToQaCollection(mContext, data.linkText, data.linkId)
}
"qa_list" -> {
DirectUtils.directToHelpAndFeedback(
mContext, bundleOf(
EntranceConsts.KEY_ENTRANCE to "选择下载加速版本-常见问题",
EntranceConsts.KEY_GAME_ID to viewModel.gameEntity.id,
EntranceConsts.KEY_GAME_NAME to viewModel.gameEntity.name
)
)
DirectUtils.directToHelpAndFeedback(mContext, isPlugin = true)
}
else -> {
//Utils.toast(mContext, "暂不支持类型:" + data.linkType)

View File

@ -61,7 +61,7 @@ object BrowserInstallHelper {
}
else -> {
val allInstalledPackageList = PackageUtils.getAllPackageName(mContext)
val allInstalledPackageList = PackageUtils.getAllPackageNameIncludeSystemApps(mContext)
if (allInstalledPackageList.isNotEmpty()) {
mValidInstalledPackageList = allInstalledPackageList

View File

@ -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()

View File

@ -44,11 +44,9 @@ import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.CommunityEntity
import com.gh.gamecenter.common.entity.SensorsEvent
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.ImageUtils.getIdealImageUrl
import com.gh.gamecenter.common.view.DragListener
import com.gh.gamecenter.common.view.DraggableBigImageView
import com.gh.gamecenter.common.view.Gh_RelativeLayout
import com.gh.gamecenter.core.runOnIoThread
@ -105,7 +103,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
private var mInitialPosition = 0
private var mUseEnterAndExitAnimation = false
private var mShowSaveBtn = false
private var mSaveBtnText = ""
private var mAnswerEntity: AnswerEntity? = null
private var mIsFromImageContainerView = false
@ -129,7 +126,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
private var mTranslationY = 0f
private var mTargetCenterX = 0f
private var mTargetCenterY = 0f
private var mSaveSensorsEvent: SensorsEvent? = null
override fun getLayoutId() = R.layout.activity_viewimage
@ -161,8 +157,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
mInitialPosition = it.getInt(EntranceConsts.KEY_CURRENT, 0)
}
mShowSaveBtn = it.getBoolean(KEY_SHOW_SAVE)
mSaveBtnText = it.getString(KEY_SAVE_TEXT, "")
mSaveSensorsEvent = it.getParcelable(KEY_SAVE_SENSORS_EVENT)
mUseEnterAndExitAnimation = it.getBoolean(KEY_USE_ENTER_AND_EXIT_ANIMATION)
mAnswerEntity = it.getParcelable(AnswerEntity::class.java.name)
mOriginLeftList = it.getIntegerArrayList(KEY_LEFT)
@ -178,9 +172,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
}
mSavePicBtn.visibleIf(mShowSaveBtn)
if (mSaveBtnText.isNotEmpty()) {
mBinding.btnSavePic.text = mSaveBtnText
}
mArticleDetailBtn.visibleIf(mAnswerEntity != null)
mIndicatorMask.goneIf(mUrlList?.size == 1)
mIndicatorTv.text = String.format("%d/%d", mInitialPosition + 1, mUrlList!!.size)
@ -226,7 +217,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
}
mSavePicBtn.setOnClickListener {
mSaveSensorsEvent?.let { SensorsBridge.trackEvent(it) }
checkStoragePermissionBeforeAction {
mBigImageView?.currentImageFile?.run {
ImageUtils.saveImageToFile(this, mFinalUrl)
@ -799,7 +789,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
} else {
rawUrl
}
var compressedStandardImageUrl: String? = if (!mShowBase64Image && rawUrl.contains("ghzs") && !rawUrl.contains("x-oss-process")) {
var compressedStandardImageUrl: String? = if (!mShowBase64Image && rawUrl.contains("ghzs")) {
// 用 oss.jpeg 加上 limit 以后会出现双指放大的情况
rawUrl + Config.getSettings()?.image?.oss?.gif
} else {
@ -816,18 +806,18 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
if (mBigImageView == null) {
mBigImageView = imageView
}
imageView.setDragListener(object : DragListener {
override fun onRelease(scale: Float) {
imageView.setDragListener(object : DraggableBigImageView.DragListener {
override fun onRelease(draggableBigImageView: DraggableBigImageView, scale: Float) {
updateOriginPosition(mViewPager.currentItem)
performExitAnimation(imageView, scale, isFadeOnly())
performExitAnimation(draggableBigImageView, scale, isFadeOnly())
}
override fun onDrag(fraction: Float) {
override fun onDrag(draggableBigImageView: DraggableBigImageView, fraction: Float) {
mBackgroundView.alpha = 1 - fraction
mIndicatorMask.visibility = View.GONE
}
override fun onRestore(fraction: Float) {
override fun onRestore(draggableBigImageView: DraggableBigImageView, fraction: Float) {
mBackgroundView.alpha = 1F
// mIndicatorMask.goneIf(mUrlList?.size == 1)
if (mUrlList?.size != 1 || mAnswerEntity != null) {
@ -848,8 +838,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
mFinalUrl = finalUrl ?: ""
imageView.setImageLoaderCallback(object : SimpleImageLoader() {
var tryCount = 0
override fun onSuccess(image: File) {
if (finalUrl != mUrlList!![position]) {
val options = BitmapFactory.Options()
@ -870,15 +858,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
onBackPressed()
}
}
override fun onFail(error: java.lang.Exception?) {
super.onFail(error)
// 加载压缩图片失败时尝试加载原图
if (finalUrl != rawUrl && tryCount == 0) {
loadImage(thumbnailImageUrl, rawUrl, imageView)
tryCount ++
}
}
})
loadImage(thumbnailImageUrl, compressedStandardImageUrl, imageView)
@ -956,10 +935,8 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
private const val KEY_BASE64 = "base64"
private const val KEY_SHOW_SAVE = "showSave"
private const val KEY_SAVE_TEXT = "saveText"
private const val KEY_USE_ENTER_AND_EXIT_ANIMATION = "use_enter_and_exit_animation"
private const val KEY_IS_FROM_IMAGE_CONTAINER_VIEW = "is_from_image_container_view"
private const val KEY_SAVE_SENSORS_EVENT = "save_sensors_event"
private const val KEY_LEFT = "left"
private const val KEY_TOP = "top"
@ -981,27 +958,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
return getIntent(context, list, position, null, entrance, false)
}
@JvmStatic
fun getSingleIntent(
context: Context,
url: String,
isShowSaveBtn: Boolean,
saveBtnText: String? = null,
entrance: String? = null,
saveSensorsEvent: SensorsEvent? = null
): Intent {
return getIntent(
context,
arrayListOf(url),
0,
null,
entrance,
isShowSaveBtn,
saveBtnText = saveBtnText,
saveSensorsEvent = saveSensorsEvent
)
}
@JvmStatic
fun getIntent(
context: Context,
@ -1038,9 +994,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
entrance: String?,
isShowSaveBtn: Boolean,
answerEntity: AnswerEntity? = null,
isFromICV: Boolean = false,
saveBtnText: String? = null,
saveSensorsEvent: SensorsEvent? = null
isFromICV: Boolean = false
): Intent {
val intent = Intent(context, ImageViewerActivity::class.java)
intent.putExtra(EntranceConsts.KEY_URL_LIST, list)
@ -1049,8 +1003,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
intent.putExtra(AnswerEntity::class.java.name, answerEntity)
intent.putExtra(EntranceConsts.KEY_ENTRANCE, entrance)
intent.putExtra(KEY_IS_FROM_IMAGE_CONTAINER_VIEW, isFromICV)
saveBtnText?.let { intent.putExtra(KEY_SAVE_TEXT, it) }
saveSensorsEvent?.let { intent.putExtra(KEY_SAVE_SENSORS_EVENT, saveSensorsEvent) }
if (originalViewList != null) {
val leftList = arrayListOf<Int>()

View File

@ -43,7 +43,6 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import com.gh.ad.AdDelegateHelper;
import com.gh.ad.SplashAdVideoView;
import com.gh.common.constant.Config;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.history.HistoryDatabase;
@ -90,16 +89,16 @@ import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.core.utils.UrlFilterUtils;
import com.gh.gamecenter.entity.StartupAdEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.utils.PlatformUtils;
import com.gh.gamecenter.feature.utils.SentryHelper;
import com.gh.gamecenter.home.custom.model.CustomPageShareRepository;
import com.gh.gamecenter.home.skip.PackageSkipActivity;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.login.utils.QuickLoginHelper;
import com.gh.gamecenter.manager.DataCollectionManager;
import com.gh.gamecenter.packagehelper.PackageViewModel;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.room.AppDatabase;
@ -130,6 +129,7 @@ import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import io.reactivex.SingleSource;
@ -138,6 +138,7 @@ import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.HttpException;
@ -147,9 +148,7 @@ public class MainActivity extends BaseActivity {
public static final String SHOW_AD = "show_ad";
public static final int COUNTDOWN_AD = 100;
private int mCountdownMaxCount = 3;
public static final int COUNTDOWN_SDK_AD = 101;
public static final int COUNTDOWN_SDK_MAX_COUNT = 5;
public static final int COUNTDOWN_MAX_COUNT = 3;
private int mCountdownCount = 0;
private static final String CURRENT_PAGE = "current_page";
@ -256,6 +255,9 @@ public class MainActivity extends BaseActivity {
}
}
// 必须放在这里,否则会导致获取 baseActivity 不是本应用包名
DownloadManager.getInstance().initDownloadService();
ReservationRepository.refreshReservations();
// 跳转至其它页面
@ -318,7 +320,7 @@ public class MainActivity extends BaseActivity {
mMainWrapperViewModel.requestAllDialogData();
QuickLoginHelper.preLogin(this);
// QuickLoginHelper.getPhoneInfo();
// TODO 搞清楚为什么这里要获取微信相关配置
WechatBindHelper.getWechatConfig(null);
@ -491,7 +493,6 @@ public class MainActivity extends BaseActivity {
if (AdDelegateHelper.INSTANCE.shouldShowStartUpAd(false)) {
ViewGroup startAdContainer = findViewById(R.id.startAdContainer);
ViewGroup sdkStartAdContainer = findViewById(R.id.sdkStartAdContainer);
TextView sdkJumpBtn = findViewById(R.id.sdkJumpBtn);
FrameLayout adsFl = findViewById(R.id.adsFl);
View icpContainer = findViewById(R.id.sdkStartAdIcpContainer);
if (icpContainer != null) {
@ -507,11 +508,6 @@ public class MainActivity extends BaseActivity {
float screenHeightInDp = DisplayUtils.px2dip(this, screenHeightInPx);
if (startAdContainer != null && sdkStartAdContainer != null && adsFl != null) {
mCountdownMaxCount = AdDelegateHelper.INSTANCE.getSplashAdDisplayInterval();
TextView jumpBtn = findViewById(R.id.jumpBtn);
if (jumpBtn != null) {
jumpBtn.setText(getString(R.string.splash_jump, mCountdownMaxCount));
}
AdDelegateHelper.requestSplashAd(
this,
screenWidthInPx,
@ -520,7 +516,6 @@ public class MainActivity extends BaseActivity {
screenHeightInDp,
startAdContainer,
sdkStartAdContainer,
sdkJumpBtn,
adsFl,
(BaseHandler) mBaseHandler,
false,
@ -540,19 +535,13 @@ public class MainActivity extends BaseActivity {
@Override
protected void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == COUNTDOWN_AD || msg.what == COUNTDOWN_SDK_AD) {
if (msg.what == COUNTDOWN_AD) {
mCountdownCount++;
int maxCount;
if (msg.what == COUNTDOWN_AD) {
maxCount = mCountdownMaxCount;
} else {
maxCount = COUNTDOWN_SDK_MAX_COUNT;
}
if (maxCount < mCountdownCount) {
if (COUNTDOWN_MAX_COUNT < mCountdownCount) {
AdDelegateHelper.INSTANCE.setShowingSplashAd(false);
hideSplashAd();
if (msg.what == COUNTDOWN_AD && msg.obj instanceof StartupAdEntity) {
if (msg.obj instanceof StartupAdEntity) {
StartupAdEntity ad = (StartupAdEntity) msg.obj;
LinkEntity linkEntity = ad.getJump();
SensorsBridge.trackEvent(
@ -565,26 +554,14 @@ public class MainActivity extends BaseActivity {
linkEntity.getLink(),
"link_text",
linkEntity.getText());
} else if (msg.what == COUNTDOWN_SDK_AD) {
SPUtils.setLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, System.currentTimeMillis());
}
} else {
if (msg.what == COUNTDOWN_AD) {
TextView jumpBtn = findViewById(R.id.jumpBtn);
if (jumpBtn != null) {
jumpBtn.setText(getString(R.string.splash_jump, maxCount - mCountdownCount));
}
Message newMsg = Message.obtain();
newMsg.what = COUNTDOWN_AD;
newMsg.obj = msg.obj;
mBaseHandler.sendMessageDelayed(newMsg, 1000);
} else {
TextView jumpBtn = findViewById(R.id.sdkJumpBtn);
if (jumpBtn != null) {
jumpBtn.setText(getString(R.string.splash_jump, maxCount - mCountdownCount));
}
mBaseHandler.sendEmptyMessageDelayed(COUNTDOWN_SDK_AD, 1000);
}
TextView jumpBtn = findViewById(R.id.jumpBtn);
jumpBtn.setText(String.format(Locale.CHINA, "跳过 %d", COUNTDOWN_MAX_COUNT - mCountdownCount));
Message newMsg = Message.obtain();
newMsg.what = COUNTDOWN_AD;
newMsg.obj = msg.obj;
mBaseHandler.sendMessageDelayed(newMsg, 1000);
}
}
}
@ -608,11 +585,6 @@ public class MainActivity extends BaseActivity {
getIntent().putExtra(SHOW_AD, false);
View startAdContainer = findViewById(R.id.startAdContainer);
if (startAdContainer != null) {
// 如果有播放开屏视频广告,需要及时释放
SplashAdVideoView adVideoView = startAdContainer.findViewById(R.id.ad_video);
if (adVideoView != null) {
adVideoView.clearAll();
}
startAdContainer.setVisibility(View.GONE);
ExtensionsKt.removeFromParent(startAdContainer, true);
}
@ -622,11 +594,7 @@ public class MainActivity extends BaseActivity {
ExtensionsKt.removeFromParent(startSdkAdContainer, true);
AdDelegateHelper.INSTANCE.cancelSplashAd(this);
}
TextView jumpBtn = findViewById(R.id.sdkJumpBtn);
if (jumpBtn != null) {
jumpBtn.setVisibility(View.GONE);
ExtensionsKt.removeFromParent(jumpBtn, true);
}
View startSdkAdIcpContainer = findViewById(R.id.sdkStartAdIcpContainer);
if (startSdkAdIcpContainer != null) {
startSdkAdIcpContainer.setVisibility(View.GONE);
@ -772,7 +740,7 @@ public class MainActivity extends BaseActivity {
ToastUtils.showToast("游戏启动中,请稍后~");
handler.postDelayed(() -> {
if (VHelper.isInnerInstalled(gamePackageName)) {
if(VHelper.isInnerInstalled(gamePackageName)) {
launchGame(gamePackageName).invoke();
} else {
VHelper.postOnInitialized(launchGame(gamePackageName));
@ -832,7 +800,7 @@ public class MainActivity extends BaseActivity {
public void onFailure(@Nullable HttpException e) {
super.onFailure(e);
try {
ErrorHelper.handleErrorWithCustomizedHandler(MainActivity.this, e.response().errorBody().string(), false, "", "", "内容实名", null, null, code -> {
ErrorHelper.handleErrorWithCustomizedHandler(MainActivity.this, e.response().errorBody().string(), false, "", "", "内容实名", null, null, code -> {
if (code == 404001) {
if (mShouldShowAd) {
AppExecutor.getUiExecutor().executeWithDelay(() -> {
@ -971,7 +939,7 @@ public class MainActivity extends BaseActivity {
Config.getNewSetting();
}
mPackageViewModel.checkData();
// mPackageViewModel.checkData();
deleteSimulatorGame();
}
}

View File

@ -10,8 +10,6 @@ import android.view.inputmethod.EditorInfo
import android.widget.*
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import com.gh.common.util.*
import com.gh.common.util.LogUtils
import com.gh.gamecenter.DisplayType.*
@ -120,7 +118,7 @@ open class SearchActivity : BaseActivity() {
trackSearchPageShow()
}
protected open fun trackSearchPageShow() {
protected open fun trackSearchPageShow(){
val bottomTab = intent.getStringExtra(EntranceConsts.KEY_BOTTOM_TAB_NAME) ?: ""
val multiTabId = intent.getStringExtra(EntranceConsts.KEY_MULTI_TAB_NAV_ID) ?: ""
val multiTabName = intent.getStringExtra(EntranceConsts.KEY_MULTI_TAB_NAV_NAME) ?: ""
@ -181,11 +179,10 @@ open class SearchActivity : BaseActivity() {
open fun search(type: SearchType, key: String?) {
mSearchType = type
mIsAutoSearchDisabled = true
// 自动搜索,默认搜索,热门搜索,历史搜索,主动搜索,榜单搜索
// 自动搜索,默认搜索,热门搜索,历史搜索,主动搜索
when (type) {
SearchType.AUTO -> handleAutoSearch(key)
SearchType.DEFAULT -> handleDefaultSearch(key)
SearchType.RANK -> handleRankSearch(key)
SearchType.HOT -> handleHotSearch(key)
SearchType.HISTORY -> handleHistorySearch(key)
SearchType.MANUAL -> handleManualSearch()
@ -216,22 +213,6 @@ open class SearchActivity : BaseActivity() {
}
}
protected open fun handleRankSearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
updateDisplayType(GAME_DETAIL)
LogUtils.uploadSearchGame("searching", "搜索页", key, "榜单搜索")
SensorsBridge.trackSearchButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key ?: "",
TRACK_SEARCH_TYPE_DEFAULT,
mSourceEntrance
)
}
protected open fun handleDefaultSearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
@ -305,72 +286,38 @@ open class SearchActivity : BaseActivity() {
protected open fun provideDao(): ISearchHistoryDao = SearchHistoryDao(this)
open fun updateDisplayType(type: DisplayType) {
val transaction = when (type) {
DEFAULT -> showFragment(
SearchDefaultFragment::class.java.name,
{ SearchDefaultFragment() }
) {
it.arguments = Bundle().also { bundle ->
bundle.putBoolean(SearchDefaultFragment.KEY_IS_GAME_SEARCH, true)
}
}
GAME_DIGEST -> showFragment(
SearchGameIndexFragment::class.java.name,
{ SearchGameIndexFragment() }
) {
removeFragment(SearchGameResultFragment::class.java.name)
it.setParams(mSearchKey ?: "", mSearchType.value)
}
GAME_DETAIL -> showFragment(
SearchGameResultFragment::class.java.name,
{ SearchGameResultFragment() }
) {
removeFragment(SearchGameIndexFragment::class.java.name)
it.setParams(mSearchKey ?: "", mSearchType.value)
}
else -> null
}
transaction?.let {
mDisplayType = type
it.commitAllowingStateLoss()
}
}
protected fun <T : Fragment> showFragment(
tag: String,
onFragmentCreate: () -> T,
onFragmentCreated: ((T) -> Unit)? = null,
): FragmentTransaction {
val transaction = supportFragmentManager.beginTransaction()
var createNewFragment = false
var fragment = supportFragmentManager
.findFragmentByTag(tag)
if (fragment == null) {
createNewFragment = true
fragment = onFragmentCreate.invoke()
}
onFragmentCreated?.invoke(fragment as T)
if (createNewFragment) {
transaction.add(R.id.search_result, fragment, tag)
transaction.addToBackStack(null)
} else if (!fragment.isAdded) {
transaction.show(fragment)
transaction.addToBackStack(null)
}
return transaction
}
when (type) {
DEFAULT -> {
val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.name)
?: SearchDefaultFragment().apply {
arguments = Bundle().also { it.putBoolean(SearchDefaultFragment.KEY_IS_GAME_SEARCH, true) }
}
transaction.replace(R.id.search_result, fragment, SearchDefaultFragment::class.java.name)
}
protected fun removeFragment(tag: String) {
val fragment = supportFragmentManager
.findFragmentByTag(tag) ?: return
supportFragmentManager
.beginTransaction()
.remove(fragment)
.commit()
supportFragmentManager.popBackStack()
GAME_DIGEST -> {
val digestListFragment =
supportFragmentManager.findFragmentByTag(SearchGameIndexFragment::class.java.name) as? SearchGameIndexFragment
?: SearchGameIndexFragment()
digestListFragment.setParams(mSearchKey ?: "", mSearchType.value)
transaction.replace(R.id.search_result, digestListFragment, SearchGameIndexFragment::class.java.name)
}
GAME_DETAIL -> {
val detailListFragment =
supportFragmentManager.findFragmentByTag(SearchGameResultFragment::class.java.name) as? SearchGameResultFragment
?: SearchGameResultFragment()
detailListFragment.setParams(mSearchKey ?: "", mSearchType.value)
transaction.replace(R.id.search_result, detailListFragment, SearchGameResultFragment::class.java.name)
}
else -> {
//do nothing
}
}
mDisplayType = type
transaction.commitAllowingStateLoss()
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -378,7 +325,6 @@ open class SearchActivity : BaseActivity() {
when (search.type) {
SearchType.HISTORY.value -> search(SearchType.HISTORY, search.key)
SearchType.HOT.value -> search(SearchType.HOT, search.key)
SearchType.RANK.value -> search(SearchType.RANK, search.key)
"click" -> DataCollectionUtils.uploadSearchClick(
this, mSearchKey, mSearchType.value, "搜索页面",
@ -395,8 +341,9 @@ open class SearchActivity : BaseActivity() {
}
override fun handleBackPressed(): Boolean {
if (supportFragmentManager.fragments.size == 1) {
finish()
val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.name)
if (fragment == null) {
updateDisplayType(DEFAULT)
return true
}
return super.handleBackPressed()
@ -470,8 +417,7 @@ enum class SearchType(var value: String) {
DEFAULT("default"),
HISTORY("history"),
MANUAL("initiative"),
HOT("remen"),
RANK("rank");
HOT("remen");
fun toChinese() = when (this) {
AUTO -> "自动搜索"
@ -479,7 +425,6 @@ enum class SearchType(var value: String) {
HISTORY -> "历史搜索"
MANUAL -> "主动搜索"
HOT -> "热门搜索"
RANK -> "榜单搜索"
}
companion object {

View File

@ -0,0 +1,21 @@
package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
import com.halo.assistant.fragment.user.SelectPortraitFragment;
/**
* Created by khy on 2017/2/10.
*/
public class SelectUserIconActivity extends ToolBarActivity {
@NonNull
public static Intent getIntent(Context context) {
return getTargetIntent(context, SelectUserIconActivity.class, SelectPortraitFragment.class);
}
}

View File

@ -9,7 +9,6 @@ import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.base.fragment.BaseFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.amway.AmwaySuccessFragment
import com.gh.gamecenter.gamedetail.LibaoListFragment
import com.halo.assistant.fragment.SwitchInstallMethodFragment
import com.halo.assistant.fragment.user.ManuallyRealNameFragment
import com.halo.assistant.fragment.user.RealNameInfoFragment
@ -30,14 +29,12 @@ class ShellActivity : ToolBarActivity() {
private fun handleIntent(bundle: Bundle?) {
// We parse the bundle to fragment to let fragment get data from bundle itself to survive configuration changes.
val intentType = Type.fromString(bundle?.getString(INTENT_TYPE) ?: "")
val extraData = bundle?.getBundle(EntranceConsts.KEY_DATA)
when (intentType) {
Type.AMWAY_SUCCESS -> startFragment(AmwaySuccessFragment().with(bundle))
Type.SWITCH_INSTALL_METHOD -> startFragment(SwitchInstallMethodFragment())
Type.REAL_NAME_INFO -> startFragment(RealNameInfoFragment().with(bundle))
Type.MANUALLY_REAL_NAME -> startFragment(ManuallyRealNameFragment().with(extraData))
Type.SIMPLE_LIBAO_LIST -> startFragment(LibaoListFragment.newInstance(extraData))
Type.MANUALLY_REAL_NAME -> startFragment(ManuallyRealNameFragment().with(bundle?.getBundle(EntranceConsts.KEY_DATA)))
}
}
@ -71,8 +68,7 @@ class ShellActivity : ToolBarActivity() {
AMWAY_SUCCESS("amway_success"),
SWITCH_INSTALL_METHOD("switch_install_method"),
REAL_NAME_INFO("real_name_info"),
MANUALLY_REAL_NAME("manually_real_name"),
SIMPLE_LIBAO_LIST("simple_libao_list");
MANUALLY_REAL_NAME("manually_real_name");
companion object {
fun fromString(typeString: String): Type {

View File

@ -5,6 +5,7 @@ import static com.gh.gamecenter.common.constant.EntranceConsts.ENTRANCE_PUSH;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ANSWER;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ARCHIVE_LOGIN;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ARTICLE;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_CATEGORY;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COLUMN;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COLUMN_COLLECTION;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COMMUNITY;
@ -14,7 +15,6 @@ import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_DOWNLOAD;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_GAME;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_GAME_COLLECTION_DETAIL;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_GAME_COLLECTION_SQUARE;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_INSTALL;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_INVOKE_ONLY;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_LIBAO;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ;
@ -56,8 +56,6 @@ import androidx.annotation.Nullable;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
@ -79,7 +77,6 @@ import com.gh.vspace.shortcut.OnCreateShortcutResult;
import com.gh.vspace.shortcut.ShortcutManager;
import com.gh.vspace.shortcut.ShortcutPermissionTipsDialog;
import com.lightgame.config.CommonDebug;
import com.lightgame.download.DownloadEntity;
import com.lightgame.utils.Utils;
import com.muugi.shortcut.core.Executor;
@ -123,7 +120,6 @@ public class SkipActivity extends BaseActivity {
String platform = uri.getQueryParameter(KEY_PLATFORM);
String platformName = PlatformUtils.getInstance(this).getPlatformName(platform);
String gameId = uri.getQueryParameter(EntranceConsts.KEY_GAMEID);
String gameName = uri.getQueryParameter(KEY_GAME_NAME);
String packageMd5 = uri.getQueryParameter(EntranceConsts.KEY_PACKAGE_MD5);
String isQaFeedbackString = uri.getQueryParameter(EntranceConsts.KEY_IS_QA_FEEDBACK);
String suggestionType = uri.getQueryParameter(KEY_TYPE);
@ -225,7 +221,7 @@ public class SkipActivity extends BaseActivity {
String categoryId = uri.getQueryParameter("category_id");
String link = uri.getQueryParameter("link");
gameId = uri.getQueryParameter("gameId");
gameName = uri.getQueryParameter("gameName");
String gameName = uri.getQueryParameter("gameName");
String tagActivityId = uri.getQueryParameter("tagActivityId");
String tagActivityName = uri.getQueryParameter("tagActivityName");
VideoLinkEntity linkEntity = new VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName);
@ -314,6 +310,10 @@ public class SkipActivity extends BaseActivity {
DirectUtils.directToCommunityColumn(this, community, columnId, entrance, "");
break;
case HOST_CATEGORY:
title = uri.getQueryParameter("title");
DirectUtils.directCategoryDirectory(this, path, title, entrance, pathName);
break;
case HOST_COLUMN_COLLECTION:
DirectUtils.directToColumnCollection(this, path, -1, entrance, "", "", "", "", null,false);
break;
@ -392,9 +392,9 @@ public class SkipActivity extends BaseActivity {
break;
case EntranceConsts.HOST_HELP_AND_FEEDBACK:
if ("vgame".equals(suggestionType)) {
DirectUtils.directToHelpAndFeedback(this, content, isQaFeedback, qaContentId, false, true, gameId, gameName, "畅玩游戏悬浮窗");
DirectUtils.directToHelpAndFeedback(this, content, isQaFeedback, qaContentId, false, true, entrance);
} else {
DirectUtils.directToHelpAndFeedback(this, content, isQaFeedback, qaContentId, true, false, gameId, gameName, "插件端悬浮窗");
DirectUtils.directToHelpAndFeedback(this, content, isQaFeedback, qaContentId, true, false, entrance);
}
break;
case HOST_GAME_COLLECTION_DETAIL:
@ -419,7 +419,7 @@ public class SkipActivity extends BaseActivity {
} else {
Bundle newBundle = new Bundle();
newBundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivityCompat(this, newBundle, null, (resultCode, data) -> {
EntranceUtils.jumpActivity(this, null, newBundle, (resultCode, data) -> {
if(CheckLoginUtils.isLogin()) {
VHelper.INSTANCE.updateAuthorizeInfo(true);
}
@ -433,16 +433,9 @@ public class SkipActivity extends BaseActivity {
String restartGamePkg = uri.getQueryParameter(EntranceConsts.KEY_GAME_PKG);
VHelper.launch(this, restartGamePkg, false, true);
break;
case HOST_INSTALL:
String packageName = uri.getQueryParameter("package_name");
DownloadEntity downloadEntity = DownloadManager
.getInstance()
.getDownloadEntitySnapshotByPackageName(packageName);
PackageInstaller.install(this, downloadEntity);
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
break;
return;
}
}
} else if ("market".equals(uri.getScheme())) {

View File

@ -12,10 +12,8 @@ import com.gh.ad.AdDelegateHelper
import com.gh.ad.AdDelegateHelper.requestSplashAd
import com.gh.ad.AdDelegateHelper.shouldShowStartUpAd
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import java.util.*
/**
@ -39,7 +37,6 @@ class SplashAdActivity : BaseActivity() {
if (shouldShowStartUpAd(true)) {
val startAdContainer = findViewById<ViewGroup>(R.id.startAdContainer)
val sdkStartAdContainer = findViewById<ViewGroup>(R.id.sdkStartAdContainer)
val sdkJumpBtn = findViewById<TextView>(R.id.sdkJumpBtn)
val adsFl = findViewById<FrameLayout>(R.id.adsFl)
val icpContainer = findViewById<View>(R.id.sdkStartAdIcpContainer)
@ -61,7 +58,6 @@ class SplashAdActivity : BaseActivity() {
screenHeightInDp,
startAdContainer!!,
sdkStartAdContainer!!,
sdkJumpBtn!!,
adsFl!!,
(mBaseHandler as BaseHandler),
true
@ -85,30 +81,21 @@ class SplashAdActivity : BaseActivity() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (msg.what == MainActivity.COUNTDOWN_AD || msg.what == MainActivity.COUNTDOWN_SDK_AD) {
if (msg.what == MainActivity.COUNTDOWN_AD) {
mCountdownCount++
val maxCount = if (msg.what == MainActivity.COUNTDOWN_AD) {
COUNTDOWN_MAX_COUNT
} else {
MainActivity.COUNTDOWN_SDK_MAX_COUNT
}
if (maxCount < mCountdownCount) {
if (MainActivity.COUNTDOWN_MAX_COUNT < mCountdownCount) {
AdDelegateHelper.isShowingSplashAd = false
if (msg.what == MainActivity.COUNTDOWN_SDK_AD) {
SPUtils.setLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, System.currentTimeMillis())
}
finishActivity()
} else {
val jumpBtn = findViewById<TextView>(if (msg.what == MainActivity.COUNTDOWN_AD) R.id.jumpBtn else R.id.sdkJumpBtn)
jumpBtn?.text = getString(R.string.splash_jump, maxCount - mCountdownCount)
mBaseHandler.sendEmptyMessageDelayed(msg.what, 1000)
val jumpBtn = findViewById<TextView>(R.id.jumpBtn)
jumpBtn.text =
String.format(Locale.CHINA, "跳过 %d", MainActivity.COUNTDOWN_MAX_COUNT - mCountdownCount)
mBaseHandler.sendEmptyMessageDelayed(MainActivity.COUNTDOWN_AD, 1000)
}
}
}
companion object {
private const val COUNTDOWN_MAX_COUNT = 3
@JvmStatic
fun getIntent(context: Context): Intent {
return Intent(context, SplashAdActivity::class.java)

View File

@ -17,11 +17,8 @@ import androidx.core.text.color
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.dialog.NewPrivacyPolicyDialogFragment
import com.gh.common.util.DeviceTokenUtils
import com.gh.common.util.DialogUtils
import com.gh.common.util.*
import com.gh.common.util.GameSubstituteRepositoryHelper.updateGameSubstituteRepository
import com.gh.common.util.PackageHelper
import com.gh.common.util.PackageUtils
import com.gh.common.util.UsageStatsHelper.checkAndPostUsageStats
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.base.activity.BaseActivity
@ -31,7 +28,6 @@ import com.gh.gamecenter.common.tracker.TrackerLogger
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.provider.IAppProvider
import com.gh.gamecenter.core.provider.IPackageUtilsProvider
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
@ -59,9 +55,6 @@ class SplashScreenActivity : BaseActivity() {
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
mIsNewForThisVersion = HaloApp.getInstance().isNewForThisVersion
HaloApp.getInstance().isBrandNewInstall = SPUtils.getBoolean(Constants.SP_BRAND_NEW_USER, true)
if (HaloApp.getInstance().isBrandNewInstall) {
SPUtils.setLong(Constants.SP_BRAND_NEW_FIRST_LAUNCH_TIME, System.currentTimeMillis())
}
// 用户不是新版本,但应用最后更新时间不是上次的时间代表用户重新安装了当前版本
if (!mIsNewForThisVersion) {
@ -281,12 +274,6 @@ class SplashScreenActivity : BaseActivity() {
SensorsBridge.init(HaloApp.getInstance(), HaloApp.getInstance().channel)
SensorsBridge.setOAID(HaloApp.getInstance().oaid)
val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
val registrationId = pushProvider?.getRegistrationId(this)
if (!registrationId.isNullOrEmpty()) {
SensorsBridge.profileAppend(KEY_REGISTRATION_ID, registrationId)
}
}
private fun prefetchData() {
@ -318,7 +305,6 @@ class SplashScreenActivity : BaseActivity() {
companion object {
private const val KEY_REGISTRATION_ID = "registration_id"
const val HONOR_CULPRIT_ID = 12324
const val HONOR_CULPRIT_CHANNEL = "荣耀通道"

View File

@ -99,7 +99,7 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mAppProvider != null) {
mAppProvider.setDisableSplashAdTemporarily(true);
mAppProvider.setSkippingThirdParty(true);
}
Bundle extras = getIntent().getExtras();
@ -365,7 +365,7 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback {
protected void onDestroy() {
super.onDestroy();
if (mAppProvider != null) {
mAppProvider.setDisableSplashAdTemporarily(false);
mAppProvider.setSkippingThirdParty(false);
}
}
}

View File

@ -7,6 +7,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Environment;
import android.view.View;
import android.view.ViewGroup;
@ -24,7 +25,6 @@ import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.KcSelectGameViewHolder;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.common.utils.BitmapUtils;
import com.gh.gamecenter.common.utils.FileUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.core.utils.TimeUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
@ -86,7 +86,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
Observable.create(emitter -> {
// 扫描和获取apk数据 分步操作 尽量避免 StackoverflowError
FindAllAPKPath(Environment.getExternalStorageDirectory());
FindAllAPKPath(new File(FileUtils.getDownloadDir(mContext)));
FindAllAPKPath(mContext.getFilesDir());
LoadApkData();
emitter.onComplete();
})
@ -123,7 +123,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
appInfo.sourceDir = apk_path;
appInfo.publicSourceDir = apk_path;
Drawable apk_icon = appInfo.loadIcon(pm);
Bitmap originalBitmap = BitmapUtils.drawableIconToBitmapIconWithDownsampling(apk_icon, true);
Bitmap originalBitmap = BitmapUtils.drawableToBitmap(apk_icon, true);
apkEntity.setGameBm(BitmapUtils.compressBitmap(originalBitmap, 100));
/** apk的绝对路劲 */
apkEntity.setGamePath(apk_path);
@ -189,11 +189,14 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
}
private int doType(String packageName) {
List<String> pakageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(mContext, 0);
for (String pkgName : pakageNameList) {
//如果这个包名在系统已经安装过的应用中存在
if (packageName.endsWith(pkgName)) {
return INSTALLED;
List<PackageInfo> pakageinfos = PackageHelper.INSTANCE.getInstalledPackages(mContext, 0);
for (PackageInfo pi : pakageinfos) {
if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
String pi_packageName = pi.packageName;
//如果这个包名在系统已经安装过的应用中存在
if (packageName.endsWith(pi_packageName)) {
return INSTALLED;
}
}
}
return UNINSTALLED;

View File

@ -14,7 +14,6 @@ import com.gh.common.util.DialogUtils;
import com.gh.common.util.DirectUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.ItemViewType;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.common.utils.ImageUtils;
@ -179,12 +178,7 @@ public class CommentDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
holder.commentTimeTv.setText(holder.commentTimeTv.getText() + " · " + commentEntity.getSource().getRegion());
}
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(
holder.commentContentTv,
commentEntity.getContent(),
Constants.DEFAULT_TEXT_WRAPPER,
new TextHelper.DirectToWebViewHighlightedTextClick(mContext, "评论详情")
);
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(holder.commentContentTv, commentEntity.getContent());
ArticleCommentParent parent = commentEntity.getParent();
if (parent != null && !TextUtils.isEmpty(parent.getUser().getName())) {
holder.quoteContainer.setVisibility(View.VISIBLE);
@ -203,12 +197,7 @@ public class CommentDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
content = mContext.getString(R.string.comment_hide_hint);
holder.quoteContentTv.setTextColor(mContext.getResources().getColor(R.color.text_d5d5d5));
}
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(
holder.quoteContentTv,
content,
Constants.DEFAULT_TEXT_WRAPPER,
new TextHelper.DirectToWebViewHighlightedTextClick(mContext, "评论详情")
);
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(holder.quoteContentTv, content);
} else {
holder.quoteContainer.setVisibility(View.GONE);
}

View File

@ -25,7 +25,6 @@ import com.gh.gamecenter.ShareCardPicActivity;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.adapter.viewholder.CommentHeadViewHolder;
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.retrofit.JSONObjectResponse;
import com.gh.gamecenter.common.retrofit.OkHttpCache;
@ -394,12 +393,7 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
return;
}
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(
holder.commentContentTv,
commentEntity.getContent(),
Constants.DEFAULT_TEXT_WRAPPER,
new TextHelper.DirectToWebViewHighlightedTextClick(holder.commentContentTv.getContext(), "消息详情")
);
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(holder.commentContentTv, commentEntity.getContent());
ArticleCommentParent parent = commentEntity.getParent();
if (parent != null && !TextUtils.isEmpty(parent.getUser().getName())) {
holder.quoteContainer.setVisibility(View.VISIBLE);
@ -418,12 +412,7 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
content = mContext.getString(R.string.comment_hide_hint);
holder.quoteContentTv.setTextColor(mContext.getResources().getColor(R.color.text_d5d5d5));
}
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(
holder.quoteContentTv,
content,
Constants.DEFAULT_TEXT_WRAPPER,
new TextHelper.DirectToWebViewHighlightedTextClick(holder.quoteContentTv.getContext(), "消息详情")
);
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(holder.quoteContentTv, content);
} else {
holder.quoteContainer.setVisibility(View.GONE);
}

View File

@ -33,7 +33,6 @@ import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.PageSwitchDataHelper
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.core.utils.ToastUtils
@ -79,9 +78,6 @@ class DetailViewHolder(
// 额外的文字 (用于一些含图片的情况)
val overlayTv: TextView?
val overlayContainer: View?
val extraOverlayTv: TextView?
var downloadPb: DownloadButton
var downloadTips: LottieAnimationView
@ -94,8 +90,6 @@ class DetailViewHolder(
downloadPb = view.findViewById(R.id.detail_progressbar)
downloadTips = view.findViewById(R.id.downloadTipsLottie)
overlayTv = view.findViewById(R.id.overlayTv)
overlayContainer = view.findViewById(R.id.overlayContainer)
extraOverlayTv = view.findViewById(R.id.extraOverlayTv)
multiVersionDownloadTv = view.findViewById(R.id.multiVersionDownloadTv)
localDownloadContainer = view.findViewById(R.id.localDownloadContainer)
localDownloadSizeTv = view.findViewById(R.id.localDownloadSizeTv)
@ -108,7 +102,7 @@ class DetailViewHolder(
val localDownloadListener = OnDetailDownloadClickListener(
mViewHolder = this,
mEntrance = entrance,
mEntrance = entrance,
mName = name ?: "",
mTitle = title ?: "",
mAsVGame = false,
@ -158,9 +152,6 @@ class DetailViewHolder(
}
}
downloadPb.putWidgetBusinessName("游戏详情页")
// "DownLoadbuttonClick" 埋点需要上报traceEvent信息
gameEntity.exposureEvent = traceEvent
downloadPb.putObject(gameEntity)
restoreDialogFragment()
}
@ -184,7 +175,6 @@ class DetailViewHolder(
private val mGameEntity: GameEntity = mViewHolder.gameEntity
private var mDownloadEntity: DownloadEntity? = null
private val mPausedText = mViewHolder.context.getString(R.string.paused)
private fun showLandPageAddressDialogIfNeeded() {
if (mGameEntity.isLandPageAddressDialog() && !mGameEntity.isLandPageAddressDialogShowOnly()) {
@ -206,11 +196,7 @@ class DetailViewHolder(
mViewHolder.downloadPb
}
if (downloadButton.buttonStyle !== ButtonStyle.INSTALL_NORMAL
&& downloadButton.buttonStyle !== ButtonStyle.INSTALL_PLUGIN
&& downloadButton.buttonStyle !== ButtonStyle.LAUNCH_OR_OPEN
&& downloadButton.buttonStyle !== ButtonStyle.NONE
&& downloadButton.buttonStyle !== ButtonStyle.NONE_WITH_HINT) {
if (downloadButton.buttonStyle !== ButtonStyle.INSTALL_NORMAL && downloadButton.buttonStyle !== ButtonStyle.INSTALL_PLUGIN && downloadButton.buttonStyle !== ButtonStyle.LAUNCH_OR_OPEN && downloadButton.buttonStyle !== ButtonStyle.NONE && downloadButton.buttonStyle !== ButtonStyle.NONE_WITH_HINT) {
// 畅玩游戏的非真实点击下载按钮下载不需要滚动到特定地方
if (!mAsVGame || VHelper.shouldLaunchGameAfterInstallation()) {
EventBus.getDefault().post(EBScroll(Constants.EB_GAME_DETAIL, mGameEntity.id))
@ -540,11 +526,11 @@ class DetailViewHolder(
mDownloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(mGameEntity)
}
if (mDownloadEntity != null) {
if (downloadButton.text.contains(mPausedText)) {
if (downloadButton.text.contains("继续加载")) {
DownloadManager.getInstance().resume(mDownloadEntity, false)
} else {
DownloadManager.getInstance().pause(mDownloadEntity!!.url)
downloadButton.text = "${DetailDownloadUtils.getValidProgress(mDownloadEntity)}% $mPausedText"
downloadButton.text = "继续加载 " + mDownloadEntity!!.percent + "%"
}
}
}
@ -628,18 +614,14 @@ class DetailViewHolder(
// 由于不想执行上面的 builder 相关的判断,所以这里还是丑陋的修改 downloadEntity 实体并保存到数据库中
downloadEntity.setVGameDownloadModeInDualDownloadMode()
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
runOnUiThread {
PackageInstaller.install(mViewHolder.context, downloadEntity)
}
PackageInstaller.install(mViewHolder.context, downloadEntity)
}
return
} else if (!mAsVGame && downloadEntity.isVGameDownloadInDualDownloadMode()) {
runOnIoThread {
downloadEntity.setLocalDownloadModeInDualDownloadMode()
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
runOnUiThread {
PackageInstaller.install(mViewHolder.context, downloadEntity)
}
PackageInstaller.install(mViewHolder.context, downloadEntity)
}
return
}
@ -652,12 +634,12 @@ class DetailViewHolder(
builder.addHandler(LandPageAddressHandler())
builder.addHandler(OverseaDownloadHandler())
builder.addHandler(CheckDownloadHandler())
builder.setProcessEndCallback(mGameEntity.id) { asVGame: Boolean, isSubscribe: Any? ->
builder.setProcessEndCallback { asVGame: Boolean, isSubscribe: Any? ->
download(asVGame, isSubscribe as Boolean)
}
} else {
builder.addHandler(VersionNumberHandler())
builder.setProcessEndCallback(mGameEntity.id) { _: Boolean?, _: Any? ->
builder.setProcessEndCallback { _: Boolean?, _: Any? ->
DownloadDialog.showDownloadDialog(
mViewHolder.context,
mGameEntity,

View File

@ -1,14 +1,7 @@
package com.gh.gamecenter.adapter.viewholder
import android.graphics.Paint
import android.widget.TextView
import androidx.core.view.marginStart
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.home.custom.model.CustomPageData
class SearchGameFooterViewHolder(val binding: SearchGameFooterBinding) : BaseRecyclerViewHolder<Any>(binding.root)
class PersonalHomeRatingViewHolder(val binding: PersonalHomeRatingBinding) : BaseRecyclerViewHolder<Any>(binding.root)
@ -29,62 +22,4 @@ class CommonCollectionImageTextItemViewHolder(val binding: CommonCollectionImage
BaseRecyclerViewHolder<Any>(binding.root)
class CommonCollectionDetailTwoItemHorizontalViewHolder(val binding: CommonCollectionDetailTwoItemHorizontalCustomBinding) :
BaseRecyclerViewHolder<Any>(binding.root)
class CustomCollectionDetailRecommendCardViewHolder(
val binding: RecyclerRecommendCardCommonContentCollectionDetailCustomBinding
) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bind(item: CustomPageData.RecommendCard) {
ImageUtils.display(binding.ivCover, item.image)
binding.tvTitle.text = item.title
binding.tvLabel.text = item.tag
binding.tvPrice.text = item.highlight.text
binding.tvOriginalPrice.text = if (item.deletion.isShowCurrencySymbol) {
itemView.context.getString(R.string.price_with_symbol, item.deletion.text)
} else {
item.deletion.text
}
binding.tvOriginalPrice.paint.flags = Paint.STRIKE_THRU_TEXT_FLAG
binding.tvCopy.text = item.addedContent
binding.tvPriceSymbol.goneIf(!item.highlight.isShowCurrencySymbol)
binding.root.post {
val views = mutableListOf(
binding.tvPrice,
binding.tvOriginalPrice,
binding.tvCopy,
)
if (item.highlight.isShowCurrencySymbol) {
views.add(0, binding.tvPriceSymbol)
}
binding.tvLabel.goneIf(item.tag.isBlank()) {
views.add(binding.tvLabel)
}
views.forEach {
it.goneIf(false)
}
hideOutOfBoundViewsIfNeed(views)
}
}
/**
* 计算统一排的view能否完整显示在 itemView 内,如果显示不下,则根据优先级依次隐藏优先级较低的
* 数据中的View优先级由高到低排列最后一个优先级最低
*/
private fun hideOutOfBoundViewsIfNeed(views: MutableList<TextView>) {
if (views.isEmpty()) {
return
}
val totalWidth = views.sumOf {
it.width + it.marginStart
}
if (totalWidth > itemView.width) {
views.removeLast().goneIf(true)
hideOutOfBoundViewsIfNeed(views)
}
}
}
BaseRecyclerViewHolder<Any>(binding.root)

View File

@ -234,14 +234,11 @@ class AmwayAdapter(
if (m.find()) {
val contents =
TextHelper.getCommentLabelSpannableStringBuilder(amway.comment.content, R.color.text_theme)
binding.amwayContentTv.setTextWithHighlightedTextWrappedInsideWrapper(
contents,
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(context, "安利墙")
)
binding.amwayContentTv.setTextWithHighlightedTextWrappedInsideWrapper(contents, copyClickedText = true)
} else {
binding.amwayContentTv.setTextWithHighlightedTextWrappedInsideWrapper(
amway.comment.content,
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(context, "安利墙")
copyClickedText = true
)
}
@ -336,11 +333,7 @@ class AmwayAdapter(
binding.sdvUserBadge.setOnClickListener {
DialogUtils.showViewBadgeDialog(context, amway.comment.user.badge, object : ConfirmListener {
override fun onConfirm() {
MtaHelper.onEvent(
"进入徽章墙_用户记录",
"安利墙",
"${amway.comment.user.name}${amway.comment.user.id}"
)
MtaHelper.onEvent("进入徽章墙_用户记录", "安利墙", "${amway.comment.user.name}${amway.comment.user.id}")
MtaHelper.onEvent("徽章中心", "进入徽章中心", "安利墙")
DirectUtils.directToBadgeWall(
context,

View File

@ -4,10 +4,11 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.DisplayType
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.search.SearchDefaultFragment
@ -63,16 +64,19 @@ class AmwaySearchActivity : SearchActivity() {
}
override fun updateDisplayType(type: DisplayType) {
val transaction = when (type) {
DisplayType.DEFAULT -> showFragment(
SearchDefaultFragment::class.java.name,
{ AmwaySearchDefaultFragment() }
)
val transaction = supportFragmentManager.beginTransaction()
when (type) {
DisplayType.DEFAULT -> {
val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.name)
?: AmwaySearchDefaultFragment()
transaction.replace(R.id.search_result, fragment, SearchDefaultFragment::class.java.name)
}
else -> showFragment(
AmwaySearchListFragment::class.java.name,
{ AmwaySearchListFragment() }
)
else -> {
val fragment = supportFragmentManager.findFragmentByTag(AmwaySearchListFragment::class.java.name)
?: AmwaySearchListFragment()
transaction.replace(R.id.search_result, fragment, AmwaySearchListFragment::class.java.name)
}
}
mDisplayType = type
transaction.commitAllowingStateLoss()

View File

@ -33,7 +33,7 @@ class AmwaySearchDefaultFragment : SearchDefaultFragment() {
mViewModel.playedGames.observeNonNull(viewLifecycleOwner) {
defaultViewModel?.isExistHotSearch = it.isNotEmpty()
updateView()
mBinding.searchDiscoveryList.run {
mBinding.hotList.run {
layoutManager = LinearLayoutManager(context)
adapter = AmwaySearchAdapter(context, mViewModel, "安利墙搜索-最近玩过").apply { setData(it) }
}
@ -45,7 +45,7 @@ class AmwaySearchDefaultFragment : SearchDefaultFragment() {
override fun provideDao(): ISearchHistoryDao = AmwaySearchDao()
override fun initView() {
mBinding = mAmwayBinding.searchContent
mBinding.searchDiscoveryHeadContainer.headTitle.text = "最近玩过"
mBinding.hotHeadContainer.headTitle.text = "最近玩过"
mBinding.historyFlexContainer.setLimitHeight(mFlexMaxHeight)
updateHistorySearchView(null)

View File

@ -57,7 +57,6 @@ class AmwaySearchListFragment : ToolbarFragment() {
when (it) {
LoadStatus.INIT_LOADING -> {
hideError()
hideRvList()
showLoading()
hideNoDataHint()
}
@ -65,19 +64,16 @@ class AmwaySearchListFragment : ToolbarFragment() {
hideError()
hideLoading()
hideNoDataHint()
showRvList()
}
LoadStatus.INIT_FAILED -> {
hideLoading()
hideNoDataHint()
showError()
hideRvList()
}
LoadStatus.INIT_EMPTY -> {
showNoDataHint()
hideError()
hideLoading()
hideRvList()
}
else -> {
// do nothing
@ -86,14 +82,6 @@ class AmwaySearchListFragment : ToolbarFragment() {
}
}
private fun hideRvList() {
mBinding.recyclerView.visibility = View.GONE
}
private fun showRvList() {
mBinding.recyclerView.visibility = View.VISIBLE
}
private fun showLoading() {
mBinding.loadingContainer.visibility = View.VISIBLE
}

View File

@ -44,7 +44,6 @@ class AmwaySearchViewModel(application: Application) : AndroidViewModel(applicat
mTempSearchKey = searchKey
currentSearchKey = searchKey
loadStatus.postValue(LoadStatus.INIT_LOADING)
searchGames.postValue(emptyList())
RetrofitManager
.getInstance().api
.getSearchGame(Config.API_HOST + "games:search?keyword=" + searchKey + "&view=anliwall" + "&channel=" + HaloApp.getInstance().channel + "&version=" + BuildConfig.VERSION_NAME)

View File

@ -10,7 +10,6 @@ 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.ImageUtils
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.DisplayUtils
@ -89,11 +88,6 @@ class AuthorizationActivity : ToolBarActivity() {
gameId = gameId,
gameName = gameName
)
SensorsBridge.trackEvent(
"LoginAuthorizationPageShow",
"authority_object",
if (mContent == TYPE_PLUGIN) "网游插件" else "其他"
)
}
private fun initData() {
@ -162,11 +156,6 @@ class AuthorizationActivity : ToolBarActivity() {
gameName = gameName,
buttonType = BUTTON_TYPE_CONFIRM
)
SensorsBridge.trackEvent(
"LoginAuthorizationClick",
"authority_object",
if (mContent == TYPE_PLUGIN) "网游插件" else "其他"
)
checkLogin {
authorization()
}
@ -196,12 +185,10 @@ class AuthorizationActivity : ToolBarActivity() {
private fun authorization() {
val remotePkgName = mRemotePkgName
if (remotePkgName == null) {
logAuthResult(false)
finish()
return
}
if (mToken.isEmpty()) {
logAuthResult(false)
toast("授权失败")
return
}
@ -218,21 +205,10 @@ class AuthorizationActivity : ToolBarActivity() {
intent.putExtra(EntranceConsts.KEY_USER_NAME, username)
intent.putExtra(EntranceConsts.KEY_USER_AVATAR, userAvatar)
sendBroadcast(intent)
logAuthResult(true)
backToLaunchApp()
finish()
}
private fun logAuthResult(isSuccess: Boolean) {
SensorsBridge.trackEvent(
"LoginAuthorizationResult",
"authority_object",
if (mContent == TYPE_PLUGIN) "网游插件" else "其他",
"authorization_result",
if (isSuccess) "成功" else "失败"
)
}
/**
* 跳转回授权app
*/
@ -263,7 +239,6 @@ class AuthorizationActivity : ToolBarActivity() {
companion object {
private const val BUTTON_TYPE_CONFIRM = "确定"
private const val BUTTON_TYPE_BACK = "返回"
private const val TYPE_PLUGIN = "plugin"
}
}

View File

@ -0,0 +1,43 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.base.DownloadToolbarActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
class CatalogActivity : DownloadToolbarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun showDownloadMenu(): Boolean {
return true
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(this, CatalogActivity::class.java, CatalogFragment::class.java)
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun isAutoResetViewBackgroundEnabled() = true
companion object {
fun getIntent(context: Context, catalogId: String, catalogTitle: String, entrance: String): Intent {
val bundle = Bundle()
bundle.putString(EntranceConsts.KEY_CATALOG_ID, catalogId)
bundle.putString(EntranceConsts.KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance)
return getTargetIntent(context, CatalogActivity::class.java, CatalogFragment::class.java, bundle)
}
}
}

View File

@ -0,0 +1,53 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.View
import android.view.ViewGroup
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.CatalogItemBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class CatalogAdapter(
context: Context,
private val mFragment: CatalogFragment,
private val mViewModel: CatalogViewModel,
private val mList: List<CatalogEntity.SubCatalogEntity>
) : BaseRecyclerAdapter<CatalogAdapter.CatalogItemViewHolder>(context) {
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
CatalogItemViewHolder(parent.toBinding())
override fun onBindViewHolder(holder: CatalogItemViewHolder, position: Int) {
holder.binding.run {
val catalogEntity = mList[position]
catalogName.text = catalogEntity.name
recommendTag.goneIf(!catalogEntity.recommended)
if (catalogEntity.name == mViewModel.selectedCatalogName) {
selectedTag.visibility = View.VISIBLE
catalogName.setTextColor(R.color.text_theme.toColor(mContext))
root.setBackgroundColor(R.color.ui_surface.toColor(mContext))
} else {
selectedTag.visibility = View.GONE
catalogName.setTextColor(R.color.text_primary.toColor(mContext))
root.background = null
}
root.setOnClickListener {
if (catalogEntity.name != mViewModel.selectedCatalogName) {
mViewModel.selectedCatalogName = catalogEntity.name
mViewModel.logSubCatalogClick(position)
mFragment.changeCatalog(position)
notifyDataSetChanged()
}
}
}
}
class CatalogItemViewHolder(val binding: CatalogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,240 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.viewModelProviderFromParent
import com.gh.gamecenter.common.view.FixLinearLayoutManager
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentCatalogBinding
import com.gh.gamecenter.entity.CatalogEntity
class CatalogFragment : LazyFragment() {
private var mBinding: FragmentCatalogBinding? = null
private var mViewModel: CatalogViewModel? = null
private var mEntity: CatalogEntity? = null
private var mSpecialCatalogFragment: SpecialCatalogFragment? = null
private var mSubCatalogFragment: SubCatalogFragment? = null
private var mCatalogId: String = ""
private var mCatalogTitle: String = ""
private var mLastSelectedPosition = -1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedInstanceState?.run {
mLastSelectedPosition = getInt(EntranceConsts.KEY_LAST_SELECTED_POSITION)
}
}
override fun onSaveInstanceState(outState: Bundle) {
mViewModel?.run {
outState.putInt(EntranceConsts.KEY_LAST_SELECTED_POSITION, selectedCatalogPosition)
}
super.onSaveInstanceState(outState)
}
override fun getRealLayoutId() = R.layout.fragment_catalog
override fun onRealLayoutInflated(inflatedView: View) {
mBinding = FragmentCatalogBinding.bind(inflatedView)
}
override fun onFragmentFirstVisible() {
mCatalogId = arguments?.getString(EntranceConsts.KEY_CATALOG_ID) ?: ""
mCatalogTitle = arguments?.getString(EntranceConsts.KEY_CATALOG_TITLE) ?: ""
mViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, mCatalogTitle), mCatalogId)
mViewModel?.validEntranceName = if (mEntrance.contains("首页")) "首页" else "板块"
if (arguments?.getBoolean(EntranceConsts.KEY_IS_HOME) == true) {
mViewModel?.validEntranceName = "首页Tab栏"
}
mViewModel?.logAppearance()
super.onFragmentFirstVisible()
}
override fun initRealView() {
super.initRealView()
setNavigationTitle(mCatalogTitle)
mViewModel?.catalogs?.observe(viewLifecycleOwner, Observer {
mBinding?.run {
reuseLoading.root.visibility = View.GONE
if (it != null) {
reuseNoConnection.root.visibility = View.GONE
if (it.subCatalog.isNotEmpty()) {
containerCatalog.visibility = View.VISIBLE
reuseNoneData.root.visibility = View.GONE
mEntity = it
if (mEntity!!.hasSpecial) {
val specialEntity = CatalogEntity.SubCatalogEntity(name = "精选")
(mEntity!!.subCatalog as ArrayList).add(0, specialEntity)
}
initView()
} else {
containerCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.VISIBLE
}
} else {
containerCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.VISIBLE
reuseNoConnection.root.setOnClickListener {
reuseNoConnection.root.visibility = View.GONE
reuseLoading.root.visibility = View.VISIBLE
mViewModel?.getCatalogs()
}
}
}
})
// 嵌入在首页时特殊处理
if (arguments?.getBoolean(EntranceConsts.KEY_IS_HOME) == true) {
mBinding?.divider?.visibility = View.GONE
mBinding?.root?.setBackgroundColor(R.color.ui_surface.toColor(requireContext()))
mBinding?.root?.setPadding(0, 8F.dip2px(), 0, 0)
mBinding?.rvCatalog?.setBackgroundColor(R.color.ui_background.toColor(requireContext()))
}
}
private fun initView() {
mEntity?.run {
mViewModel?.run {
if (subCatalog.isNotEmpty()) {
if (mLastSelectedPosition != -1) {
selectedCatalogPosition = mLastSelectedPosition
selectedCatalogName = subCatalog[mLastSelectedPosition].name
} else {
selectedCatalogPosition = 0
selectedCatalogName = subCatalog[0].name
}
mBinding?.rvCatalog?.layoutManager = FixLinearLayoutManager(requireContext())
mBinding?.rvCatalog?.adapter =
CatalogAdapter(requireContext(), this@CatalogFragment, this, subCatalog)
if (hasSpecial && selectedCatalogPosition == 0) {
mSpecialCatalogFragment =
childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.name) as? SpecialCatalogFragment
?: SpecialCatalogFragment()
mSpecialCatalogFragment?.arguments = bundleOf(
EntranceConsts.KEY_IS_CATEGORY_V2 to false,
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_CATALOG_TITLE to mCatalogTitle,
EntranceConsts.KEY_EXPOSURE_SOURCE to arguments?.getParcelable(
EntranceConsts.KEY_EXPOSURE_SOURCE
)
)
childFragmentManager.beginTransaction().replace(
R.id.container_sub_catalog,
mSpecialCatalogFragment!!,
SpecialCatalogFragment::class.java.name
).commitAllowingStateLoss()
} else {
mSubCatalogFragment =
childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.name) as? SubCatalogFragment
?: SubCatalogFragment()
mSubCatalogFragment?.arguments = bundleOf(
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_PRIMARY_CATALOG_ID to subCatalog[selectedCatalogPosition].id,
EntranceConsts.KEY_CATALOG_TITLE to mCatalogTitle
)
childFragmentManager.beginTransaction().replace(
R.id.container_sub_catalog,
mSubCatalogFragment!!,
SubCatalogFragment::class.java.name
).commitAllowingStateLoss()
}
}
}
}
}
fun changeCatalog(position: Int) {
mEntity?.run {
mViewModel?.run {
if (hasSpecial) {
changeCatalogIfHasSpecial(position)
} else {
changeSubCatalogInSubCatalogFragment(position)
}
selectedCatalogPosition = position
}
}
}
private fun changeCatalogIfHasSpecial(position: Int) {
mViewModel?.run {
when {
selectedCatalogPosition == 0 -> changeToSubCatalogFragment(position)
position == 0 -> changeToSpecialCatalogFragment()
else -> changeSubCatalogInSubCatalogFragment(position)
}
}
}
private fun changeToSubCatalogFragment(position: Int) {
mEntity?.run {
mSubCatalogFragment =
childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.name) as? SubCatalogFragment
?: SubCatalogFragment()
mSubCatalogFragment?.arguments = bundleOf(
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_PRIMARY_CATALOG_ID to subCatalog[position].id,
EntranceConsts.KEY_CATALOG_TITLE to mCatalogTitle
)
childFragmentManager.beginTransaction().replace(
R.id.container_sub_catalog,
mSubCatalogFragment!!,
SubCatalogFragment::class.java.name
).commitAllowingStateLoss()
}
}
private fun changeToSpecialCatalogFragment() {
mEntity?.run {
mSpecialCatalogFragment =
childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.name) as? SpecialCatalogFragment
?: SpecialCatalogFragment()
mSpecialCatalogFragment?.arguments = bundleOf(
EntranceConsts.KEY_IS_CATEGORY_V2 to false,
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_CATALOG_TITLE to mCatalogTitle,
EntranceConsts.KEY_EXPOSURE_SOURCE to arguments?.getParcelable(
EntranceConsts.KEY_EXPOSURE_SOURCE
)
)
childFragmentManager.beginTransaction().replace(
R.id.container_sub_catalog,
mSpecialCatalogFragment!!,
SpecialCatalogFragment::class.java.name
).commitAllowingStateLoss()
}
}
private fun changeSubCatalogInSubCatalogFragment(position: Int) {
mEntity?.run {
if (mSubCatalogFragment?.isStateSaved == false) {
mSubCatalogFragment?.arguments = bundleOf(
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_PRIMARY_CATALOG_ID to subCatalog[position].id,
EntranceConsts.KEY_CATALOG_TITLE to mCatalogTitle
)
}
mSubCatalogFragment?.changeSubCatalog(subCatalog[position].id)
}
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mBinding?.rvCatalog?.adapter?.run {
notifyItemRangeChanged(0, itemCount)
}
}
}

View File

@ -0,0 +1,72 @@
package com.gh.gamecenter.catalog
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.util.LogUtils
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class CatalogViewModel(application: Application, val catalogId: String, val catalogTitle: String) :
AndroidViewModel(application) {
private val api = RetrofitManager.getInstance().api
var catalogs = MutableLiveData<CatalogEntity>()
var selectedCatalogName: String = ""
var selectedCatalogPosition: Int = 0
var validEntranceName: String = ""
init {
getCatalogs()
}
@SuppressLint("CheckResult")
fun getCatalogs() {
api.getCatalogs(catalogId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<CatalogEntity>() {
override fun onSuccess(data: CatalogEntity) {
catalogs.postValue(data)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
catalogs.postValue(null)
}
})
}
fun logAppearance() {
LogUtils.logNewCatalogAppearanceEvent(validEntranceName, catalogTitle)
}
fun logSubCatalogClick(position: Int) {
LogUtils.logSubCatalogClickEvent(validEntranceName, "${catalogTitle}_${selectedCatalogName}", position)
}
fun logSubCatalogContentClick(itemName: String, listPosition: Int) {
LogUtils.logSubCatalogContentClickEvent(
validEntranceName,
"${catalogTitle}_${selectedCatalogName}_${itemName}",
selectedCatalogPosition,
listPosition
)
}
class Factory(private val catalogId: String, private val catalogTitle: String) :
ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return CatalogViewModel(HaloApp.getInstance().application, catalogId, catalogTitle) as T
}
}
}

View File

@ -0,0 +1,56 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.base.DownloadToolbarActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.entity.CatalogEntity
class NewCatalogListActivity : DownloadToolbarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun showDownloadMenu(): Boolean {
return true
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun isAutoResetViewBackgroundEnabled() = true
companion object {
fun getIntent(
context: Context,
primaryCatalogId: String, // 一级分类 id
primaryCatalogName: String, // 一级分类名
catalogTitle: String,
catalog: CatalogEntity,
initTitle: String
): Intent {
val bundle = Bundle()
bundle.putParcelable(EntranceConsts.KEY_DATA, catalog)
bundle.putString(EntranceConsts.KEY_PRIMARY_CATALOG_ID, primaryCatalogId)
bundle.putString(EntranceConsts.KEY_PRIMARY_CATALOG_NAME, primaryCatalogName)
bundle.putString(EntranceConsts.KEY_NAME, catalog.name)
bundle.putString(EntranceConsts.KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(EntranceConsts.KEY_CATALOG_INIT_TITLE, initTitle)
return getTargetIntent(
context,
NewCatalogListActivity::class.java,
NewCatalogListFragment::class.java,
bundle
)
}
}
}

View File

@ -0,0 +1,192 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.util.SparseArray
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.IExposable
import com.gh.common.util.DownloadItemUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.game.GameItemViewHolder
import com.lightgame.download.DownloadEntity
class NewCatalogListAdapter(
context: Context,
private val mBaseExposureSource: ExposureSource,
private val mViewModel: NewCatalogListViewModel,
private val mEntrance: String?
) : ListAdapter<GameEntity>(context), IExposable {
private val mExposureEventSparseArray: SparseArray<ExposureEvent> = SparseArray()
val positionAndPackageMap = HashMap<String, Int>()
override fun setListData(updateData: MutableList<GameEntity>?) {
// 记录游戏位置
if (updateData != null) {
for (i in 0 until updateData.size) {
val gameEntity = updateData[i]
var packages = gameEntity.id
for (apkEntity in gameEntity.getApk()) {
packages += apkEntity.packageName
}
positionAndPackageMap[packages + i] = i
}
}
super.setListData(updateData)
}
fun clearPositionAndPackageMap() {
positionAndPackageMap.clear()
}
override fun areItemsTheSame(oldItem: GameEntity?, newItem: GameEntity?): Boolean {
return oldItem?.id == newItem?.id
}
override fun getItemViewType(position: Int): Int {
if (position == itemCount - 1) {
return ItemViewType.ITEM_FOOTER
}
return ItemViewType.GAME_NORMAL
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ItemViewType.GAME_NORMAL -> {
GameItemViewHolder(parent.toBinding())
}
else -> {
FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
}
}
}
override fun getItemCount(): Int {
return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameItemViewHolder) {
val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px()
holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px())
val gameEntity = mEntityList[position]
holder.bindGameItem(gameEntity)
holder.initServerType(gameEntity)
val sortType = mViewModel.sortType.value
val sortSize = mViewModel.sortSize.text
val toolbarTitle = mViewModel.title
val selectedCatalogName = mViewModel.selectedCatalog.name
val exposureSources = ArrayList<ExposureSource>()
exposureSources.add(mBaseExposureSource)
exposureSources.add(ExposureSource(toolbarTitle))
exposureSources.add(ExposureSource("二级分类详情", "$selectedCatalogName+$sortType+$sortSize"))
val event = ExposureEvent.createEvent(gameEntity, exposureSources, null, ExposureType.EXPOSURE)
mExposureEventSparseArray.put(position, event)
holder.itemView.setOnClickListener {
GameDetailActivity.startGameDetailActivity(
mContext,
gameEntity,
StringUtils.buildString(
mEntrance,
"+(",
toolbarTitle,
":列表[",
selectedCatalogName,
"=",
sortType,
"=",
(position + 1).toString(),
"])"
),
traceEvent = event
)
}
DownloadItemUtils.setOnClickListener(
mContext,
holder.binding.downloadBtn,
gameEntity,
position,
this,
StringUtils.buildString(
StringUtils.buildString(
mEntrance,
"+(",
toolbarTitle,
":列表[",
selectedCatalogName,
"=",
sortType,
"=",
(position + 1).toString(),
"])"
)
),
location = StringUtils.buildString(selectedCatalogName, ":", gameEntity.name),
traceEvent = event
)
DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(holder.binding), "star&brief")
} else if (holder is FooterViewHolder) {
holder.initItemPadding()
holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
}
}
fun notifyItemByDownload(download: DownloadEntity) {
for (key in positionAndPackageMap.keys) {
// sentry上报download.packageName可能为空
if (download.packageName != null
&& download.gameId != null
&& key.contains(download.packageName)
&& key.contains(download.gameId)
) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size) {
mEntityList[position].getEntryMap()[download.platform] = download
notifyItemChanged(position)
}
}
}
}
fun notifyItemAndRemoveDownload(status: EBDownloadStatus) {
for (key in positionAndPackageMap.keys) {
if (key.contains(status.packageName) && key.contains(status.gameId)) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size) {
mEntityList[position].getEntryMap().remove(status.platform)
notifyItemChanged(position)
}
}
}
}
override fun getEventByPosition(pos: Int): ExposureEvent? {
return mExposureEventSparseArray.get(pos)
}
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? {
return null
}
}

View File

@ -0,0 +1,209 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import com.ethanhua.skeleton.Skeleton
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.DialogUtils
import com.gh.common.view.CatalogFilterView
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.baselist.ListFragment
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.databinding.FragmentCatalogListBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class NewCatalogListFragment : ListFragment<GameEntity, NewCatalogListViewModel>() {
private var mPrimaryCatalogName: String = "" // 一级分类名
private var mPrimaryCatalogId: String = "" // 一级分类 id
private var mPrimeCatalog: CatalogEntity? = null
private var mSubCatalogList = arrayListOf<CatalogEntity.SubCatalogEntity>()
private var mInitCatalogName = ""
private var mAdapter: NewCatalogListAdapter? = null
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
mAdapter?.notifyItemByDownload(downloadEntity)
if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) {
showUnzipFailureDialog(downloadEntity)
}
}
override fun onDataInit(downloadEntity: DownloadEntity) {
mAdapter?.notifyItemByDownload(downloadEntity)
}
}
private var mBinding: FragmentCatalogListBinding? = null
private lateinit var mExposureListener: ExposureListener
private lateinit var mViewModel: NewCatalogListViewModel
override fun getLayoutId() = 0
override fun getInflatedLayout() = FragmentCatalogListBinding.inflate(layoutInflater).apply { mBinding = this }.root
override fun provideListViewModel() = viewModelProvider<NewCatalogListViewModel>()
override fun provideListAdapter() = mAdapter
?: NewCatalogListAdapter(
requireContext(),
ExposureSource(mPrimaryCatalogName),
mViewModel,
mEntrance
).apply { mAdapter = this }
override fun getItemDecoration() = null
override fun onCreate(savedInstanceState: Bundle?) {
mViewModel = provideListViewModel()
mViewModel.title = arguments?.getString(EntranceConsts.KEY_NAME) ?: ""
mViewModel.categoryTitle = arguments?.getString(EntranceConsts.KEY_CATALOG_TITLE) ?: ""
mEntrance = arguments?.getString(EntranceConsts.KEY_ENTRANCE) ?: Constants.ENTRANCE_UNKNOWN
mPrimeCatalog = arguments?.getParcelable(EntranceConsts.KEY_DATA)
mSubCatalogList = mPrimeCatalog?.subCatalog as? ArrayList<CatalogEntity.SubCatalogEntity> ?: arrayListOf()
mInitCatalogName = arguments?.getString(EntranceConsts.KEY_CATALOG_INIT_TITLE) ?: ""
mPrimaryCatalogName = arguments?.getString(EntranceConsts.KEY_PRIMARY_CATALOG_NAME) ?: ""
mPrimaryCatalogId = arguments?.getString(EntranceConsts.KEY_PRIMARY_CATALOG_ID) ?: ""
mViewModel.selectedCatalog = mSubCatalogList.find { entity -> entity.name == mInitCatalogName }
?: CatalogEntity.SubCatalogEntity()
mViewModel.primaryCatalogId = mPrimaryCatalogId
initSortType()
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setNavigationTitle(mViewModel.title)
initFilterView()
mViewModel.refresh.observeNonNull(this) { onRefresh() }
mExposureListener = ExposureListener(this, mAdapter!!)
mListRv.addOnScrollListener(mExposureListener)
mSkeletonScreen = Skeleton.bind(mBinding?.listSkeleton)
.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_tags_skeleton)
.show()
}
private fun initSortType() {
mPrimeCatalog?.switch?.run {
if (hotSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.RECOMMENDED
return@run
}
if (newSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.NEWEST
return@run
}
if (starSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.RATING
return@run
}
}
}
private fun initFilterView() {
mBinding?.filterContainer?.run {
visibility = View.VISIBLE
setTypeList(mPrimeCatalog?.switch ?: CatalogEntity.CatalogSwitch())
setCatalogList(mSubCatalogList, mInitCatalogName)
setOnConfigSetupListener(object : CatalogFilterView.OnCatalogFilterSetupListener {
override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) {
mViewModel.updateSortConfig(sortSize = sortSize)
}
override fun onSetupSortType(sortType: CatalogFilterView.SortType) {
mViewModel.updateSortConfig(sortType = sortType)
}
override fun onSetupSortCatalog(sortCatalog: CatalogEntity.SubCatalogEntity) {
mViewModel.updateSortConfig(sortCatalog = sortCatalog)
}
})
}
}
override fun onResume() {
super.onResume()
DownloadManager.getInstance().addObserver(mDataWatcher)
}
override fun onPause() {
super.onPause()
DownloadManager.getInstance().removeObserver(mDataWatcher)
}
override fun onRefresh() {
mAdapter?.clearPositionAndPackageMap()
super.onRefresh()
}
// 下载被删除事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(status: EBDownloadStatus) {
if ("delete" == status.status) {
mAdapter?.notifyItemAndRemoveDownload(status)
}
}
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
mAdapter?.notifyDataSetChanged()
}
}
fun showUnzipFailureDialog(downloadEntity: DownloadEntity) {
val data = mAdapter?.positionAndPackageMap ?: return
for (gameAndPosition in data) {
if (gameAndPosition.key.contains(downloadEntity.packageName)) {
val targetView = mLayoutManager.findViewByPosition(gameAndPosition.value)
if (targetView != null) {
DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
return
}
}
}
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mBinding?.filterContainer?.run {
setRootBackgroundColor(R.color.ui_surface.toColor(requireContext()))
setItemTextColor(R.color.text_secondary.toColor(requireContext()))
updatePopupWindow()
}
}
}

View File

@ -0,0 +1,98 @@
package com.gh.gamecenter.catalog
import android.app.Application
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.common.entity.ExposureEntity
import com.gh.common.exposure.ExposureUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.common.view.CatalogFilterView
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.Single
class NewCatalogListViewModel(application: Application) : ListViewModel<GameEntity, GameEntity>(application) {
var title = "" // 显示在 Toolbar 的标题
var categoryTitle = "" // 跳转进来的分类的标题
val refresh = MutableLiveData<Boolean>()
var selectedCatalog = CatalogEntity.SubCatalogEntity()
var sortType = CatalogFilterView.SortType.RECOMMENDED
var sortSize = SubjectSettingEntity.Size()
var primaryCatalogId = "" // 一级分类 id
private val sensitiveApi = RetrofitManager.getInstance().api
override fun provideDataObservable(page: Int): Observable<List<GameEntity>>? = null
override fun provideDataSingle(page: Int): Single<List<GameEntity>> {
return if (selectedCatalog.link.type == "column") { // column(专题)/tag(标签)
sensitiveApi.getColumn(selectedCatalog.link.link, getSortType(), getSortSize(), page) // 专题
} else {
sensitiveApi.getGamesWithSpecificTag(getSortSize(), getSortType(), page) // 标签
}
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) {
it.forEach { game -> game.hideSizeInsideDes = true }
ExposureUtils.updateExposureInfo(
gameList = it,
containerId = primaryCatalogId,
containerType = ExposureEntity.CATEGORY_ID
)
mResultLiveData.postValue(it)
}
}
fun updateSortConfig(
sortSize: SubjectSettingEntity.Size? = null,
sortType: CatalogFilterView.SortType? = null,
sortCatalog: CatalogEntity.SubCatalogEntity? = null
) {
when {
sortSize != null && sortSize != this.sortSize -> {
this.sortSize = sortSize
refresh.postValue(true)
}
sortType != null && sortType != this.sortType -> {
this.sortType = sortType
refresh.postValue(true)
}
sortCatalog != null && sortCatalog != selectedCatalog -> {
selectedCatalog = sortCatalog
refresh.postValue(true)
}
}
}
private fun getSortSize(): String? {
return if (selectedCatalog.link.type == "column") {
UrlFilterUtils.getFilterQuery(
"min_size", sortSize.min.toString(),
"max_size", sortSize.max.toString()
)
} else {
UrlFilterUtils.getFilterQuery(
"tag_id", selectedCatalog.link.link,
"min_size", sortSize.min.toString(),
"max_size", sortSize.max.toString()
)
}
}
private fun getSortType(): String? {
return when (sortType) {
CatalogFilterView.SortType.RECOMMENDED -> if (selectedCatalog.link.type == "column") "position:1" else "download:-1"
CatalogFilterView.SortType.NEWEST -> "publish:-1"
CatalogFilterView.SortType.RATING -> "star:-1"
}
}
}

View File

@ -0,0 +1,54 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.ViewGroup
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.SubCatalogItemBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class SubCatalogAdapter(
context: Context,
private val mCatalogViewModel: CatalogViewModel,
private val mPrimaryCatalog: CatalogEntity,
private var mList: List<CatalogEntity.SubCatalogEntity>
) : BaseRecyclerAdapter<SubCatalogAdapter.SubCatalogItemViewHolder>(context) {
private val mTypes = listOf("专题", "标签")
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
SubCatalogItemViewHolder(parent.toBinding())
override fun onBindViewHolder(holder: SubCatalogItemViewHolder, position: Int) {
holder.binding.run {
val catalogEntity = mList[position]
ImageUtils.display(catalogIcon, catalogEntity.icon)
catalogName.text = catalogEntity.name
catalogName.setTextColor(R.color.text_primary.toColor(mContext))
recommendTag.goneIf(!catalogEntity.recommended)
root.setOnClickListener {
mCatalogViewModel.logSubCatalogContentClick(catalogEntity.name, position)
if (mTypes.contains(catalogEntity.type)) {
root.context.startActivity(
NewCatalogListActivity.getIntent(
mContext,
mCatalogViewModel.catalogId,
mCatalogViewModel.catalogTitle,
catalogEntity.name,
mPrimaryCatalog,
catalogEntity.name
)
)
} else {
DialogHelper.showUpgradeDialog(mContext)
}
}
}
}
class SubCatalogItemViewHolder(val binding: SubCatalogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

Some files were not shown because too many files have changed in this diff Show More