Compare commits

..

2 Commits

4409 changed files with 82566 additions and 182269 deletions

4
.gitignore vendored
View File

@ -9,6 +9,4 @@ build/
release-app/
test-app/
scripts/apk-channel/
app/src/test/java/com/gh/gamecenter
app/src/main/assets-debug/
app/src/main/assets-release/
app/src/test/java/com/gh/gamecenter

View File

@ -61,7 +61,7 @@ android_build:
script:
- export GRADLE_USER_HOME=/home/gitlab-runner/ci-build-cache/$CI_PROJECT_PATH/.gradle
- chmod +x ./gradlew
- ./scripts/jenkins_build.sh $CI_COMMIT_REF_NAME $BEFORE_COMMIT_SHA $CI_COMMIT_SHA
- ./scripts/jenkins_build.sh -c
#设置打包后的产物用于job之间共享
artifacts:
paths:
@ -71,14 +71,15 @@ android_build:
exit_codes: 137
only:
- dev
- release
- dev-5.29.0
- dev-5.30.0
# 代码检查
sonarqube_analysis:
tags:
- offline-test
stage: build&analyze
image: hub.shanqu.cc/library/sonar-scanner-cli:latest
image: sonarsource/sonar-scanner-cli:latest
dependencies: [] #禁止传递来的artifact
script:
## 获取项目的一级组和二级组和项目名作为projectKey例如projectKey=platform-backend-eci-monitor
@ -102,7 +103,8 @@ sonarqube_analysis:
exit_codes: 137
only:
- dev
- release
- dev-5.29.0
- dev-5.30.0
## 发送简易检测结果报告
send_sonar_report:
@ -120,24 +122,22 @@ send_sonar_report:
exit_codes: 137
only:
- dev
- release
- dev-5.29.0
- dev-5.30.0
oss-upload&send-email:
tags:
- sysadm-devops
- rancher-k8s
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 # 固定值
VAULT_SECRET_PATH: prod/devops/android-apk-oss-upload # 固定值
VAULT_ROLE: android-apk-oss-upload # 固定值
ENDPOINT: "tos-cn-guangzhou.ivolces.com" # 固定值
BUCKET: "sysadm-public" # 固定值
FILE_PATH: "app/build/tmp/" # APK 存放路径
ENDPOINT: "oss-cn-shenzhen-internal.aliyuncs.com" # 固定值
BUCKET: "shanqu" # 固定值
FILE_PATH: "app/build/tmp/" # APK 存放路径
Email_To_List: $EMAIL_TO_LIST # 邮件接受人列表
Email_Title: "光环助手 $CI_COMMIT_BRANCH" # 邮件标题
PIPELINE_ID: $CI_PIPELINE_ID # 流水线id
@ -148,13 +148,12 @@ 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
### 发送邮件
- /usr/local/bin/python /ci-android-mail-jira-comment.py
- /usr/local/bin/python /ci-android-mail.py
only:
- dev
- release
- dev-5.29.0
- dev-5.30.0

6
.gitmodules vendored
View File

@ -5,9 +5,9 @@
[submodule "vspace-bridge"]
path = vspace-bridge
url = ../../../cwzs/android/vspace-bridge.git
[submodule "module_common/src/debug/assets/assistant-android-mock"]
path = module_common/src/debug/assets/assistant-android-mock
url = ../../../halo/android/assistant-android-mock.git
[submodule "ndownload"]
path = ndownload
url = ../../../android/ndownload.git
[submodule "vasdk"]
path = vasdk
url = ../../../sdg/android/vasdk.git

View File

@ -30,7 +30,14 @@
### git 版本管理
本项目使用简化版的 git flow 来管理分支,细节请看 [光环安卓简单 git 规范](https://git.shanqu.cc/halo/android/assistant-android/-/wikis/%E5%85%89%E7%8E%AF%E5%AE%89%E5%8D%93%E7%AE%80%E5%8D%95-git-%E8%A7%84%E8%8C%83)
本项目使用简化版的 git flow 来管理分支,细节请看 [光环安卓简单 git 规范](https://git.ghzs.com/halo/android/assistant-android/-/wikis/%E5%85%89%E7%8E%AF%E5%AE%89%E5%8D%93%E7%AE%80%E5%8D%95-git-%E8%A7%84%E8%8C%83)
### API 环境配置
本项目使用 Build Variants 来切换 API 环境
* internal 为测试环境
* publish 为正式环境
### 图片资源配置
@ -44,4 +51,16 @@
### 混淆配置
* 本项目使用了微信的 [AndResGuard](https://github.com/shwenzhang/AndResGuard) 作为资源混淆压缩方案,新增需要使用 `getIdentifier` 获取的资源文件时需要添加至白名单
* 本项目默认使用 R8 作为混淆工具,往 proguard-rules.txt 添加 proguard 新配置项时请检查可用性(如语法等)
### APK打包配置
> 打内部测试包:`./scripts/test_build.sh`
> 打邮件测试包:`./scripts/jenkins_build.sh`
### TODO
* 把原有 EventBus 的消息 Type 统一到一个文件内
* 将实现细节从 View(Fragment、Activity) 剥离并以 MVVM 结构改造
* 重构 MainActivity

View File

@ -2,9 +2,8 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' // kotlin
apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.devtools.ksp'
apply plugin: 'kotlin-kapt'
apply plugin: 'therouter'
apply plugin: 'AndResGuard'
import groovy.xml.XmlUtil
@ -24,8 +23,6 @@ android {
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@ -53,10 +50,6 @@ android {
}
}
ksp {
arg("ROUTER_MODULE_NAME", project.getName())
}
defaultConfig {
vectorDrawables.useSupportLibrary = true
multiDexEnabled true
@ -80,7 +73,7 @@ android {
versionName rootProject.ext.versionName
applicationId rootProject.ext.applicationId
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt', rootProject.ext.va_proguard_rules
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
String CORE_EVENT_GAME_CATEGORY = ""
@ -102,20 +95,13 @@ android {
buildConfigField "int", "ACTIVATE_REPORTING_RATIO", "${ACTIVATE_REPORTING_RATIO}"
// All third-party appid/appkey
buildConfigField "boolean", "IS_GAT_APP", "false"
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST}\""
buildConfigField "String", "LOG_HUB_PROJECT", "\"${LOG_HUB_PROJECT}\""
buildConfigField "String", "VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "WGAME_CPM_BUSIAPPID", "\"${WGAME_CPM_BUSIAPPID}\""
buildConfigField "String", "WGAME_CPM_API_HOST", "\"${WGAME_CPM_API_HOST}\""
buildConfigField "String", "WECHAT_APPID", "\"${WECHAT_APPID}\""
buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\""
buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\""
buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\""
buildConfigField "String", "DSP_API_HOST","\"${DSP_API_HOST}\""
// 一体包的32位畅玩游戏助手包名
buildConfigField "String", "EXT_PACKAGE_NAME", "\"${rootProject.ext.EXT_PACKAGE_NAME}\""
}
// gradle 2.2以上默认同时启用v1和v2优先用于Android N
@ -130,21 +116,10 @@ android {
}
}
packagingOptions {
// exclude 部分冗余的文件
exclude 'META-INF/gradle/incremental.annotation.processors'
exclude 'darwin/x86_64/liblz4-java.dylib'
exclude 'assets/libwbsafeedit_x86'
exclude 'assets/libwbsafeedit_x86_64'
exclude 'lib/armeabi-v7a/libRSSupport.so'
exclude 'lib/arm64-v8a/libRSSupport.so'
exclude 'lib/armeabi-v7a/librsjni.so'
exclude 'lib/arm64-v8a/librsjni.so'
resources.excludes += "com/j256/*"
resources.excludes += "org/apache/commons/codec/language/bm/*"
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.name)
}
}
buildTypes {
@ -154,7 +129,7 @@ android {
zipAlignEnabled false
signingConfig signingConfigs.debug
buildConfigField "String", "EXPOSURE_REPO", "\"exposure\""
buildConfigField "String", "EXPOSURE_REPO", "\"test\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E4\""
multiDexKeepProguard file("tinker_multidexkeep.pro")
@ -182,23 +157,14 @@ android {
}
}
flavorDimensions("env", "region")
flavorDimensions("env")
sourceSets {
debug {
assets.srcDirs += 'src/main/assets-debug'
}
release {
assets.srcDirs += 'src/main/assets-release'
}
publish {
java.srcDirs = ['src/main/java', "src/default/java"]
}
internal {
java.srcDirs = ['src/main/java', "src/default/java", "src/internal/java"]
java.srcDirs = ['src/main/java', "src/default/java"]
}
tea {
java.srcDirs = ['src/main/java', 'src/tea/java']
@ -209,15 +175,6 @@ android {
gdt {
java.srcDirs = ['src/main/java', 'src/gdt/java']
}
gat {
java.srcDirs = ['src/main/java', 'src/gat/java']
}
cn {
java.srcDirs = ['src/main/java', 'src/cn/java']
}
sm {
java.srcDirs = ['src/main/java', 'src/sm/java']
}
}
productFlavors {
@ -231,11 +188,7 @@ android {
buildConfigField "String", "DEV_VAPI_HOST", "\"${DEV_VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${DEV_QUICK_LOGIN_APPID}\""
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")
buildConfigField "String", "CSJ_APPID", "\"${DEV_CSJ_APPID}\""
}
// publish 发布时候使用的 flavor接口仅包含正式环境
@ -247,11 +200,7 @@ android {
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
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 {
@ -262,13 +211,9 @@ android {
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
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("APPLOG_SCHEME", "rangersapplog.byAx6uYt".toLowerCase())
manifestPlaceholders.put("VA_VERSION_NAME", "${rootProject.ext.VA_VERSION}")
}
kuaishou {
@ -279,11 +224,7 @@ android {
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
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 {
@ -294,45 +235,7 @@ android {
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
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 {
dimension "env"
buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\""
buildConfigField "String", "NEW_DEV_API_HOST", "\"${NEW_API_HOST}\""
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
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}")
}
// 港澳台
gat {
dimension "region"
applicationId rootProject.ext.applicationIdGat
// 支持繁体
resConfigs "zh", "zh-rTW"
buildConfigField "boolean", "IS_GAT_APP", "true"
buildConfigField "String", "LOG_HUB_PROJECT", "\"${LOG_HUB_PROJECT_GAT}\""
buildConfigField "String", "API_HOST", "\"${API_HOST_GAT}\""
buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST_GAT}\""
}
cn {
dimension "region"
}
}
}
@ -343,21 +246,6 @@ repositories {
}
}
// 删除不需要的 assets
android.applicationVariants.configureEach { variant ->
variant.mergeAssets.doLast {
def assetDir = variant.mergeAssetsProvider.get().outputDir.get()
def unwantedAssets = ['1832823466', 'gdt_plugin/gdtadv2.jar']
unwantedAssets.each { assetPath ->
def file = new File([assetDir, assetPath].join(File.separator))
if (file.exists()) {
file.delete()
}
}
}
}
dependencies {
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
@ -365,13 +253,14 @@ dependencies {
teaImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/tea/libs')
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}"
// debugImplementation "com.gu.android:toolargetool:${toolargetool}" // 需要使用调试时才启用
debugImplementation "com.github.nichbar:WhatTheStack:${whatTheStack}"
// debugImplementation "io.github.didi.dokit:dokitx:${dokit}"
implementation "androidx.multidex:multidex:${multiDex}"
implementation "androidx.fragment:fragment-ktx:${fragment}"
@ -379,10 +268,11 @@ dependencies {
implementation "androidx.annotation:annotation:${annotation}"
implementation "androidx.viewpager2:viewpager2:${viewpager2}"
ksp("androidx.room:room-compiler:${room}")
kapt "androidx.room:room-compiler:${room}"
implementation "com.tencent.vasdolly:helper:${apkChannelPackage}"
implementation "com.tencent.vasdolly:writer:${apkChannelPackage}"
implementation "com.kyleduo.switchbutton:library:${switchButton}"
implementation "com.leon.channel:helper:${apkChannelPackage}"
implementation "com.j256.ormlite:ormlite-android:${ormlite}"
implementation "com.j256.ormlite:ormlite-core:${ormlite}"
@ -403,14 +293,14 @@ dependencies {
exclude module: "gsyvideoplayer-androidvideocache"
exclude group: "tv.danmaku.ijk.media"
})
implementation("com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-exo_player2:$gsyVideo") {
exclude group: 'com.google.android.exoplayer', module: 'extension-rtmp'
}
implementation "com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-exo_player2:$gsyVideo"
// implementation "androidx.work:work-runtime:${workManager}"
implementation "com.llew.huawei:verifier:${verifier}"
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:${bytedanceApplog}"
teaImplementation "com.bytedance.ads:AppConvert:${bytedanceAppConvert}"
teaImplementation "com.bytedance.applog:RangersAppLog-All-convert:${bytedanceApplog}"
implementation "net.lingala.zip4j:zip4j:${zip4j}"
@ -419,128 +309,53 @@ dependencies {
implementation "com.lg:easyfloat:${easyFloat}"
implementation("com.lg:apksig:${apksig}") {
exclude group: 'com.google.protobuf'
}
implementation "io.github.florent37:shapeofview:${shapeOfView}"
implementation "com.lg:apksig:${apksig}"
implementation "com.lg:gid:${gid}"
implementation "com.lg:shortcut:${shortcut}"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:${desugarJdkLibs}"
kapt "com.google.auto.service:auto-service:${autoServiceVersion}"
ksp "cn.therouter:apt:${routerVersion}"
kapt "com.alibaba:arouter-compiler:$arouterVersion"
implementation project(':ndownload')
implementation project(':vspace-bridge:vspace')
implementation(project(':feature:xapk-installer'))
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_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'
}
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:vpn'))
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'))
}
if (gradle.ext.enableRouteDoc) {
ksp project(":feature:route_doc")
}
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'
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableAccelerator) {
implementation(project(":feature:accelerator"))
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableAliPay) {
implementation(project(":feature:ali_pay"))
}
if(!gradle.ext.excludeOptionalModules || gradle.ext.enableWechatPay){
implementation(project(":feature:wechat_pay"))
}
implementation "me.xdrop:fuzzywuzzy:${fuzzyVersion}"
}
File propFile = file('sign.properties')
@ -600,6 +415,106 @@ 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.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"
]
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
]
sevenzip {
artifact = 'io.github.leon406:SevenZip:1.2.22.5'
}
}
project.afterEvaluate {
def variants = null
try {

View File

@ -20,7 +20,6 @@
-keep class com.gh.gamecenter.db.info.* {*;}
-keep class com.gh.gamecenter.entity.** {<fields>;}
-keep class com.gh.gamecenter.qa.entity.** {<fields>;}
-keep class com.gh.gamecenter.gamedetail.entity.** {<fields>;}
-keep class com.gh.download.DownloadDataSimpleEntity {<fields>;}
-keep class com.gh.gamecenter.floatingwindow.FloatingWindowEntity {<fields>;}
-keep class com.gh.gamecenter.BR
@ -77,24 +76,19 @@
### TEA
-keep class com.gh.gamecenter.TeaHelper { *; }
-keep class com.bytedance.ads.convert.broadcast.common.EncryptionTools {*;}
### EasyFloat
-keep class com.lzf.easyfloat.* {*;}
### dokit
-keep class com.didichuxing.** {*;}
### 广点通SDK
-dontwarn com.qq.gdt.action.**
-keep class com.qq.gdt.action.** {*;}
-keep public class com.tencent.turingfd.sdk.**
### 神马 SDK
-dontwarn com.gism.**
-keepclasseswithmembers class * {
native <methods>;
}
-keepclassmembernames class com.contrarywind.view.WheelView {
private int itemsVisible;
}

View File

@ -8,7 +8,7 @@ import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.PackageFlavorHelper
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.tencent.vasdolly.helper.ChannelReaderUtil
import com.leon.channel.helper.ChannelReaderUtil
class FlavorProviderImp : IFlavorProvider {
override fun getChannelStr(application: Application): String {

View File

@ -5,7 +5,6 @@ import com.lightgame.utils.Utils
import com.qq.gdt.action.ActionParam
import com.qq.gdt.action.ActionType
import com.qq.gdt.action.GDTAction
import com.qq.gdt.action.PrivateController
import org.json.JSONObject
object GdtHelper {
@ -17,20 +16,11 @@ object GdtHelper {
@JvmStatic
fun init(application: Application, channel: String) {
GDTAction.setPrivateController(object : PrivateController() {
override fun isCanUsePhoneState(): Boolean {
return false
}
})
if (channel == "KS_GDT_GHZS_MC01") {
GDTAction.init(application, KS_USER_ACTION_SET_ID, KS_APP_SECRET_ID, channel)
} else {
GDTAction.init(application, USER_ACTION_SET_ID, APP_SECRET_ID, channel)
}
GDTAction.start()
Utils.log("init GdtHelper")
}

View File

@ -8,7 +8,7 @@ import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils
import com.halo.assistant.HaloApp
import com.tencent.vasdolly.helper.ChannelReaderUtil
import com.leon.channel.helper.ChannelReaderUtil
class FlavorProviderImp : IFlavorProvider {

Binary file not shown.

View File

@ -1,42 +0,0 @@
package com.gh.vspace
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.Keep
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.lightgame.utils.Utils
import java.io.File
@Keep
class ExternalGameUsage : ITestCase {
private fun buttonTemplate(viewParent: ViewGroup, id: Int, fn: (LayoutPersonalOtherItemBinding) -> Unit) {
val context = viewParent.context
viewParent.findViewById<View>(id) ?: run {
val binding = LayoutPersonalOtherItemBinding.inflate(LayoutInflater.from(context)).apply {
root.id = id
fn(this)
}
viewParent.addView(binding.root, 0)
}
}
override fun addInstallExternalGameButton(viewParent: ViewGroup) {
val context = viewParent.context
buttonTemplate(viewParent, R.id.install_game_from_external) {
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 })
}
}
}
}

View File

@ -1,5 +0,0 @@
package com.gh.vspace.installexternalgames;
public class Constants {
public static final String TAG = "从SD卡安装";
}

View File

@ -1,52 +0,0 @@
package com.gh.vspace.installexternalgames
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toBinding
class ExternalGameAdapter(private val games: List<ExternalGameUiState>, private val onItemClickListener: OnItemClickListener) :
RecyclerView.Adapter<ExternalGameViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExternalGameViewHolder {
return ExternalGameViewHolder(parent.toBinding())
}
override fun getItemCount(): Int {
return games.size
}
override fun onBindViewHolder(holder: ExternalGameViewHolder, position: Int) {
val item = games[position]
holder.apkInfo.text = item.externalGameEntity.let { item ->
"""
应用程序名:${item.appName}
版本号:${item.apkVersion}
包名: ${item.apkPackageName}
路径:${item.apkPath}
""".trimIndent()
}
holder.update.setOnClickListener {
onItemClickListener.onItemClick(item, OnItemClickListener.ClickType.CLICK_INSTALL)
}
holder.install.goneIf(item.isInstalled) {
holder.install.setOnClickListener {
onItemClickListener.onItemClick(item, OnItemClickListener.ClickType.CLICK_INSTALL)
}
}
holder.uninstall.goneIf(!item.isInstalled) {
holder.uninstall.setOnClickListener {
onItemClickListener.onItemClick(
item,
OnItemClickListener.ClickType.CLICK_UNINSTALL
)
}
}
holder.start.goneIf(!item.isInstalled) {
holder.start.setOnClickListener {
onItemClickListener.onItemClick(item, OnItemClickListener.ClickType.CLICK_START)
}
}
}
}

View File

@ -1,11 +0,0 @@
package com.gh.vspace.installexternalgames
data class ExternalGameEntity(
val cpuAbi: Set<String>,
val apkPath: String,
val apkFileName: String,
val appName: String,
val apkVersion: String,
val apkPackageName: String,
val lastModified: Long,
)

View File

@ -1,6 +0,0 @@
package com.gh.vspace.installexternalgames
data class ExternalGameUiState(
val externalGameEntity: ExternalGameEntity,
val isInstalled: Boolean
)

View File

@ -1,12 +0,0 @@
package com.gh.vspace.installexternalgames
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.databinding.LayoutExternalGameItemBinding
class ExternalGameViewHolder(binding: LayoutExternalGameItemBinding) : RecyclerView.ViewHolder(binding.root) {
val apkInfo = binding.apkFileInfo
val install = binding.btnInstall
val uninstall = binding.btnUninstall
val start = binding.btnStart
val update = binding.btnUpdate
}

View File

@ -1,14 +0,0 @@
package com.gh.vspace.installexternalgames
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.gamecenter.common.base.activity.ToolBarActivity
class InstallExternalGameActivity : ToolBarActivity() {
companion object {
fun getIntent(context: Context): Intent {
return getTargetIntent(context, InstallExternalGameActivity::class.java, InstallExternalGameFragment::class.java, Bundle())
}
}
}

View File

@ -1,231 +0,0 @@
package com.gh.vspace.installexternalgames
import android.Manifest
import android.app.Dialog
import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.gh.common.util.DialogUtils
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.view.divider.HorizontalDividerItemDecoration
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.databinding.FragmentInstallExternalGamesBinding
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lg.vspace.VirtualAppManager
import com.lightgame.download.DownloadEntity
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
private val mViewModel: InstallExternalGameViewModel by lazy { viewModelProvider() }
private lateinit var mBinding: FragmentInstallExternalGamesBinding
private val games = mutableListOf<ExternalGameUiState>()
private var adapter = ExternalGameAdapter(games, this)
private var uninstallDisposable: Disposable? = null
private var shouldScan = false
override fun getLayoutId() = 0
override fun getInflatedLayout() =
FragmentInstallExternalGamesBinding.inflate(layoutInflater).apply { mBinding = this }.root
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))
initView()
mViewModel.gamesList.observe(this) {
if (dialog.isShowing) {
dialog.dismiss()
}
games.clear()
games.addAll(
it.map {
ExternalGameUiState(it, VHelper.isInstalled(it.apkPackageName))
}
)
adapter.notifyDataSetChanged()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
shouldScan = true
AlertDialog.Builder(requireContext()).setMessage("请在设置页面允许光环助手")
.setNegativeButton("") { dialog, which ->
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
}.show()
} else {
mViewModel.scanPaths()
}
} else {
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)
}
}
}
override fun onStart() {
super.onStart()
if (shouldScan) {
mViewModel.scanPaths()
}
}
private fun initView() {
dialog = DialogUtils.showWaitDialog(requireContext(), "")
mBinding.externalGamesList.let {
it.adapter = adapter
it.layoutManager = LinearLayoutManager(requireContext())
val itemDecoration = HorizontalDividerItemDecoration.Builder(requireContext())
.size(2F.dip2px())
.color(com.gh.gamecenter.common.R.color.ui_divider.toColor(requireContext()))
.build()
if (it.itemDecorationCount != 0) {
it.removeItemDecorationAt(0)
}
it.addItemDecoration(itemDecoration)
}
}
override fun onDestroy() {
super.onDestroy()
if (dialog.isShowing) {
dialog.dismiss()
}
if (uninstallDisposable?.isDisposed != true) {
uninstallDisposable?.dispose()
}
}
override fun onItemClick(externalGameUiState: ExternalGameUiState, clickType: OnItemClickListener.ClickType) {
when (clickType) {
OnItemClickListener.ClickType.CLICK_INSTALL -> {
install(externalGameUiState)
}
OnItemClickListener.ClickType.CLICK_UNINSTALL -> {
uninstall(externalGameUiState)
}
OnItemClickListener.ClickType.CLICK_START -> {
start(externalGameUiState)
}
}
}
private fun install(externalGameUiState: ExternalGameUiState) {
VHelper.disableLaunchGameAfterInstallation()
VHelper.install(requireContext(), DownloadEntity().apply {
externalGameUiState.externalGameEntity.apply {
packageName = apkPackageName
path = apkPath
}
}, true)
VHelper.newCwValidateVspaceBeforeAction(
requireContext(), null,
) {
dialog.show()
}
}
private fun uninstall(externalGameUiState: ExternalGameUiState) {
dialog.show()
uninstallDisposable = Single.create<Void> {
VHelper.uninstall(externalGameUiState.externalGameEntity.apkPackageName)
}.subscribeOn(Schedulers.from(AppExecutor.lightWeightIoExecutor)).observeOn(AndroidSchedulers.mainThread())
.subscribe { t1, t2 ->
if (dialog.isShowing) {
dialog.dismiss()
}
}
}
private fun start(externalGameUiState: ExternalGameUiState) {
val intent = VirtualAppManager.get().getStartGameIntent(
externalGameUiState.externalGameEntity.apkPackageName,
"",
externalGameUiState.externalGameEntity.appName,
"",
MetaUtil.getBase64EncodedAndroidId(),
HaloApp.getInstance().gid,
com.gh.gamecenter.BuildConfig.VERSION_NAME,
HaloApp.getInstance().channel,
"",
"",
com.gh.gamecenter.BuildConfig.VA_VERSION_NAME,
HaloApp.getInstance().oaid
)
intent.setComponent(
ComponentName(
com.gh.gamecenter.BuildConfig.APPLICATION_ID,
VirtualAppManager.AIDL_SERVER_REMOTE_GUIDE_ACTIVITY
)
)
requireActivity().startActivity(intent)
}
}

View File

@ -1,64 +0,0 @@
package com.gh.vspace.installexternalgames
import android.app.Application
import android.content.pm.PackageManager
import android.os.Environment
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.core.runOnIoThread
import com.gh.vspace.VHelper
import com.lg.vspace.helper.compat.NativeLibraryHelperCompat
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
class InstallExternalGameViewModel(application: Application) : AndroidViewModel(application) {
private val _gamesList = MutableLiveData<List<ExternalGameEntity>>(listOf())
val gamesList: LiveData<List<ExternalGameEntity>> = _gamesList
private val pkgManger = getApplication<Application>().packageManager
private var disposable: Disposable = VHelper.callSite.observeOn(AndroidSchedulers.mainThread()).subscribe {
scanPaths()
}
fun scanPaths() {
runOnIoThread {
_gamesList.postValue(Environment.getExternalStorageDirectory().walk().maxDepth(1)
.filter { it.isHidden.not() }
.filter { it.isFile }
.onEach {
Utils.log(Constants.TAG, "获得文件: ${it.name}")
}
.filter { it.extension == "apk" }
.map {
val packageInfo = pkgManger.getPackageArchiveInfo(
it.absolutePath,
PackageManager.GET_META_DATA or PackageManager.GET_ACTIVITIES
)
packageInfo?.let { packageInfo ->
val applicationInfo = packageInfo.applicationInfo
applicationInfo.publicSourceDir = it.absolutePath
applicationInfo.sourceDir = it.absolutePath
ExternalGameEntity(
cpuAbi = NativeLibraryHelperCompat.getPackageAbiList(it.absolutePath),
apkPath = it.absolutePath,
apkFileName = it.name,
apkPackageName = packageInfo.packageName,
apkVersion = packageInfo.versionName,
appName = pkgManger.getApplicationLabel(applicationInfo).toString(),
lastModified = it.lastModified()
)
}
}.filterNotNull()
.toList().sortedByDescending { it.lastModified }
)
}
}
override fun onCleared() {
super.onCleared()
disposable.dispose()
}
}

View File

@ -1,11 +0,0 @@
package com.gh.vspace.installexternalgames
interface OnItemClickListener {
enum class ClickType {
CLICK_INSTALL, CLICK_UNINSTALL, CLICK_START
}
fun onItemClick(externalGameUiState: ExternalGameUiState, clickType: ClickType)
}

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/external_games_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/apk_file_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
tools:text="文件名:\n路径" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btn_install"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_install"
android:visibility="gone"
tools:visibility="visible" />
<Button
android:id="@+id/btn_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_update"
android:visibility="visible"
tools:visibility="visible" />
<Button
android:id="@+id/btn_uninstall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_uninstall"
android:visibility="gone"
tools:visibility="visible" />
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_start"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
</LinearLayout>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="install_game_from_external" type="id" />
</resources>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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

@ -12,7 +12,7 @@ import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.halo.assistant.HaloApp
import com.kwai.monitor.payload.TurboHelper
import com.tencent.vasdolly.helper.ChannelReaderUtil
import com.leon.channel.helper.ChannelReaderUtil
class FlavorProviderImp : IFlavorProvider {

Binary file not shown.

Binary file not shown.

View File

@ -7,29 +7,10 @@
<package android:name="com.gh.gamecenter" />
</queries>
<queries>
<package android:name="com.gh.toolmap" />
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="ghtoolmap" />
</intent>
</queries>
<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.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"
tools:ignore="ScopedStorage" />
<!-- 允许应用程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 允许应用程序写入外部存储如SD卡上写文件 -->
@ -50,7 +31,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" />
@ -65,16 +46,6 @@
<!-- 如果有视频相关的广告且使用textureView播放请务必添加否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 悬浮窗 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 适配 双开/分身 游戏授权登录 -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<!-- 日历 -->
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-sdk tools:overrideLibrary="
com.shuyu.gsyvideoplayer,
com.shuyu.gsyvideoplayer.lib,
@ -107,39 +78,11 @@
androidx.constraintlayout.compose,
androidx.compose.ui.test.manifest,
com.bytedance.sdk.openadsdk,
com.bykv.vk.openvk,
com.bytedance.tools,
androidx.compose.ui.tooling.preview,
com.tencent.qqmini,
com.tencent.qqmini.minigame.external,
com.tencent.qqmini.minigame.opensdk,
com.tencent.qqmini.union.ad,
com.lg.vspace,
io.lg.va.common,
com.va.floating,
com.lg.cloud,
com.lg.archive,
com.lg.vclient,
com.va.realname,
com.lg.vspace.flavor,
com.lg.update,
com.lg.login,
com.lg.accelerator,
com.lody.virtual,
com.lg.core,
com.lg.ads,
com.lg.common,
com.lg.vspace.network,
com.lody.virtual.lib.res,
com.va.host,
com.lg.vspace.plugin.host,
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.tencent.qqmini.union.ad" />
<!-- 去掉 SDK 一些流氓权限 -->
<uses-permission
@ -154,18 +97,6 @@
android:name="android.permission.GET_TASKS"
tools:node="remove" />
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"
tools:node="remove" />
<uses-permission
android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
tools:node="remove" />
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"
tools:node="remove" />
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
@ -181,12 +112,10 @@
android:label="@string/app_name"
android:largeHeap="true"
android:networkSecurityConfig="@xml/network_security_config"
android:preserveLegacyExternalStorage="true"
android:requestLegacyExternalStorage="true"
android:resizeableActivity="true"
android:theme="@style/AppCompatTheme.APP"
tools:replace="android:name,android:allowBackup"
tools:targetApi="r">
tools:targetApi="n">
<meta-data
android:name="EasyGoClient"
@ -201,10 +130,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
@ -263,7 +188,7 @@
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.newsdetail.NewsDetailActivity"
android:name="com.gh.gamecenter.NewsDetailActivity"
android:screenOrientation="portrait" />
<activity
@ -318,7 +243,7 @@
android:windowSoftInputMode="stateHidden" />
<activity
android:name="com.gh.gamecenter.libao.LibaoDetailActivity"
android:name="com.gh.gamecenter.LibaoDetailActivity"
android:screenOrientation="portrait" />
<activity
@ -329,6 +254,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"
@ -346,13 +275,21 @@
<activity
android:name="com.gh.gamecenter.VoteActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateAlwaysHidden|adjustPan" />
android:windowSoftInputMode="stateAlwaysHidden|adjustResize" />
<activity
android:name="com.gh.gamecenter.WeiBoShareActivity"
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" />
@ -370,6 +307,14 @@
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden" />
<activity
android:name="com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.answer.edit.AnswerEditActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.InfoActivity"
android:screenOrientation="portrait" />
@ -378,6 +323,10 @@
android:name=".qa.questions.invite.QuestionsInviteActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.myqa.MyAskActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.questions.edit.QuestionEditActivity"
android:screenOrientation="portrait" />
@ -415,6 +364,10 @@
android:name="com.gh.gamecenter.qa.article.edit.ArticleEditActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.article.MyArticleActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.article.draft.ArticleDraftActivity"
android:screenOrientation="portrait" />
@ -453,6 +406,10 @@
android:name="com.gh.gamecenter.history.HistoryActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.personalhome.rating.RatingActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamedetail.rating.logs.CommentLogsActivity"
android:screenOrientation="portrait" />
@ -474,6 +431,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"
@ -506,19 +466,17 @@
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"
android:screenOrientation="portrait" />
<activity
android:name=".gamedetail.fuli.kaifu.ServersCalendarManagementActivity"
android:name=".qa.answer.draft.AnswerDraftActivity"
android:screenOrientation="portrait" />
<activity
android:name=".gamedetail.fuli.kaifu.ServersSubscribedGameListActivity"
android:screenOrientation="portrait" />
<activity
android:name=".gamedetail.rating.RatingFoldActivity"
android:screenOrientation="portrait" />
@ -526,6 +484,14 @@
android:name=".video.data.VideoDataActivity"
android:screenOrientation="portrait" />
<activity
android:name=".video.poster.PosterEditActivity"
android:screenOrientation="portrait" />
<activity
android:name=".video.poster.PosterClipActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.detail.ForumDetailActivity"
android:screenOrientation="portrait" />
@ -567,6 +533,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" />
@ -587,6 +561,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" />
@ -619,10 +597,6 @@
android:name=".game.commoncollection.detail.CommonCollectionDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name=".game.commoncollection.detail.CustomCommonCollectionDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name=".gamecollection.detail.GameCollectionDetailActivity"
android:screenOrientation="portrait" />
@ -643,9 +617,8 @@
<!-- android:theme="@android:style/Theme.Translucent" />-->
<activity
android:name="com.gh.gamecenter.SkipCompatActivity"
android:name="com.gh.gamecenter.SkipActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/Theme.AppCompat.Light.Fullscreen.Transparent">
<intent-filter>
<data android:scheme="ghzhushou" />
@ -669,8 +642,7 @@
android:name=".authorization.AuthorizationActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:taskAffinity=".auth">
android:screenOrientation="portrait">
<intent-filter>
<data android:scheme="ghzhushou_authorization" />
<category android:name="android.intent.category.DEFAULT" />
@ -716,7 +688,7 @@
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.toolbox.ToolBoxActivity"
android:name="com.gh.gamecenter.toolbox.ToolBoxBlockActivity"
android:screenOrientation="portrait" />
<activity
@ -774,55 +746,17 @@
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.minigame.qq.QGameHomeWrapperActivity"
android:name="com.gh.gamecenter.qgame.QGameHomeWrapperActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.minigame.MiniGameSearchActivity"
android:name="com.gh.gamecenter.qgame.QGameSearchActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamecollection.hotlist.GameCollectionListDetailActivity"
android:name="com.gh.gamecenter.qgame.QGameSubjectActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.UserAuthActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SplashAdActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.wrapper.ToolbarWrapperActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.home.CommunityActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.home.follow.FollowDynamicActivity"
android:theme="@style/Theme.Transparent" />
<activity
android:name=".forum.home.follow.AllFollowedActivity"
android:screenOrientation="portrait"
android:theme="@style/AppCompatTheme.APP" />
<activity
android:name=".search.SearchTabActivity"
android:configChanges="keyboardHidden"
android:screenOrientation="portrait"
android:theme="@style/AppCompatTheme.APP" />
<activity
android:name=".video.poster.PosterEditActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.halo.assistant.accelerator.MyAssetsActivity"
android:screenOrientation="portrait" />
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
@ -834,8 +768,7 @@
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
@ -896,8 +829,8 @@
<activity
android:name="com.gh.common.xapk.XapkInstallReceiver"
android:exported="false"
android:theme="@style/Theme.Transparent" />
android:theme="@style/Theme.Transparent"
android:exported="false" />
<receiver
android:name="com.gh.gamecenter.receiver.ActivitySkipReceiver"
@ -906,6 +839,7 @@
<action android:name="com.gh.gamecenter.ACTIVITYSKIP" />
</intent-filter>
</receiver>
</application>
</manifest>

View File

@ -6,6 +6,8 @@
<link rel="stylesheet" type="text/css" href="normalize.css">
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" type="text/css" href="video-js.min.css">
<!-- <link rel="stylesheet" href="https://static-web.ghzs.com/website-static/lib/video-js.min.css">--> <!--在web页面播放视频-->
<!--<link rel="stylesheet" type="text/css" href="https://resource.ghzs.com/css/halo_app.css">-->
</head>
<body style="overflow-x: hidden; word-break: break-all;">
@ -13,5 +15,8 @@
<script type="text/javascript" src="zepto.min.js"></script>
<script type="text/javascript" src="rich_editor.js"></script>
<script type="text/javascript" src="video.min.js"></script>
<!--<script src="https://static-web.ghzs.com/website-static/lib/video.min.js"></script>--> <!--在web页面播放视频-->
<!--<script type="text/javascript" src="content.js"></script>-->
<!--<script type="text/javascript" src="https://resource.ghzs.com/js/halo_app.js"></script>-->
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"v":"5.6.9","fr":30,"ip":0,"op":20,"w":66,"h":66,"nm":"bottom bar tab/论坛/选中/E","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"白-修正","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":4,"s":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":9,"s":[110,110,100]},{"t":13,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":0,"s":[{"i":[[0,-0.66],[0,0],[1.38,0],[0,1.38],[0,0],[-0.66,0],[0,0]],"o":[[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.66],[0,0],[0.66,0]],"v":[[2.5,-1.3],[2.5,0],[0,2.5],[-2.5,0],[-2.5,-1.3],[-1.3,-2.5],[1.3,-2.5]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":4,"s":[{"i":[[0,-0.66],[0,0],[1.38,0],[0,1.38],[0,0],[-0.66,0],[0,0]],"o":[[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.66],[0,0],[0.66,0]],"v":[[2.5,-0.102],[2.5,0],[0,2.109],[-2.5,0],[-2.5,-0.102],[-1.3,-1.302],[1.3,-1.302]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":9,"s":[{"i":[[0,-0.66],[0,0],[1.38,0],[0,1.38],[0,0],[-0.66,0],[0,0]],"o":[[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.66],[0,0],[0.66,0]],"v":[[2.498,-1.845],[2.5,0],[0,2.734],[-2.5,0],[-2.502,-1.845],[-1.302,-3.045],[1.298,-3.045]],"c":true}]},{"t":13,"s":[{"i":[[0,-0.66],[0,0],[1.38,0],[0,1.38],[0,0],[-0.66,0],[0,0]],"o":[[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.66],[0,0],[0.66,0]],"v":[[2.5,-1.3],[2.5,0],[0,2.5],[-2.5,0],[-2.5,-1.3],[-1.3,-2.5],[1.3,-2.5]],"c":true}]}],"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"蓝","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33.76,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.8,0.42],[-3.44,-0.79],[-0.09,-1.71],[0,0],[0,0],[1.98,-0.1],[0,0],[0,0],[0,0],[0.62,0.57],[0,0],[0,0],[0,0],[0,0],[0,0],[0.2,1.89],[0,0],[0,0],[0,0]],"o":[[3.44,-0.79],[1.74,0.41],[0,0],[0,0],[0,2],[0,0],[0,0],[0,0],[-0.69,0.52],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.94,0],[0,0],[0,0],[0,0],[0,-1.8]],"v":[[-6.39,-8.971],[6.39,-8.971],[9.49,-5.471],[9.5,-5.271],[9.5,3.249],[5.95,6.989],[5.75,6.999],[3.25,6.999],[0.3,9.209],[-1.95,9.089],[-2.06,8.969],[-2.17,8.849],[-2.21,8.779],[-3.4,6.999],[-5.75,6.999],[-9.48,3.639],[-9.49,3.449],[-9.5,3.249],[-9.5,-5.271]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.266,0.638,1,0.5,0.242,0.595,1,1,0.217,0.552,1],"ix":9}},"s":{"a":0,"k":[-9.5,-9.561],"ix":5},"e":{"a":0,"k":[9.5,9.561],"ix":6},"t":1,"nm":"color","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"路径","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"预合成 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2},"a":{"a":0,"k":[33,33,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[70,70,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":9,"s":[110,110,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[90,90,100]},{"t":16,"s":[100,100,100]}],"ix":6}},"ao":0,"w":66,"h":66,"ip":0,"op":20,"st":0,"bm":0}],"markers":[]}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"v":"5.12.2","fr":60,"ip":0,"op":40,"w":66,"h":66,"nm":"icon_tab_my","ddd":0,"assets":[{"id":"comp_0","nm":"icon","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"highlight","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33.134,34.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":0.733},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,-0.004],[0.493,0],[0,0.004],[-0.493,0]],"o":[[0,0.004],[-0.493,0],[0,-0.004],[0.493,0]],"v":[[0.893,1.488],[0,1.496],[-0.893,1.488],[0,1.483]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0.267},"t":10,"s":[{"i":[[0,-1.018],[1.793,0],[0,1.018],[-1.793,0]],"o":[[0,1.018],[-1.793,0],[0,-1.018],[1.793,0]],"v":[[2.914,-0.344],[0,1.5],[-2.914,-0.344],[0,-1.5]],"c":true}]},{"i":{"x":0.333,"y":1},"o":{"x":0.667,"y":0},"t":18,"s":[{"i":[[0,-1.181],[1.407,0],[0,1.181],[-1.407,0]],"o":[[0,1.181],[-1.407,0],[0,-1.181],[1.407,0]],"v":[[2.226,-0.341],[0,1.74],[-2.211,-0.341],[0,-1.74]],"c":true}]},{"i":{"x":0.333,"y":1},"o":{"x":0.667,"y":0},"t":26,"s":[{"i":[[0,-0.905],[1.381,0],[0,0.905],[-1.381,0]],"o":[[0,0.905],[-1.381,0],[0,-0.905],[1.381,0]],"v":[[2.5,-0.306],[0,1.333],[-2.5,-0.306],[0,-1.333]],"c":true}]},{"t":32,"s":[{"i":[[0,-1.018],[1.381,0],[0,1.018],[-1.381,0]],"o":[[0,1.018],[-1.381,0],[0,-1.018],[1.381,0]],"v":[[2.5,-0.344],[0,1.5],[-2.5,-0.344],[0,-1.5]],"c":true}]}],"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"color","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"body","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,34.204,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.866,0],[0,3.866],[3.866,0],[0,-3.866]],"o":[[3.866,0],[0,-3.866],[-3.866,0],[0,3.866]],"v":[[0,4.599],[7,-2.401],[0,-9.401],[-7,-2.401]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.207,0.359],[2.438,0],[1.189,-2.104],[-0.361,-0.204],[-0.204,0.361],[-1.915,0],[-0.932,-1.613],[-0.359,0.207]],"o":[[-1.198,-2.072],[-2.462,0],[-0.204,0.361],[0.361,0.204],[0.925,-1.638],[1.897,0],[0.207,0.359],[0.359,-0.207]],"v":[[5.848,8.225],[0,4.849],[-5.88,8.282],[-5.596,9.304],[-4.574,9.02],[0,6.349],[4.549,8.976],[5.574,9.25]],"c":true},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.267,0.639,1,0.5,0.241,0.596,1,1,0.216,0.553,1],"ix":9}},"s":{"a":0,"k":[-3.812,-4.384],"ix":5},"e":{"a":0,"k":[6.345,8.129],"ix":6},"t":1,"nm":"color","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Union","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"icon","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2,"l":2},"a":{"a":0,"k":[33,33,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[70,70,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":18,"s":[110,110,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":26,"s":[90,90,100]},{"t":32,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"w":66,"h":66,"ip":0,"op":60,"st":0,"bm":0}],"markers":[],"props":{}}

View File

@ -0,0 +1 @@
{"v":"5.5.9","fr":30,"ip":0,"op":20,"w":66,"h":66,"nm":"tab_video","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"形状图层 1","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.771],"y":[0]},"t":0,"s":[0]},{"t":5,"s":[100]}],"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[-3.742,6.835,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[30.937,31.042,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":29.286,"ix":7},"os":{"a":0,"k":75,"ix":9},"ix":1,"nm":"多边星形路径 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-20.75,-13.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[102.743,88.578],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"多边星形 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.657],"y":[0]},"t":0,"s":[0]},{"t":8,"s":[100]}],"ix":2},"o":{"a":0,"k":-115,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"路径 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33.004,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.508,0.508,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.488,0.488,0.333],"y":[0,0,0]},"t":4,"s":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.502,0.502,0.333],"y":[0,0,0]},"t":9,"s":[110,110,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.534,0.534,0.333],"y":[0,0,0]},"t":13,"s":[95,95,100]},{"t":16,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[2.16,0.38],[3.22,-0.55],[0.38,-2.16],[-0.55,-3.22],[-2.16,-0.38],[-1.63,0],[-1.61,0.27],[-0.38,2.16],[0.55,3.22]],"o":[[-0.38,-2.16],[-3.22,-0.55],[-2.16,0.38],[-0.55,3.22],[0.38,2.16],[1.61,0.27],[1.63,0],[2.16,-0.38],[0.55,-3.22],[0,0]],"v":[[9.09,-4.86],[4.86,-9.09],[-4.86,-9.09],[-9.09,-4.86],[-9.09,4.86],[-4.86,9.09],[0,9.5],[4.86,9.09],[9.09,4.86],[9.09,-4.86]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.266,0.638,1,0.5,0.242,0.595,1,1,0.217,0.552,1],"ix":9}},"s":{"a":0,"k":[-5.174,-4.43],"ix":5},"e":{"a":0,"k":[8.612,8.214],"ix":6},"t":1,"nm":"Gradient Fill 3","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"路径","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"bm":0}],"markers":[]}

File diff suppressed because one or more lines are too long

View File

@ -34,18 +34,18 @@ try {
var script = document.createElement("script")
document.body.appendChild(script)
if (isDebug) {
script.src = "https://dev-and-static.ghzs66.com/web/js/halo.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
script.src = "https://resource.ghzs.com/js/halo_app_test.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
} else {
script.src = "https://and-static.ghzs66.com/web/js/halo.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
script.src = "https://resource.ghzs.com/js/halo.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
}
var style = document.createElement("link")
style.rel = "stylesheet"
style.type = "text/css"
if (isDebug) {
style.href = "https://dev-and-static.ghzs66.com/web/css/halo.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
style.href = "https://resource.ghzs.com/css/halo_app_test.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
} else {
style.href = "https://and-static.ghzs66.com/web/css/halo.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
style.href = "https://resource.ghzs.com/css/halo.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
}
document.head.appendChild(style)
@ -205,17 +205,14 @@ RE.setOutdent = function() {
RE.setJustifyLeft = function() {
document.execCommand('justifyLeft', false, null);
RE.enabledEditingItems()
}
RE.setJustifyCenter = function() {
document.execCommand('justifyCenter', false, null);
RE.enabledEditingItems()
}
RE.setJustifyRight = function() {
document.execCommand('justifyRight', false, null);
RE.enabledEditingItems()
}
RE.setBlockquote = function() {
@ -230,16 +227,6 @@ RE.insertImage = function(url) {
RE.insertHTML(html);
}
// 设置分割线
RE.insertHorizontalRule = function() {
document.execCommand('insertHorizontalRule', false, null);
}
// 设置编辑器默认换行符
RE.setDefaultParagraphSeparator = function(separator) {
document.execCommand('defaultParagraphSeparator', false, separator);
}
// 替换成缩略图
RE.replaceTbImage = function(imgRuleFlag, gifRuleFlag) {
var imgs = document.getElementsByTagName("img");
@ -587,10 +574,6 @@ document.addEventListener("selectionchange", function(e) {
RE.sendElementNameToNative()
});
document.addEventListener("selectionchange", function(e) {
setTimeout(() => RE.enabledEditingItems(e), 10)
});
RE.recursion = function(dom) {
var parenDom = dom.parentElement
if (parenDom && parenDom instanceof Element &&
@ -633,6 +616,7 @@ RE.sendElementNameToNative = function() {
// android function to open link
function customLinkgo(self) {
var datas = self.dataset.datas
// console.log(datas)
window.OnLinkClickListener.onClick(datas)
}

View File

@ -30,6 +30,7 @@ body {
}
#editor {
display: table-cell;
outline: 0px solid transparent;
background-repeat: no-repeat;
background-position: center;

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -4,9 +4,6 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.SharedPreferences
import android.graphics.drawable.Animatable
import android.os.Build
import android.os.Message
import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
@ -14,25 +11,21 @@ import android.widget.FrameLayout
import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import com.therouter.TheRouter
import com.facebook.drawee.controller.BaseControllerListener
import com.alibaba.android.arouter.launcher.ARouter
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.image.ImageInfo
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.common.util.LogUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.PackageUtils
import com.gh.common.util.NewFlatLogUtils.logOpenScreenAdSkip
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.MainActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
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
@ -40,41 +33,36 @@ import com.gh.gamecenter.core.utils.TimeUtils.getToday
import com.gh.gamecenter.entity.AdConfig
import com.gh.gamecenter.entity.StartupAdEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
import java.util.Locale
/**
* 广告实现代理类
*
* 由它来分发功能实现到具体的实现
*
* 以开屏广告为例,有种实现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() }
private var mAdConfigList: ArrayList<AdConfig>? = null
private var mSplashAd: AdConfig? = null
private var mDownloadManagerAd: AdConfig? = null
private val mGameSearchAdList: ArrayList<AdConfig> by lazy { arrayListOf() }
private var mVGameLaunchAd: AdConfig? = null
private var ownerSplashAdLoadTime = 0L
val vGameLaunchAd: AdConfig?
get() = mVGameLaunchAd
val splashAdDisplayInterval: Int
get() = mSplashAd?.ownerAd?.startAd?.displayInterval ?: 3
private const val AD_SDK_CSJ = "穿山甲"
const val AD_TYPE_SDK = "third_party_ads" // 第三方 SDK 广告
const val AD_TYPE_OWNER = "owner_ads" // 自有广告
private const val AD_SDK_BEIZI = "倍孜"
private const val AD_TYPE_SDK = "third_party_ads" // 第三方 SDK 广告
private const val KEY_CACHE_CONFIG = "cache_config" // 放在 SP 里的广告缓存(避免接口加载问题)
@ -82,29 +70,19 @@ object AdDelegateHelper {
HaloApp.getInstance().getSharedPreferences("AdConfig", Context.MODE_PRIVATE)
}
var isShowingSplashAd = false // 是否正在显示开屏广告
var isOwnerSplashAdShown = false // 自有开屏广告是否展示
var gameSearchKeyword = ""
fun initAdSdk(context: Context) {
if (AdPluginDownloadHelper.isCsjPluginDownloaded()) {
initAdSdkInternal(context)
} else {
// 首次启动,为了不影响首页加载,延迟 3 秒再下载广告插件并初始化
AppExecutor.uiExecutor.executeWithDelay({
AdPluginDownloadHelper.downloadPluginIfNeeded(isCsj = true) {
initAdSdkInternal(context)
}
}, 3000L)
// 初始化 Beizi
if (mBeiziAdImpl == null) {
mBeiziAdImpl =
ARouter.getInstance().build(RouteConsts.provider.beiziAd).navigation() as? IBeiziAdProvider
mBeiziAdImpl?.initSDK(context)
}
}
private fun initAdSdkInternal(context: Context) {
// 初始化穿山甲
if (mCsjAdImpl == null) {
mCsjAdImpl = TheRouter.get(ICsjAdProvider::class.java)
val csjAppId = if (EnvHelper.isDevEnv) BuildConfig.DEV_CSJ_APPID else BuildConfig.CSJ_APPID
mCsjAdImpl?.initSDK(context, csjAppId, HaloApp.getInstance().oaid)
mCsjAdImpl =
ARouter.getInstance().build(RouteConsts.provider.csjAd).navigation() as? ICsjAdProvider
mCsjAdImpl?.initSDK(context, BuildConfig.CSJ_APPID, HaloApp.getInstance().oaid)
// 监听亮色/暗色模式切换
DarkModeUtils.registerModeChangeListener {
val topActivity = CurrentActivityHolder.getCurrentActivity() ?: return@registerModeChangeListener
@ -117,26 +95,19 @@ object AdDelegateHelper {
* 请求接口获取广告相关配置
*/
@SuppressLint("CheckResult")
fun requestAdConfig(isFromRetry: Boolean, keyword: String = "", callback: (() -> Unit)? = null) {
fun requestAdConfig(isFromRetry: Boolean) {
// mAdConfigList 不为空不需要重试
if (isFromRetry && mAdConfigList.isNotEmpty()) {
if (isFromRetry && mAdConfigList != null) {
return
}
val paramsMap = if (keyword.isNotEmpty()) {
mapOf("keyword" to keyword, "android_sdk_version" to Build.VERSION.SDK_INT)
} else {
mapOf("android_sdk_version" to Build.VERSION.SDK_INT)
}
RetrofitManager.getInstance()
.newApi
.getAdConfig(paramsMap)
.adConfig
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<List<AdConfig>>() {
override fun onSuccess(data: List<AdConfig>) {
gameSearchKeyword = keyword
handleAdConfig(data)
callback?.invoke()
// 缓存数据到 SP 供接口请求失败用
SPUtils.setString(mAdConfigSp, KEY_CACHE_CONFIG, data.toJson())
@ -147,11 +118,9 @@ object AdDelegateHelper {
// 若接口请求失败时,从 SP 里获取上次缓存的数据
val cachedConfig: List<AdConfig>? = SPUtils.getString(mAdConfigSp, KEY_CACHE_CONFIG).toObject()
if (cachedConfig != null && mAdConfigList.isEmpty()) {
if (cachedConfig != null) {
handleAdConfig(cachedConfig)
}
callback?.invoke()
}
})
}
@ -174,34 +143,10 @@ object AdDelegateHelper {
* 处理广告配置
*/
fun handleAdConfig(configList: List<AdConfig>) {
mAdConfigList.clear()
mGameSearchAdList.clear()
mSplashAd = null
mDownloadManagerAd = null
mVGameLaunchAd = null
for (config in configList) {
mAdConfigList.add(config)
// 处理返回的数据
when (config.location) {
"halo_launch" -> {
config.ownerAd?.startAd?.let { it.id = config.ownerAd.id }
// HarmonyOS 2.2.0 版本不展示第三方开屏广告 (因为会引起奇怪的闪退)
if (MetaUtil.getRom().name == "HarmonyOS"
&& MetaUtil.getRom().versionName == "2.2.0"
&& config.displayRule.adSource == AD_TYPE_SDK) {
return
}
// 华为系 Android 10 不展示第三方开屏广告 (因为会引起奇怪的闪退)
if (isBuggyHuaweiDevice() && config.displayRule.adSource == AD_TYPE_SDK) {
return
}
mSplashAd = config
}
"halo_launch" -> mSplashAd = config
"download_manager" -> mDownloadManagerAd = config
"game_search" -> config.let { mGameSearchAdList.add(it) }
"helper_launch" -> mVGameLaunchAd = config
@ -211,96 +156,9 @@ object AdDelegateHelper {
/**
* 是否需要显示开屏广告
* @param isHotLaunch 是否为热启动
*/
fun shouldShowStartUpAd(isHotLaunch: Boolean): Boolean {
fun shouldShowStartUpAd(): Boolean {
return mSplashAd != null
&& !isShowingSplashAd
&& (!isHotLaunch || shouldShowStartUpAdWhenHotLaunch())
&& !isMatchAdFreeRule(mSplashAd)
&& isMatchStartUpAdDisplayRule()
}
/**
* 热启动是否需要显示开屏广告(目前只展示第三方广告)
*/
private fun shouldShowStartUpAdWhenHotLaunch() = (mCsjAdImpl != null)
&& mSplashAd?.displayRule?.hotStartSplashAd?.type == AD_TYPE_SDK
&& mSplashAd?.hotStartThirdPartyAd != null
&& !isBuggyHuaweiDevice()
/**
* 是否需要显示下载管理广告
*/
fun shouldShowDownloadManagerAd(): Boolean {
return mDownloadManagerAd != null && !isMatchAdFreeRule(mDownloadManagerAd) && isMatchDownloadManagerAdDisplayRule()
}
fun shouldShowHelperLaunchAd(): Boolean {
return mVGameLaunchAd != null && !isMatchAdFreeRule(mVGameLaunchAd) && isMatchAdDisplayRule(mVGameLaunchAd, Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME)
}
/**
* 是否需要显示游戏搜索广告
*/
fun shouldShowGameSearchAd(adConfig: AdConfig): Boolean {
return !isMatchAdFreeRule(adConfig) && isMatchGameSearchAdDisplayRule(adConfig)
}
/**
* 是否在免广告时长内
*/
private fun isMatchAdFreeRule(adConfig: AdConfig?): Boolean {
adConfig?.displayRule?.run {
if (adFreeDuration > 0) {
val ghInstalledDurationInHours = (System.currentTimeMillis() - PackageUtils.getInstalledTime(
HaloApp.getInstance(),
BuildConfig.APPLICATION_ID
)).toFloat() / 1000 / 3600
return ghInstalledDurationInHours < adFreeDuration
} else {
return false
}
}
return false
}
/**
* 是否大于开屏广告展示间隔时长
*/
private fun isMatchStartUpAdDisplayRule(): Boolean = isMatchAdDisplayRule(mSplashAd, Constants.SP_LAST_SPLASH_AD_SHOW_TIME)
/**
* 是否大于广告管理展示间隔时长
*/
private fun isMatchDownloadManagerAdDisplayRule(): Boolean = isMatchAdDisplayRule(mDownloadManagerAd, Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME)
private fun isMatchAdDisplayRule(adConfig: AdConfig?, spKey: String): Boolean {
adConfig?.displayRule?.run {
if (adDisplayInterval > 0) {
val lastShowTime = SPUtils.getLong(spKey, 0L)
val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60
return durationInMinutes > adDisplayInterval
} else {
return true
}
}
return true
}
/**
* 是否大于游戏搜索展示间隔时长
*/
private fun isMatchGameSearchAdDisplayRule(adConfig: AdConfig?): Boolean {
adConfig?.displayRule?.run {
if (adDisplayInterval > 0) {
val lastShowTime = SPUtils.getLong(Constants.SP_LAST_GAME_SEARCH_AD_SHOW_TIME + adConfig.position, 0L)
val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60
return durationInMinutes > adDisplayInterval
} else {
return true
}
}
return true
}
/**
@ -322,134 +180,52 @@ object AdDelegateHelper {
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
sdkStartAdContainer: ViewGroup,
sdkJumpBtn: TextView,
adsViewGroup: FrameLayout,
handler: BaseActivity.BaseHandler,
isHotLaunch: Boolean,
hideAction: () -> Unit
) {
val hideCallback = {
isShowingSplashAd = false
isOwnerSplashAdShown = false
hideAction.invoke()
}
if (mSplashAd != null) {
when (if (isHotLaunch) mSplashAd!!.displayRule.hotStartSplashAd?.type else mSplashAd!!.displayRule.adSource) {
AD_TYPE_SDK -> {
isShowingSplashAd = true
requestThirdPartySplashAd(
activity,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
sdkJumpBtn,
adsViewGroup,
handler,
isHotLaunch,
hideCallback
)
}
AD_TYPE_OWNER -> {
isShowingSplashAd = true
requestStandardSplashAd(
activity,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
sdkJumpBtn,
adsViewGroup,
handler,
isHotLaunch,
hideCallback
)
}
}
} else {
hideCallback.invoke()
}
}
/**
* 获取第三方开屏广告
*/
private fun requestThirdPartySplashAd(
activity: Activity,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
adViewWidthInDp: Float,
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
sdkStartAdContainer: ViewGroup,
sdkJumpBtn: TextView,
adsViewGroup: FrameLayout,
handler: BaseActivity.BaseHandler,
isHotLaunch: Boolean,
hideCallback: () -> Unit
) {
// 第三方开屏广告回调,失败时根据接口配置选项决定是否显示自有开屏广告
val sdkSplashCallback: (isSuccess: Boolean) -> Unit = { isSuccess ->
if (isSuccess) {
hideCallback.invoke()
SPUtils.setLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, System.currentTimeMillis())
} else {
if (mSplashAd?.displayRule?.adSource == AD_TYPE_SDK && mSplashAd?.displayRule?.onFailedAction == "show" && !isHotLaunch) {
sdkStartAdContainer.visibility = View.GONE
requestStandardSplashAd(
if (mSplashAd != null) {
if (mSplashAd!!.displayRule.adSource == AD_TYPE_SDK) {
// 第三方开屏广告回调,失败时根据接口配置选项决定是否显示自有开屏广告
val sdkSplashCallback: (isSuccess: Boolean) -> Unit = { isSuccess ->
if (isSuccess) {
hideCallback.invoke()
} else {
if (mSplashAd?.displayRule?.onFailedAction == "show") {
sdkStartAdContainer.visibility = View.GONE
requestStandardSplashAd(mSplashAd!!.ownerAd, startAdContainer, handler, hideCallback)
} else {
hideCallback.invoke()
}
}
}
// 第三方广告的数据为空,按加载失败处理
if (mSplashAd?.thirdPartyAd == null) {
sdkSplashCallback.invoke(false)
return
}
if (mSplashAd?.thirdPartyAd?.sourceName == AD_SDK_BEIZI) {
sdkStartAdContainer.visibility = View.VISIBLE
requestBeiziSplashAd(sdkStartAdContainer, adsViewGroup, adViewWidthInPx, adViewHeightInPx, sdkSplashCallback)
} else if (mSplashAd?.thirdPartyAd?.sourceName == AD_SDK_CSJ) {
sdkStartAdContainer.visibility = View.VISIBLE
requestCsjSplashAd(
activity,
mSplashAd?.thirdPartyAd?.slotId ?: "unknown",
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
sdkJumpBtn,
adsViewGroup,
handler,
isHotLaunch,
hideCallback
sdkSplashCallback
)
} else {
hideCallback.invoke()
}
} else {
requestStandardSplashAd(mSplashAd!!.ownerAd, startAdContainer, handler, hideCallback)
}
}
val thirdPartyAd = if (isHotLaunch) mSplashAd?.hotStartThirdPartyAd else mSplashAd?.thirdPartyAd
// 第三方广告的数据为空,按加载失败处理
if (mSplashAd == null || thirdPartyAd == null) {
sdkSplashCallback.invoke(false)
return
}
val timeout = if (isHotLaunch) {
((mSplashAd?.displayRule?.hotStartSplashAd?.timeout ?: 3.5F) * 1000).toInt()
} else {
((mSplashAd?.displayRule?.timeout ?: 3.5F) * 1000).toInt()
}
if (thirdPartyAd.sourceName == AD_SDK_CSJ) {
sdkStartAdContainer.visibility = View.VISIBLE
requestCsjSplashAd(
activity,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
sdkStartAdContainer,
sdkJumpBtn,
timeout,
isHotLaunch,
sdkSplashCallback
)
}
}
/**
@ -457,111 +233,58 @@ 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,
callback: (isSuccess: Boolean) -> Unit,
) {
if (mBeiziAdImpl == null) {
callback.invoke(false)
} else {
mBeiziAdImpl?.requestSplashAd(startAdContainer, adsFl, adViewWidthInPx, adViewHeightInPx, callback)
}
}
/**
* 显示自有的开屏广告
*/
private fun requestStandardSplashAd(
activity: Activity,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
adViewWidthInDp: Float,
adViewHeightInDp: Float,
splashAd: StartupAdEntity?,
startAdContainer: ViewGroup,
sdkStartAdContainer: ViewGroup,
sdkJumpBtn: TextView,
adsViewGroup: FrameLayout,
handler: BaseActivity.BaseHandler,
isHotLaunch: Boolean,
hideCallback: () -> Unit
) {
val splashAd = mSplashAd?.ownerAd?.startAd
val onEmptyCallback = {
if (mSplashAd?.displayRule?.adSource == AD_TYPE_OWNER && mSplashAd?.displayRule?.onFailedAction == "show" && mSplashAd?.thirdPartyAd != null) {
// 自有广告为空时,显示第三方广告
requestThirdPartySplashAd(
activity,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
sdkJumpBtn,
adsViewGroup,
handler,
isHotLaunch,
hideCallback
)
} else {
hideCallback.invoke()
}
}
if (splashAd == null) {
onEmptyCallback.invoke()
hideCallback.invoke()
return
}
@ -574,7 +297,7 @@ object AdDelegateHelper {
) {
showStandardSplashAd(splashAd, startAdContainer, handler, hideCallback)
} else {
onEmptyCallback.invoke()
hideCallback.invoke()
}
"everyday" -> {
@ -585,7 +308,7 @@ object AdDelegateHelper {
) {
showStandardSplashAd(splashAd, startAdContainer, handler, hideCallback)
} else {
onEmptyCallback.invoke()
hideCallback.invoke()
}
}
@ -603,17 +326,10 @@ object AdDelegateHelper {
handler: BaseActivity.BaseHandler,
hideCallback: () -> Unit
) {
isOwnerSplashAdShown = false
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(
@ -621,64 +337,20 @@ object AdDelegateHelper {
R.drawable.ic_startup_ad_arrow
), null, null
)
if (ad.isImageType) {
adVideo.visibleIf(false)
adImage.visibleIf(true)
ImageUtils.displayWithCallback(adImage, ad.img, true, object : BaseControllerListener<ImageInfo>() {
override fun onSubmit(id: String?, callerContext: Any?) {
super.onSubmit(id, callerContext)
adImage.post {
ownerSplashAdLoadTime = System.currentTimeMillis()
NewFlatLogUtils.logSplashAdLoad(ad.id)
}
}
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
isOwnerSplashAdShown = true
adImage.post {
NewFlatLogUtils.logSplashAdShow(ad.id, System.currentTimeMillis() - ownerSplashAdLoadTime)
}
}
override fun onFailure(id: String?, throwable: Throwable?) {
super.onFailure(id, throwable)
NewFlatLogUtils.logSplashAdFail(ad.id, "启动广告图加载失败")
}
})
} else {
adImage.visibleIf(false)
adVideo.startPlay(ad.video.url)
}
ImageUtils.display(adImage, ad.img)
startAdContainer.setOnClickListener {
// 拦截点击事件传递
}
jumpBtn.setOnClickListener {
it.debounceActionWithInterval(1000L) {
if (!isOwnerSplashAdShown) {
NewFlatLogUtils.logSplashAdFail(ad.id, "加载过程中点击跳过广告")
}
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
val linkEntity = ad.jump
NewFlatLogUtils.logOpenScreenAdSkip(
ad.id,
(if (linkEntity.text != null) linkEntity.text else "")!!,
(if (linkEntity.type != null) linkEntity.type else "")!!,
(if (linkEntity.link != null) linkEntity.link else "")!!
)
SensorsBridge.trackEvent(
"SplashAdOwnSkip",
"splash_ad_id",
ad.id,
"link_type",
linkEntity.type ?: "",
"link_id",
linkEntity.link ?: "",
"link_text",
linkEntity.text ?: ""
)
}
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
val linkEntity = ad.jump
logOpenScreenAdSkip(
ad.id,
(if (linkEntity.text != null) linkEntity.text else "")!!,
(if (linkEntity.type != null) linkEntity.type else "")!!,
(if (linkEntity.link != null) linkEntity.link else "")!!
)
}
val sources: MutableList<ExposureSource> = ArrayList()
sources.add(ExposureSource("开屏广告", ad.id))
@ -686,19 +358,7 @@ object AdDelegateHelper {
ExposureManager.log(event)
if (ad.button) {
jumpDetailBtn.setOnClickListener { v: View ->
val linkEntity = ad.jump
directToLinkPage(v.context, linkEntity, "(启动广告)", "", event)
SensorsBridge.trackEvent(
"SplashAdOwnClick",
"splash_ad_id",
ad.id,
"link_type",
linkEntity.type ?: "",
"link_id",
linkEntity.link ?: "",
"link_text",
linkEntity.text ?: ""
)
directToLinkPage(v.context, ad.jump, "(启动广告)", "", event)
v.postDelayed({
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
@ -709,38 +369,30 @@ object AdDelegateHelper {
} else {
LogUtils.logStartAd("start_ads", ad)
}
SPUtils.setLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, System.currentTimeMillis())
val msg = Message.obtain()
msg.what = MainActivity.COUNTDOWN_AD
msg.obj = ad
handler.sendMessageDelayed(msg, 1000)
handler.sendEmptyMessageDelayed(MainActivity.COUNTDOWN_AD, 1000)
}
/**
* 获取第三方信息流广告
* 获取信息流广告
*/
fun requestThirdPartyFlowAd(
fun requestFlowAd(
fragment: Fragment,
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)
}
/**
* 获取第三方 Banner 广告
* 获取 Banner 广告
*/
fun requestThirdPartyBannerAd(
fun requestBannerAd(
fragment: Fragment,
containerView: ViewGroup,
ad: AdConfig.ThirdPartyAd,
expressViewWidthInDp: Float,
onAdShowAction: () -> Unit,
onAdClickAction: () -> Unit,
callback: (isSuccess: Boolean) -> Unit
) {
@ -763,28 +415,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
)
}
@ -793,19 +423,8 @@ object AdDelegateHelper {
* 取消开屏广告
*/
fun cancelSplashAd(context: Context) {
mBeiziAdImpl?.cancelSplashAd(context)
mCsjAdImpl?.cancelSplashAd(context)
}
/**
* 是否为有问题的华为系 Android 10 设备
*/
private fun isBuggyHuaweiDevice(): Boolean {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
val manufacturer = Build.MANUFACTURER.lowercase(Locale.CHINA) ?: ""
return manufacturer == "huawei" || manufacturer == "honor"
} else {
return false
}
}
}

View File

@ -1,149 +0,0 @@
package com.gh.ad
import com.gh.download.simple.DownloadMessageHandler
import com.gh.download.simple.SimpleDownloadDatabase
import com.gh.download.simple.SimpleDownloadManager
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.PluginRedirectHelper
import com.gh.gamecenter.core.utils.SPUtils
import com.lg.download.DownloadError
import com.lg.download.DownloadStatus
import com.lg.download.httpclient.DefaultHttpClient
import com.lg.download.listener.InnerDownloadListener
import com.lg.ndownload.DownloadConfig
import com.lg.ndownload.DownloadConfigBuilder
import com.lg.ndownload.DownloadIoExecutor
import com.lightgame.utils.Utils
import java.lang.Exception
import java.net.URLConnection
object AdPluginDownloadHelper : InnerDownloadListener {
private const val CSJ_FILE_NAME = "1832823466"
private const val GDT_FILE_NAME = "gdt_plugin/gdtadv2.jar"
private const val CSJ_PLUGIN_URL = "https://and-static.ghzs66.com/android/static/1832823466"
private const val GDT_PLUGIN_URL = "https://and-static.ghzs66.com/android/static/gdtadv2.jar"
private var csjDownloadedCallback: (() -> Unit)? = null
/**
* 是否已经下载了广告插件
*/
fun isCsjPluginDownloaded(): Boolean {
return SPUtils.getBoolean(CSJ_FILE_NAME, false)
}
/**
* 下载广告插件并初始化 (初始化限定穿山甲)
*/
fun downloadPluginIfNeeded(isCsj: Boolean = false, isGdt: Boolean = false, csjCallback: (() -> Unit)? = null) {
val isCsjPluginDownloaded = SPUtils.getBoolean(CSJ_FILE_NAME, false)
val isGdtPluginDownloaded = SPUtils.getBoolean(GDT_FILE_NAME, false)
if (isCsj && isCsjPluginDownloaded) {
csjCallback?.invoke()
return
}
if (isGdt && isGdtPluginDownloaded) {
return
}
runOnIoThread {
csjDownloadedCallback = csjCallback
DownloadMessageHandler.init(SimpleDownloadDatabase.instance.downloadDao())
if (!isCsjPluginDownloaded && isCsj) {
val csjPluginConfig = DownloadConfigBuilder()
.setUniqueId(CSJ_FILE_NAME)
.setUrl(CSJ_PLUGIN_URL)
.setFileName(CSJ_FILE_NAME)
.setHttpClient(DefaultHttpClient())
.setDownloadThreadSize(2)
.setPathToStore(PluginRedirectHelper.getAssetDir())
.setDownloadExecutor(DownloadIoExecutor.getInstance())
.setDownloadListener(this).build()
SimpleDownloadManager.download(csjPluginConfig)
}
if (!isGdtPluginDownloaded && isGdt) {
val gdtPluginConfig = DownloadConfigBuilder()
.setUniqueId(GDT_FILE_NAME)
.setUrl(GDT_PLUGIN_URL)
.setFileName(GDT_FILE_NAME)
.setHttpClient(DefaultHttpClient())
.setDownloadThreadSize(2)
.setPathToStore(PluginRedirectHelper.getAssetDir())
.setDownloadExecutor(DownloadIoExecutor.getInstance())
.setDownloadListener(this).build()
SimpleDownloadManager.download(gdtPluginConfig)
}
}
}
override fun onError(id: String?, error: DownloadError?, exception: Exception?) {
Utils.log("下载广告插件失败 $id")
id?.let {
if (it == CSJ_FILE_NAME) {
csjDownloadedCallback = null
}
SimpleDownloadManager.cancel(it)
}
}
override fun onProgress(id: String?, progress: Float) {
Utils.log("下载广告插件进度 $id $progress")
}
override fun onProgressWithoutThrottle(id: String?, progress: Float) {
// do nothing
}
override fun onSizeReceived(id: String?, fileSize: Long) {
// do nothing
}
override fun onReadyToDownload(id: String?, actualThreadSize: Int) {
// do nothing
}
override fun onStatusChanged(id: String?, status: DownloadStatus?) {
// do nothing
}
override fun onDownloadComplete(id: String?, elapsedTime: Long) {
id?.let {
// id 即为插件名
SPUtils.setBoolean(it, true)
if (it == CSJ_FILE_NAME) {
csjDownloadedCallback?.invoke()
csjDownloadedCallback = null
}
}
}
override fun onSpeedChanged(id: String?, speed: Float) {
// do nothing
}
override fun onRedirectingUrl(
id: String?,
connection: URLConnection?,
config: DownloadConfig?
) {
// do nothing
}
override fun onRedirectedUrl(
id: String?,
connection: URLConnection?,
redirectedUrl: String?
) {
// do nothing
}
}

View File

@ -1,102 +0,0 @@
package com.gh.ad
import android.view.View
import android.view.ViewGroup
import android.view.ViewStub
import androidx.fragment.app.Fragment
import com.gh.gamecenter.common.constant.Constants
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
@com.therouter.inject.ServiceProvider
class LaunchAdImpl : ILaunchAd {
override fun requestAd(fragment: Fragment, container: ViewGroup, maskView: View, topViewStub: ViewStub, bottomViewStub: ViewStub, adClickAction: () -> Unit): 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()
}
}
}
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,88 +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 touchSurfaceMoveFullLogic(absDeltaX: Float, absDeltaY: Float) {
// no nothing
}
override fun onPrepared() {
super.onPrepared()
visibility = VISIBLE
}
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,38 +21,30 @@ 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.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.LocalVideoEntity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.entity.VideoEntity
import com.gh.gamecenter.entity.*
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.entity.GameEntity
import com.gh.gamecenter.feature.selector.ChooseType
import com.gh.gamecenter.feature.selector.LocalMediaActivity
import com.gh.gamecenter.qa.editor.*
import com.gh.gamecenter.qa.entity.EditorInsertEntity
import com.gh.gamecenter.video.poster.video.VideoPosterFragment
import com.gh.gamecenter.video.poster.PosterEditActivity
import com.gh.gamecenter.video.upload.UploadManager
import com.google.gson.JsonObject
import com.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_Keyboard
import com.lightgame.utils.Utils
import com.lightgame.view.CheckableImageView
import com.therouter.TheRouter
import io.reactivex.disposables.Disposable
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
// TODO: 移动到module_bbs模块
abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor() : ToolBarActivity(),
abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> : ToolBarActivity(),
KeyboardHeightObserver, UploadVideoListener {
lateinit var mRichEditor: RichEditor
@ -65,16 +57,11 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
private lateinit var mEditorFontItalic: CheckableImageView
private lateinit var mEditorFontStrikeThrough: CheckableImageView
private lateinit var mEditorFontUnderline: CheckableImageView
private lateinit var mEditorParagraphDivider: CheckableImageView
private lateinit var mEditorParagraphH1: CheckableImageView
private lateinit var mEditorParagraphH2: CheckableImageView
private lateinit var mEditorParagraphH3: CheckableImageView
private lateinit var mEditorParagraphH4: CheckableImageView
private lateinit var mEditorParagraphQuote: CheckableImageView
private lateinit var mEditorAlignLeft: CheckableImageView
private lateinit var mEditorAlignCenter: CheckableImageView
private lateinit var mEditorAlignRight: CheckableImageView
private lateinit var mEditorAlignContainer: View
private lateinit var mEditorFontContainer: View
private lateinit var mEditorParagraphContainer: View
private lateinit var mEditorLinkContainer: View
@ -110,7 +97,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mRichEditor.insertCustomStyleLink(insertData)
}
}
INSERT_ARTICLE_CODE -> {
val article =
data?.getParcelableExtra<ArticleEntity>(ArticleEntity::class.java.simpleName)
@ -120,7 +106,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mRichEditor.insertCustomStyleLink(insertData)
}
}
INSERT_GAME_CODE -> {
val game = data?.getParcelableExtra<GameEntity>(GameEntity::class.java.simpleName)
if (game != null) {
@ -129,7 +114,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mRichEditor.insertCustomStyleLink(insertData)
}
}
INSERT_GAME_COLLECTION_CODE -> {
val gameCollectionEntity =
data?.getParcelableExtra<GamesCollectionEntity>(GamesCollectionEntity::class.java.simpleName)
@ -139,11 +123,9 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mRichEditor.insertCustomStyleLink(insertData)
}
}
REQUEST_CODE_IMAGE -> {
if (data != null) mViewModel.uploadPic(data)
}
INSERT_MEDIA_VIDEO_CODE -> {
val localVideoList =
data?.getParcelableArrayListExtra<LocalVideoEntity>(LocalVideoEntity::class.java.name)
@ -153,14 +135,12 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
uploadVideo(localVideoList)
}
}
REQUEST_CODE_IMAGE_CROP -> {
val imagePath = data?.getStringExtra(CropImageActivity.RESULT_CLIP_PATH)
if (!imagePath.isNullOrEmpty()) {
mViewModel.uploadPoster(imagePath)
}
}
INSERT_VIDEO_CODE -> {
val videoEntity = data?.getParcelableExtra<MyVideoEntity>(MyVideoEntity::class.java.simpleName)
if (videoEntity != null) {
@ -214,12 +194,7 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mEditorParagraphH2 = findViewById(R.id.editor_paragraph_h2)
mEditorParagraphH3 = findViewById(R.id.editor_paragraph_h3)
mEditorParagraphH4 = findViewById(R.id.editor_paragraph_h4)
mEditorParagraphDivider = findViewById(R.id.editor_paragraph_divider)
mEditorParagraphQuote = findViewById(R.id.editor_paragraph_quote)
mEditorAlignLeft = findViewById(R.id.editor_align_left)
mEditorAlignCenter = findViewById(R.id.editor_align_center)
mEditorAlignRight = findViewById(R.id.editor_align_right)
mEditorAlignContainer = findViewById(R.id.editor_align_container)
mEditorFontContainer = findViewById(R.id.editor_font_container)
mEditorParagraphContainer = findViewById(R.id.editor_paragraph_container)
mEditorLinkContainer = findViewById(R.id.editor_link_container)
@ -234,7 +209,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
@SuppressLint("AddJavascriptInterface", "ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
VideoPosterFragment.createVideoCoverFile(this)
findView()
onRichClick()
mViewModel = provideViewModel()
@ -242,7 +216,7 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mKeyboardHeightProvider = KeyboardHeightProvider(this)
mRichEditor.post { mKeyboardHeightProvider?.start() }
mRichEditor.enableForceDark(DarkModeUtils.isDarkModeOn(this))
mRichEditor.setEditorBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(this))
mRichEditor.setEditorBackgroundColor(R.color.background_white.toColor(this))
mRichEditor.setEditorFontColor(if (mIsDarkModeOn) Color.parseColor("#C2C2C2") else Color.parseColor("#4A4A4A"))
// 防止个别手机在Js里无法获取粘贴内容
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
@ -267,13 +241,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mRichEditor.hasFocus()
} else false
}
mRichEditor.setOnDecorationChangeListener { _, types ->
mEditorAlignLeft.isChecked = types.contains(RichEditor.Type.JUSTIFYLEFT)
mEditorAlignCenter.isChecked = types.contains(RichEditor.Type.JUSTIFYCENTER)
mEditorAlignRight.isChecked = types.contains(RichEditor.Type.JUSTIFYRIGHT)
}
mOriginalCb.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
mOriginalTipsContainer.alpha = 0f
@ -358,9 +325,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-下滑线")
}
}
mEditorParagraphDivider.setOnClickListener {
mRichEditor.insertDivider()
}
mEditorParagraphH1.setOnClickListener {
if (mEditorParagraphH1.isChecked) {
mRichEditor.formatBlock()
@ -406,27 +370,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
}
mEditorParagraphQuote.isChecked = !mEditorParagraphQuote.isChecked
}
mEditorAlignLeft.setOnClickListener {
if (!mEditorAlignLeft.isChecked) {
mRichEditor.setAlignLeft()
MtaHelper.onEvent(mtaEventName(), "文本对齐选项", "文本对齐选项-靠左")
mEditorAlignLeft.isChecked = !mEditorAlignLeft.isChecked
}
}
mEditorAlignCenter.setOnClickListener {
if (!mEditorAlignCenter.isChecked) {
mRichEditor.setAlignCenter()
MtaHelper.onEvent(mtaEventName(), "文本对齐选项", "文本对齐选项-靠中")
mEditorAlignCenter.isChecked = !mEditorAlignCenter.isChecked
}
}
mEditorAlignRight.setOnClickListener {
if (!mEditorAlignRight.isChecked) {
mRichEditor.setAlignRight()
MtaHelper.onEvent(mtaEventName(), "文本对齐选项", "文本对齐选项-靠右")
mEditorAlignRight.isChecked = !mEditorAlignRight.isChecked
}
}
findViewById<View>(R.id.editor_link_answer).setOnClickListener {
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-回答")
startActivityForResult(
@ -506,22 +449,25 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
return
}
try {
PermissionHelper.checkStoragePermissionBeforeAction(this) {
val maxChooseCount = if (videoCount + 3 <= MAX_MEDIA_COUNT) 3 else MAX_MEDIA_COUNT - videoCount
startActivityForResult(
LocalMediaActivity.getIntent(
this@BaseRichEditorActivity,
ChooseType.VIDEO,
maxChooseCount,
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
), INSERT_MEDIA_VIDEO_CODE
)
NewLogUtils.logChooseMedia(
"view_media",
if (mtaEventName() == "提问帖") "提问帖" else "帖子",
"视频"
)
}
PermissionHelper.checkStoragePermissionBeforeAction(this,
object : EmptyCallback {
override fun onCallback() {
val maxChooseCount = if (videoCount + 3 <= MAX_MEDIA_COUNT) 3 else MAX_MEDIA_COUNT - videoCount
startActivityForResult(
LocalMediaActivity.getIntent(
this@BaseRichEditorActivity,
LocalMediaActivity.ChooseType.VIDEO,
maxChooseCount,
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
), INSERT_MEDIA_VIDEO_CODE
)
NewLogUtils.logChooseMedia(
"view_media",
if (mtaEventName() == "提问帖") "提问帖" else "帖子",
"视频"
)
}
})
} catch (e: Exception) {
toast(R.string.media_image_hint)
e.printStackTrace()
@ -536,16 +482,18 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
return
}
try {
PermissionHelper.checkStoragePermissionBeforeAction(this) {
val maxChooseCount = if (imageCount + 10 <= MAX_IMAGE_COUNT) 10 else MAX_IMAGE_COUNT - imageCount
val intent = LocalMediaActivity.getIntent(
this@BaseRichEditorActivity,
ChooseType.IMAGE,
maxChooseCount,
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
)
startActivityForResult(intent, REQUEST_CODE_IMAGE)
}
PermissionHelper.checkStoragePermissionBeforeAction(this, object : EmptyCallback {
override fun onCallback() {
val maxChooseCount = if (imageCount + 10 <= MAX_IMAGE_COUNT) 10 else MAX_IMAGE_COUNT - imageCount
val intent = LocalMediaActivity.getIntent(
this@BaseRichEditorActivity,
LocalMediaActivity.ChooseType.IMAGE,
maxChooseCount,
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
)
startActivityForResult(intent, REQUEST_CODE_IMAGE)
}
})
} catch (e: Exception) {
toast(R.string.media_image_hint)
e.printStackTrace()
@ -568,7 +516,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mEditorFontContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorParagraphContainer.visibility =
if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorAlignContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = View.GONE
mTagsContainer.visibility = View.GONE
mIsExtendedKeyboardShow = mEditorFont.isChecked
@ -590,7 +537,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
if (mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorFontContainer.visibility = View.GONE
mEditorAlignContainer.visibility = View.GONE
mEditorParagraphContainer.visibility = View.GONE
mTagsContainer.visibility = View.GONE
mIsExtendedKeyboardShow = mEditorLink.isChecked
@ -745,9 +691,9 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mViewModel.id = id
mViewModel.videoId = videoId
val videoEntity = VideoEntity(url = url)
TheRouter.build(RouteConsts.activity.videoCoverEditActivity)
.withParcelable(EntranceConsts.KEY_VIDEO_ENTITY, videoEntity)
.navigation(this@BaseRichEditorActivity, REQUEST_CODE_IMAGE_CROP)
val intent =
PosterEditActivity.getIntentByVideo(this@BaseRichEditorActivity, videoEntity)
startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
}
@JavascriptInterface
@ -806,9 +752,9 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(com.gh.gamecenter.common.R.color.ui_surface, com.gh.gamecenter.common.R.color.ui_surface)
updateStatusBarColor(R.color.background_white, R.color.background_white)
mRichEditor.enableForceDark(DarkModeUtils.isDarkModeOn(this))
mRichEditor.setEditorBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(this))
mRichEditor.setEditorBackgroundColor(R.color.background_white.toColor(this))
mRichEditor.setEditorFontColor(if (mIsDarkModeOn) Color.parseColor("#C2C2C2") else Color.parseColor("#4A4A4A"))
}
@ -830,7 +776,7 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
const val INSERT_VIDEO_CODE = 415
const val MAX_INPUT_TEXT_NUM = 10000
const val MAX_MEDIA_COUNT = 20
const val MAX_IMAGE_COUNT = 70
const val MAX_IMAGE_COUNT = 35
const val REQUEST_CODE_IMAGE = 120
const val INSERT_MEDIA_VIDEO_CODE = 121

View File

@ -10,16 +10,17 @@ import android.text.TextUtils
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.WaitingDialogFragment
import com.gh.gamecenter.common.entity.ErrorEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.common.entity.ErrorEntity
import com.gh.gamecenter.common.retrofit.BiResponse
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
@ -37,8 +38,6 @@ import okhttp3.ResponseBody
import retrofit2.HttpException
import java.io.File
import java.io.FileOutputStream
import java.util.*
import kotlin.collections.LinkedHashMap
import kotlin.collections.set
// TODO: 移动到module_bbs模块
@ -58,6 +57,7 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo
val TITLE_MIN_LENGTH = 6
val MIN_TEXT_LENGTH = 6
val MAX_TEXT_LENGTH = 10000
val FILE_HOST = "file:///"
var id = ""//视频标记
var videoId = ""//更改封面视频id
val quoteCountEntity = QuoteCountEntity()//数据上报用
@ -83,7 +83,7 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo
val application: Application = getApplication()
Utils.toast(
getApplication(),
application.getString(com.gh.gamecenter.common.R.string.pic_max_hint, count)
application.getString(R.string.pic_max_hint, count)
)
continue
}
@ -124,15 +124,8 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo
}
val map = LinkedHashMap<String, String>()
for (key in imageUrlMap.keys) {
// 文件格式为 HEIC 时,使用经 OSS 转码的图片作为预览图片
if (FileUtils.getFileMimeType(getApplication(), key.decodeURI())?.lowercase(Locale.CHINA)?.contains("heic") == true) {
val transformedImgUrl = ImageUtils.getIdealImageUrl(imageUrlMap[key], 5000) ?: ""
map[MD5Utils.getUrlMD5(key)] = transformedImgUrl
mapImages[transformedImgUrl.decodeURI()] = imageUrlMap[key] ?: ""
} else {
map[MD5Utils.getUrlMD5(key)] = imageUrlMap[key] ?: ""
mapImages[TextUtils.htmlEncode(key).decodeURI()] = imageUrlMap[key] ?: ""
}
map[MD5Utils.getUrlMD5(key)] = FILE_HOST + key.decodeURI()
mapImages[TextUtils.htmlEncode(key).decodeURI()] = imageUrlMap[key] ?: ""
}
chooseImagesUploadSuccess.value = map
}

View File

@ -46,7 +46,7 @@ abstract class DownloadToolbarActivity : ToolBarActivity() {
override fun inflateMenu(res: Int) {
super.inflateMenu(res)
if (!getBoolean(Constants.SP_TEENAGER_MODE) && showDownloadMenu()) {
if (showDownloadMenu()) {
createDownloadMenu(res)
}
}
@ -60,7 +60,7 @@ abstract class DownloadToolbarActivity : ToolBarActivity() {
}
val downloadMenuView = mActionMenuView.menu.findItem(R.id.menu_download).actionView
mDownloadCountHint = downloadMenuView?.findViewById(R.id.menu_download_count_hint)
mDownloadCountHint?.typeface = Typeface.createFromAsset(assets, Constants.DIN_FONT_PATH)
mDownloadCountHint?.typeface = Typeface.createFromAsset(assets, "fonts/d_din_bold_only_number.ttf")
}
override fun onMenuItemClick(item: MenuItem?): Boolean {

View File

@ -2,50 +2,22 @@ package com.gh.base
import android.app.Activity
import android.app.Application
import android.content.res.Configuration
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.gh.ad.AdDelegateHelper
import com.gh.common.util.FloatingBackViewManager
import com.gh.common.xapk.XapkInstaller
import com.gh.download.DownloadManager
import com.gh.gamecenter.SingletonWebActivity
import com.gh.gamecenter.SkipActivity
import com.gh.gamecenter.SplashAdActivity
import com.gh.gamecenter.SplashScreenActivity
import com.gh.gamecenter.authorization.AuthorizationActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
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.login.utils.QuickLoginHelper
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.gamecenter.va.VCore
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.therouter.TheRouter
// TODO移动到对应的模块
class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
private var isFromBackgroundToForeground = false // 是否后台回到前台
override fun onActivityPreCreated(activity: Activity, savedInstanceState: Bundle?) {
if (QuickLoginHelper.isLoginAuthPage(activity)) {
try {
val resources = activity.resources
val config = Configuration(resources.configuration)
config.fontScale = 1.0f
// 更新Resources配置
val metrics = resources.displayMetrics
metrics.scaledDensity = metrics.density
resources.updateConfiguration(config, metrics)
} catch (e: Exception) {
// 设置字体失败
}
}
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
// do nothing
@ -53,31 +25,6 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
override fun onActivityStarted(activity: Activity) {
GlobalActivityManager.currentActivity = activity
GlobalActivityManager.activityCount++
if (GlobalActivityManager.activityCount == 1 && isFromBackgroundToForeground) {
if (AdDelegateHelper.shouldShowStartUpAd(true)
&& !HaloApp.getInstance().isDisableSplashAdTemporarily
&& activity !is SplashScreenActivity
&& activity !is SkipActivity
&& activity !is AuthorizationActivity
&& activity !is SplashAdActivity
&& !isSuggestionActivity(activity)
) {
activity.startActivity(SplashAdActivity.getIntent(activity))
}
isFromBackgroundToForeground = false
}
if (GlobalActivityManager.activityCount == 1) {
// 清除桌面角标
if (activity !is SplashScreenActivity && activity !is AuthorizationActivity) {
val pushProvider = TheRouter.get(IPushProvider::class.java)
pushProvider?.cleanBadgeNumber(activity.applicationContext)
}
}
if (QuickLoginHelper.isLoginAuthPage(activity)) {
QuickLoginHelper.addCustomViewToLoginAuthPage(activity)
}
}
override fun onActivityResumed(activity: Activity) {
@ -109,8 +56,6 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
if (activity is AppCompatActivity
&& !VCore.getInstance().isLaunchActivity(activity)
&& activity !is LoginActivity
&& activity !is SplashScreenActivity
&& activity !is SkipActivity
&& activity !is AuthorizationActivity
@ -129,8 +74,7 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
override fun onActivityStopped(activity: Activity) {
GlobalActivityManager.activityCount--
isFromBackgroundToForeground = GlobalActivityManager.activityCount <= 0
// do nothing
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
@ -138,14 +82,7 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
override fun onActivityDestroyed(activity: Activity) {
if (QuickLoginHelper.isLoginAuthPage(activity)) {
QuickLoginHelper.release()
}
}
private fun isSuggestionActivity(activity: Activity): Boolean {
val helpAndFeedbackProvider = TheRouter.get(IHelpAndFeedbackProvider::class.java)
return helpAndFeedbackProvider?.isSuggestionActivity(activity) ?: false
// do nothing
}
}

View File

@ -3,8 +3,6 @@ package com.gh.common
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.Base64
import android.view.View
import android.webkit.JavascriptInterface
@ -13,7 +11,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.*
import com.gh.common.util.LogUtils
@ -21,37 +19,27 @@ import com.gh.download.DownloadManager
import com.gh.download.PackageObserver
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.callback.BiCallback
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.Constants.SP_MEMBER_PAYMENT_BUTTON_CLICK
import com.gh.gamecenter.common.constant.Constants.SP_MEMBER_RECHARGE_BUTTON_CLICK
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.NotificationUgc
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.loghub.LoghubUtils
import com.gh.gamecenter.common.provider.IHelpAndFeedbackProvider
import com.gh.gamecenter.common.tracker.Tracker
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.common.utils.SensorsBridge.EVENT_MEMBER_RECHARGE_BUTTON_CLICK
import com.gh.gamecenter.common.utils.SensorsBridge.EVENT_NAME
import com.gh.gamecenter.common.utils.SensorsBridge.KEY_IS_FIRST_TIME
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.SensorsEvent
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.AcctRecordEntity
import com.gh.gamecenter.feature.entity.Badge
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.OrderEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.login.user.LoginTag
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserRepository
@ -62,14 +50,10 @@ import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
import com.gh.gamecenter.setting.SettingBridge
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.halo.assistant.accelerator.repository.AccelerationRepository.Companion.PAYMENT_TYPE_ALIPAY
import com.halo.assistant.accelerator.repository.AccelerationRepository.Companion.PAYMENT_TYPE_WECHAT
import com.halo.assistant.accelerator.repository.AcceleratorDataHolder
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus.*
import com.lightgame.utils.Utils
import com.therouter.TheRouter
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@ -82,25 +66,17 @@ import java.util.*
class DefaultJsApi(
var context: Context,
val entrance: String = "",
private val mFragment: Fragment? = null,
private var mFragment: Fragment? = null,
private var mBbsId: String? = "",
private var mOriginUrl: String? = "",
private val mForumName: String? = "",
private val listener: OnWebClickListener? = null
private var mOriginUrl: String?= "",
) {
companion object {
private const val SOURCE_ENTRANCE = "webView"
}
private var mLoginHandler: CompletionHandler<Any>? = null
private var mDownloadWatcher: DataWatcher? = null // 下载观察者
private var mDownloadUrlSet: HashSet<String>? = null // 下载的 url 集合
private var mDownloadHandler: CompletionHandler<Any>? = null // 下载信息回调
private var mExposureEvent: ExposureEvent? = null // 活动曝光实体
private val handler = Handler(Looper.getMainLooper())
init {
if (mFragment != null) {
EventBus.getDefault().register(this)
@ -108,11 +84,6 @@ class DefaultJsApi(
}
}
@JavascriptInterface
fun isEnableForceDark(msg: Any): Boolean {
return DarkModeUtils.isWebViewForceDarkEnabled
}
@JavascriptInterface
fun isGhzs(msg: Any): String {
return "true"
@ -153,7 +124,7 @@ class DefaultJsApi(
@JavascriptInterface
fun login(msg: Any) {
if (NetworkUtils.isQuickLoginEnabled(context)) {
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
QuickLoginHelper.startLogin(context, "浏览器")
} else {
val intent = LoginActivity.getIntent(context, "浏览器")
@ -243,16 +214,10 @@ class DefaultJsApi(
runOnUiThread {
// 若畅玩列表中安装了,优先启动畅玩游戏
if (VHelper.isInstalled(packageName)) {
VHelper.validateVSpaceBeforeAction(context, packageName, null) {
if (!VHelper.showDialogIfVSpaceIsNeeded(context, "", "", "", "")) {
VHelper.launch(context, packageName)
}
} else {
val wechatPkgName = "com.tencent.mm"
if (packageName == wechatPkgName && !PackageUtils.isInstalled(context, wechatPkgName)) {
// 如果是微信客户端,需要检查是否安装微信
ToastUtils.showToast(R.string.wechat_app_not_install_tips.toResString())
return@runOnUiThread
}
PackageLauncher.launchApp(context, packageName = packageName)
}
}
@ -264,19 +229,12 @@ class DefaultJsApi(
val context = CurrentActivityHolder.getCurrentActivity()
context?.startActivity(
ImageViewerActivity.getIntent(
context,
imageEvent.imageList,
imageEvent.position,
"浏览器"
)
)
context?.startActivity(ImageViewerActivity.getIntent(context, imageEvent.imageList, imageEvent.position, "浏览器"))
}
@JavascriptInterface
fun isInstalled(event: Any): String {
val localInstalledPackageList = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
val localInstalledPackageList = PackageUtils.getAllPackageName(HaloApp.getInstance().application)
val packageNameList: ArrayList<String> = event.toString().toObject() ?: ArrayList()
for (packageName in packageNameList) {
@ -320,18 +278,11 @@ class DefaultJsApi(
/**
* 打开论坛搜索页
* 如果用户是从 webView跳转到论坛搜索页则sourceEntrance为空
*/
@JavascriptInterface
fun openForumSearch(msg: Any) {
runOnUiThread {
DirectUtils.directToForumOrUserSearch(
context,
mBbsId ?: "",
entrance.ifBlank { "内部网页" },
SOURCE_ENTRANCE,
mForumName ?: ""
)
DirectUtils.directToForumOrUserSearch(context, mBbsId ?: "", entrance.ifBlank { "内部网页" })
}
}
@ -358,17 +309,6 @@ class DefaultJsApi(
return HaloApp.getInstance().gid
}
@JavascriptInterface
fun getOaid(msg: Any): String {
return HaloApp.getInstance().oaid
}
@JavascriptInterface
fun getPushId(): String {
val pushProvider = TheRouter.get(IPushProvider::class.java)
return pushProvider?.getRegistrationId(HaloApp.getInstance()) ?: "unknown"
}
@JavascriptInterface
fun showIncompatibleVersionDialog(msg: Any) {
DialogHelper.showUpgradeDialog(context)
@ -444,7 +384,8 @@ class DefaultJsApi(
@JavascriptInterface
fun showQaFeedbackDialog(msg: Any) {
val mHelpAndFeedbackHelp = TheRouter.get(IHelpAndFeedbackProvider::class.java)
val mHelpAndFeedbackHelp =
ARouter.getInstance().build(RouteConsts.provider.helpAndFeedback).navigation() as? IHelpAndFeedbackProvider
mHelpAndFeedbackHelp?.showQaFeedbackDialogFragment(context as AppCompatActivity, msg.toString())
}
@ -515,44 +456,6 @@ class DefaultJsApi(
}
}
@JavascriptInterface
fun saveWechatQRCode(msg: Any) {
val base64StringData = msg.toString()
runOnUiThread {
(context as? FragmentActivity)?.checkStoragePermissionBeforeAction {
runOnIoThread {
val base64String = base64StringData.replace("data:image/png;base64", "")
tryWithDefaultCatch {
val imageFile =
File(HaloApp.getInstance().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".png")
val decodedString = Base64.decode(base64String, Base64.DEFAULT)
val bos = BufferedOutputStream(FileOutputStream(imageFile))
bos.write(decodedString)
bos.flush()
bos.close()
ImageUtils.saveImageToFile(imageFile, "", true) {
// 这里是 ui 线程
// 保存微信二维码成功1s 以后跳转微信
if (mFragment != null && mFragment.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
handler.removeCallbacksAndMessages(null)
handler.postDelayed({
val wechatPkgName = "com.tencent.mm"
if (!PackageUtils.isInstalled(context, wechatPkgName)) {
ToastUtils.showToast(R.string.wechat_app_not_install_tips.toResString())
return@postDelayed
}
PackageLauncher.launchApp(context, packageName = wechatPkgName)
}, 1000)
}
}
}
}
}
}
}
@JavascriptInterface
fun loginWithCallback(msg: Any, handler: CompletionHandler<Any>) {
mLoginHandler = handler
@ -612,7 +515,7 @@ class DefaultJsApi(
@JavascriptInterface
fun getInstallStatus(event: Any): String {
val localInstalledPackageList = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
val localInstalledPackageList = PackageUtils.getAllPackageName(HaloApp.getInstance().application)
val packageNameList: ArrayList<String> = event.toString().toObject() ?: ArrayList()
val installStatusMap: HashMap<String, Boolean> = hashMapOf()
@ -627,24 +530,13 @@ class DefaultJsApi(
@JavascriptInterface
fun installDownloadedGame(event: Any) {
val url = event.toString()
val vUrl = VHelper.getVUrl(url)
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(url, null)
?: DownloadManager.getInstance().getDownloadEntitySnapshot(url, null)
NewFlatLogUtils.logGameInstall(
gameId = downloadEntity?.gameId ?: "",
gameName = downloadEntity?.name ?: "",
trigger = "主动安装"
)
SensorsBridge.trackInstallGameClick(
gameId = downloadEntity?.gameId ?: "",
gameName = downloadEntity?.name ?: "",
action = "主动安装"
)
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(url, null, false)
?: DownloadManager.getInstance().getDownloadEntitySnapshot(vUrl, null, false)
downloadEntity?.let {
PackageInstaller.install(context, it, showUnzipToast = false, ignoreAsVGame = false)
PackageInstaller.install(context, it, showUnzipToast = false)
}
}
@ -757,86 +649,6 @@ class DefaultJsApi(
}
}
@JavascriptInterface
fun preOrderWithAli(json: Any) {
val order = json.toString().toObject<OrderEntity>() ?: return
trackMemberPaymentButtonClick(order, PAYMENT_TYPE_ALIPAY)
listener?.onPreOrderWithAli(order)
}
@JavascriptInterface
fun preOrderWithWechat(json: Any) {
val order = json.toString().toObject<OrderEntity>() ?: return
trackMemberPaymentButtonClick(order, PAYMENT_TYPE_WECHAT)
listener?.onPreOrderWithWechat(order)
}
private fun trackMemberPaymentButtonClick(order: OrderEntity, paymentType: String) {
val isFirstTime = SPUtils.getBoolean(SP_MEMBER_PAYMENT_BUTTON_CLICK, true)
SPUtils.setBoolean(SP_MEMBER_PAYMENT_BUTTON_CLICK, false)
SensorsBridge.trackMemberPaymentButtonClick(
isFirstTime,
paymentType,
order.setMenuName,
order.paymentAmount
)
}
@JavascriptInterface
fun startGameAccelerate(acctJson: Any) {
if (acctJson is String) {
val acctRecord = GsonUtils.fromJson(acctJson, AcctRecordEntity::class.java)
val accInfo = acctRecord.accInfo
listener?.onStartGameAccelerate(accInfo)
}
}
@JavascriptInterface
fun getCurAcctGameId(): String {
return AcceleratorDataHolder.instance.getAcceleratingGameId()
}
@JavascriptInterface
fun stopGameAccelerate() {
listener?.onStopGameAccelerate()
}
@JavascriptInterface
fun getDurationRemainingTime(msg: Any, handler: CompletionHandler<Any>) {
TheRouter.get(IAcceleratorProvider::class.java)?.loadQyUserPermissionData {
val durationExpiredMinute = AcceleratorDataHolder.instance.vipEntity?.durationExpiredTime ?: 0L
handler.complete(durationExpiredMinute)
}
}
@JavascriptInterface
fun refreshToken(token: Any, handler: CompletionHandler<Any>) {
val accessToken = token.toString()
UserManager.getInstance().refreshToken(accessToken, object : UserManager.refreshCallBack {
override fun onLogin() {
handler.complete(true)
}
override fun onLoginFailure(errorMessage: String?) {
handler.complete(false)
}
})
}
@JavascriptInterface
fun trackSensorsAnalytics(json: Any) {
val hashMap = json.toString().toObject<HashMap<String, Any>>() ?: return
val eventName = hashMap.remove(EVENT_NAME) ?: return
when (eventName) {
EVENT_MEMBER_RECHARGE_BUTTON_CLICK -> {
hashMap[KEY_IS_FIRST_TIME] = SPUtils.getBoolean(SP_MEMBER_RECHARGE_BUTTON_CLICK, true)
SPUtils.setBoolean(SP_MEMBER_RECHARGE_BUTTON_CLICK, false)
}
}
SensorsBridge.trackSensorsAnalyticsFromWeb(eventName.toString(), hashMap)
}
/**
* 获取 ExposureEvent可能为空
*/
@ -857,8 +669,6 @@ class DefaultJsApi(
}
EventBus.getDefault().unregister(this@DefaultJsApi)
handler.removeCallbacksAndMessages(null)
}
}
@ -927,7 +737,6 @@ class DefaultJsApi(
var status: String = "" // DOWNLOADING, PAUSED, DOWNLOADED, ERROR, UNKNOWN
) {
companion object {
fun fromDownloadEntity(downloadEntity: DownloadEntity): SimpleDownloadEntity {
val status: String = when (downloadEntity.status) {
add,
@ -955,15 +764,4 @@ class DefaultJsApi(
}
}
}
interface OnWebClickListener {
fun onPreOrderWithAli(order: OrderEntity)
fun onPreOrderWithWechat(order: OrderEntity)
fun onStartGameAccelerate(accInfo: AcctRecordEntity.AccInfo)
fun onStopGameAccelerate()
}
}

View File

@ -15,7 +15,9 @@ import com.gh.common.util.DirectUtils.directToLegacyVideoDetail
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.common.util.DirectUtils.directToQa
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.SkipCompatActivity
import com.gh.gamecenter.LibaoDetailActivity
import com.gh.gamecenter.MainActivity
import com.gh.gamecenter.NewsDetailActivity
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
@ -32,12 +34,12 @@ import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.ActivityLabelEntity
import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.entity.VideoLinkEntity
import com.gh.gamecenter.eventbus.EBSkip
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.utils.PlatformUtils
import com.gh.gamecenter.fragment.MainWrapperFragment
import com.gh.gamecenter.gamecollection.publish.GameCollectionEditActivity
import com.gh.gamecenter.libao.LibaoDetailActivity
import com.gh.gamecenter.newsdetail.NewsDetailActivity
import com.gh.gamecenter.qa.BbsType
import com.gh.gamecenter.qa.video.publish.VideoPublishActivity
import com.gh.gamecenter.subject.SubjectActivity
@ -49,8 +51,8 @@ import java.nio.charset.Charset
object DefaultUrlHandler {
@JvmStatic
fun interceptUrl(context: Context, url: String, entrance: String, sourceEntrance: String = ""): Boolean {
return interceptUrl(context, url, null, entrance, false, sourceEntrance)
fun interceptUrl(context: Context, url: String, entrance: String): Boolean {
return interceptUrl(context, url, null, entrance, false)
}
/**
@ -64,13 +66,8 @@ object DefaultUrlHandler {
fun interceptUrl(context: Context, url: String,
traceEvent: ExposureEvent? = null,
entrance: String,
bringAppToFront: Boolean = false,
sourceEntrance: String = ""): Boolean {
bringAppToFront: Boolean = false): Boolean {
val uri = Uri.parse(url)
// 优先交给新的路由拦截处理
if (SkipCompatActivity.handleSkip(context, uri)) return true
if ("ghzhushou" == uri.scheme) {
Utils.log("url = $url")
Utils.log("url = " + uri.scheme!!)
@ -138,7 +135,7 @@ object DefaultUrlHandler {
}
}
"question" -> DirectUtils.directToQuestionDetail(context, id, entrance, "文章链接", sourceEntrance)
"question" -> DirectUtils.directToQuestionDetail(context, id, entrance, "文章链接")
"real_name" -> DirectUtils.directToRealName(context)
@ -181,7 +178,7 @@ object DefaultUrlHandler {
if ("articles" == type) {
DirectUtils.directToCommunityArticle(
context, typeId, communityId,
entrance, "文章链接", sourceEntrance
entrance, "文章链接"
)
}
}
@ -249,22 +246,24 @@ object DefaultUrlHandler {
act,
paginationType,
fieldId,
sectionName,
sourceEntrance = sourceEntrance
sectionName
)
}
EntranceConsts.HOST_VIDEO_DETAIL -> {
DirectUtils.directToVideoDetail(context, id, entrance, path, sourceEntrance)
DirectUtils.directToVideoDetail(context, id, entrance, path)
}
EntranceConsts.HOST_VIDEO_SINGLE -> {
val referer = uri.getQueryParameter("referer") ?: ""
DirectUtils.directToVideoDetail(
context, id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value,
false, "", entrance, "", if (TextUtils.isEmpty(referer)) "" else referer, sourceEntrance
false, "", entrance, "", if (TextUtils.isEmpty(referer)) "" else referer
)
}
EntranceConsts.HOST_VIDEO_STREAMING_HOME -> {
DirectUtils.directToHomeVideoTab(context)
intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true)
context.startActivity(intent)
}
EntranceConsts.HOST_VIDEO_STREAMING_DESC -> {
directToGameDetailVideoStreaming(context, id, entrance)
@ -273,6 +272,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 ?: "")
@ -322,7 +325,7 @@ object DefaultUrlHandler {
val linkData = Base64.decode(dataString, Base64.DEFAULT)
val linkDataString = String(linkData, Charset.defaultCharset())
val le = gson.fromJson(linkDataString, LinkEntity::class.java)
directToLinkPage(context, le, entrance, sourceEntrance, "")
directToLinkPage(context, le, entrance, "")
}
} catch (e: Exception) {
e.printStackTrace()
@ -347,8 +350,7 @@ object DefaultUrlHandler {
}
EntranceConsts.HOST_FORUM_DETAIL -> {
val sectionId = uri.getQueryParameter("section_id") ?: ""
DirectUtils.directForumDetailSection(context, id, sectionId, entrance)
DirectUtils.directForumDetail(context, id, entrance)
}
EntranceConsts.HOST_GAME_RATING_DETAIL -> {
@ -361,8 +363,9 @@ object DefaultUrlHandler {
}
EntranceConsts.HOST_FORUM -> {
val position = uri.getQueryParameter(EntranceConsts.KEY_POSITION)?.toInt()
DirectUtils.directToHomeCommunityTab(context)
DirectUtils.directToForum(context, position ?: 0)
}
EntranceConsts.HOST_UPLOAD_VIDEO_NEW -> {
@ -379,7 +382,7 @@ object DefaultUrlHandler {
val iconSubscript = uri.getQueryParameter("game_icon_subscript") ?: ""
val gameEntity =
if (forumType == BbsType.OFFICIAL_BBS.value && gameId.isNotEmpty() && gameName.isNotEmpty() && icon.isNotEmpty()) {
GameEntity(_id = gameId, mName = gameName, mIcon = icon, mIconSubscript = iconSubscript)
GameEntity(id = gameId, mName = gameName, mIcon = icon, mIconSubscript = iconSubscript)
} else null
val activityLabelEntity = if (activityId.isNotEmpty() && activityName.isNotEmpty()) {
ActivityLabelEntity(
@ -435,17 +438,17 @@ object DefaultUrlHandler {
directToFeedback(
context,
content,
null,
isQaFeedback,
qaContentId,
isPlugin = false,
isSmoothGame = false,
EntranceConsts.ENTRANCE_BROWSER
)
}
}
EntranceConsts.HOST_HELP_AND_FEEDBACK -> {
DirectUtils.directToHelpAndFeedback(context)
val position = uri.getQueryParameter("position") ?: ""
DirectUtils.directToHelpAndFeedback(context, position.toInt())
}
EntranceConsts.HOST_HELP_DETAIL -> {
@ -486,24 +489,25 @@ object DefaultUrlHandler {
val activityName = uri.getQueryParameter("activity_name") ?: ""
val gameId = uri.getQueryParameter("game_id") ?: ""
context.startActivity(
GameCollectionEditActivity.getCreateIntent(
GameCollectionEditActivity.getIntent(
context,
activityId,
activityName,
gameId,
entrance,
"其他"
entrance
)
)
}
EntranceConsts.HOST_GAME_LIBRARY -> {
DirectUtils.directToMainActivity(context)
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_GAME))
}
EntranceConsts.HOST_HOME_GAME_COLLECTION_SQUARE -> {
DirectUtils.directToMainActivity(context)
DirectUtils.directToHomeDefaultTab(context)
EventBus.getDefault()
.post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_HOME))
EventBus.getDefault().post(EBReuse(host))
}
@ -558,7 +562,7 @@ object DefaultUrlHandler {
}
// 处理内部页面逻辑
if (transformNormalScheme(context, url, entrance, sourceEntrance)) {
if (transformNormalScheme(context, url, entrance)) {
return true
}
@ -567,14 +571,14 @@ object DefaultUrlHandler {
}
@JvmStatic
fun transformNormalScheme(context: Context, url: String, entrance: String, sourceEntrance: String): Boolean {
val b = transformNewNormalScheme(context, url, entrance, sourceEntrance)
fun transformNormalScheme(context: Context, url: String, entrance: String): Boolean {
val b = transformNewNormalScheme(context, url, entrance)
if (b) return b
return transformOldNormalScheme(context, url, entrance, sourceEntrance)
return transformOldNormalScheme(context, url, entrance)
}
@JvmStatic
fun transformOldNormalScheme(context: Context, url: String, entrance: String, sourceEntrance: String): Boolean {
fun transformOldNormalScheme(context: Context, url: String, entrance: String): Boolean {
val uri = Uri.parse(url)
if (uri.host == "www.ghzs666.com"
|| uri.host == "www.ghzs.com"
@ -590,7 +594,6 @@ object DefaultUrlHandler {
DirectUtils.directToGameDetail(
context,
gameId,
"",
entrance,
autoDownload = false,
traceEvent = null
@ -600,7 +603,7 @@ object DefaultUrlHandler {
val questionId = split("/")[2]
val answerId = uri.getQueryParameter("answer")
if (answerId.isNullOrEmpty()) {
DirectUtils.directToQuestionDetail(context, questionId, entrance, "", sourceEntrance)
DirectUtils.directToQuestionDetail(context, questionId, entrance, "")
} else {
DirectUtils.directToAnswerDetail(context, answerId, entrance, "")
}
@ -630,7 +633,7 @@ object DefaultUrlHandler {
if ("articles" == type || "article" == type) {
DirectUtils.directToCommunityArticle(
context, typeId, communityId,
entrance, "文章链接", sourceEntrance
entrance, "文章链接"
)
}
}
@ -661,7 +664,7 @@ object DefaultUrlHandler {
}
@JvmStatic
fun transformNewNormalScheme(context: Context, url: String, entrance: String, sourceEntrance: String): Boolean {
fun transformNewNormalScheme(context: Context, url: String, entrance: String): Boolean {
val uri = Uri.parse(url)
if (uri.host == "www.ghzs666.com"
|| uri.host == "www.ghzs.com"
@ -679,7 +682,7 @@ object DefaultUrlHandler {
val articleId = splits[2].substring(7)
DirectUtils.directToCommunityArticle(
context, articleId, "",
entrance, "文章链接", sourceEntrance
entrance, "文章链接"
)
}
//https://m.ghzs666.com/article/文章ID
@ -699,7 +702,7 @@ object DefaultUrlHandler {
//https://m.ghzs666.com/bbs/video-视频ID
splits.size >= 3 && splits[1] == "bbs" && splits[2].startsWith("video-") -> {
val videoId = splits[2].substring(6)
DirectUtils.directToVideoDetail(context, videoId, entrance, sourceEntrance)
DirectUtils.directToVideoDetail(context, videoId, entrance)
}
else -> return false
}

View File

@ -2,22 +2,23 @@ package com.gh.common
import com.gh.common.exposure.ExposureManager
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.util.AdHelper
import com.gh.common.videolog.VideoRecordUtils
import com.gh.download.DownloadDataHelper
import com.gh.gamecenter.common.loghub.LoghubUtils
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.doOnMainProcessOnly
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.entity.TimeEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.schedulers.Schedulers
import kotlin.concurrent.fixedRateTimer
object FixedRateJobHelper {
private const val CHECKER_PERIOD: Long = 15 * 1000L
private const val TIME_PERIOD: Long = 24 * 60 * 60 * 1000L
private const val TIME_PERIOD: Long = 10 * 60 * 1000L
private const val LOGHUB_PERIOD: Long = 2 * 60 * 1000L
private const val EXPOSURE_PERIOD: Long = 1 * 60 * 1000L
private const val REGION_SETTING_PERIOD: Long = 60 * 1000L
@ -25,6 +26,7 @@ object FixedRateJobHelper {
private const val DOWNLOAD_HEARTBEAT_PERIOD: Long = 60 * 1000L
private const val DOWNLOAD_HEARTBEAT_SHEET_PERIOD: Long = 15 * 1000L
private const val STARTUP_AD: Long = 30 * 60 * 1000L
private var mExecuteCount: Int = 0
@ -32,56 +34,58 @@ object FixedRateJobHelper {
@JvmStatic
fun begin() {
// 时间检查每15秒检查一次
fixedRateTimer("Global-Fixed-Rate-Timer", initialDelay = 100, period = CHECKER_PERIOD) {
val elapsedTime = mExecuteCount * CHECKER_PERIOD
// 时间校对24 小时一次
if (elapsedTime % TIME_PERIOD == 0L) {
RetrofitManager.getInstance().api.time
.subscribeOn(Schedulers.io())
.subscribe(object : Response<TimeEntity>() {
override fun onResponse(response: TimeEntity?) {
val serverTime = response?.time
serverTime?.let {
timeDeltaBetweenServerAndClient = it * 1000 - System.currentTimeMillis()
doOnMainProcessOnly {
// 时间检查每15秒检查一次
fixedRateTimer("Global-Fixed-Rate-Timer", initialDelay = 100, period = CHECKER_PERIOD) {
val elapsedTime = mExecuteCount * CHECKER_PERIOD
// 时间校对10分钟一次
if (elapsedTime % TIME_PERIOD == 0L) {
RetrofitManager.getInstance().api.time
.subscribeOn(Schedulers.io())
.subscribe(object : Response<TimeEntity>() {
override fun onResponse(response: TimeEntity?) {
val serverTime = response?.time
serverTime?.let {
timeDeltaBetweenServerAndClient = it * 1000 - System.currentTimeMillis()
}
}
}
})
}
// 提交曝光数据
if (elapsedTime % EXPOSURE_PERIOD == 0L) {
ExposureManager.commitSavedExposureEvents(true)
}
// 分片检测下载进度
if (elapsedTime % DOWNLOAD_HEARTBEAT_SHEET_PERIOD == 0L) {
tryCatchInRelease {
val upload = (mExecuteCount * CHECKER_PERIOD) % DOWNLOAD_HEARTBEAT_PERIOD == 0L
DownloadDataHelper.uploadDownloadHeartbeat(upload)
})
}
}
// 提交普通 loghub 数据
if (elapsedTime % LOGHUB_PERIOD == 0L) {
runOnUiThread {
LoghubUtils.commitSavedLoghubEvents(true)
// 提交曝光数据
if (elapsedTime % EXPOSURE_PERIOD == 0L) {
ExposureManager.commitSavedExposureEvents(true)
}
}
// 更新游戏屏蔽信息
if (elapsedTime % REGION_SETTING_PERIOD == 0L) {
if (HaloApp.getInstance().isRunningForeground) {
RegionSettingHelper.getRegionSetting()
// 分片检测下载进度
if (elapsedTime % DOWNLOAD_HEARTBEAT_SHEET_PERIOD == 0L) {
tryCatchInRelease {
val upload = (mExecuteCount * CHECKER_PERIOD) % DOWNLOAD_HEARTBEAT_PERIOD == 0L
DownloadDataHelper.uploadDownloadHeartbeat(upload)
}
}
}
// 提交视频浏览记录数据
if (elapsedTime % VIDEO_RECORD_PERIOD == 0L) {
VideoRecordUtils.commitVideoRecord()
}
// 提交普通 loghub 数据
if (elapsedTime % LOGHUB_PERIOD == 0L) {
runOnUiThread {
LoghubUtils.commitSavedLoghubEvents(true)
}
}
mExecuteCount++
// 更新游戏屏蔽信息
if (elapsedTime % REGION_SETTING_PERIOD == 0L) {
if (HaloApp.getInstance().isRunningForeground) {
RegionSettingHelper.getRegionSetting()
}
}
// 提交视频浏览记录数据
if (elapsedTime % VIDEO_RECORD_PERIOD == 0L) {
VideoRecordUtils.commitVideoRecord()
}
mExecuteCount++
}
}
}
}

View File

@ -1,351 +0,0 @@
package com.gh.common.browse
import android.os.Handler
import android.os.Looper
import android.os.Message
import androidx.lifecycle.*
import androidx.lifecycle.Lifecycle.Event
/**
* 浏览时长计时器核心接口类,用于页面浏览时长相关埋点上报
*/
interface IBrowseTimerCore {
/**
* 开始计时
*/
fun start()
/**
* 结束计时
*/
fun stop()
}
/**
* 浏览时长计时器核心实现类
*/
class BrowseTimerCore internal constructor() : IBrowseTimerCore {
/**
* 延迟执行的时间
*/
var delayInMills: Long = 3000L
/**
* 开始计时函数回调
*/
var onStart: (() -> Unit)? = null
/**
* 结束计时函数回调
*/
var onResult: ((Long) -> Unit)? = null
/**
* 开始计时的时间点
*/
private var startTimeInMills: Long = 0L
/**
* Handler操作类
*/
private val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
if (msg.what == MESSAGE_START) {
dispatchOnStart()
}
}
}
/**
* 延迟执行开始计时
* @see delayInMills
* @see onStart
*/
override fun start() {
if (delayInMills <= 0) {
dispatchOnStart()
} else {
handler.sendEmptyMessageDelayed(MESSAGE_START, delayInMills)
}
}
/**
* 结束计时,统计浏览时长并回调结束计时函数
* @see onResult
*/
override fun stop() {
handler.removeMessages(MESSAGE_START)
if (startTimeInMills > 0L) {
onResult?.invoke(System.currentTimeMillis() - startTimeInMills)
startTimeInMills = 0L
}
}
/**
* 开始计时,回调开始计时函数
*/
private fun dispatchOnStart() {
startTimeInMills = System.currentTimeMillis()
onStart?.invoke()
}
companion object {
private const val MESSAGE_START = 1
}
}
/**
* 无数据浏览计时器接口类
*/
interface IBrowseTimer : IBrowseTimerCore {
fun withDelayInMills(delayInMills: Long): IBrowseTimer
fun withStart(onStart: () -> Unit): IBrowseTimer
fun withResult(onResult: (Long) -> Unit): IBrowseTimer
}
/**
* 无数据的浏览计时器实现类
*/
class BrowseTimer : IBrowseTimer {
private val core = BrowseTimerCore()
private var isStarted: Boolean = false
override fun withDelayInMills(delayInMills: Long): IBrowseTimer {
core.delayInMills = delayInMills
return this
}
override fun withStart(onStart: () -> Unit): IBrowseTimer {
core.onStart = onStart
return this
}
override fun withResult(onResult: (Long) -> Unit): IBrowseTimer {
core.onResult = onResult
return this
}
override fun start() {
if (isStarted) return
isStarted = true
core.start()
}
override fun stop() {
if (!isStarted) return
core.stop()
isStarted = false
}
}
/**
* 支持Lifecycle的无数据的浏览计时器
*/
class LifecycleBoundBrowseTimer internal constructor(
private val base: IBrowseTimer,
private val onStateChanged: (IBrowseTimer, Event) -> Unit
) : IBrowseTimer, LifecycleEventObserver {
override fun withDelayInMills(delayInMills: Long): IBrowseTimer {
return base.withDelayInMills(delayInMills)
}
override fun withStart(onStart: () -> Unit): IBrowseTimer {
return base.withStart(onStart)
}
override fun withResult(onResult: (Long) -> Unit): IBrowseTimer {
return base.withResult(onResult)
}
override fun start() {
base.start()
}
override fun stop() {
base.stop()
}
override fun onStateChanged(source: LifecycleOwner, event: Event) {
onStateChanged.invoke(this, event)
}
}
fun IBrowseTimer.withLifecycle(
owner: LifecycleOwner,
onStateChanged: (IBrowseTimer, Event) -> Unit = { timer, event ->
when(event) {
Event.ON_START -> timer.start()
Event.ON_STOP -> timer.stop()
else -> {}
}
}
): LifecycleBoundBrowseTimer = LifecycleBoundBrowseTimer(this, onStateChanged).apply {
owner.lifecycle.addObserver(this)
}
/**
* 带数据的浏览计时器接口类
*/
interface IValueBrowseTimer<T> : IBrowseTimerCore {
fun withDelayInMills(delayInMills: Long): IValueBrowseTimer<T>
fun withStart(onStart: (T?) -> Unit): IValueBrowseTimer<T>
fun withResult(onResult: (T?, Long) -> Unit): IValueBrowseTimer<T>
fun dispatchValue(value: T?)
}
/**
* 带数据的浏览计时器实现类
*/
class ValueBrowseTimer<T> : IValueBrowseTimer<T> {
private val core = BrowseTimerCore()
private var isDispatchValue: Boolean = false
private var isStarted: Boolean = false
private var value: T? = null
override fun withDelayInMills(delayInMills: Long): IValueBrowseTimer<T> {
core.delayInMills = delayInMills
return this
}
override fun withStart(onStart: (T?) -> Unit): IValueBrowseTimer<T> {
core.onStart = { onStart.invoke(value) }
return this
}
override fun withResult(onResult: (T?, Long) -> Unit): IValueBrowseTimer<T> {
core.onResult = { onResult.invoke(value, it) }
return this
}
override fun start() {
if (isStarted) return
isStarted = true
if (isDispatchValue) {
core.start()
}
}
override fun stop() {
if (!isStarted) return
core.stop()
isStarted = false
}
override fun dispatchValue(value: T?) {
this.value = value
if (isStarted && !isDispatchValue) {
core.start()
}
isDispatchValue = true
}
}
/**
* 支持LiveData的带数据的浏览计时器
*/
class ObserverBoundValueBrowseTimer<T> internal constructor(private val base: IValueBrowseTimer<T>) : IValueBrowseTimer<T>, Observer<T> {
override fun withDelayInMills(delayInMills: Long): IValueBrowseTimer<T> {
return base.withDelayInMills(delayInMills)
}
override fun withResult(onResult: (T?, Long) -> Unit): IValueBrowseTimer<T> {
return base.withResult(onResult)
}
override fun withStart(onStart: (T?) -> Unit): IValueBrowseTimer<T> {
return base.withStart(onStart)
}
override fun start() {
base.start()
}
override fun stop() {
base.stop()
}
override fun dispatchValue(value: T?) {
base.dispatchValue(value)
}
override fun onChanged(t: T) {
dispatchValue(t)
}
}
/**
* 支持Lifecycle的带数据的浏览计时器
*/
class LifecycleBoundValueBrowseTimer<T> internal constructor(
private val base: IValueBrowseTimer<T>,
private val onStateChanged: (IValueBrowseTimer<T>, Event) -> Unit
) : IValueBrowseTimer<T>, LifecycleEventObserver {
override fun withDelayInMills(delayInMills: Long): IValueBrowseTimer<T> {
return base.withDelayInMills(delayInMills)
}
override fun withResult(onResult: (T?, Long) -> Unit): IValueBrowseTimer<T> {
return base.withResult(onResult)
}
override fun withStart(onStart: (T?) -> Unit): IValueBrowseTimer<T> {
return base.withStart(onStart)
}
override fun start() {
base.start()
}
override fun stop() {
base.stop()
}
override fun dispatchValue(value: T?) {
base.dispatchValue(value)
}
override fun onStateChanged(source: LifecycleOwner, event: Event) {
onStateChanged.invoke(this, event)
}
}
fun <T> IValueBrowseTimer<T>.asObserver(): ObserverBoundValueBrowseTimer<T> = ObserverBoundValueBrowseTimer(this)
fun <T> IValueBrowseTimer<T>.withLifecycle(
owner: LifecycleOwner,
onStateChanged: (IValueBrowseTimer<T>, Event) -> Unit = { timer, event ->
when(event) {
Event.ON_START -> timer.start()
Event.ON_STOP -> timer.stop()
else -> {}
}
}
): LifecycleBoundValueBrowseTimer<T> = LifecycleBoundValueBrowseTimer(this, onStateChanged).apply {
owner.lifecycle.addObserver(this)
}

View File

@ -1,21 +1,22 @@
package com.gh.common.chain
import android.content.Context
import com.gh.common.xapk.XapkInstaller
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.feature.entity.GameEntity
class BrowserInstallHandler : DownloadChainHandler() {
class BrowserInstallHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
BrowserInstallHelper.showBrowserInstallHintDialog(
context,
gameEntity,
asVGame || gameEntity.isSplitXApk()
gameEntity.isVGame() || gameEntity.isSplitXApk()
) {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(asVGame, null)
processEndCallback?.invoke(null)
}
}
}

View File

@ -0,0 +1,18 @@
package com.gh.common.chain
import android.content.Context
import com.gh.common.dialog.CertificationDialog
import com.gh.gamecenter.feature.entity.GameEntity
class CertificationHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
CertificationDialog.showCertificationDialog(context, gameEntity) {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
}
}
}

View File

@ -0,0 +1,28 @@
package com.gh.common.chain
class ChainBuilder {
private val handlers: MutableList<ChainHandler> = ArrayList()
private var processEndCallback: ((Any?) -> Unit)? = null
fun setProcessEndCallback(callback: (Any?) -> Unit): ChainBuilder {
processEndCallback = callback
return this
}
fun addHandler(handler: ChainHandler): ChainBuilder {
handlers.add(handler)
return this
}
fun buildHandlerChain(): ChainHandler? {
for (i in handlers.indices) {
handlers[i].processEndCallback = processEndCallback
if (i + 1 < handlers.size) {
handlers[i].setNext(handlers[i + 1])
}
}
return if (handlers.isEmpty()) null else handlers[0]
}
}

View File

@ -0,0 +1,24 @@
package com.gh.common.chain
import android.content.Context
import com.gh.gamecenter.feature.entity.GameEntity
abstract class ChainHandler {
private var next: ChainHandler? = null
var processEndCallback: ((Any?) -> Unit)? = null
fun setNext(next: ChainHandler?) {
this.next = next
}
fun getNext(): ChainHandler? {
return next
}
fun hasNext(): Boolean {
return next != null
}
abstract fun handleRequest(context: Context, gameEntity: GameEntity)
}

View File

@ -5,15 +5,15 @@ import com.gh.common.util.DialogUtils
import com.gh.gamecenter.common.utils.safelyGetInRelease
import com.gh.gamecenter.feature.entity.GameEntity
class CheckDownloadHandler : DownloadChainHandler() {
class CheckDownloadHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
val apk = gameEntity.getApk().safelyGetInRelease(0) ?: return
DialogUtils.checkDownload(context, apk.size, gameEntity.id, gameEntity.name, gameEntity.categoryChinese) { isSubscribe: Boolean ->
DialogUtils.checkDownload(context, apk.size, gameEntity.id, gameEntity.name) { isSubscribe: Boolean ->
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(asVGame, isSubscribe)
processEndCallback?.invoke(isSubscribe)
}
}

View File

@ -2,23 +2,20 @@ package com.gh.common.chain
import android.content.Context
import com.gh.gamecenter.common.utils.PermissionHelper
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.feature.entity.GameEntity
class CheckStoragePermissionHandler : DownloadChainHandler() {
class CheckStoragePermissionHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
PermissionHelper.checkStoragePermissionBeforeAction(
context,
gameEntity.id,
gameEntity.name ?: "",
gameEntity.categoryChinese,
gameEntity.getApk().firstOrNull()?.format,
) {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
} else {
processEndCallback?.invoke(asVGame, null)
override fun handleRequest(context: Context, gameEntity: GameEntity) {
PermissionHelper.checkStoragePermissionBeforeAction(context, object : EmptyCallback {
override fun onCallback() {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
}
}
})
}
}

View File

@ -1,28 +0,0 @@
package com.gh.common.chain
class DownloadChainBuilder {
private val handlers: MutableList<DownloadChainHandler> = ArrayList()
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
return this
}
fun addHandler(handler: DownloadChainHandler): DownloadChainBuilder {
handlers.add(handler)
return this
}
fun buildHandlerChain(): DownloadChainHandler? {
for (i in handlers.indices) {
handlers[i].processEndCallback = processEndCallback
if (i + 1 < handlers.size) {
handlers[i].setNext(handlers[i + 1])
}
}
return if (handlers.isEmpty()) null else handlers[0]
}
}

View File

@ -1,40 +0,0 @@
package com.gh.common.chain
import android.content.Context
import com.gh.gamecenter.feature.entity.GameEntity
abstract class DownloadChainHandler {
private var next: DownloadChainHandler? = null
// asVGame: 当前下载是否以畅玩游戏来进行
var processEndCallback: ((asVGame: Boolean, Any?) -> Unit)? = null
/**
* 设置下一个处理者
*/
fun setNext(next: DownloadChainHandler?) {
this.next = next
}
/**
* 获取下一个处理者
*/
fun getNext(): DownloadChainHandler? {
return next
}
/**
* 是否存在下一个处理者
*/
fun hasNext(): Boolean {
return next != null
}
/**
* 处理请求
* @param gameEntity 游戏实体
* @param asVGame 是否作为畅玩游戏进行
*/
abstract fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean)
}

View File

@ -3,18 +3,21 @@ package com.gh.common.chain
import android.content.Context
import com.gh.common.util.DownloadDialogHelper
import com.gh.gamecenter.common.utils.safelyGetInRelease
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.feature.entity.GameEntity
class DownloadDialogHelperHandler : DownloadChainHandler() {
class DownloadDialogHelperHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
val apk = gameEntity.getApk().safelyGetInRelease(0) ?: return
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk) {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
} else {
processEndCallback?.invoke(asVGame, null)
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, object : EmptyCallback {
override fun onCallback() {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
}
}
})
}
}

View File

@ -5,14 +5,14 @@ import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
class GamePermissionHandler : DownloadChainHandler() {
class GamePermissionHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(asVGame, null)
processEndCallback?.invoke(null)
}
}
}

View File

@ -1,44 +1,22 @@
package com.gh.common.chain
import android.app.Activity
import android.content.Context
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.PackageChangeHelper
import com.gh.common.util.TempCertificationUtils
import com.gh.gamecenter.feature.entity.GameEntity
class LandPageAddressHandler : DownloadChainHandler() {
class LandPageAddressHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
if (gameEntity.isLandPageAddressDialog()) {
TempCertificationUtils.checkCertificationBeforeAction(gameEntity) {
if (context is Activity && context.isFinishing) {
// 当前 context 已经无效,不需要再传递执行下去了
return@checkCertificationBeforeAction
}
DialogUtils.showLandPageAddressDialog(context, gameEntity) {// 跳转第三方落地页
if (gameEntity.isLandPageAddressDialogShowOnly()) {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
} else {
processEndCallback?.invoke(asVGame, null)
}
} else {
val packageName = gameEntity.getApk().firstOrNull()?.packageName
if (packageName?.isNotEmpty() == true) {
PackageChangeHelper.addInstallPendingPackage(packageName)
}
DirectUtils.directToExternalBrowser(context, gameEntity.landPageAddressDialog!!.link!!)
}
}
DialogUtils.showLandPageAddressDialog(context, gameEntity) {// 跳转第三方落地页
DirectUtils.directToExternalBrowser(context, gameEntity.landPageAddressDialog!!.link!!)
}
} else {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(asVGame, null)
processEndCallback?.invoke(null)
}
}
}

View File

@ -1,34 +1,25 @@
package com.gh.common.chain
import android.app.Activity
import android.content.Context
import com.gh.common.util.DialogUtils
import com.gh.common.util.TempCertificationUtils
import com.gh.gamecenter.feature.entity.GameEntity
class OverseaDownloadHandler : DownloadChainHandler() {
class OverseaDownloadHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
if (gameEntity.isOverseaAddressDialog()) {
TempCertificationUtils.checkCertificationBeforeAction(gameEntity) {
if (context is Activity && context.isFinishing) {
// 当前 context 已经无效,不需要再传递执行下去了
return@checkCertificationBeforeAction
}
DialogUtils.showOverseaDownloadDialog(context, gameEntity) {// 跳转海外下载地址弹窗
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
} else {
processEndCallback?.invoke(asVGame, null)
}
DialogUtils.showOverseaDownloadDialog(context, gameEntity) {// 跳转海外下载地址弹窗
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
}
} else {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(asVGame, null)
processEndCallback?.invoke(null)
}
}
}

View File

@ -5,24 +5,15 @@ import androidx.appcompat.app.AppCompatActivity
import com.gh.common.dialog.PackageCheckDialogFragment
import com.gh.gamecenter.feature.entity.GameEntity
class PackageCheckHandler : DownloadChainHandler() {
class PackageCheckHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
fun nextOrProcessEnd() {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
PackageCheckDialogFragment.show((context as AppCompatActivity), gameEntity) {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(asVGame, null)
processEndCallback?.invoke(null)
}
}
if (gameEntity.canSpeed) {
nextOrProcessEnd()
} else {
PackageCheckDialogFragment.show((context as AppCompatActivity), gameEntity) {
nextOrProcessEnd()
}
}
}
}

View File

@ -4,20 +4,18 @@ import android.content.Context
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.feature.entity.GameEntity
class UnsupportedFeatureHandler : DownloadChainHandler() {
class UnsupportedFeatureHandler : ChainHandler() {
override fun handleRequest(
context: Context,
gameEntity: GameEntity,
asVGame: Boolean
context: Context, gameEntity: GameEntity
) {
if (shouldShowUnsupportedFeatureDialog()) {
DialogHelper.showUnsupportedFeatureDialog(context)
} else {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(asVGame, null)
processEndCallback?.invoke(null)
}
}
}

View File

@ -5,27 +5,31 @@ import com.gh.common.simulator.NewSimulatorGameManager
import com.gh.common.simulator.SimulatorGameManager
import com.gh.gamecenter.feature.entity.GameEntity
class UpdateNewSimulatorHandler: DownloadChainHandler() {
class UpdateNewSimulatorHandler: ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
if (NewSimulatorGameManager.shouldShowUpdateNewSimulatorAlert(context)) {
NewSimulatorGameManager.showUpdateNewsSimulator(context, gameEntity) {
NewSimulatorGameManager.showUpdateNewsSimulator(context) {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(asVGame, null)
processEndCallback?.invoke(null)
}
}
} else {
}
else{
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
}
}
} else {
}
else{
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
}
}
}
}

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

@ -4,23 +4,15 @@ import android.content.Context
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.vspace.VHelper
class ValidateVSpaceHandler : DownloadChainHandler() {
class ValidateVSpaceHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
val closure = {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
VHelper.validateVSpaceBeforeAction(context, gameEntity) {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(asVGame, null)
processEndCallback?.invoke(null)
}
}
if (asVGame) {
VHelper.validateVSpaceBeforeAction(context,gameEntity.getUniquePackageName(), gameEntity) {
closure.invoke()
}
} else {
closure.invoke()
}
}
}

View File

@ -3,59 +3,29 @@ package com.gh.common.chain
import android.content.Context
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.toResString
import com.gh.gamecenter.feature.entity.GameEntity
class VersionNumberHandler : DownloadChainHandler() {
class VersionNumberHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
val confirmCallback = {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(asVGame, null)
processEndCallback?.invoke(null)
}
}
if (!gameEntity.isShowVersionNumber()) {
confirmCallback.invoke()
} else {
SensorsBridge.trackGameDemoDialogShow(
gameId = gameEntity.id,
gameName = gameEntity.name ?: "",
gameType = gameEntity.categoryChinese
)
DialogHelper.showGuideDialog(
context,
"温馨提示",
gameEntity.getVersionNumberString(),
"继续下载",
com.gh.gamecenter.common.R.string.cancel.toResString(),
{
confirmCallback.invoke()
SensorsBridge.trackGameDemoDialogClick(
buttonName = "继续下载",
gameId = gameEntity.id,
gameName = gameEntity.name ?: "",
gameType = gameEntity.categoryChinese
)
},
cancelClickCallback = {
SensorsBridge.trackGameDemoDialogClick(
buttonName = com.gh.gamecenter.common.R.string.cancel.toResString(),
gameId = gameEntity.id,
gameName = gameEntity.name ?: "",
gameType = gameEntity.categoryChinese
)
},
touchOutsideCallback = {
SensorsBridge.trackGameDemoDialogClick(
buttonName = "关闭弹窗",
gameId = gameEntity.id,
gameName = gameEntity.name ?: "",
gameType = gameEntity.categoryChinese
)
},
R.string.cancel.toResString(),
{ confirmCallback.invoke() },
extraConfig = DialogHelper.Config(titleIcon = R.drawable.ic_dialog_tips)
)
}

View File

@ -1,59 +1,49 @@
package com.gh.common.constant;
import android.annotation.SuppressLint;
import android.content.IntentFilter;
import android.content.SharedPreferences;
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.AdHelper;
import com.gh.common.util.PackageHelper;
import com.gh.common.util.PackageUtils;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.constant.CommonConsts;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
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;
import com.gh.gamecenter.entity.AppEntity;
import com.gh.gamecenter.entity.FloatWindowSettingEntity;
import com.gh.gamecenter.entity.GameGuidePopupEntity;
import com.gh.gamecenter.entity.NewApiSettingsEntity;
import com.gh.gamecenter.entity.NewSettingsEntity;
import com.gh.gamecenter.entity.VNewSetting;
import com.gh.gamecenter.entity.VSetting;
import com.gh.gamecenter.feature.entity.NewsEntity;
import com.gh.gamecenter.feature.entity.SettingsEntity;
import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.feature.utils.ContentBlockedHelper;
import com.gh.gamecenter.receiver.PackageChangeBroadcastReceiver;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.retrofit.service.VApiService;
import com.gh.vspace.VHelper;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.functions.Function;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
import okhttp3.ResponseBody;
public class Config {
@ -63,11 +53,6 @@ public class Config {
public static final String NEW_API_HOST = EnvHelper.getNewHost();
public static final String VAPI_HOST = EnvHelper.getVHost();
public static final String WGAME_CPM_BUSIAPPID = BuildConfig.WGAME_CPM_BUSIAPPID;
public static final String WGAME_CPM_API_HOST = EnvHelper.getWGameCPMHost();
public static final String DSP_API_HOST = EnvHelper.getDspHost();
// Third-Party confs
public static final String WECHAT_APPID = BuildConfig.WECHAT_APPID;
public static final String WECHAT_SECRET = BuildConfig.WECHAT_SECRET;
@ -75,7 +60,8 @@ public class Config {
public static final String WEIBO_APPKEY = BuildConfig.WEIBO_APPKEY;
public static final String QUICK_LOGIN_APPID = BuildConfig.QUICK_LOGIN_APPID;
public static final String QUICK_LOGIN_APPKEY = BuildConfig.QUICK_LOGIN_APPKEY;
public static final String URL_ARTICLE = "www.ghzs666.com/article/"; // ghzs/ghzs666 统一
// http://www.ghzs666.com/article/${articleId}.html
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // ghzs/ghzs666 统一
private static final String SETTINGS_KEY = "settingsKey";
@ -86,26 +72,139 @@ public class Config {
private static NewApiSettingsEntity.NightMode mNightModeSetting;
private static SimulatorEntity mNewSimulatorEntity;
private static VSetting mVSetting;
private volatile static VNewSetting mVNewSetting;
private static FloatWindowSettingEntity mFloatWindowSetting;
private static AppEntity mNew32UpdateEntity;
private static BehaviorSubject<VNewSetting> vNewSettingSubject = BehaviorSubject.create();
private static GameGuidePopupEntity mGameGuidePopupEntity;
private static SharedPreferences mDefaultSharedPreferences;
public static final String FIX_DOWNLOAD_KEY = "isFixDownload";
public static final String FIX_PLUGIN_KEY = "isFixPlugin";
public static final int VIDEO_PAGE_SIZE = 21; // 视频列表大多都是一行3个
public static boolean isShow() {
return !SPUtils.getBoolean(Constants.SP_TEENAGER_MODE);
if (SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) return false;
if (getPreferences().getBoolean(FIX_DOWNLOAD_KEY, false)) return true;
if (!isExistDownloadFilter()) return false;
for (SettingsEntity.Download entity : getSettings().getDownload()) {
if ("all".equals(entity.getGame())) {
if (entity.getPluginfy() && "normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
return true;
}
}
}
return false;
}
public static boolean isShowDownload(String gameId) {
if (getPreferences().getBoolean(FIX_DOWNLOAD_KEY, false)) return true;
if (TextUtils.isEmpty(gameId) || !isExistDownloadFilter())
return false;
for (SettingsEntity.Download entity : getSettings().getDownload()) {
if (gameId.equals(entity.getGame())) {
if ("normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
return true;
} else {
return false;
}
} else if ("all".equals(entity.getGame())) {
if ("normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
return true;
}
}
}
return false;
}
/**
* VPN 开关选项是否开启
*/
public static boolean isVpnOptionEnabled() {
if (mNewApiSettingsEntity == null
|| mNewApiSettingsEntity.getInstall() == null
|| mNewApiSettingsEntity.getInstall().getVpnRequired() == null) {
return false;
}
return mNewApiSettingsEntity.getInstall().getVpnRequired().getShouldShowVpnOption();
}
public static boolean isShowPlugin(String gameId) {
SharedPreferences preferences = getPreferences();
boolean isFixPlugin = preferences.getBoolean(FIX_PLUGIN_KEY, false);
if (isFixPlugin) return true;
if (TextUtils.isEmpty(gameId) || !isExistDownloadFilter())
return false;
for (SettingsEntity.Download entity : getSettings().getDownload()) {
if (gameId.equals(entity.getGame())) {
if (entity.getPluginfy() && filterTime(entity.getTime())) {
return true;
} else {
return false;
}
}
if ("all".equals(entity.getGame())) {
if (entity.getPluginfy() && filterTime(entity.getTime())) {
preferences.edit().putBoolean(FIX_PLUGIN_KEY, true).apply();
return true;
}
}
}
return false;
}
public static boolean isShowPlugin() {
SharedPreferences preferences = getPreferences();
boolean isFixPlugin = preferences.getBoolean(FIX_PLUGIN_KEY, false);
if (isFixPlugin) return true;
if (!isExistDownloadFilter())
return false;
for (SettingsEntity.Download entity : getSettings().getDownload()) {
if ("all".equals(entity.getGame())) {
if (entity.getPluginfy() && filterTime(entity.getTime())) {
preferences.edit().putBoolean(FIX_PLUGIN_KEY, true).apply();
return true;
}
}
}
return false;
}
private static boolean filterTime(SettingsEntity.Download.TimeEntity timeEntity) {
long end = timeEntity.getEnd();
long start = timeEntity.getStart();
long curTime = Utils.getTime(HaloApp.getInstance().getApplication());
if ((start == 0 || curTime >= start) && (end == 0 || curTime <= end)) {
return true;
}
return false;
}
public static void setSettings(SettingsEntity settingsEntity) {
getPreferences().edit().putString(SETTINGS_KEY, GsonUtils.toJson(settingsEntity)).apply();
mSettingsEntity = settingsEntity;
PackageHelper.refreshPackageNameList();
// 更新设置状态
mSettingsEntity.showArticleEntrance();
mSettingsEntity.showCommunityEntrance();
// 加载完设置后刷新下
PackageHelper.initList();
}
@Nullable
@ -116,6 +215,8 @@ public class Config {
if (!TextUtils.isEmpty(json)) {
mSettingsEntity = GsonUtils.fromJson(json, SettingsEntity.class);
}
mSettingsEntity.setGameSmooth("off");
} catch (Exception e) {
e.printStackTrace();
}
@ -204,52 +305,6 @@ public class Config {
return mVSetting;
}
@Nullable
public static VNewSetting getVNewSettingEntity() {
if (mVNewSetting == null) {
try {
String json = SPUtils.getString(Constants.SP_V_NEW_SETTINGS);
if (!TextUtils.isEmpty(json)) {
mVNewSetting = GsonUtils.fromJson(json, VNewSetting.class);
vNewSettingSubject.onNext(mVNewSetting);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return mVNewSetting;
}
@Nullable
public static FloatWindowSettingEntity getFloatWindowSettingEntity() {
if (mFloatWindowSetting == null) {
try {
String json = SPUtils.getString(Constants.SP_FLOAT_WINDOW_SETTINGS);
if (!TextUtils.isEmpty(json)) {
mFloatWindowSetting = GsonUtils.fromJson(json, FloatWindowSettingEntity.class);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return mFloatWindowSetting;
}
@NonNull
public static Observable<VNewSetting> getVNewSettingObservable() {
if (mVNewSetting != null) {
return Observable.just(mVNewSetting);
} else {
return vNewSettingSubject.hide();
}
}
@Nullable
public static AppEntity getNew32UpdateEntity() {
return mNew32UpdateEntity;
}
/**
* 请求网络数据,尝试刷新畅玩相关配置
*/
@ -258,41 +313,14 @@ 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) {
mVSetting = data;
SPUtils.setString(Constants.SP_V_SETTINGS, GsonUtils.toJson(data));
VHelper.checkVspaceUpdate(HaloApp.getInstance());
}
});
}
@SuppressLint("CheckResult")
public static void getNewSetting() {
VApiService vApi = RetrofitManager.getInstance().getVApi();
vApi.getNewSettings(BuildConfig.VERSION_NAME, Build.VERSION.SDK_INT).flatMap(new Function<VNewSetting, SingleSource<AppEntity>>() {
@Override
public SingleSource<AppEntity> apply(VNewSetting data) throws Exception {
mVNewSetting = data;
vNewSettingSubject.onNext(mVNewSetting);
SPUtils.setString(Constants.SP_V_NEW_SETTINGS, GsonUtils.toJson(data));
if (data.getVa() != null && data.getVa().getArch32() != null) {
String versionNameByPackageName = PackageUtils.getVersionNameByPackageName(data.getVa().getArch32().getPackageName());
return vApi.getNewPackageUpdate(
BuildConfig.VERSION_NAME,
versionNameByPackageName != null ? versionNameByPackageName : "",
HaloApp.getInstance().getChannel()
);
}
return Single.error(new IllegalStateException("VNewSetting entity is not expected"));
}
})
.subscribeOn(Schedulers.io())
.subscribe(new BiResponse<AppEntity>() {
@Override
public void onSuccess(AppEntity data) {
mNew32UpdateEntity = data;
VHelper.init(HaloApp.getInstance());
}
});
}
@ -302,6 +330,27 @@ public class Config {
return mGameGuidePopupEntity;
}
private static boolean isExistDownloadFilter() {
if (getSettings() == null || getSettings().getDownload() == null || getSettings().getDownload().size() == 0) {
return false;
} else {
return true;
}
}
public static void filterPluginArticle(List<NewsEntity> list) {
if (isShowPlugin() || list == null) return;
for (int i = 0; i < list.size(); i++) {
NewsEntity newsEntity = list.get(i);
String title = newsEntity.getTitle();
if (!TextUtils.isEmpty(title) && title.contains("插件")) {
list.remove(i);
i--;
}
}
}
public static SharedPreferences getPreferences() {
if (mDefaultSharedPreferences == null) {
mDefaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication());
@ -320,6 +369,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) {
@ -331,8 +381,11 @@ public class Config {
GsonUtils.toJson(response.getSuggestion()));
edit.apply();
if (!getPreferences().getBoolean(Config.FIX_DOWNLOAD_KEY, false) && Config.isShow()) {
getPreferences().edit().putBoolean(Config.FIX_DOWNLOAD_KEY, true).apply();
}
if (!SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) {
AppExecutor.getUiExecutor().execute(() -> EventBus.getDefault().post(new EBReuse("Refresh")));
EventBus.getDefault().post(new EBReuse("Refresh"));
}
}
});
@ -340,6 +393,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) {
@ -349,12 +403,11 @@ public class Config {
});
refreshVSettingEntity();
getNewSetting();
getFloatWindowSetting();
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) {
@ -366,6 +419,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) {
@ -389,13 +443,12 @@ public class Config {
String filterString = UrlFilterUtils.getFilterQuery(
"manufacturer", Build.MANUFACTURER,
"model", Build.MODEL,
"android_sdk_version", String.valueOf(Build.VERSION.SDK_INT),
"rom", MetaUtil.INSTANCE.getRom().name() + " " + MetaUtil.INSTANCE.getRom().getVersionName()
);
"android_sdk_version", String.valueOf(Build.VERSION.SDK_INT));
RetrofitManager.getInstance()
.getNewApi().getNewSettings(PackageUtils.getGhVersionName(), channel, filterString)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<NewApiSettingsEntity>() {
@Override
public void onSuccess(NewApiSettingsEntity data) {
@ -404,53 +457,11 @@ 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));
// 刷新屏蔽字段
if (mNewApiSettingsEntity.getGameShieldContents() != null) {
ContentBlockedHelper.INSTANCE.init(mNewApiSettingsEntity.getGameShieldContents());
}
// 更新安装列表是否开启的配置
if (mNewApiSettingsEntity.getInstalledComplianceSwitch() != null) {
PackageHelper.INSTANCE.updateIsGetInstalledPackagesApiAgreedRequired(mNewApiSettingsEntity.getInstalledComplianceSwitch());
} else {
PackageHelper.INSTANCE.updateIsGetInstalledPackagesApiAgreedRequired(false);
}
// 更新包名监听是否开启
if (mNewApiSettingsEntity.isPackageObserveEnable()) {
AppExecutor.getUiExecutor().execute(() -> observePackageChange(mNewApiSettingsEntity.getPackageObserveActions()));
}
}
});
}
}
@SuppressLint("CheckResult")
private static void getFloatWindowSetting() {
RetrofitManager.getInstance().getNewApi()
.getFloatWindowSettings()
.subscribeOn(Schedulers.io())
.subscribe(new BiResponse<FloatWindowSettingEntity>() {
@Override
public void onSuccess(FloatWindowSettingEntity data) {
mFloatWindowSetting = data;
SPUtils.setString(Constants.SP_FLOAT_WINDOW_SETTINGS, GsonUtils.toJson(data));
}
});
}
public static void observePackageChange(NewApiSettingsEntity.PackageObserveActions packageObserveActions) {
PackageChangeBroadcastReceiver receiver = new PackageChangeBroadcastReceiver(packageObserveActions);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(packageObserveActions.getAdd());
intentFilter.addAction(packageObserveActions.getRem());
intentFilter.addAction(packageObserveActions.getRep());
intentFilter.addDataScheme("package");
HaloApp.getInstance().registerReceiver(receiver, intentFilter);
}
}

View File

@ -13,14 +13,14 @@ import android.widget.PopupWindow
import androidx.core.content.ContextCompat
import androidx.databinding.BindingAdapter
import androidx.recyclerview.widget.LinearLayoutManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.callback.OnViewClickListener
import com.gh.gamecenter.common.databinding.LayoutPopupContainerBinding
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toDrawable
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.KaifuAddItemBinding
import com.gh.gamecenter.databinding.LayoutAddKaifuPopupBinding
import com.gh.gamecenter.databinding.LayoutPopupContainerBinding
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
import com.gh.gamecenter.servers.add.AddKaiFuPopupAdapter
import java.text.SimpleDateFormat
@ -120,14 +120,14 @@ object AddKaiFuBindingAdapter {
@BindingAdapter("kaiFuTextColor", "kaiFuTextPosition")
fun kaiFuTextColor(view: EditText, dataMark: Int, position: Int) {
if (dataMark == 1 && view.id == R.id.kaifu_add_time || dataMark == 2 && view.id == R.id.kaifu_add_first_name || dataMark == 3 && view.id == R.id.kaifu_add_server_name || dataMark == 4) {
view.setTextColor(ContextCompat.getColor(view.context, com.gh.gamecenter.common.R.color.secondary_red))
view.setHintTextColor(ContextCompat.getColor(view.context, com.gh.gamecenter.common.R.color.secondary_red))
view.setTextColor(ContextCompat.getColor(view.context, R.color.theme_red))
view.setHintTextColor(ContextCompat.getColor(view.context, R.color.theme_red))
} else if (position == 0) {
view.setTextColor(ContextCompat.getColor(view.context, com.gh.gamecenter.common.R.color.hint))
view.setHintTextColor(ContextCompat.getColor(view.context, com.gh.gamecenter.common.R.color.hint))
view.setTextColor(ContextCompat.getColor(view.context, R.color.hint))
view.setHintTextColor(ContextCompat.getColor(view.context, R.color.hint))
} else {
view.setTextColor(ContextCompat.getColor(view.context, com.gh.gamecenter.common.R.color.text_primary))
view.setHintTextColor(ContextCompat.getColor(view.context, com.gh.gamecenter.common.R.color.hint))
view.setTextColor(ContextCompat.getColor(view.context, R.color.text_title))
view.setHintTextColor(ContextCompat.getColor(view.context, R.color.hint))
}
}
@ -176,7 +176,7 @@ object AddKaiFuBindingAdapter {
popupWindow.isTouchable = true
popupWindow.inputMethodMode = PopupWindow.INPUT_METHOD_NEEDED
popupWindow.isOutsideTouchable = true
popupWindow.animationStyle = com.gh.gamecenter.common.R.style.popwindow_option_anim_style
popupWindow.animationStyle = R.style.popwindow_option_anim_style
// 设置偏移
windowPos[1] = windowPos[1] - 12F.dip2px()

View File

@ -1,32 +1,31 @@
package com.gh.common.databind;
import static com.gh.gamecenter.entity.SubjectEntity.SUBJECT_TAG_SELLING_POINT;
import static com.gh.gamecenter.entity.SubjectEntity.SUBJECT_TAG_TEST;
import static com.gh.gamecenter.entity.SubjectEntity.SUBJECT_TAG_TYPE;
import static com.gh.gamecenter.entity.SubjectEntity.SUBJECT_TAG_UPDATE;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.content.ContextCompat;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.common.chain.BrowserInstallHandler;
import com.gh.common.chain.CertificationHandler;
import com.gh.common.chain.ChainBuilder;
import com.gh.common.chain.ChainHandler;
import com.gh.common.chain.CheckDownloadHandler;
import com.gh.common.chain.CheckStoragePermissionHandler;
import com.gh.common.chain.DownloadChainBuilder;
import com.gh.common.chain.DownloadChainHandler;
import com.gh.common.chain.DownloadDialogHelperHandler;
import com.gh.common.chain.GamePermissionHandler;
import com.gh.common.chain.LandPageAddressHandler;
@ -35,6 +34,7 @@ import com.gh.common.chain.PackageCheckHandler;
import com.gh.common.chain.UnsupportedFeatureHandler;
import com.gh.common.chain.ValidateVSpaceHandler;
import com.gh.common.chain.VersionNumberHandler;
import com.gh.common.constant.Config;
import com.gh.common.filter.RegionSetting;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.history.HistoryHelper;
@ -46,6 +46,7 @@ import com.gh.common.util.DialogUtils;
import com.gh.common.util.GameUtils;
import com.gh.common.util.GameViewUtils;
import com.gh.common.util.LogUtils;
import com.gh.common.util.NewsUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageLauncher;
import com.gh.common.util.PackageUtils;
@ -56,19 +57,24 @@ import com.gh.download.server.BrowserInstallHelper;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.common.databinding.LayoutGameItemSellingPointBinding;
import com.gh.gamecenter.common.baselist.LoadStatus;
import com.gh.gamecenter.common.callback.OnViewClickListener;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.common.utils.DarkModeUtils;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.FileUtils;
import com.gh.gamecenter.common.utils.NewFlatLogUtils;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.common.utils.ImageUtils;
import com.gh.gamecenter.common.view.DrawableView;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.core.utils.TimeUtils;
import com.gh.gamecenter.core.utils.NumberUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.databinding.KaifuDetailItemRowBinding;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.CommunityVideoEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.PluginLocation;
import com.gh.gamecenter.feature.entity.ServerCalendarEntity;
import com.gh.gamecenter.feature.entity.TagStyleEntity;
import com.gh.gamecenter.feature.entity.TestEntity;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
@ -77,21 +83,149 @@ import com.gh.gamecenter.feature.view.DownloadButton;
import com.gh.gamecenter.feature.view.GameIconView;
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.vspace.VDownloadManagerActivity;
import com.gh.vspace.VHelper;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import kotlin.collections.CollectionsKt;
/**
* Created by khy on 12/02/18.
*/
public class BindingAdapters {
public static void loadIcon(SimpleDraweeView view, String imageUrl) {
ImageUtils.displayIcon(view, imageUrl);
}
public static void loadImage(SimpleDraweeView view, String imageUrl) {
ImageUtils.display(view, imageUrl);
}
public static void setTextSize(TextView view, int number) {
view.setTextSize(number);
}
public static void setTypeface(TextView view, String type) {
if (type == null) return;
switch (type) {
case "bold":
view.setTypeface(null, Typeface.BOLD);
break;
case "italic":
view.setTypeface(null, Typeface.ITALIC);
break;
case "bold_italic":
view.setTypeface(null, Typeface.BOLD_ITALIC);
break;
default:
view.setTypeface(null, Typeface.NORMAL);
break;
}
}
public static void addDetailKaiFuView(LinearLayout view, List<ServerCalendarEntity> list
, OnViewClickListener listener, Boolean isReadyPatch) {
if (list == null) return;
view.removeAllViews();
for (int i = 0; i < list.size() + 1; i++) { // 1 is Title
View inflate = LayoutInflater.from(view.getContext()).inflate(R.layout.kaifu_detail_item_row, null);
KaifuDetailItemRowBinding binding = KaifuDetailItemRowBinding.bind(inflate);
binding.getRoot().setBackgroundColor(isReadyPatch != null && isReadyPatch ? ExtensionsKt.toColor(R.color.theme) : ExtensionsKt.toColor(R.color.white));
binding.getRoot().setPadding(DisplayUtils.dip2px(1), DisplayUtils.dip2px(1), DisplayUtils.dip2px(1), i == list.size() ? DisplayUtils.dip2px(1) : 0);
ServerCalendarEntity serverEntity = list.get(i - 1);
binding.timeTv.setText(i == 0 ? "时间" : serverEntity.getFormatTime("HH:mm"));
binding.remarkTv.setText(i == 0 ? "备注" : serverEntity.getRemark());
binding.nameTv.setText(i == 0 ? "名字" : (TextUtils.isEmpty(serverEntity.getNote()) ? "-" : serverEntity.getNote()));
if (i != 0) {
binding.getRoot().setOnClickListener(v -> {
listener.onClick(v, isReadyPatch != null && isReadyPatch ? serverEntity : null);
});
// 滑动冲突处理
binding.getRoot().setOnTouchListener((v, event) -> {
if (list.size() > 5) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
EventBus.getDefault().post(new EBReuse("CalenderDown"));
} else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
EventBus.getDefault().post(new EBReuse("CalenderCancel"));
}
}
return false;
});
}
view.addView(inflate);
}
}
// 如果超过10000则转换为1.0W
public static void transSimpleCount(TextView view, int count) {
view.setText(NumberUtils.transSimpleCount(count));
}
public static void textColorFromString(TextView tv, String hexString) {
if (TextUtils.isEmpty(hexString)) return;
try {
tv.setTextColor(Color.parseColor(hexString));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void showHide(View view, Boolean show) {
if (show != null && show) {
view.setVisibility(View.VISIBLE);
} else {
view.setVisibility(View.GONE);
}
}
public static void goneIf(View view, Boolean gone) {
if (gone != null && gone) {
view.setVisibility(View.GONE);
} else {
view.setVisibility(View.VISIBLE);
}
}
/**
* lazy 的 paddingTop
*/
public static void lazyPaddingLeft(View view, int paddingLeftInDp) {
view.setPadding(DisplayUtils.dip2px(paddingLeftInDp), view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
}
/**
* lazy 的 paddingTop
*/
public static void lazyPaddingTop(View view, int paddingTopInDp) {
view.setPadding(view.getPaddingLeft(), DisplayUtils.dip2px(paddingTopInDp), view.getPaddingRight(), view.getPaddingBottom());
}
/**
* lazy 的 paddingBottom
*/
public static void lazyPaddingBottom(View view, int paddingBottomInDp) {
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), DisplayUtils.dip2px(paddingBottomInDp));
}
public static void visibleInvisible(View view, Boolean show) {
if (show != null && show) {
view.setVisibility(View.VISIBLE);
} else {
view.setVisibility(View.INVISIBLE);
}
}
public static void setMessageUnread(TextView view, int unreadCount) {
if (unreadCount < 100) {
view.setText(String.valueOf(unreadCount));
@ -100,19 +234,117 @@ public class BindingAdapters {
}
}
public static void setServerTypePadding(TextView view, String serverType) {
int paddRight = 0;
if (TextUtils.isEmpty(serverType)) {
} else {
if ("删档内测".equals(serverType) || "不删档内测".equals(serverType)) {
if ("删档内测".equals(serverType)) {
paddRight = DisplayUtils.dip2px(view.getContext(), 50);
} else {
paddRight = DisplayUtils.dip2px(view.getContext(), 60);
}
} else {
paddRight = DisplayUtils.dip2px(view.getContext(), 30);
}
}
view.setPadding(0, 0, paddRight, 0);
}
public static void setServerType(TextView view, String serverType) {
view.setText(serverType);
if ("删档内测".equals(serverType) || "不删档内测".equals(serverType)) {
view.setBackgroundResource(R.drawable.textview_server_tag);
} else {
view.setBackgroundResource(R.drawable.textview_orange_up);
}
}
public static void setGame(View view, GameEntity gameEntity) {
if (gameEntity != null && view instanceof GameIconView) {
((GameIconView) view).displayGameIcon(gameEntity);
}
}
public static void setDownloadButton(DownloadButton progressBar,
GameEntity gameEntity,
ExposureEvent traceEvent,
@Nullable View.OnClickListener clickCallBack,
@Nullable String entrance,
@Nullable String location) {
setDownloadButton(progressBar, gameEntity, traceEvent, clickCallBack, entrance, location, "其他");
public static void setGameIcon(View view, GameEntity gameEntity) {
if (gameEntity != null && view instanceof GameIconView) {
((GameIconView) view).displayGameIcon(gameEntity.getIcon(), gameEntity.getIconSubscript(), gameEntity.getIconFloat());
}
}
public static void setArticleType(TextView view, String articleType) {
NewsUtils.setNewsType(view, articleType, 0, 0);
}
public static void setDetailDownloadText(TextView view, GameEntity gameEntity) {
if (gameEntity == null || gameEntity.getApk().isEmpty()) {
view.setBackgroundResource(R.drawable.game_item_btn_pause_style);
view.setTextColor(0xFF999999);
view.setClickable(false);
}
}
public static void setLiBaoBtn(TextView view, String status) {
if (TextUtils.isEmpty(status)) return;
switch (status) {
case "coming":
view.setText(R.string.libao_coming);
view.setBackgroundResource(R.drawable.textview_blue_style);
break;
case "ling":
view.setText(R.string.libao_ling);
view.setBackgroundResource(R.drawable.textview_green_style);
break;
case "tao":
view.setText(R.string.libao_tao);
view.setBackgroundResource(R.drawable.textview_orange_style);
break;
case "used_up":
view.setText(R.string.libao_used_up);
view.setBackgroundResource(R.drawable.textview_cancel_up);
break;
case "finish":
view.setText(R.string.libao_finish);
view.setBackgroundResource(R.drawable.textview_cancel_up);
break;
case "linged":
view.setText(R.string.libao_linged);
view.setBackgroundResource(R.drawable.libao_linged_style);
view.setTextColor(ContextCompat.getColorStateList(view.getContext(), R.color.libao_linged_selector));
break;
case "taoed":
view.setText(R.string.libao_taoed);
view.setBackgroundResource(R.drawable.libao_taoed_style);
view.setTextColor(ContextCompat.getColorStateList(view.getContext(), R.color.libao_taoed_selector));
break;
case "copy":
view.setText(R.string.libao_copy);
view.setBackgroundResource(R.drawable.textview_blue_style);
break;
case "repeatLing":
view.setText(R.string.libao_repeat_ling);
view.setBackgroundResource(R.drawable.textview_cancel_up);
break;
case "repeatLinged":
view.setText(R.string.libao_repeat_ling);
view.setBackgroundResource(R.drawable.textview_green_style);
break;
case "repeatTao":
view.setText(R.string.libao_repeat_tao);
view.setBackgroundResource(R.drawable.textview_cancel_up);
break;
case "repeatTaoed":
view.setText(R.string.libao_repeat_tao);
view.setBackgroundResource(R.drawable.textview_orange_style);
break;
case "unshelve":
view.setBackgroundResource(R.drawable.textview_cancel_style);
view.setText(R.string.libao_unshelve);
break;
default:
view.setBackgroundResource(R.drawable.textview_cancel_style);
view.setText("异常");
}
}
// 大图下的进度条
@ -121,14 +353,14 @@ public class BindingAdapters {
ExposureEvent traceEvent,
@Nullable View.OnClickListener clickCallBack,
@Nullable String entrance,
@Nullable String location,
String sourceEntrance) {
@Nullable String location) {
// 恢复DialogFragment
restoreDialogFragment(progressBar);
// 判断是否显示按钮
if (gameEntity != null
&& Config.isShowDownload(gameEntity.getId())
&& !"光环助手".equals(gameEntity.getName())) {
progressBar.setVisibility(View.VISIBLE);
} else {
@ -142,9 +374,13 @@ public class BindingAdapters {
switch (progressBar.getButtonStyle()) {
case DOWNLOADING_PLUGIN:
case DOWNLOADING_NORMAL:
Intent intent = DownloadManagerActivity.getDownloadMangerIntent(v.getContext(),
gameEntity.getApk().isEmpty() ? "" : gameEntity.getApk().get(0).getUrl(), entrance);
v.getContext().startActivity(intent);
if (gameEntity.isVGame()) {
v.getContext().startActivity(VDownloadManagerActivity.getIntent(v.getContext(), true));
} else {
Intent intent = DownloadManagerActivity.getDownloadMangerIntent(v.getContext(),
gameEntity.getApk().get(0).getUrl(), entrance);
v.getContext().startActivity(intent);
}
break;
case NONE:
Utils.toast(v.getContext(), "该游戏已关闭下载");
@ -162,12 +398,12 @@ public class BindingAdapters {
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(v.getContext(), gameEntity.getSimulator().getApk().getPackageName());
if (downloadEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity) && !isInstalled) {
SimulatorDownloadManager.getInstance().showDownloadDialog(v.getContext(), gameEntity.getSimulator(),
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(), gameEntity.getCategoryChinese(), null);
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(), null);
return;
}
}
DownloadChainBuilder builder = new DownloadChainBuilder();
ChainBuilder builder = new ChainBuilder();
builder.addHandler(new UnsupportedFeatureHandler());
builder.addHandler(new GamePermissionHandler());
builder.addHandler(new CheckStoragePermissionHandler());
@ -175,53 +411,39 @@ public class BindingAdapters {
builder.addHandler(new BrowserInstallHandler());
builder.addHandler(new PackageCheckHandler());
builder.addHandler(new DownloadDialogHelperHandler());
builder.addHandler(new CertificationHandler());
builder.addHandler(new VersionNumberHandler());
builder.addHandler(new LandPageAddressHandler());
builder.addHandler(new OverseaDownloadHandler());
builder.addHandler(new CheckDownloadHandler());
builder.setProcessEndCallback(gameEntity.getId(), (asVGame, isSubscribe) -> {
download(v.getContext(),
progressBar,
gameEntity,
traceEvent,
asVGame,
(boolean) isSubscribe,
entrance,
location);
builder.setProcessEndCallback(o -> {
download(v.getContext(), progressBar, gameEntity, traceEvent, (boolean) o, entrance, location);
return null;
});
final DownloadChainHandler chainHandler = builder.buildHandlerChain();
final ChainHandler chainHandler = builder.buildHandlerChain();
if (chainHandler != null) {
chainHandler.handleRequest(
v.getContext(),
gameEntity,
GameUtils.shouldPerformAsVGame(gameEntity)
);
chainHandler.handleRequest(v.getContext(), gameEntity);
}
} else {
DownloadChainBuilder builder = new DownloadChainBuilder();
ChainBuilder builder = new ChainBuilder();
builder.addHandler(new UnsupportedFeatureHandler());
builder.addHandler(new GamePermissionHandler());
builder.addHandler(new CertificationHandler());
builder.addHandler(new VersionNumberHandler());
builder.setProcessEndCallback(gameEntity.getId(), (asVGame, isSubscribe) -> {
builder.setProcessEndCallback(o -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location + ":" + gameEntity.getName(),
null);
location + ":" + gameEntity.getName());
return null;
});
final DownloadChainHandler chainHandler = builder.buildHandlerChain();
final ChainHandler chainHandler = builder.buildHandlerChain();
if (chainHandler != null) {
chainHandler.handleRequest(
v.getContext(),
gameEntity,
GameUtils.shouldPerformAsVGame(gameEntity)
);
chainHandler.handleRequest(v.getContext(), gameEntity);
}
}
}
@ -230,18 +452,11 @@ public class BindingAdapters {
if (gameEntity.getApk().size() == 1) {
//启动模拟器游戏
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().isEmpty() ? "" : gameEntity.getApk().get(0).getUrl());
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
if (downloadEntity != null) {
File file = new File(downloadEntity.getPath());
if (!file.exists()) {
download(v.getContext(),
progressBar,
gameEntity,
traceEvent,
false,
false,
entrance,
location);
download(v.getContext(), progressBar, gameEntity, traceEvent, false, entrance, location);
return;
}
@ -250,50 +465,40 @@ public class BindingAdapters {
return;
}
PackageLauncher.launch(v.getContext(), gameEntity, null);
if (gameEntity.isVGame()) {
VHelper.installOrLaunch((AppCompatActivity) v.getContext(), gameEntity, null);
return;
}
PackageLauncher.launchApp(v.getContext(), gameEntity, gameEntity.getApk().get(0).getPackageName());
} else {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location + ":" + gameEntity.getName(),
null);
location + ":" + gameEntity.getName());
}
break;
case INSTALL_PLUGIN:
case INSTALL_NORMAL:
if (gameEntity.getApk().size() == 1) {
NewFlatLogUtils.INSTANCE.logGameInstall(
gameEntity.getId(),
gameEntity.getName() != null ? gameEntity.getName() : "",
"主动安装"
);
SensorsBridge.trackInstallGameClick(
gameEntity.getId(),
gameEntity.getName() != null ? gameEntity.getName() : "",
"主动安装",
gameEntity.isDspGame(),
gameEntity.getDspAdId()
);
DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity);
if (gameEntity.isVGame()) {
VHelper.installOrLaunch(v.getContext(), gameEntity, null);
return;
}
if (downloadEntity != null) {
if (ExtensionsKt.isLocalDownloadInDualDownloadMode(downloadEntity)) {
PackageInstaller.install(v.getContext(), downloadEntity);
} else {
VHelper.installOrLaunch(v.getContext(), gameEntity, null);
}
PackageInstaller.install(v.getContext(), downloadEntity);
}
}
break;
case RESERVABLE:
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
ReservationHelper.reserve(v.getContext(), gameEntity, sourceEntrance, () -> {
ReservationHelper.reserve(v.getContext(), gameEntity.getId(), gameEntity.getName(), () -> {
LogUtils.logReservation(gameEntity, traceEvent);
updateReservation(progressBar, gameEntity);
});
@ -301,11 +506,19 @@ public class BindingAdapters {
});
break;
case RESERVED:
ReservationHelper.showCancelReservationDialog(progressBar.getContext(), gameEntity, () -> {
ReservationHelper.cancelReservation(gameEntity, () -> {
updateReservation(progressBar, gameEntity);
if ("download".equals(gameEntity.getReserveStatus())) {
ReservationHelper.showDeleteReservationDialog(progressBar.getContext(), () -> {
ReservationHelper.deleteReservation(gameEntity, () -> {
updateReservation(progressBar, gameEntity);
});
});
});
} else {
ReservationHelper.showCancelReservationDialog(progressBar.getContext(), () -> {
ReservationHelper.cancelReservation(gameEntity, () -> {
updateReservation(progressBar, gameEntity);
});
});
}
break;
case H5_GAME:
LinkEntity linkEntity = gameEntity.getH5Link();
@ -351,9 +564,9 @@ public class BindingAdapters {
}
progressBar.setButtonStyle(DownloadButton.ButtonStyle.H5_GAME);
} else {
if (("dialog".equals(offStatus) || "third_party".equals(offStatus))) {
if (offStatus != null && "dialog".equals(offStatus)) {
progressBar.setText("查看");
progressBar.setButtonStyle(DownloadButton.ButtonStyle.NONE_WITH_HINT);
progressBar.setButtonStyle(DownloadButton.ButtonStyle.NONE);
} else if ("updating".equals(offStatus)) {
progressBar.setText("更新中");
progressBar.setButtonStyle(DownloadButton.ButtonStyle.UPDATING);
@ -364,7 +577,7 @@ public class BindingAdapters {
}
} else {
String status = GameUtils.getDownloadBtnText(progressBar.getContext(), gameEntity, true, false, PluginLocation.only_game);
String status = GameUtils.getDownloadBtnText(progressBar.getContext(), gameEntity, PluginLocation.only_game);
switch (status) {
case "插件化":
progressBar.setButtonStyle(DownloadButton.ButtonStyle.PLUGIN);
@ -393,7 +606,7 @@ public class BindingAdapters {
case diskisfull:
case diskioerror:
case waiting:
progressBar.setText(com.gh.gamecenter.feature.R.string.downloading);
progressBar.setText(R.string.downloading);
if (downloadEntity.isPluggable() && PackagesManager.isInstalled(downloadEntity.getPackageName())) {
progressBar.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN);
} else {
@ -401,7 +614,7 @@ public class BindingAdapters {
}
break;
case done:
progressBar.setText(com.gh.gamecenter.feature.R.string.install);
progressBar.setText(R.string.install);
if (downloadEntity.isPluggable()
&& PackagesManager.isInstalled(downloadEntity.getPackageName())) {
progressBar.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_PLUGIN);
@ -436,6 +649,24 @@ public class BindingAdapters {
}
}
/*private static void download(DownloadProgressBar progressBar, GameEntity gameEntity, ExposureEvent traceEvent, @Nullable String entrance, @Nullable String location, View v) {
if (gameEntity.getApk().size() == 1) {
ApkEntity apk = gameEntity.getApk().get(0);
DownloadDialogHelper.findAvailableDialogAndShow(
v.getContext(),
gameEntity,
apk,
() -> {
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
});
} else {
DownloadDialog.getInstance(v.getContext()).showPopupWindow(v, gameEntity,
entrance, location + gameEntity.getName(), traceEvent);
}
}*/
private static void updateReservation(DownloadButton progressBar, GameEntity gameEntity) {
// 显示预约
if (gameEntity.isReservable()) {
@ -455,66 +686,78 @@ public class BindingAdapters {
DownloadButton progressBar,
GameEntity gameEntity,
ExposureEvent traceEvent,
boolean asVGame,
boolean isSubscribe,
String entrance,
String location) {
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint));
}
String buttonText = progressBar.getText();
ApkEntity apkEntity = CollectionsKt.firstOrNull(gameEntity.getApk());
String msg = FileUtils.isCanDownload(progressBar.getContext(), apkEntity == null ? "" : apkEntity.getSize());
if (apkEntity != null && TextUtils.isEmpty(msg)) {
String str = progressBar.getText().toString();
String method;
if (str.contains("更新")) {
method = "更新";
} else if (str.contains("插件化")) {
method = "插件化";
} else {
method = progressBar.getContext().getString(R.string.download);
}
ApkEntity apkEntity = gameEntity.getApk().get(0);
String msg = FileUtils.isCanDownload(progressBar.getContext(), apkEntity.getSize());
if (TextUtils.isEmpty(msg)) {
DownloadManager.createDownload(progressBar.getContext(),
apkEntity,
gameEntity,
asVGame,
gameEntity.isDualBtnModeEnabled(),
method,
entrance,
location + gameEntity.getName(),
isSubscribe,
traceEvent);
progressBar.setProgress(0);
progressBar.setButtonStyle(buttonText.contains("插件化") ?
progressBar.setButtonStyle("插件化".equals(method) ?
DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN : DownloadButton.ButtonStyle.DOWNLOADING_NORMAL);
} else {
Utils.toast(progressBar.getContext(), msg);
}
}
/**
* 包含测试开服标签
*
* @param layout
* @param gameEntity
* @param subjectTag 默认为 “”只有游戏专题可以配置subjectTag
*/
public static void setGameTags(LinearLayout layout, GameEntity gameEntity, String subjectTag) {
public static void setGameLabelList(LinearLayout layout, List<TagStyleEntity> tagStyle) {
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle);
}
// 包含测试开服标签
public static void setGameTags(LinearLayout layout, GameEntity gameEntity) {
try {
if (layout.getVisibility() == View.GONE) return;
ArrayList<TagStyleEntity> tagStyle = new ArrayList<>();
TestEntity test = gameEntity.getTest();
if (test != null && subjectTag.equals(SUBJECT_TAG_TEST)) {
// 显示开测表标签
TagStyleEntity typeTag = new TagStyleEntity();
boolean isDarkModeOn = DarkModeUtils.INSTANCE.isDarkModeOn(layout.getContext());
typeTag.setName(test.getType() != null ? test.getType() : "");
typeTag.setBackground("1AFFA142");
typeTag.setColor(isDarkModeOn ? "EB9238" : "FFA142");
tagStyle.add(typeTag);
TagStyleEntity timeTag = new TagStyleEntity();
if (test.getStartPending()) {
timeTag.setName(test.getStartText());
if (test != null
// 这个判断用于开测表列表
&& !"type_tag".equals(test.getGameTag())) {
if ("custom".equals(test.getGameTag())) {
TagStyleEntity typeTag = new TagStyleEntity();
if (!TextUtils.isEmpty(test.getText())) {
typeTag.setName(test.getText() != null ? test.getText() : "");
} else {
typeTag.setName(test.getType() != null ? test.getType() : "");
}
typeTag.setBackground("E8F3FF");
typeTag.setColor("1383EB");
tagStyle.add(typeTag);
} else {
timeTag.setName(GameViewUtils.getGameTestDate(test.getStart()));
}
timeTag.setBackground("1A06CEA8");
timeTag.setColor(isDarkModeOn ? "07A385" : "06CEA8");
tagStyle.add(timeTag);
TagStyleEntity typeTag = new TagStyleEntity();
boolean isDarkModeOn = DarkModeUtils.INSTANCE.isDarkModeOn(layout.getContext());
typeTag.setName(test.getType() != null ? test.getType() : "");
typeTag.setBackground("1AFFA142");
typeTag.setColor(isDarkModeOn ? "EB9238" : "FFA142");
tagStyle.add(typeTag);
TagStyleEntity timeTag = new TagStyleEntity();
timeTag.setName(GameViewUtils.getGameTestDate(test.getStart()));
timeTag.setBackground("1A06CEA8");
timeTag.setColor(isDarkModeOn ? "07A385" : "06CEA8");
tagStyle.add(timeTag);
}
} else {
tagStyle = gameEntity.getTagStyle();
}
@ -524,68 +767,6 @@ public class BindingAdapters {
}
}
public static void setGameTagsWithSellingPoint(LinearLayout layout, LayoutGameItemSellingPointBinding binding, GameEntity gameEntity, String subjectTag) {
if (subjectTag.equals(SUBJECT_TAG_SELLING_POINT)) {
layout.setVisibility(View.GONE);
binding.getRoot().setVisibility(View.VISIBLE);
GameEntity.SellingPoints sellingPoints = gameEntity.getSellingPoints();
if (sellingPoints != null) {
binding.tvSellingPoints.setVisibility(View.VISIBLE);
binding.tvSellingPoints.setText(sellingPoints.getText());
} else {
binding.tvSellingPoints.setVisibility(View.GONE);
}
ArrayList<TagStyleEntity> tagStyle = gameEntity.getTagStyle();
StringBuilder tagText = new StringBuilder();
for (int i = 0; i < tagStyle.size(); i++) {
if (i < 3) {
tagText.append(i == 0 ? "" : "·").append(tagStyle.get(i).getName());
}
}
binding.gtcvTags.setText(tagText);
} else {
layout.setVisibility(View.VISIBLE);
binding.getRoot().setVisibility(View.GONE);
switch (subjectTag) {
case SUBJECT_TAG_UPDATE:
List<TagStyleEntity> updateTags = new ArrayList<>();
TagStyleEntity updateTag = new TagStyleEntity(
"local_generated",
TimeUtils.getFormatTime(gameEntity.getUpdateTime(), "MM-dd") + " 更新",
"",
"1383EB",
"E8F3FF",
"1383EB",
false
);
updateTags.add(updateTag);
GameViewUtils.setLabelList(layout.getContext(), layout, updateTags);
break;
case SUBJECT_TAG_TYPE:
GameViewUtils.setLabelList(layout.getContext(), layout, gameEntity.getTagStyle());
break;
default:
setGameTags(layout, gameEntity, subjectTag);
break;
}
}
ViewParent parent = binding.getRoot().getParent();
if (parent instanceof ConstraintLayout) {
ConstraintLayout constraintLayout = (ConstraintLayout) parent;
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(constraintLayout);
constraintSet.clear(R.id.gameDesSpace, ConstraintSet.BOTTOM);
if (subjectTag.equals(SUBJECT_TAG_SELLING_POINT)) {
constraintSet.connect(R.id.gameDesSpace, ConstraintSet.BOTTOM, R.id.layout_selling_points, ConstraintSet.TOP);
} else {
constraintSet.connect(R.id.gameDesSpace, ConstraintSet.BOTTOM, R.id.label_list, ConstraintSet.TOP);
}
constraintSet.applyTo(constraintLayout);
}
}
public static void setVideoDetailGameTags(LinearLayout layout, GameEntity gameEntity) {
try {
ArrayList<TagStyleEntity> tagStyle = new ArrayList<>();
@ -613,26 +794,57 @@ public class BindingAdapters {
}
}
public static void setGameName(TextView view, GameEntity game, boolean isShowPlatform) {
public static void isRefreshing(SwipeRefreshLayout layout, LoadStatus status) {
if (status != LoadStatus.INIT_LOADING && status != LoadStatus.LIST_LOADING) {
layout.setRefreshing(false);
}
}
public static void setGameName(TextView view, GameEntity game, boolean isShowPlatform, @Nullable Boolean isShowSuffix) {
if (isShowSuffix == null) isShowSuffix = true; // 默认显示
String gameName;
if (isShowPlatform && game.getApk().size() > 0) {
gameName = String.format("%s - %s", game.getName(),
gameName = String.format("%s - %s", !isShowSuffix ? game.getNameWithoutSuffix() : game.getName(),
PlatformUtils.getInstance(view.getContext()).getPlatformName(
game.getApk().get(0).getPlatform()));
if (!gameName.equals((String) view.getTag(com.gh.gamecenter.common.R.string.tag_game_name_id))) {
if (!gameName.equals((String) view.getTag(R.string.tag_game_name_id))) {
view.setText(gameName);
view.setTag(com.gh.gamecenter.common.R.string.tag_game_name_id, gameName);
view.setTag(R.string.tag_game_name_id, gameName);
}
} else {
gameName = game.getName();
if (gameName != null && !gameName.equals((String) view.getTag(com.gh.gamecenter.common.R.string.tag_game_name_id))) {
gameName = !isShowSuffix ? game.getNameWithoutSuffix() : game.getName();
if (gameName != null && !gameName.equals((String) view.getTag(R.string.tag_game_name_id))) {
view.setText(gameName);
view.setTag(com.gh.gamecenter.common.R.string.tag_game_name_id, gameName);
view.setTag(R.string.tag_game_name_id, gameName);
}
}
}
public static void setCommunityImage(SimpleDraweeView imageView, List<String> images, List<CommunityVideoEntity> videos) {
if (videos.size() > 0) {
CommunityVideoEntity videoEntity = videos.get(0);
ImageUtils.display(imageView, videoEntity.getPoster());
imageView.setVisibility(View.VISIBLE);
} else if (images.size() > 0) {
imageView.setVisibility(View.VISIBLE);
ImageUtils.display(imageView, images.get(0));
} else {
imageView.setVisibility(View.GONE);
}
}
public static void setCommunityVideoDuration(TextView mVideoDuration, List<CommunityVideoEntity> videos) {
if (videos != null && videos.size() > 0) {
CommunityVideoEntity videoEntity = videos.get(0);
mVideoDuration.setBackground(DrawableView.getOvalDrawable(R.color.black_alpha_50, 999F));
mVideoDuration.setText(videoEntity.getDuration());
mVideoDuration.setVisibility(View.VISIBLE);
} else {
mVideoDuration.setVisibility(View.GONE);
}
}
public static void setGameTags(TextView view, List<TagStyleEntity> tags, int maxTags) {
if (tags == null) {
view.setText("");
@ -660,4 +872,16 @@ public class BindingAdapters {
}
view.setText(span);
}
public static void setVideoData(TextView view, int count) {
if (count > 0) {
ExtensionsKt.setDrawableStart(view, ContextCompat.getDrawable(view.getContext(), R.drawable.ic_video_data_up), null, null);
view.setTextColor(ContextCompat.getColor(view.getContext(), R.color.text_EA3333));
view.setText(count + "");
} else {
ExtensionsKt.removeDrawable(view);
view.setTextColor(ContextCompat.getColor(view.getContext(), R.color.text_subtitleDesc));
view.setText("-");
}
}
}

View File

@ -1,294 +0,0 @@
package com.gh.common.dialog
import android.content.Context
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.HaloApp
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.DialogFragmentAccelerateExporationBinding
import kotlinx.parcelize.Parcelize
public class AccelerateExpirationDialogFragment : BaseDialogFragment() {
private lateinit var binding: DialogFragmentAccelerateExporationBinding
private var _reminder: ExpirationReminder? = null
override fun onBack(): Boolean {
return true
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_reminder = arguments?.getParcelable(KEY_EXPIRATION_REMINDER)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return DialogFragmentAccelerateExporationBinding.inflate(inflater, container, false)
.also {
binding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val reminder = _reminder ?: return
val (title, content) = when (reminder) {
is ExpirationReminder.UserExpired -> {
SensorsBridge.trackMonthlyPackageExpiresDialogShow(
reminder.gameId, reminder.gameName, reminder.pkgName, reminder.sourceEntrance
)
getString(
R.string.membership_expiration_reminder_title,
"${reminder.days}"
) to getString(R.string.membership_expiration_reminder_content)
}
is ExpirationReminder.InsufficientDuration -> {
SensorsBridge.trackInsufficientDurationDialogShow(
reminder.gameId,
reminder.gameName,
reminder.pkgName,
reminder.sourceEntrance
)
getString(
R.string.duration_time_out_reminder_title,
"${reminder.hours}"
) to getString(R.string.duration_time_out_reminder_content)
}
is ExpirationReminder.DurationExpired -> {
SensorsBridge.trackTimedPackageExpiresDialogShow(
reminder.gameId,
reminder.gameName,
reminder.pkgName,
reminder.sourceEntrance
)
getString(
R.string.duration_expiration_reminder_title,
"${reminder.days}"
) to getString(R.string.duration_expiration_reminder_content)
}
is ExpirationReminder.TimeRunsOut -> {
SensorsBridge.trackDurationExhaustedDialogShow()
getString(R.string.accelerator_member_expired_title) to getString(R.string.accelerator_member_expired_content)
}
}
binding.tvTitle.text = title
binding.tvContent.text = content
binding.tvCancel.setOnClickListener {
when (reminder) {
is ExpirationReminder.UserExpired -> {
SensorsBridge.trackMonthlyPackageExpiresDialogClick(
reminder.gameId, reminder.gameName, reminder.pkgName, reminder.sourceEntrance, BUTTON_NAME_KNOW
)
}
is ExpirationReminder.InsufficientDuration -> {
SensorsBridge.trackInsufficientDurationDialogClick(
reminder.gameId, reminder.gameName, reminder.pkgName, reminder.sourceEntrance, BUTTON_NAME_KNOW
)
}
is ExpirationReminder.DurationExpired -> {
SensorsBridge.trackTimedPackageExpiresDialogClick(
reminder.gameId, reminder.gameName, reminder.pkgName, reminder.sourceEntrance, BUTTON_NAME_KNOW
)
}
is ExpirationReminder.TimeRunsOut -> {
SensorsBridge.trackDurationExhaustedDialogClick(BUTTON_NAME_KNOW)
}
}
dismissAllowingStateLoss()
}
binding.tvSubmit.setOnClickListener {
when (reminder) {
is ExpirationReminder.UserExpired -> {
SensorsBridge.trackMonthlyPackageExpiresDialogClick(
reminder.gameId, reminder.gameName, reminder.pkgName, reminder.sourceEntrance, BUTTON_NAME_BUY
)
}
is ExpirationReminder.InsufficientDuration -> {
SensorsBridge.trackInsufficientDurationDialogClick(
reminder.gameId, reminder.gameName, reminder.pkgName, reminder.sourceEntrance, BUTTON_NAME_BUY
)
}
is ExpirationReminder.DurationExpired -> {
SensorsBridge.trackTimedPackageExpiresDialogClick(
reminder.gameId, reminder.gameName, reminder.pkgName, reminder.sourceEntrance, BUTTON_NAME_BUY
)
}
is ExpirationReminder.TimeRunsOut -> {
SensorsBridge.trackDurationExhaustedDialogClick(BUTTON_NAME_BUY)
}
}
SensorsBridge.trackMyAssetsPageShow(
reminder.pkgName,
reminder.gameId,
reminder.gameName,
reminder.dialogName
)
dismissAllowingStateLoss()
DirectUtils.navigateToMyAssetsPage(requireContext(), reminder.sourceEntrance)
}
}
override fun onStart() {
super.onStart()
val width = HaloApp.getInstance().resources.displayMetrics.widthPixels - 60F.dip2px()
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
}
companion object {
const val KEY_EXPIRATION_REMINDER = "key_expiration_reminder"
private const val BUTTON_NAME_KNOW = "知道了"
private const val BUTTON_NAME_BUY = "前往购买"
fun checkDialogShown(context: Context, reminder: ExpirationReminder, callback: ((Boolean) -> Unit)? = null) {
when (reminder) {
is ExpirationReminder.UserExpired -> {
val days = SPUtils.getLong(Constants.SP_ACCELERATOR_USER_REMAINING_REMIND)
if (reminder.days != days) {
SPUtils.setLong(Constants.SP_ACCELERATOR_USER_REMAINING_REMIND, reminder.days)
show(context, reminder)
callback?.invoke(true)
} else {
callback?.invoke(false)
}
}
is ExpirationReminder.InsufficientDuration -> {
val hours = SPUtils.getLong(Constants.SP_ACCELERATOR_DURATION_REMAINING_HOURS)
if (reminder.hours != hours) {
SPUtils.setLong(Constants.SP_ACCELERATOR_DURATION_REMAINING_HOURS, reminder.hours)
show(context, reminder)
callback?.invoke(true)
} else {
callback?.invoke(false)
}
}
is ExpirationReminder.DurationExpired -> {
val days = SPUtils.getLong(Constants.SP_ACCELERATOR_DURATION_REMAINING_DAYS)
if (reminder.days != days) {
SPUtils.setLong(Constants.SP_ACCELERATOR_DURATION_REMAINING_DAYS, reminder.days)
show(context, reminder)
callback?.invoke(true)
} else {
callback?.invoke(false)
}
}
is ExpirationReminder.TimeRunsOut -> {
val hasShow = SPUtils.getBoolean(Constants.SP_ACCELERATOR_MEMBERSHIP_EXPIRED)
if (!hasShow) {
SPUtils.setBoolean(Constants.SP_ACCELERATOR_MEMBERSHIP_EXPIRED, true)
show(context, reminder)
callback?.invoke(true)
} else {
callback?.invoke(false)
}
}
}
}
fun show(context: Context, reminder: ExpirationReminder) {
if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
}?.let {
val fragment = AccelerateExpirationDialogFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_EXPIRATION_REMINDER, reminder)
}
}
fragment.show(it, AcceleratorPermissionGuideDialogFragment::class.java.name)
}
}
}
sealed class ExpirationReminder(
val gameId: String,
val gameName: String,
val pkgName: String,
val sourceEntrance: String
) :
Parcelable {
abstract val dialogName: String
@Parcelize
data class InsufficientDuration(
val hours: Long,
private val _gameId: String,
private val _gameName: String,
private val _pkgName: String,
private val _sourceEntrance: String,
) :
ExpirationReminder(_gameId, _gameName, _pkgName, _sourceEntrance) {
override val dialogName: String
get() = "时长不足提示弹窗"
}
@Parcelize
data class DurationExpired(
val days: Long,
private val _gameId: String,
private val _gameName: String,
private val _pkgName: String,
private val _sourceEntrance: String,
) :
ExpirationReminder(_gameId, _gameName, _pkgName, _sourceEntrance) {
override val dialogName: String
get() = "计时套餐临期提示弹窗"
}
@Parcelize
data class UserExpired(
val days: Long,
private val _gameId: String,
private val _gameName: String,
private val _pkgName: String,
private val _sourceEntrance: String,
) :
ExpirationReminder(_gameId, _gameName, _pkgName, _sourceEntrance) {
override val dialogName: String
get() = "包月套餐临期提示弹窗"
}
@Parcelize
data class TimeRunsOut(
private val _sourceEntrance: String,
) : ExpirationReminder("", "", "", _sourceEntrance) {
override val dialogName: String
get() = "时长耗尽提示弹窗"
}
}
}

View File

@ -1,68 +0,0 @@
package com.gh.common.dialog
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.common.HaloApp
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.DialogFragmentAcceleratorPermissionGuideBinding
class AcceleratorPermissionGuideDialogFragment : BaseDialogFragment() {
private lateinit var binding: DialogFragmentAcceleratorPermissionGuideBinding
private var callback: (() -> Unit)? = null
override fun onBack(): Boolean {
return true
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return DialogFragmentAcceleratorPermissionGuideBinding.inflate(inflater, container, false)
.also {
binding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
SPUtils.setBoolean(Constants.SP_ACCELERATOR_PERMISSION_GUIDE_SHOW, true)
binding.tvSubmit.setOnClickListener {
dismiss()
callback?.invoke()
}
}
fun setOnCallback(block: () -> Unit) {
this.callback = block
}
override fun onStart() {
super.onStart()
val width = HaloApp.getInstance().resources.displayMetrics.widthPixels - 60F.dip2px()
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
}
companion object {
fun show(context: Context, callback: () -> Unit) {
if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
}?.let {
val fragment = AcceleratorPermissionGuideDialogFragment()
fragment.setOnCallback(callback)
fragment.show(it, AcceleratorPermissionGuideDialogFragment::class.java.name)
}
}
}
}

View File

@ -7,6 +7,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.dip2px
@ -48,7 +49,7 @@ class ApplyModeratorDialogFragment : BaseDialogFragment() {
requireContext(),
startText.length,
startText.length + mGroupNumber.length,
com.gh.gamecenter.common.R.color.text_theme,
R.color.theme_font,
true
) {
DirectUtils.directToQqGroup(

View File

@ -0,0 +1,221 @@
package com.gh.common.dialog
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.Paint
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.CheckBox
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.common.avoidcallback.AvoidOnResultManager
import com.gh.gamecenter.common.avoidcallback.Callback
import com.gh.gamecenter.common.constant.Constants
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.ShellActivity
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.core.utils.GsonUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.feature.entity.AuthDialogEntity
import com.gh.gamecenter.feature.entity.AuthDialogLevel
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.login.user.UserManager
import com.google.gson.reflect.TypeToken
import com.halo.assistant.fragment.user.UserInfoEditFragment
import com.lightgame.utils.AppManager
class CertificationDialog(
context: Context,
private val authDialogEntity: AuthDialogEntity,
val gameEntity: GameEntity,
val listener: ConfirmListener
) :
Dialog(context, R.style.GhAlertDialog) {
private lateinit var view: View
private lateinit var detailedDesTv: TextView
private lateinit var noRemindAgainCb: CheckBox
private lateinit var actionLeftTv: TextView
private lateinit var actionRightTv: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
view = LayoutInflater.from(context).inflate(R.layout.dialog_sertification, null)
setContentView(view)
detailedDesTv = view.findViewById(R.id.detailedDesTv)
noRemindAgainCb = view.findViewById(R.id.noRemindAgainCb)
actionLeftTv = view.findViewById(R.id.actionLeftTv)
actionRightTv = view.findViewById(R.id.actionRightTv)
detailedDesTv.paint.flags = Paint.UNDERLINE_TEXT_FLAG
detailedDesTv.paint.isAntiAlias = true
detailedDesTv.setOnClickListener {
DirectUtils.directToWebView(context, authDialogEntity.link)
}
when (authDialogEntity.level) {
AuthDialogLevel.MUST_PASS.value -> {
actionLeftTv.text = "暂不下载"
actionRightTv.text = "去实名认证"
noRemindAgainCb.visibility = View.GONE
actionLeftTv.setOnClickListener {
SensorsBridge.trackEvent("VerificationPopupClick", "button_name", actionLeftTv.text.toString())
dismiss()
}
actionRightTv.setOnClickListener {
SensorsBridge.trackEvent("VerificationPopupClick", "button_name", actionRightTv.text.toString())
if (UserManager.getInstance().isLoggedIn) {
gotoAuthPage()
} else {
gotoLoginPage()
}
}
}
AuthDialogLevel.ALWAYS_HINT.value -> {
actionLeftTv.text = "去实名认证"
actionRightTv.text = "继续下载"
noRemindAgainCb.visibility = View.GONE
actionLeftTv.setOnClickListener {
SensorsBridge.trackEvent("VerificationPopupClick", "button_name", actionLeftTv.text.toString())
if (UserManager.getInstance().isLoggedIn) {
gotoAuthPage()
} else {
gotoLoginPage()
}
}
actionRightTv.setOnClickListener {
SensorsBridge.trackEvent("VerificationPopupClick", "button_name", actionRightTv.text.toString())
listener.onConfirm()
dismiss()
}
}
AuthDialogLevel.OPTIONAL_HINT.value -> {
actionLeftTv.text = "去实名认证"
actionRightTv.text = "继续下载"
noRemindAgainCb.visibility = View.VISIBLE
actionLeftTv.setOnClickListener {
SensorsBridge.trackEvent("VerificationPopupClick", "button_name", actionLeftTv.text.toString())
if (noRemindAgainCb.isChecked) {
SPUtils.setBoolean(gameEntity.id, true)
}
if (UserManager.getInstance().isLoggedIn) {
gotoAuthPage()
} else {
gotoLoginPage()
}
}
actionRightTv.setOnClickListener {
SensorsBridge.trackEvent("VerificationPopupClick", "button_name", actionRightTv.text.toString())
if (noRemindAgainCb.isChecked) {
SPUtils.getBoolean(gameEntity.id, true)
}
listener.onConfirm()
dismiss()
}
}
}
SensorsBridge.trackEvent(
"VerificationDialogShow",
"game_id",
gameEntity.id,
"game_name",
gameEntity.name ?: "",
"game_type",
gameEntity.categoryChinese
)
}
//跳转登录页面
private fun gotoLoginPage() {
val currentActivity = AppManager.getInstance().currentActivity() ?: return
CheckLoginUtils.checkLogin(
currentActivity as AppCompatActivity,
null, true, "实名认证弹窗"
) {
if (UserManager.getInstance().isAuth) {
listener.onConfirm()
dismiss()
}
}
}
//跳转实名认证页面
private fun gotoAuthPage() {
val currentActivity = AppManager.getInstance().currentActivity() ?: return
AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity)
.startForResult(
ShellActivity.getIntent(
context,
ShellActivity.Type.REAL_NAME_INFO,
).apply {
putExtra(EntranceConsts.KEY_GAME_ID, gameEntity.id)
}, object : Callback {
override fun onActivityResult(resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && data != null) {
val isAuthSuccess =
data.getBooleanExtra(UserInfoEditFragment.AUTH_SUCCESS, false)
if (isAuthSuccess) {
listener.onConfirm()
dismiss()
}
}
}
})
}
companion object {
@JvmStatic
fun showCertificationDialog(context: Context, game: GameEntity, listener: ConfirmListener) {
//1.先判断是否登录 是执行2 否执行3
//2.判断是否实名认证 是终止 否执行3
//3.判断是否需要弹出认证弹窗接口
if (UserManager.getInstance().isLoggedIn) {
if (UserManager.getInstance().isAuth) {//已实名认证
listener.onConfirm()
} else {
authDialog(context, game, listener)
}
} else {
authDialog(context, game, listener)
}
}
@SuppressLint("CheckResult")
private fun authDialog(context: Context, game: GameEntity, listener: ConfirmListener) {
var authDialog: AuthDialogEntity? = null
if (game.authDialog != null) {
authDialog = game.authDialog
}
if (authDialog == null) {
val datas = SPUtils.getString(Constants.SP_AUTH_DIALOG)
val type = object : TypeToken<List<AuthDialogEntity>>() {}.type
val authDialogs = GsonUtils.gson.fromJson<List<AuthDialogEntity>>(datas, type)
if (!authDialogs.isNullOrEmpty()) {
authDialog = authDialogs.find { it.gameCategory == game.category }
}
}
val isCloseAuthDialog = SPUtils.getBoolean(game.id, false)
if (authDialog != null && (authDialog.level != AuthDialogLevel.OPTIONAL_HINT.value || !isCloseAuthDialog)) {
val dialog = CertificationDialog(context, authDialog, game, listener)
dialog.show()
} else {
listener.onConfirm()
}
}
}
}

View File

@ -40,7 +40,7 @@ import java.lang.ref.WeakReference
* 设备提醒弹窗
*/
class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val gameEntity: GameEntity) :
Dialog(context, com.gh.gamecenter.common.R.style.GhAlertDialog) {
Dialog(context, R.style.GhAlertDialog) {
private val mBinding: DialogDeviceRemindBinding by lazy { DialogDeviceRemindBinding.inflate(layoutInflater) }
private var currentPage = 0
private var mSlideLooperInterval = 3000L
@ -136,13 +136,13 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
val isFirst = SPUtils.getBoolean(Constants.SP_FIRST_DEVICE_REMIND, false)
if (!isFirst) {
mBinding.cancelTv.isEnabled = false
mBinding.cancelTv.background = ContextCompat.getDrawable(context, com.gh.gamecenter.common.R.drawable.button_round_f5f5f5)
mBinding.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_round_f5f5f5)
disposable = countDownTimer(3) { finish, time ->
if (finish) {
mBinding.cancelTv.isEnabled = true
mBinding.cancelTv.background = ContextCompat.getDrawable(context, com.gh.gamecenter.common.R.drawable.button_blue_oval)
mBinding.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_blue_oval)
mBinding.cancelTv.text = "我知道了"
mBinding.cancelTv.setTextColor(ContextCompat.getColor(context, com.gh.gamecenter.common.R.color.white))
mBinding.cancelTv.setTextColor(ContextCompat.getColor(context, R.color.white))
} else {
mBinding.cancelTv.text = "我知道了(${time}S)"
}
@ -153,8 +153,8 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
mBinding.noRemindAgainCb.visibility = View.VISIBLE
mBinding.cancelTv.text = "我知道了"
mBinding.cancelTv.isEnabled = true
mBinding.cancelTv.setTextColor(ContextCompat.getColor(context, com.gh.gamecenter.common.R.color.white))
mBinding.cancelTv.background = ContextCompat.getDrawable(context, com.gh.gamecenter.common.R.drawable.button_blue_oval)
mBinding.cancelTv.setTextColor(ContextCompat.getColor(context, R.color.white))
mBinding.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_blue_oval)
}
mBinding.cancelTv.setOnClickListener {
SPUtils.setBoolean(Constants.SP_NO_REMIND_AGAIN, mBinding.noRemindAgainCb.isChecked)

View File

@ -14,6 +14,7 @@ import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogGameOffServiceBinding
import com.gh.gamecenter.feature.entity.GameEntity
@ -22,7 +23,6 @@ class GameOffServiceDialogFragment : BaseDialogFragment() {
private var mDialog: GameEntity.Dialog? = null
private var mBinding: DialogGameOffServiceBinding? = null
private var mCallback: (() -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -44,7 +44,6 @@ class GameOffServiceDialogFragment : BaseDialogFragment() {
titleTv.text = title
contentTv.text = HtmlCompat.fromHtml(content, HtmlCompat.FROM_HTML_MODE_LEGACY)
okTv.setOnClickListener {
mCallback?.invoke()
dismissAllowingStateLoss()
}
@ -61,10 +60,11 @@ class GameOffServiceDialogFragment : BaseDialogFragment() {
if (index == notEmptySite.size - 1) bottomMargin = 8F.dip2px()
}
siteTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14F)
siteTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
siteTv.setTextColor(R.color.theme_font.toColor(requireContext()))
siteTv.text = site.text
siteTv.paintFlags = siteTv.paintFlags or Paint.UNDERLINE_TEXT_FLAG
siteTv.setOnClickListener {
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
dismissAllowingStateLoss()
}
@ -83,13 +83,11 @@ class GameOffServiceDialogFragment : BaseDialogFragment() {
const val KEY_DIALOG = "dialog"
@JvmStatic
fun getInstance(dialog: GameEntity.Dialog, callback: (() -> Unit)? = null) =
GameOffServiceDialogFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_DIALOG, dialog)
}
mCallback = callback
fun getInstance(dialog: GameEntity.Dialog) = GameOffServiceDialogFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_DIALOG, dialog)
}
}
}
}

View File

@ -1,7 +1,6 @@
package com.gh.common.dialog
import android.app.Activity.RESULT_OK
import android.content.DialogInterface
import android.content.Intent
import android.os.Build
import android.os.Bundle
@ -19,10 +18,13 @@ import com.gh.common.xapk.XapkInstaller
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.PermissionHelper
import com.gh.gamecenter.common.utils.PermissionHelper.INSTALL_PERMISSION_CODE
import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.core.utils.SPUtils
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import kotlin.random.Random
class InstallPermissionDialogFragment : BaseDialogFragment() {
@ -32,11 +34,8 @@ class InstallPermissionDialogFragment : BaseDialogFragment() {
var url: String = ""
var gameId: String = ""
var gameName: String = ""
var gameType: String = ""
var mCallBack: ((isFromPermissionGrantedCallback: Boolean) -> Unit)? = null
private var dismissByTouchInside = false
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mView = inflater.inflate(R.layout.dialog_install_permission, null, false)
return mView
@ -56,12 +55,6 @@ class InstallPermissionDialogFragment : BaseDialogFragment() {
if (isXapk) NewFlatLogUtils.logXApkInstallPermissionDialogShowed(gameId, gameName)
SensorsBridge.trackInstallPermissionDialogShow(
gameId = gameId,
gameName = gameName,
gameType = gameType
)
val randomNumber = if (isXapk) 1 else Random.nextInt(2)
closeTv.goneIf(randomNumber == 0)
closeIv.goneIf(randomNumber != 0)
@ -71,38 +64,18 @@ class InstallPermissionDialogFragment : BaseDialogFragment() {
}
closeTv.setOnClickListener {
dismissByTouchInside = true
if (isXapk) {
NewFlatLogUtils.logXApkInstallPermissionDialogClick("尝试解压", false, gameId, gameName)
mCallBack?.invoke(false)
}
SensorsBridge.trackInstallPermissionDialogClick(
buttonName = "尝试解压",
gameId = gameId,
gameName = gameName,
gameType = gameType
)
dismiss()
}
closeIv.setOnClickListener {
dismissByTouchInside = true
if (isXapk) NewFlatLogUtils.logXApkInstallPermissionDialogClick("关闭", false, gameId, gameName)
SensorsBridge.trackInstallPermissionDialogClick(
buttonName = "关闭",
gameId = gameId,
gameName = gameName,
gameType = gameType
)
dismiss()
}
activateTv.setOnClickListener {
NewFlatLogUtils.logXApkInstallPermissionDialogClick("立即开启", false, gameId, gameName)
SensorsBridge.trackInstallPermissionDialogClick(
buttonName = "立即开启",
gameId = gameId,
gameName = gameName,
gameType = gameType
)
PermissionHelper.toInstallPermissionSetting(requireActivity())
if (isXapk) {
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, requireActivity().javaClass.name)
@ -111,23 +84,9 @@ class InstallPermissionDialogFragment : BaseDialogFragment() {
}
}
override fun onDismiss(dialog: DialogInterface) {
if (!dismissByTouchInside) {
SensorsBridge.trackInstallPermissionDialogClick(
buttonName = "关闭弹窗",
gameId = gameId,
gameName = gameName,
gameType = gameType
)
}
super.onDismiss(dialog)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISSION_CODE) {
dismissByTouchInside = true
NewFlatLogUtils.logXApkInstallPermissionDialogClick("立即开启", true, gameId, gameName)
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
@ -158,7 +117,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
}
@ -177,7 +136,6 @@ class InstallPermissionDialogFragment : BaseDialogFragment() {
installPermissionDialogFragment.url = downloadEntity.url
installPermissionDialogFragment.gameId = downloadEntity.gameId
installPermissionDialogFragment.gameName = downloadEntity.name
installPermissionDialogFragment.gameType = downloadEntity.categoryChinese
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
transaction.show(installPermissionDialogFragment)
transaction.commit()
@ -188,7 +146,6 @@ class InstallPermissionDialogFragment : BaseDialogFragment() {
this.url = downloadEntity.url
this.gameId = downloadEntity.gameId
this.gameName = downloadEntity.name
this.gameType = downloadEntity.categoryChinese
}
installPermissionDialogFragment.show(
activity.supportFragmentManager,

View File

@ -76,12 +76,12 @@ class NewPrivacyPolicyDialogFragment : BaseDialogFragment() {
contentText.setSpan(object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.text_theme)
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
ds.isUnderlineText = false
}
override fun onClick(widget: View) {
val privacyPolicyUrl = requireContext().getString(com.gh.gamecenter.common.R.string.privacy_policy_url)
val privacyPolicyUrl = requireContext().getString(R.string.privacy_policy_url)
val childrenPrivacyPolicyUrl = requireContext().getString(R.string.children_policy_url)
val thirdPartySdkUrl = requireContext().getString(R.string.sdk_list_url)
val permissionListUrl = requireContext().getString(R.string.permission_and_usage_url)

View File

@ -2,7 +2,7 @@ package com.gh.common.dialog
import android.animation.ValueAnimator
import android.content.Context
import android.content.DialogInterface
import android.content.pm.PackageInfo
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -11,7 +11,6 @@ import android.view.animation.LinearInterpolator
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.LinearLayoutManager
@ -20,6 +19,7 @@ import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.constant.Constants
@ -57,11 +57,10 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private val mDuration = 3000
private var mDisposable: Disposable? = null
private var mAdapter: PackageCheckAdapter? = null
private var mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
var gameEntity: GameEntity? = null
var callBack: ConfirmListener? = null
private var mDismissByTouchInside = false
private val dataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
val packageName = downloadEntity.packageName
@ -91,11 +90,6 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
EventBus.getDefault().register(this)
gameEntity?.let {
LogUtils.uploadPackageCheck("pkg_check_pop_click", "出现弹窗", it, "", "", "", "")
SensorsBridge.trackPkgCheckDialogShow(
gameId = it.id,
gameName = it.name ?: "",
gameType = it.categoryChinese
)
}
}
@ -122,7 +116,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
requireContext(),
0,
(link.title ?: "").length,
com.gh.gamecenter.common.R.color.text_theme,
R.color.theme_font,
true
) {
LogUtils.uploadPackageCheck(
@ -134,18 +128,6 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
"",
""
)
SensorsBridge.trackPkgCheckDialogClick(
buttonName = "点击链接",
gameId = gameEntity?.id ?: "",
gameName = gameEntity?.name ?: "",
gameType = gameEntity?.categoryChinese ?: "",
isNotPrompt = if (binding.noRemindAgainCb.isVisible) {
binding.noRemindAgainCb.isChecked
} else null,
linkId = link.link ?: "",
linkType = link.type ?: "",
linkText = link.linkText ?: ""
)
DirectUtils.directToLinkPage(requireContext(), link, "包名检测弹窗", "")
}.build()
spanBuilder.append(linkSpan)
@ -192,9 +174,8 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
if (binding.noRemindAgainCb.isChecked) {
saveRecord(entity)
}
val isAllPackageInstalled = isAllPackageInstalled(entity)
val isAllPackageInstalled = isAllPackageInstalled(mAllInstalledPackages, entity)
if (isAllPackageInstalled) {
mDismissByTouchInside = true
callBack?.onConfirm()
dismissAllowingStateLoss()
} else {
@ -212,15 +193,6 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
"",
""
)
SensorsBridge.trackPkgCheckDialogClick(
buttonName = "点击前往下载",
gameId = gameEntity?.id ?: "",
gameName = gameEntity?.name ?: "",
gameType = gameEntity?.categoryChinese ?: "",
isNotPrompt = if (binding.noRemindAgainCb.isVisible) {
binding.noRemindAgainCb.isChecked
} else null
)
DirectUtils.directToLinkPage(requireContext(), packageLink, "包名检测弹窗", "")
}
}
@ -234,19 +206,6 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
saveRecord(entity)
LogUtils.uploadPackageCheck("pkg_check_pop_click", "不再提示", gameEntity, "", "", "", "")
}
mDismissByTouchInside = true
SensorsBridge.trackPkgCheckDialogClick(
buttonName = binding.cancelTv.text.toString(),
gameId = gameEntity?.id ?: "",
gameName = gameEntity?.name ?: "",
gameType = gameEntity?.categoryChinese ?: "",
isNotPrompt = if (binding.noRemindAgainCb.isVisible) {
binding.noRemindAgainCb.isChecked
} else null
)
dismissAllowingStateLoss()
}
}
@ -281,7 +240,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
if (it >= mDuration) {
mDisposable?.dispose()
binding.downloadBtn.isEnabled = true
binding.downloadBtn.background = com.gh.gamecenter.common.R.drawable.bg_notification_open_btn_style_2.toDrawable()
binding.downloadBtn.background = R.drawable.bg_notification_open_btn_style_2.toDrawable()
}
}
val animator = ValueAnimator.ofInt(0, 100)
@ -296,7 +255,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private fun getNotInstalledLink(packageDialogEntity: PackageDialogEntity): LinkEntity? {
val links = LinkedHashSet<LinkEntity>()
packageDialogEntity.detectionObjects.forEach { obj ->
if (!checkDetectionsInstalled(obj.packages)) {
if (!checkDetectionsInstalled(mAllInstalledPackages, obj.packages)) {
obj.assignDownload.forEach {
links.add(packageDialogEntity.links[it])
}
@ -322,8 +281,9 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
override fun onResume() {
super.onResume()
mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
gameEntity?.packageDialog?.let {
if (isAllPackageInstalled(it)) {
if (isAllPackageInstalled(mAllInstalledPackages, it)) {
callBack?.onConfirm()
dismissAllowingStateLoss()
}
@ -340,25 +300,11 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
DownloadManager.getInstance().removeObserver(dataWatcher)
}
override fun onDismiss(dialog: DialogInterface) {
if (!mDismissByTouchInside) {
SensorsBridge.trackPkgCheckDialogClick(
buttonName = "关闭弹窗",
gameId = gameEntity?.id ?: "",
gameName = gameEntity?.name ?: "",
gameType = gameEntity?.categoryChinese ?: "",
isNotPrompt = if (binding.noRemindAgainCb.isVisible) {
binding.noRemindAgainCb.isChecked
} else null
)
}
super.onDismiss(dialog)
}
//安装、卸载事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
mAdapter?.notifyDataSetChanged()
}
}
@ -383,13 +329,13 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
val entity = entities[position]
holder.binding.gameNameTv.text = entity.text
if (position <= index) {
val isAllInstalled = checkDetectionsInstalled(entity.packages)
val isAllInstalled = checkDetectionsInstalled(mAllInstalledPackages, entity.packages)
if (isAllInstalled) {
holder.binding.statusTv.text = "已安装"
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, com.gh.gamecenter.common.R.color.text_theme))
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
} else {
holder.binding.statusTv.text = "未安装"
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, com.gh.gamecenter.common.R.color.secondary_red))
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_red))
}
holder.binding.statusTv.visibility = View.VISIBLE
} else {
@ -411,7 +357,8 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
return
}
if (isAllPackageInstalled(packageDialogEntity)) {
val allInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
if (isAllPackageInstalled(allInstalledPackages, packageDialogEntity)) {
callBack.onConfirm()
return
}
@ -447,11 +394,13 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
}
private fun checkDetectionsInstalled(
allInstalledPackages: List<PackageInfo>,
packages: ArrayList<String>
): Boolean {
var isPackagesInstalled = false
packages.forEach { packageName ->
if (PackageUtils.isInstalledFromAllPackage(HaloApp.getInstance(), packageName)) {
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
if (isInstalled) {
isPackagesInstalled = true
return@forEach
}
@ -461,14 +410,17 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
fun isAllPackageInstalled(
allInstalledPackages: List<PackageInfo>,
packageDialogEntity: PackageDialogEntity
): Boolean {
var isAllInstalled = true
packageDialogEntity.detectionObjects.forEach loop@{ obj ->
if (!checkDetectionsInstalled(obj.packages)) {
return false
if (!checkDetectionsInstalled(allInstalledPackages, obj.packages)) {
isAllInstalled = false
return isAllInstalled
}
}
return true
return isAllInstalled
}
}
}

View File

@ -12,6 +12,7 @@ import android.view.*
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentTransaction
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.Constants
@ -28,15 +29,6 @@ class PrivacyPolicyDialogFragment : BaseDialogFragment() {
private var mCallBack: ((isSuccess: Boolean) -> Unit)? = null
private val mBinding by lazy { DialogPrivacyProtocolBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
dismiss()
return
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -67,13 +59,13 @@ class PrivacyPolicyDialogFragment : BaseDialogFragment() {
skipText.setSpan(object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.text_theme)
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
ds.isUnderlineText = false
}
override fun onClick(widget: View) {
val intent =
WebActivity.getIntent(requireContext(), context!!.getString(com.gh.gamecenter.common.R.string.privacy_policy_url), true)
WebActivity.getIntent(requireContext(), context!!.getString(R.string.privacy_policy_url), true)
context?.startActivity(intent)
}
}, skipText.length - 6, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
@ -109,13 +101,13 @@ class PrivacyPolicyDialogFragment : BaseDialogFragment() {
skipText.setSpan(object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.text_theme)
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
ds.isUnderlineText = false
}
override fun onClick(widget: View) {
val intent =
WebActivity.getIntent(requireContext(), context!!.getString(com.gh.gamecenter.common.R.string.privacy_policy_url), true)
WebActivity.getIntent(requireContext(), context!!.getString(R.string.privacy_policy_url), true)
context?.startActivity(intent)
}
}, skipText.length - 9, skipText.length - 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
@ -123,12 +115,12 @@ class PrivacyPolicyDialogFragment : BaseDialogFragment() {
skipText.setSpan(object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.text_theme)
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
ds.isUnderlineText = false
}
override fun onClick(widget: View) {
val intent = WebActivity.getIntent(requireContext(), context!!.getString(com.gh.gamecenter.common.R.string.disclaimer_url), true)
val intent = WebActivity.getIntent(requireContext(), context!!.getString(R.string.disclaimer_url), true)
context?.startActivity(intent)
}
}, skipText.length - 4, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

View File

@ -1,210 +1,92 @@
package com.gh.common.dialog
import android.content.Context
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureListener
import com.gh.common.exposure.IExposable
import com.gh.gamecenter.DownloadManagerActivity
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.exposure.ExposureSource
import com.gh.gamecenter.common.utils.*
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.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.DialogReserveBinding
import com.gh.gamecenter.databinding.DialogReserveItemBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.ReserveOnlineEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.mygame.MyGameActivity
import com.halo.assistant.HaloApp
import com.lightgame.adapter.BaseRecyclerAdapter
class ReserveDialog : BaseDialogFragment() {
private lateinit var reserveOnlineEntity: ReserveOnlineEntity
val games: List<GameEntity>
get() = reserveOnlineEntity.games
private lateinit var mReserveList: List<SimpleGameEntity>
private var mDismissListener: (() -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
dismiss()
return
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val binding: DialogReserveBinding = DialogReserveBinding.inflate(layoutInflater, null, false)
reserveOnlineEntity = arguments?.getParcelable(RESERVE_ONLINE) ?: ReserveOnlineEntity()
mReserveList = arguments?.getParcelableArrayList(RESERVE_LIST) ?: arrayListOf()
binding.tvTitle.text =
resources.getString(R.string.dialog_reserve_title, reserveOnlineEntity.gamesTotal).fromHtml()
binding.tvViewAllAppointment.setOnClickListener {
SensorsBridge.trackAppointmentGameOnlineDialogClick(buttonName = "查看全部预约")
val intent = MyGameActivity.getIntentWithConfig(requireContext(), MyGameActivity.RESERVATION_INDEX)
binding.title.text = resources.getString(R.string.dialog_reserve_title, mReserveList.size).fromHtml()
binding.more.visibility = if (mReserveList.size > 4) {
View.VISIBLE
} else View.GONE
binding.more.setOnClickListener {
val intent = MyGameActivity.getIntentWithConfig(requireContext(), 2)
startActivity(intent)
}
val adapter = ReserveDialogAdapter(requireContext(), games)
binding.rvGames.layoutManager = FixLinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
binding.rvGames.adapter = adapter
val exposureListener = ExposureListener(this, adapter)
binding.rvGames.addOnScrollListener(exposureListener)
binding.ivClose.setOnClickListener {
dismissAllowingStateLoss()
}
binding.recyclerView.layoutManager = if (mReserveList.size > 4) {
GridLayoutManager(context, 4)
} else {
FixLinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
}
binding.recyclerView.adapter = object : BaseRecyclerAdapter<ReserveDialogItemViewHolder>(context) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReserveDialogItemViewHolder {
val inflate = mLayoutInflater.inflate(R.layout.dialog_reserve_item, parent, false)
return ReserveDialogItemViewHolder(DialogReserveItemBinding.bind(inflate))
}
checkHasAutoDownload(binding)
override fun getItemCount(): Int {
return if (mReserveList.size > 4) 4 else mReserveList.size
}
override fun onBindViewHolder(holder: ReserveDialogItemViewHolder, position: Int) {
val entity = mReserveList[position]
ImageUtils.display(holder.binding.icon, entity.icon)
holder.binding.gameNameTv.text = entity.name
holder.itemView.setOnClickListener {
GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(预约弹窗)")
dismissAllowingStateLoss()
}
}
}
dialog?.setCanceledOnTouchOutside(true)
return binding.root
}
private fun checkHasAutoDownload(binding: DialogReserveBinding) {
if (reserveOnlineEntity.wifiAutoDownloadTotal > 0) {
// 开启自动下载
binding.tvAutoDownloadTips.goneIf(false)
var firstAutoDownloadGameName =
reserveOnlineEntity.games.find { it.wifiAutoDownload && !it.isLandPageAddressDialog() }?.name
if(!firstAutoDownloadGameName.isNullOrBlank() && firstAutoDownloadGameName.length > GAME_NAME_SHOW_MAX_LENGTH){
firstAutoDownloadGameName = "${firstAutoDownloadGameName.take(GAME_NAME_SHOW_MAX_LENGTH-1)}..."
}
val isWifiOpen = NetworkUtils.isWifiConnected(HaloApp.getInstance())
binding.tvAutoDownloadTips.text =
if (isWifiOpen) {
if (firstAutoDownloadGameName.isNullOrBlank()) {
getString(
R.string.reserve_reminder_auto_download,
"${reserveOnlineEntity.wifiAutoDownloadTotal}"
)
} else {
getString(
R.string.reserve_reminder_auto_download_with_name,
firstAutoDownloadGameName,
"${reserveOnlineEntity.wifiAutoDownloadTotal}"
)
}
} else {
if (firstAutoDownloadGameName.isNullOrBlank()) {
getString(
R.string.reserve_reminder_wait_for_wifi_to_auto_download,
"${reserveOnlineEntity.wifiAutoDownloadTotal}"
)
} else {
getString(
R.string.reserve_reminder_wait_for_wifi_to_auto_download_with_name,
firstAutoDownloadGameName,
"${reserveOnlineEntity.wifiAutoDownloadTotal}"
)
}
}
binding.tvAutoDownloadTips.setOnClickListener {
SensorsBridge.trackAppointmentGameOnlineDialogClick(buttonName = "查看进度")
val intent = DownloadManagerActivity.getDownloadMangerIntent(requireContext(), "")
startActivity(intent)
}
} else {
binding.tvAutoDownloadTips.goneIf(true)
}
}
fun setOnDismissListener(dismissListener: () -> Unit) {
mDismissListener = dismissListener
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
SensorsBridge.trackAppointmentGameOnlineDialogClick(buttonName = "关闭弹窗")
}
override fun onStart() {
super.onStart()
dialog?.window?.let {
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val params = it.attributes
params.width = DisplayUtils.dip2px(300F)
it.attributes = params
}
}
override fun onDestroy() {
super.onDestroy()
mDismissListener?.invoke()
}
companion object {
const val RESERVE_ONLINE = "reserve_online"
private const val GAME_NAME_SHOW_MAX_LENGTH = 8
const val RESERVE_LIST = "reserve_list"
@JvmStatic
fun getInstance(reserveOnlineEntity: ReserveOnlineEntity?) = ReserveDialog().apply {
arguments = Bundle().apply {
putParcelable(RESERVE_ONLINE, reserveOnlineEntity)
}
fun getInstance(reserveList: List<SimpleGameEntity>) = ReserveDialog().apply {
arguments = Bundle()
arguments?.putParcelableArrayList(RESERVE_LIST, ArrayList(reserveList))
}
}
}
class ReserveDialogAdapter(
context: Context,
private val games: List<GameEntity>
) :
BaseRecyclerAdapter<ReserveDialogItemViewHolder>(context), IExposable {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReserveDialogItemViewHolder {
return ReserveDialogItemViewHolder(parent.toBinding())
}
override fun getItemCount(): Int {
return if (games.size > 8) 8 else games.size
}
override fun onBindViewHolder(holder: ReserveDialogItemViewHolder, position: Int) {
val entity = games[position]
holder.binding.icon.displayGameIcon(entity)
holder.binding.gameNameTv.text = entity.name
holder.itemView.setOnClickListener {
SensorsBridge.trackAppointmentGameOnlineDialogClick(
"游戏",
entity.id,
entity.name ?: "",
entity.categoryChinese,
)
GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(预约弹窗)", entity.exposureEvent)
}
entity.exposureEvent = ExposureEvent.createEvent(
entity,
listOf(ExposureSource("预约上线弹窗", ""))
)
}
override fun getEventByPosition(pos: Int): ExposureEvent? {
return games.getOrNull(pos)?.exposureEvent
}
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? {
return null
}
}
class ReserveDialogItemViewHolder(val binding: DialogReserveItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)

View File

@ -1,278 +0,0 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.text.InputFilter
import android.view.LayoutInflater
import androidx.core.widget.addTextChangedListener
import com.gh.gamecenter.R
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.toResString
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.DialogReserveReminderPhoneNumberBinding
import com.gh.gamecenter.entity.ReserveModifyEntity
import com.gh.gamecenter.entity.ValidateCodeResponse
import com.halo.assistant.fragment.reserve.OnReserveReminderListener
import com.halo.assistant.fragment.reserve.ReserveReminderRepository
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
import java.util.concurrent.TimeUnit
class ReserveReminderPhoneNumberDialog(
context: Context,
themeResId: Int,
private val dialogType: Int,
private val phoneNumber: String,
private var serviceId: String,
private val gameId: String,
private val repository: ReserveReminderRepository,
private val listener: OnReserveReminderListener
) :
Dialog(context, themeResId) {
private val compositeDisposable = CompositeDisposable()
private lateinit var binding: DialogReserveReminderPhoneNumberBinding
private var hasValidated = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DialogReserveReminderPhoneNumberBinding.inflate(LayoutInflater.from(context))
setContentView(binding.root)
initView()
}
private fun initView() {
binding.vClose.setOnClickListener {
dismiss()
}
setSubmitState(phoneNumber)
binding.etInput.addTextChangedListener {
val content = binding.etInput.text?.toString() ?: ""
if (dialogType == DIALOG_TYPE_BIND_PHONE || dialogType == DIALOG_TYPE_CHANGE_PHONE) {
setSubmitState(content)
} else {
val length = content.length
if (length == VALIDATE_CODE_LENGTH) {
verifyPhoneNumber(content)
}
}
}
when (dialogType) {
DIALOG_TYPE_BIND_PHONE -> {
binding.tvTitle.setText(R.string.enable_sms_reminder)
binding.tvDescription.setText(R.string.enable_sms_reminder_description)
binding.etInput.setText(phoneNumber)
binding.etInput.setHint(com.gh.gamecenter.login.R.string.input_phone_hint)
}
DIALOG_TYPE_CHANGE_PHONE -> {
binding.tvTitle.setText(R.string.change_phone_number_2)
binding.tvDescription.setText(R.string.enable_sms_reminder_description)
binding.etInput.setText(phoneNumber)
binding.etInput.setHint(com.gh.gamecenter.login.R.string.input_phone_hint)
}
DIALOG_TYPE_VERIFY_PHONE -> {
startCountDown()
binding.tvTitle.setText(R.string.please_input_sms_verify_code)
if (phoneNumber.length == PHONE_NUMBER_LENGTH) {
val phoneNumberWithMask = phoneNumber.substring(0, 3) + MASK + phoneNumber.substring(7)
binding.tvDescription.text =
context.getString(R.string.verify_code_send_with_phone_number, phoneNumberWithMask)
}
binding.tvSubmit.alpha = 1.0F
binding.etInput.filters = arrayOf<InputFilter>(InputFilter.LengthFilter(VALIDATE_CODE_LENGTH))
binding.etInput.setHint(R.string.please_input_verify_code)
}
}
binding.tvSubmit.setOnClickListener {
val text = binding.etInput.text?.toString() ?: ""
if (dialogType == DIALOG_TYPE_VERIFY_PHONE) {
resendValidateCode()
} else {
if (isEnableSubmit(text)) {
when (dialogType) {
DIALOG_TYPE_BIND_PHONE -> bindPhoneNumber(text)
DIALOG_TYPE_CHANGE_PHONE -> bindPhoneNumber(text)
}
} else {
if (text != phoneNumber) {
ToastUtils.toast(R.string.invalid_phone_number_format.toResString())
}
}
}
}
}
private fun resendValidateCode() {
repository.sendVerifyCode(phoneNumber)
.compose(singleToMain())
.subscribe(object : BiResponse<ValidateCodeResponse>() {
override fun onSuccess(data: ValidateCodeResponse) {
serviceId = data.serviceId
startCountDown()
}
}).let(compositeDisposable::add)
}
private fun verifyPhoneNumber(content: String) {
repository.verifyPhoneNumber(phoneNumber, content, serviceId)
.compose(singleToMain())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
hasValidated = true
listener.phoneNumberValidateSuccessfully()
ToastUtils.toast(R.string.phone_number_validate_successfully.toResString())
dismiss()
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
binding.etInput.text = null
ToastUtils.toast(R.string.phone_number_validate_failure.toResString())
}
}).let(compositeDisposable::add)
}
private fun bindPhoneNumber(phone: String) {
repository.bindPhone(gameId, phone)
.compose(singleToMain())
.subscribe(object : BiResponse<ReserveModifyEntity>() {
override fun onSuccess(data: ReserveModifyEntity) {
listener.bindPhoneSuccessfully(data.smsConfig.mobileValidated, phone)
dismiss()
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
if (exception is HttpException) {
try {
val string = exception.response().errorBody()?.string()
if (!string.isNullOrBlank()) {
val json = JSONObject(string)
val message = json.getJSONObject("toast").getString("sms_config.mobile")
ToastUtils.showToast(message)
}
} catch (e: Exception) {
// no implement
}
}
}
}).let(compositeDisposable::add)
}
private fun startCountDown() {
binding.tvSubmit.isEnabled = false
binding.tvSubmit.setBackgroundResource(com.gh.gamecenter.common.R.drawable.bg_common_button_light_fill_gray)
binding.tvSubmit.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
Observable.interval(0, 1, TimeUnit.SECONDS)
.take(COUNT_DOWN_DURATION)
.map {
COUNT_DOWN_DURATION - it
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<Long>() {
override fun onSubscribe(d: Disposable) {
compositeDisposable.add(d)
}
override fun onNext(time: Long) {
binding.tvSubmit.text = context.getString(R.string.resend_with_time, "$time")
}
override fun onComplete() {
binding.tvSubmit.isEnabled = true
binding.tvSubmit.setBackgroundResource(com.gh.gamecenter.common.R.drawable.bg_common_button_fill_blue)
binding.tvSubmit.setTextColor(com.gh.gamecenter.common.R.color.text_aw_primary.toColor(context))
binding.tvSubmit.setText(R.string.resend)
}
})
}
override fun dismiss() {
compositeDisposable.clear()
if (dialogType == DIALOG_TYPE_VERIFY_PHONE && !hasValidated) {
ToastUtils.toast(R.string.phone_number_validate_cancel.toResString())
}
super.dismiss()
}
private fun isEnableSubmit(phone: String) =
PHONE_NUMBER_PATTERN.toRegex().matches(phone)
&& if (dialogType == DIALOG_TYPE_CHANGE_PHONE) phone != phoneNumber else true
private fun setSubmitState(phone: String) {
val isEnable = isEnableSubmit(phone)
binding.tvSubmit.alpha = if (isEnable) {
TV_SUBMIT_ENABLE_ALPHA
} else {
TV_SUBMIT_UNABLE_ALPHA
}
}
companion object {
private const val PHONE_NUMBER_PATTERN = "^1\\d{10}$"
private const val MASK = "****"
private const val PHONE_NUMBER_LENGTH = 11
private const val VALIDATE_CODE_LENGTH = 6
const val DIALOG_TYPE_BIND_PHONE = 0
const val DIALOG_TYPE_CHANGE_PHONE = 1
const val DIALOG_TYPE_VERIFY_PHONE = 2
private const val COUNT_DOWN_DURATION = 60L
private const val TV_SUBMIT_ENABLE_ALPHA = 1F
private const val TV_SUBMIT_UNABLE_ALPHA = 0.4F
fun create(
context: Context,
dialogType: Int,
phoneNumber: String,
serviceId: String,
gameId: String,
repository: ReserveReminderRepository,
listener: OnReserveReminderListener
) =
ReserveReminderPhoneNumberDialog(
context,
com.gh.gamecenter.common.R.style.DialogWindowTransparent,
dialogType,
phoneNumber,
serviceId,
gameId,
repository,
listener
)
}
}

View File

@ -1,499 +0,0 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import android.view.*
import android.view.ViewGroup.MarginLayoutParams
import androidx.core.view.updateLayoutParams
import com.gh.common.pop.EditBindPhoneInfoPop
import com.gh.common.pop.EditBindWechatPop
import com.gh.common.pop.RealNameTipsPop
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.WechatConfigEntity
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.entity.ReserveReminderEntity
import com.gh.gamecenter.login.entity.UserInfoEntity
import com.gh.gamecenter.login.user.UserManager
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.reserve.OnReserveReminderListener
class ReserveSuccessReminderDialog(
context: Context,
themeResId: Int,
private val listener: OnReserveReminderListener
) :
Dialog(context, themeResId), OnReserveSuccessListener {
private var reserveReminder = ReserveReminderEntity()
private val handler = Handler(Looper.getMainLooper())
private val handlers = arrayListOf<ReminderContentHandler>()
private lateinit var binding: DialogReserveSuccessWithSmsBinding
private val realNameQuestionPop by lazy {
RealNameTipsPop.create(context, listener)
}
private var hasAutoPopped = false
private var isInit = true
override fun onTouchEvent(event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_UP) {
if (realNameQuestionPop.isShowing) {
realNameQuestionPop.dismiss()
return true
} else if (handlers.any { it.hasPopShowing }) {
handlers.forEach {
it.dismissPop()
}
return true
}
}
return super.onTouchEvent(event)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DialogReserveSuccessWithSmsBinding.inflate(LayoutInflater.from(context))
setContentView(binding.root)
binding.ivClose.setOnClickListener {
dismiss()
}
binding.ivQuestion.setOnClickListener {
realNameQuestionPop.showAtLocation(binding.cbAutoDownload, Gravity.BOTTOM, 0, 4F.dip2px())
}
}
private fun initView() {
handlers.clear()
binding.flContentContainer.removeAllViews()
val configTypes = mutableListOf<Int>()
// 短信
if (reserveReminder.hasSmsConfig) {
if (reserveReminder.smsConfig.notice) {
configTypes.add(SMS_REMINDER_ENABLE_TYPE)
} else {
configTypes.add(SMS_REMINDER_UNABLE_TYPE)
}
}
// 微信
if (reserveReminder.wechatConfig.isReminderEnable) {
configTypes.add(WECHAT_REMINDER_ENABLE_TYPE)
} else {
configTypes.add(WECHAT_REMINDER_UNABLE_TYPE)
}
// 日历
if (reserveReminder.hasCalendarConfig) {
if (reserveReminder.calendarConfig.notice) {
configTypes.add(CALENDAR_REMINDER_ENABLE_TYPE)
} else {
configTypes.add(CALENDAR_REMINDER_UNABLE_TYPE)
}
}
if (configTypes.size == 1) {
// 只有微信提醒
if (configTypes.first() == WECHAT_REMINDER_ENABLE_TYPE) {
binding.tvContent.setText(R.string.reverse_success_with_reminder_tips)
handlers.add(
WechatReminderEnableHandler(reserveReminder.wechatConfig, 8.dp, binding.flContentContainer, this)
)
} else {
binding.tvContent.setText(R.string.reverse_success_without_reminder_tips)
handlers.add(OnlyWechatReminderUnableHandler(16.dp, binding.flContentContainer, this))
}
} else {
binding.tvContent.setText(R.string.reverse_success_with_reminder_tips)
var isLargerSpacing = true
fun getPaddingTop(): Int {
val paddingTop = if (isLargerSpacing) 16.dp else 8.dp
isLargerSpacing = false
return paddingTop
}
configTypes.sorted().forEach {
when (it) {
SMS_REMINDER_ENABLE_TYPE -> {
isLargerSpacing = true
SmsReminderEnableHandler(reserveReminder.smsConfig, 8.dp, binding.flContentContainer, this)
}
SMS_REMINDER_UNABLE_TYPE -> {
SmsReminderUnableHandler(getPaddingTop(), binding.flContentContainer, this)
}
WECHAT_REMINDER_ENABLE_TYPE -> {
isLargerSpacing = true
WechatReminderEnableHandler(
reserveReminder.wechatConfig,
8.dp,
binding.flContentContainer,
this
)
}
WECHAT_REMINDER_UNABLE_TYPE ->
WechatReminderUnableHandler(getPaddingTop(), binding.flContentContainer, this)
CALENDAR_REMINDER_ENABLE_TYPE -> {
isLargerSpacing = true
CalendarReminderEnableHandler(8.dp, binding.flContentContainer, this)
}
CALENDAR_REMINDER_UNABLE_TYPE ->
CalendarReminderUnableHandler(getPaddingTop(), binding.flContentContainer, this)
else -> null
}?.let(handlers::add)
}
}
handlers.forEach {
binding.flContentContainer.addView(it.init())
}
if (isInit) {
isInit = false
binding.gAutoDownload.goneIf(!reserveReminder.isEnableAutoDownload)
if (reserveReminder.isEnableAutoDownload) {
binding.cbAutoDownload.isChecked = reserveReminder.wifiAutoDownload
checkIfShowRealNamePop()
}
binding.cbAutoDownload.setOnCheckedChangeListener { _, isChecked ->
listener.enableAutoDownload(isChecked)
checkIfShowRealNamePop()
}
}
}
private fun checkIfShowRealNamePop() {
if (hasAutoPopped) {
return
}
hasAutoPopped = true
handler.postDelayed({
val idCard = UserManager.getInstance().userInfoEntity?.idCard
if (idCard != null && idCard.status != 1 && idCard.minor != true) {
// 账号已实名
return@postDelayed
}
val deviceCertificationInfoString =
SPUtils.getString(Constants.SP_DEVICE_CERTIFICATION_PREFIX + HaloApp.getInstance().gid)
if (!TextUtils.isEmpty(deviceCertificationInfoString)) {
val deviceIdCard = deviceCertificationInfoString.toObject<UserInfoEntity>()?.idCard
if (deviceIdCard != null && deviceIdCard.status != 1 && deviceIdCard.minor != true) {
// 设备已实名
return@postDelayed
}
}
realNameQuestionPop.showAtLocation(binding.cbAutoDownload, Gravity.BOTTOM, 0, 0)
}, 16)
}
override fun updateSmsReminder(isEnable: Boolean) {
listener.updateSmsReminder(isEnable)
}
override fun updateWechatReminder() {
listener.updateWechatReminder()
}
override fun changePhoneNumber() {
listener.changedPhoneNumber()
}
override fun verifyPhoneNumber() {
listener.verifyPhoneNumber()
}
override fun changeWechatBinding() {
listener.changeWechatBinding()
}
override fun updateCalendarReminder() {
listener.updateCalendarReminder()
}
override fun onStart() {
super.onStart()
window?.let {
it.setDimAmount(0.4F)
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val params = it.attributes
params.width = DisplayUtils.dip2px(300F)
it.attributes = params
}
}
fun updateReserveReminder(reserveReminder: ReserveReminderEntity) {
this.reserveReminder = reserveReminder
initView()
}
override fun dismiss() {
handler.removeCallbacksAndMessages(null)
super.dismiss()
}
companion object {
private val Int.dp: Int
get() = DisplayUtils.dip2px(this.toFloat())
private const val SMS_REMINDER_ENABLE_TYPE = 1
private const val WECHAT_REMINDER_ENABLE_TYPE = 2
private const val CALENDAR_REMINDER_ENABLE_TYPE = 3
private const val SMS_REMINDER_UNABLE_TYPE = 4
private const val WECHAT_REMINDER_UNABLE_TYPE = 5
private const val CALENDAR_REMINDER_UNABLE_TYPE = 6
fun create(context: Context, listener: OnReserveReminderListener) =
ReserveSuccessReminderDialog(
context,
com.gh.gamecenter.common.R.style.DialogWindowTransparent,
listener
).apply {
}
}
abstract class ReminderContentHandler(
val topMargin: Int,
val parent: ViewGroup,
val listener: OnReserveSuccessListener
) {
open val hasPopShowing: Boolean = false
fun init(): View {
val root = createView(LayoutInflater.from(parent.context))
root.updateLayoutParams<MarginLayoutParams> {
this.topMargin = this@ReminderContentHandler.topMargin
}
initView()
return root
}
protected abstract fun createView(inflater: LayoutInflater): View
protected abstract fun initView()
open fun dismissPop() = Unit
}
class SmsReminderUnableHandler(topMargin: Int, parent: ViewGroup, listener: OnReserveSuccessListener) :
ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveSmsReminderUnableBinding
override fun createView(inflater: LayoutInflater): View {
return LayoutReserveSmsReminderUnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
}
override fun initView() {
binding.vSmsAdd.setOnClickListener {
listener.updateSmsReminder(true)
}
}
}
class WechatReminderUnableHandler(topMargin: Int, parent: ViewGroup, listener: OnReserveSuccessListener) :
ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveWechatReminderUnableBinding
override fun createView(inflater: LayoutInflater): View {
return LayoutReserveWechatReminderUnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
}
override fun initView() {
binding.vWechatAdd.setOnClickListener {
listener.updateWechatReminder()
}
}
}
class SmsReminderEnableHandler(
private val smsConfig: ReserveReminderEntity.SmsConfig,
topMargin: Int,
parent: ViewGroup, listener:
OnReserveSuccessListener
) :
ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveSmsReminderEnableBinding
override val hasPopShowing: Boolean
get() = editBindPhoneInfoPop.isShowing
override fun dismissPop() {
if (hasPopShowing) {
editBindPhoneInfoPop.dismiss()
}
}
private val editBindPhoneInfoPop by lazy {
EditBindPhoneInfoPop.create(parent.context, smsConfig.mobileValidated, listener)
}
override fun createView(inflater: LayoutInflater) =
LayoutReserveSmsReminderEnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
override fun initView() {
binding.tvPhone.text = smsConfig.mobile
binding.vSmsEdit.setOnClickListener {
editBindPhoneInfoPop.showAsDropDown(
binding.ivSmsEdit,
(-104).dp,
0,
)
}
}
}
class WechatReminderEnableHandler(
private val wechatConfig: WechatConfigEntity,
topMargin: Int,
parent: ViewGroup,
listener: OnReserveSuccessListener
) :
ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveWechatReminderEnableBinding
private val editWechatPop by lazy {
EditBindWechatPop.create(parent.context, listener)
}
override fun createView(inflater: LayoutInflater) =
LayoutReserveWechatReminderEnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
override fun initView() {
binding.tvWechat.text = wechatConfig.nickName
binding.vModifyWechat.setOnClickListener {
editWechatPop.showAsDropDown(
binding.ivModifyWechat,
(-104).dp,
0
)
}
}
}
class OnlyWechatReminderUnableHandler(topMargin: Int, parent: ViewGroup, listener: OnReserveSuccessListener) :
ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveOnlyWechatUnableBinding
override fun createView(inflater: LayoutInflater) =
LayoutReserveOnlyWechatUnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
override fun initView() {
binding.vSubmitBackground.setOnClickListener {
listener.updateWechatReminder()
}
}
}
class CalendarReminderUnableHandler(
topMargin: Int,
parent: ViewGroup,
listener: OnReserveSuccessListener
) : ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveWechatReminderUnableBinding
// 复用微信提醒未开启状态布局
override fun createView(inflater: LayoutInflater) =
LayoutReserveWechatReminderUnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
override fun initView() {
binding.tvWechatReminderTitle.setText(R.string.calendar_reminders)
binding.tvWechatReminderDescription.setText(R.string.calendar_reminders_description)
binding.vWechatAdd.setOnClickListener {
listener.updateCalendarReminder()
}
}
}
class CalendarReminderEnableHandler(
topMargin: Int,
parent: ViewGroup,
listener: OnReserveSuccessListener
) : ReminderContentHandler(topMargin, parent, listener) {
private lateinit var binding: LayoutReserveCalendarReminderUnableBinding
override fun createView(inflater: LayoutInflater) =
LayoutReserveCalendarReminderUnableBinding.inflate(inflater, parent, false)
.also {
binding = it
}.root
override fun initView() {
}
}
}
interface OnReserveSuccessListener {
fun updateSmsReminder(isEnable: Boolean)
fun updateWechatReminder()
fun changePhoneNumber()
fun verifyPhoneNumber()
fun changeWechatBinding()
fun updateCalendarReminder()
}

View File

@ -1,63 +0,0 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.DialogWechatBindingConflictBinding
class WechatBindingConflictDialogFragment : BaseDialogFragment() {
private lateinit var binding: DialogWechatBindingConflictBinding
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
setCanceledOnTouchOutside(true)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return DialogWechatBindingConflictBinding.inflate(inflater, container, false)
.also {
binding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.tvIKnow.setOnClickListener {
dismiss()
}
}
override fun onStart() {
super.onStart()
dialog?.window?.let {
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val params = it.attributes
params.width = DisplayUtils.dip2px(300F)
it.attributes = params
}
}
companion object {
fun show(context: Context) {
if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
}?.let {
WechatBindingConflictDialogFragment().show(it, WechatBindingConflictDialogFragment::class.java.name)
}
}
}
}

View File

@ -1,125 +0,0 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.entity.ErrorEntity
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.DialogWechatBindingFailedBinding
import com.gh.gamecenter.login.user.UserManager
import com.lightgame.utils.Utils
class WechatBindingFailedDialogFragment : BaseDialogFragment() {
private lateinit var binding: DialogWechatBindingFailedBinding
private var currentUserId: String? = null
private lateinit var userConflict: ErrorEntity.Data.UserConflict
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
userConflict = arguments?.getParcelable(KEY_USER_CONFLICT) ?: ErrorEntity.Data.UserConflict()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
setCanceledOnTouchOutside(true)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return DialogWechatBindingFailedBinding.inflate(inflater, container, false)
.also {
binding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
UserManager.getInstance().userInfoEntity?.let {
currentUserId = it.getShortUserId()
binding.tvCurrentName.text = it.name ?: ""
binding.ivCurrentAvatar.displayAvatar(it.icon)
binding.tvUserId.text = getString(R.string.user_id, currentUserId)
}
binding.tvConflictName.text = userConflict.name
binding.ivConflictAvatar.displayAvatar(userConflict.icon)
binding.tvConflictUserId.text = getString(R.string.user_id, userConflict.seq)
binding.tvConflictProblem.setOnClickListener {
dismiss()
WechatBindingConflictDialogFragment.show(requireContext())
}
binding.tvIKnow.setOnClickListener {
dismiss()
}
binding.tvUserId.setOnLongClickListener {
currentUserId?.let {
copyTextToClipboard(it)
true
} ?: false
}
binding.tvConflictUserId.setOnLongClickListener {
copyTextToClipboard(userConflict.id)
true
}
}
private fun copyTextToClipboard(text: String) {
val clipboardManager = context?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
if (clipboardManager != null) {
val clip = ClipData.newPlainText(COPY_ID_TEXT, text)
clipboardManager.setPrimaryClip(clip)
Utils.toast(requireContext(), R.string.copy_user_id_successfully)
}
}
override fun onStart() {
super.onStart()
dialog?.window?.let {
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val params = it.attributes
params.width = DisplayUtils.dip2px(300F)
it.attributes = params
}
}
companion object {
private const val COPY_ID_TEXT = "user_id"
private const val KEY_USER_CONFLICT = "key_user_conflict"
fun show(context: Context, userConflict: ErrorEntity.Data.UserConflict?) {
if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
}?.let {
val fragment = WechatBindingFailedDialogFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_USER_CONFLICT, userConflict)
}
}
fragment.show(it, WechatBindingFailedDialogFragment::class.java.name)
}
}
}
}

View File

@ -1,54 +0,0 @@
package com.gh.common.exposure
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.IExposureStateChangeListener
import com.gh.gamecenter.feature.exposure.RecyclerViewExposureHelper
import com.lightgame.utils.Utils
class DefaultExposureStateChangeListener : IExposureStateChangeListener {
override fun onExposureStateChange(
exposureEvent: ExposureEvent,
position: Int,
inExposure: Boolean
) {
val exposureStatus = if (inExposure) "曝光中" else "结束曝光"
val isCPMExposureEvent = exposureEvent.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM
Utils.log(
RecyclerViewExposureHelper.TAG,
"onExposureStateChange: 名称 ${exposureEvent.payload.gameName} 位置 $position, $exposureStatus"
)
// 如果是 CPM 曝光事件,且在曝光中,直接上报 CPM 曝光 (内部有做简单的去重处理CPM 曝光追求一个及时上报,不用理会曝光时长)
if (isCPMExposureEvent && inExposure) {
Utils.log(
RecyclerViewExposureHelper.TAG,
"上报 CPM 曝光 ${exposureEvent.payload.gameName} ${exposureEvent.id}"
)
ExposureManager.logCPM(exposureEvent)
}
if (!inExposure
&& System.currentTimeMillis() - exposureEvent.timeInMillisecond > DEFAULT_VALID_EXPOSURE_THRESHOLD
) {
Utils.log(
RecyclerViewExposureHelper.TAG,
"上报曝光 ${exposureEvent.payload.gameName} ${exposureEvent.id},是否为 CPM 小游戏 -> ${isCPMExposureEvent}" +
"曝光时长为 ${System.currentTimeMillis() - exposureEvent.timeInMillisecond}ms"
)
// 标记当前 ExposureEvent 已经被使用过
exposureEvent.markIsUsed()
ExposureManager.log(exposureEvent)
}
}
companion object {
// 默认曝光有效时长
const val DEFAULT_VALID_EXPOSURE_THRESHOLD = 1000L
}
}

View File

@ -6,7 +6,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.LayoutManager
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.feature.exposure.ExposureEvent
import io.reactivex.functions.Consumer
@ -17,9 +16,8 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
val throttleBus: ExposureThrottleBus by lazy {
ExposureThrottleBus(
{ commitExposure(it) },
Consumer(Throwable::printStackTrace),
{ commitExternalExposure(it) }
Consumer { commitExposure(it) },
Consumer(Throwable::printStackTrace)
)
}
var layoutManager: LayoutManager? = null
@ -31,7 +29,6 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
if (fragment == f) {
visibleState?.let { commitExposure(it) }
visibleState?.let { commitExternalExposure(it) }
throttleBus.clear()
}
}
@ -96,43 +93,4 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
ExposureManager.log(eventList)
}
/**
* 提交第三方的曝光事件 微信小游戏CPM 和 DSP 游戏)
* 由于普通曝光事件的上报通道存在节流特性不符合CPM接口对于数据上报的实时性和准确性的要求所以使用额外的通道进行上报
*/
private fun commitExternalExposure(visibleState: ExposureThrottleBus.VisibleState) {
val cpmEventList = arrayListOf<ExposureEvent>()
val dspEventList = arrayListOf<ExposureEvent>()
for (pos in visibleState.firstVisiblePosition..visibleState.lastVisiblePosition) {
try {
exposable.getEventByPosition(pos)?.let {
when (it.payload.miniGameType) {
Constants.WECHAT_MINI_GAME_CPM -> cpmEventList.add(it)
Constants.DSP_GAME -> dspEventList.add(it)
else -> {
// do nothing
}
}
}
exposable.getEventListByPosition(pos)?.let { list ->
list.forEach {
when (it.payload.miniGameType) {
Constants.WECHAT_MINI_GAME_CPM -> cpmEventList.add(it)
Constants.DSP_GAME -> dspEventList.add(it)
else -> {
// do nothing
}
}
}
}
} catch (ignore: Exception) {
// Just ignore the error.
}
}
ExposureManager.logExternal(cpmEventList, dspEventList)
}
}

View File

@ -1,19 +1,13 @@
package com.gh.common.exposure
import com.aliyun.sls.android.producer.Log
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.loghub.TLogHubHelper
import com.gh.gamecenter.common.loghub.LoghubHelper
import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.dsp.DspReportHelper
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.minigame.wechat.WGameSubjectCPMListReportHelper
import com.google.gson.ExclusionStrategy
import com.google.gson.FieldAttributes
import com.google.gson.GsonBuilder
import com.lightgame.utils.Utils
import com.volcengine.model.tls.LogItem
/**
* A handful tool for committing logs to aliyun loghub.
@ -33,32 +27,11 @@ object ExposureManager {
private val exposureSet by lazy { hashSetOf<ExposureEvent>() }
private val exposureCache by lazy { FixedSizeLinkedHashSet<String>(300) }
private val gson by lazy {
GsonBuilder()
.addSerializationExclusionStrategy(object: ExclusionStrategy {
override fun shouldSkipClass(clazz: Class<*>): Boolean {
return false
}
override fun shouldSkipField(f: FieldAttributes): Boolean {
return f.name == "additional"
}
})
.create()
}
/**
* Log a single exposure event.
*/
fun log(event: ExposureEvent) {
AppExecutor.logExecutor.execute {
if (event.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM) {
WGameSubjectCPMListReportHelper.reportExposure(event)
} else if (event.payload.miniGameType == Constants.DSP_GAME) {
if (event.event == ExposureType.DOWNLOAD_COMPLETE) {
DspReportHelper.report(event.payload.downloadUrl)
}
}
if (!exposureCache.contains(event.id)) {
exposureSet.add(event)
exposureCache.add(event.id)
@ -85,32 +58,6 @@ object ExposureManager {
}
}
/**
* Log a collection of exposure event for external use.
*/
fun logExternal(cpmEventList: List<ExposureEvent>, dspEventList: ArrayList<ExposureEvent>) {
AppExecutor.logExecutor.execute {
if (cpmEventList.isNotEmpty()) {
WGameSubjectCPMListReportHelper.reportExposure(cpmEventList.toSet())
}
if (dspEventList.isNotEmpty()) {
for (event in dspEventList) {
DspReportHelper.report(event.payload.showUrl)
}
}
}
}
/**
* Log a wechat mini game cpm collection of exposure event.
*/
fun logCPM(event: ExposureEvent) {
AppExecutor.logExecutor.execute {
WGameSubjectCPMListReportHelper.reportExposure(event)
}
}
/**
* @param forcedUpload Ignore all restrictions.
*/
@ -131,22 +78,21 @@ object ExposureManager {
private fun uploadExposures(eventSet: HashSet<ExposureEvent>, forced: Boolean) {
eventSet.forEach {
TLogHubHelper.sendLog(buildLog(it), LOG_STORE)
// LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced)
LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced)
// it.recycle()
}
}
private fun buildLog(event: ExposureEvent) = LogItem(System.currentTimeMillis()).apply {
addContent("__id", event.id)
addContent("payload", gson.toJson(event.payload))
addContent("event", event.event.toString())
addContent("source", eliminateMultipleBrackets(gson.toJson(event.source)))
addContent("meta", gson.toJson(event.meta))
addContent("real_millisecond", event.timeInMillisecond.toString())
addContent(
private fun buildLog(event: ExposureEvent) = Log().apply {
putContent("id", event.id)
putContent("payload", event.payload.toJson())
putContent("event", event.event.toString())
putContent("source", eliminateMultipleBrackets(event.source.toJson()))
putContent("meta", event.meta.toJson())
putContent("real_millisecond", event.timeInMillisecond.toString())
putContent(
"e-traces", if (event.eTrace != null) {
eliminateMultipleBrackets(gson.toJson(event.eTrace))
eliminateMultipleBrackets(event.eTrace?.toJson() ?: "")
} else ""
)
}

View File

@ -3,20 +3,16 @@ package com.gh.common.exposure
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.BehaviorSubject
import io.reactivex.subjects.PublishSubject
import java.util.concurrent.TimeUnit
class ExposureThrottleBus(
var onSuccess: Consumer<VisibleState>,
var onError: Consumer<Throwable>,
onPreSuccess: Consumer<VisibleState>
) {
class ExposureThrottleBus(var onSuccess: Consumer<VisibleState>, var onError: Consumer<Throwable>) {
companion object {
private const val THRESHOLD_TIME = 300L
}
private val mPublishSubject: BehaviorSubject<VisibleState> = BehaviorSubject.create()
private val mPublishSubject: PublishSubject<VisibleState> = PublishSubject.create()
private val mCompositeDisposable: CompositeDisposable = CompositeDisposable()
init {
@ -28,7 +24,6 @@ class ExposureThrottleBus(
*/
val disposable = mPublishSubject
.distinctUntilChanged()
.doOnNext(onPreSuccess)
.throttleWithTimeout(THRESHOLD_TIME, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.subscribe(onSuccess, onError)

View File

@ -8,13 +8,13 @@ object ExposureTraceUtils {
val traceList = arrayListOf<ExposureEvent>()
event?.let {
//这里使用 copy是为了防止循环引用调用hashCode方法触发StackOverflowError错误
val exposureCopy = it.shallowCopy()
if (exposureCopy.eTrace == null) {
traceList.add(exposureCopy)
//这里使用deepCopy是为了防止循环引用调用hashCode方法触发StackOverflowError错误
val deepCopy = it.deepCopy()
if (deepCopy.eTrace == null) {
traceList.add(deepCopy)
} else {
traceList.addAll(exposureCopy.eTrace!!)
traceList.add(flattenTrace(exposureCopy))
traceList.addAll(deepCopy.eTrace!!)
traceList.add(flattenTrace(deepCopy))
}
}

View File

@ -27,7 +27,7 @@ object ExposureUtils {
): ExposureEvent {
val gameEntity = entity.copy()
gameEntity.id = if (entity.id.contains(DownloadEntity.GAME_ID_DIVIDER)) {
entity.id.split(DownloadEntity.GAME_ID_DIVIDER).toTypedArray().firstOrNull() ?: ""
entity.id.split(DownloadEntity.GAME_ID_DIVIDER).toTypedArray()[0]
} else {
entity.id
}
@ -53,6 +53,7 @@ object ExposureUtils {
return exposureEvent
}
@JvmStatic
fun logADownloadCompleteExposureEvent(
entity: GameEntity,
platform: String?,
@ -60,19 +61,18 @@ object ExposureUtils {
speed: Long,
host: String? = "unknown",
path: String? = "unknown",
redirectedUrlList: String? = "unknown",
downloadType: DownloadType
): ExposureEvent? {
) {
val gameEntity = entity.copy()
gameEntity.platform = platform
gameEntity.downloadCompleteType = downloadType.toString()
val traceEvent = trace?.toObject<ExposureEvent>()
if (TextUtils.isEmpty(entity.id)) return null
if (TextUtils.isEmpty(entity.id)) return
// 避免生成 trace 相同的下载完成事件,根据日志看下载完成的同一秒有可能生成两条
if (mDownloadCompleteTraceEventIdSet.contains(traceEvent?.id)) {
return null
return
}
traceEvent?.payload?.gameId?.let { mDownloadCompleteTraceEventIdSet.add(it) }
@ -88,19 +88,15 @@ object ExposureUtils {
exposureEvent.payload.host = host
exposureEvent.payload.path = path
exposureEvent.payload.speed = speed
exposureEvent.payload.redirectedUrlList = redirectedUrlList
exposureEvent.payload.downloadUrl = gameEntity.downloadUrl
ExposureManager.log(exposureEvent)
ExposureManager.commitSavedExposureEvents(forcedUpload = true)
return exposureEvent
}
@JvmStatic
fun getDownloadType(apkEntity: ApkEntity, gameId: String, asVGame: Boolean): DownloadType {
fun getDownloadType(apkEntity: ApkEntity, gameId: String, isVGame: Boolean): DownloadType {
return when {
asVGame -> getVGameDownloadType(apkEntity, gameId)
isVGame -> getVGameDownloadType(apkEntity, gameId)
PackageUtils.isInstalled(
HaloApp.getInstance().application,
apkEntity.packageName
@ -111,7 +107,7 @@ object ExposureUtils {
private fun getVGameDownloadType(apkEntity: ApkEntity, gameId: String): DownloadType {
return when {
PackagesManager.isCanUpdate(gameId, apkEntity.packageName, asVGame = true) -> DownloadType.FUN_UPDATE
PackagesManager.isCanUpdate(gameId, apkEntity.packageName) -> DownloadType.FUN_UPDATE
else -> DownloadType.FUN_DOWNLOAD
}
}

View File

@ -4,7 +4,6 @@ import android.annotation.SuppressLint
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.PackageFlavorHelper
import com.gh.gamecenter.common.utils.debounceActionWithInterval
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.common.utils.toObject
@ -124,16 +123,10 @@ object RegionSettingHelper {
mIsInit = false
}
val fakeIp = if (PackageFlavorHelper.IS_TEST_FLAVOR) {
SPUtils.getString(Constants.SP_TEST_FLAVOR_IP)
} else {
""
}
// 使用默认的 Schdulers.io() 可能会触发 OOM
RetrofitManager.getInstance()
.api
.getRegionSetting(HaloApp.getInstance().channel, fakeIp)
.getRegionSetting(HaloApp.getInstance().channel)
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<RegionSetting>() {
override fun onSuccess(data: RegionSetting) {

View File

@ -1,45 +0,0 @@
package com.gh.common.fragment
import androidx.fragment.app.FragmentManager
import java.lang.reflect.Field
fun FragmentManager.popBackStackAllowStateLoss() {
popBackStackAllowStateLoss(-1, 0)
}
fun FragmentManager.popBackStackAllowStateLoss(id: Int, flags: Int) {
if (!isStateSaved) {
popBackStack(id, flags)
}
}
fun FragmentManager.popBackStackAllowStateLoss(name: String?, flags: Int) {
if (!isStateSaved) {
popBackStack(name, flags)
}
}
fun FragmentManager.popBackStackImmediateAllowStateLoss() = popBackStackAllowStateLoss(-1, 0)
fun FragmentManager.popBackStackImmediateAllowStateLoss(id: Int, flags: Int) =
if (!isStateSaved) {
popBackStackImmediate(id, flags)
} else {
false
}
@Throws(NoSuchFieldException::class)
private fun getField(clazz: Class<*>, name: String): Field {
var cls: Class<*>? = clazz
while (cls != null) {
try {
val declaredField = cls.getDeclaredField(name)
declaredField.isAccessible = true
return declaredField
} catch (e: NoSuchFieldException) {
e.printStackTrace()
}
cls = cls.superclass
}
throw NoSuchFieldException()
}

View File

@ -7,20 +7,19 @@ import androidx.room.TypeConverters
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.entity.HistoryGameDetailEntity
import com.gh.gamecenter.entity.HistoryGameEntity
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.feature.entity.NewsEntity
import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.feature.entity.ArticleEntity
import com.gh.gamecenter.feature.entity.NewsEntity
import com.gh.gamecenter.feature.room.converter.*
import com.gh.gamecenter.room.converter.*
import com.gh.gamecenter.room.dao.*
import com.halo.assistant.HaloApp
@Database(
entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class, GamesCollectionEntity::class, HistoryGameDetailEntity::class],
version = 15,
entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class, GamesCollectionEntity::class],
version = 13,
exportSchema = false
)
@TypeConverters(
@ -42,8 +41,7 @@ import com.halo.assistant.HaloApp
SimpleGameListConverter::class,
TagInfoListConverter::class,
ActivityLabelListConverter::class,
IconFloatConverter::class,
SectionConverter::class
IconFloatConverter::class
)
abstract class HistoryDatabase : RoomDatabase() {
@ -54,7 +52,6 @@ abstract class HistoryDatabase : RoomDatabase() {
abstract fun gameDao(): GameDao
abstract fun videoHistoryDao(): VideoHistoryDao
abstract fun gamesCollectionDao(): GamesCollectionDao
abstract fun gameDetailDao(): GameDetailHistoryDao
companion object {
@ -146,20 +143,6 @@ abstract class HistoryDatabase : RoomDatabase() {
}
}
val MIGRATION_13_14: Migration = object : Migration(13, 14) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("Alter TABLE ArticleEntity add type TEXT NOT NULL DEFAULT 'community_article'")
database.execSQL("Alter TABLE ArticleEntity add sections TEXT NOT NULL DEFAULT ''")
database.execSQL("Alter TABLE ArticleEntity add tagActivityName TEXT NOT NULL DEFAULT ''")
}
}
val MIGRATION_14_15: Migration = object : Migration(14, 15) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE HistoryGameDetailEntity (id TEXT NOT NULL PRIMARY KEY, name TEXT DEFAULT '')")
}
}
val instance by lazy {
Room.databaseBuilder(
HaloApp.getInstance().application,
@ -177,8 +160,6 @@ abstract class HistoryDatabase : RoomDatabase() {
.addMigrations(MIGRATION_10_11)
.addMigrations(MIGRATION_11_12)
.addMigrations(MIGRATION_12_13)
.addMigrations(MIGRATION_13_14)
.addMigrations(MIGRATION_14_15)
.build()
}
}

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