Compare commits
371 Commits
pack/test-
...
feat/vacor
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b1a368047 | |||
| 30135bdb8f | |||
| f8ac85d29c | |||
| 39bba71e7a | |||
| 5daddeadda | |||
| 58b1c0295c | |||
| a56082d002 | |||
| 877ab7cf39 | |||
| 428e3496d8 | |||
| b33419ea05 | |||
| e9bcd0a0d6 | |||
| 98b877671a | |||
| 6c61a62799 | |||
| 391e409ee1 | |||
| cfd1ee845a | |||
| 34b123a0a7 | |||
| 51515171a8 | |||
| 24941a165a | |||
| 9d661eefa7 | |||
| 373fa7fc80 | |||
| d9743a89d6 | |||
| 0f596836dc | |||
| eb08575f3e | |||
| 405268bbce | |||
| 2453e34a74 | |||
| 2830367826 | |||
| 782d94289f | |||
| 3e2c2fe18f | |||
| 1afd154364 | |||
| b24cac0cb1 | |||
| d5db516112 | |||
| b2a7a606e5 | |||
| 219866e195 | |||
| dea7ceb5f6 | |||
| da1da1c1af | |||
| 9b4fa45492 | |||
| 01df42b76b | |||
| cef8aa1968 | |||
| 4147612d9b | |||
| 9b57d10e2d | |||
| 19f4e70ada | |||
| 49b7e4c245 | |||
| 638de59562 | |||
| 69b092be46 | |||
| 27d1d02d58 | |||
| e4bfa5e6bf | |||
| 3ea3238011 | |||
| 2dcae2168b | |||
| 4b1c198818 | |||
| e42e2fbd56 | |||
| 713e4157db | |||
| 76cf7dce1d | |||
| 37a3689a2c | |||
| 7429f17538 | |||
| 32ba015686 | |||
| e5365fd527 | |||
| 1c873d0194 | |||
| 1424ee2b45 | |||
| 69cb916364 | |||
| 04f1d712cd | |||
| ee14ae51be | |||
| 4683217e44 | |||
| df94d6677a | |||
| 6f85e12edf | |||
| 020c826f1d | |||
| 5640d778a2 | |||
| 2300475a9e | |||
| 612b4061d5 | |||
| 49c7ff8f8e | |||
| 1c408f3966 | |||
| 055f5b23da | |||
| 9810b3e8fe | |||
| dba7042b12 | |||
| 6695dc596e | |||
| 079ba014f8 | |||
| 14eeb00539 | |||
| 56843f18d4 | |||
| 53a46892a4 | |||
| a2153761c2 | |||
| 26a8c0abd8 | |||
| 21bf0fd8e9 | |||
| 9787d23ea0 | |||
| 6ae34b81db | |||
| 0b1e770c03 | |||
| f4681dab31 | |||
| 79a7f994eb | |||
| 3276fca27c | |||
| 372db8e52c | |||
| 9b6d986f1c | |||
| 0e88db1600 | |||
| 05b59c8732 | |||
| 28f68cae95 | |||
| 22713db44e | |||
| d9389ac4aa | |||
| 31ec9311fc | |||
| fca62df263 | |||
| 978c01d7dc | |||
| b7a24e331a | |||
| b1eac6a043 | |||
| 9f8a712be6 | |||
| 930ab904ed | |||
| 3c207244e6 | |||
| 0f59e03afa | |||
| c5d99fa304 | |||
| a313cd8050 | |||
| ce477e2bd0 | |||
| 7cf2adaa37 | |||
| 0852497df2 | |||
| 592df6ea44 | |||
| 7b5d1b1bf3 | |||
| 5b1a614eb7 | |||
| ae9fbfb8c4 | |||
| 48b118d342 | |||
| 39625369d7 | |||
| 05b9920f6d | |||
| 8a5fa2c31a | |||
| c2dc6d7dbe | |||
| a027442ae6 | |||
| ba1584f642 | |||
| 4124d571b7 | |||
| a545401ca3 | |||
| 4b7f2401dd | |||
| daa1e4fc64 | |||
| 064135a057 | |||
| b56946d6f0 | |||
| 1a46d371e4 | |||
| d2a062907a | |||
| 56e945eb43 | |||
| 91579194a4 | |||
| c42a7d5963 | |||
| d2293bd881 | |||
| db4eb9f811 | |||
| 24d95b8e95 | |||
| 435dac11a1 | |||
| bffa2dab7f | |||
| 136975c067 | |||
| f389fcc206 | |||
| 9c5ef246a4 | |||
| 5f71f52fe1 | |||
| 2bfa0c1031 | |||
| 97c9dd9923 | |||
| cc3733e6fe | |||
| cacdc13b9a | |||
| ab3ebd7b37 | |||
| 08879b63da | |||
| ca8d41bac2 | |||
| 31c54b8f3b | |||
| 038da5dae2 | |||
| 3bcf332dfa | |||
| ee7723a4d8 | |||
| aed68e3268 | |||
| 6902e748e4 | |||
| fa9186cb54 | |||
| 119a684112 | |||
| 72d8016c4b | |||
| 6569eecbb1 | |||
| 83cb925be2 | |||
| a98b54269a | |||
| 570cf800e5 | |||
| 83ec4414f9 | |||
| 004bd3421a | |||
| f365a80a84 | |||
| ff078ab2a1 | |||
| 0ba49550b3 | |||
| 251e867833 | |||
| ca20d7e2a3 | |||
| 8fb4b373d3 | |||
| 58fa40fe08 | |||
| cd4f2783b5 | |||
| 4ee735b8cd | |||
| 605b886315 | |||
| 54eb44d072 | |||
| 5866b0d28a | |||
| 9f47f30f38 | |||
| dcb3fa3910 | |||
| 12bbd008d8 | |||
| 49b35b2837 | |||
| 1269560541 | |||
| a788b7b485 | |||
| f47a2db92b | |||
| aa41551c4e | |||
| 813634379a | |||
| e884e9b45a | |||
| e86a301d10 | |||
| 89bdafe7ed | |||
| 8dc4b86790 | |||
| 989d1578ef | |||
| ba3b86a00e | |||
| 2a279762e1 | |||
| 574ae0eece | |||
| 9412c255eb | |||
| c2c6901b04 | |||
| e8cca4b491 | |||
| b4e2685f19 | |||
| 8f9c5fac95 | |||
| e28a4a8fed | |||
| 45b4d1214e | |||
| a7dc78b969 | |||
| 11a0d55d12 | |||
| 398ff16f76 | |||
| 5d7056735a | |||
| 3bd0444dde | |||
| 4d2d3d24ee | |||
| 7310056d2e | |||
| 5cf8b80ea4 | |||
| bf5b7ced89 | |||
| b1e44ea89b | |||
| 1f5b9bde3e | |||
| c57063bcfe | |||
| 5fd7d0bb62 | |||
| a45d6ce0b4 | |||
| dcff648d37 | |||
| 513938da99 | |||
| 6490111940 | |||
| 56437855d8 | |||
| 29facb49df | |||
| f023a315b9 | |||
| b9d217d773 | |||
| cbdab7cd50 | |||
| 5b2f710be8 | |||
| b15dafb852 | |||
| 37b36a9632 | |||
| 17495e3699 | |||
| d9ee277e82 | |||
| bb6bdb1351 | |||
| 204300ca98 | |||
| 24815cd398 | |||
| b963281eb6 | |||
| 95721268f7 | |||
| dfd542f5df | |||
| 14522e5d07 | |||
| 71efe3b69a | |||
| b8cbbc0301 | |||
| 2fe8051280 | |||
| 0d4a893552 | |||
| e07216365a | |||
| 1c04e966d9 | |||
| ba0ad10f61 | |||
| 9592731033 | |||
| 0dc9fb1aa3 | |||
| fd450f0d67 | |||
| 57984d160f | |||
| 165ca21926 | |||
| e19c091532 | |||
| 5db6b3511f | |||
| 8557b230ac | |||
| 44a817be12 | |||
| c76e0b8bfa | |||
| bbbd77b8ab | |||
| 08ab5ec727 | |||
| 39afbecce8 | |||
| 4229f0e335 | |||
| efae6cb459 | |||
| 8f8cfb757f | |||
| 1e894e1158 | |||
| 96b479b8f0 | |||
| 342eefe7ba | |||
| e9c9f6f66b | |||
| 7da90ffb0b | |||
| c71f8676dd | |||
| 50555cb217 | |||
| 766e4fc3ab | |||
| c091e496e7 | |||
| ecd81ea353 | |||
| 21e7198589 | |||
| d6c97bc215 | |||
| 321e9b6ee6 | |||
| 7cc3e7ec67 | |||
| 08dac2eb42 | |||
| 85c7746206 | |||
| a35700e2f7 | |||
| 6a44294338 | |||
| b8c275d8fc | |||
| 638bf86d1e | |||
| 158c46f210 | |||
| a28ef7d20b | |||
| bae20a4e7d | |||
| 4a2f0896bb | |||
| 51ccc532d5 | |||
| 1bf977f3e4 | |||
| da2aeeeaf2 | |||
| 52d160a0e0 | |||
| cbba9c09b5 | |||
| 3c877ada98 | |||
| 9b95e01d33 | |||
| 567576fc04 | |||
| 1b7913a00e | |||
| 05e2719e1c | |||
| 8ed10c411a | |||
| f9f4bb84b4 | |||
| 44a2e616ab | |||
| fffd3ef789 | |||
| d53782b8de | |||
| b16c5d723b | |||
| 1dfd636283 | |||
| 65feed01f4 | |||
| 2a596bd2a0 | |||
| 16c4f1016c | |||
| 1ced82c1f6 | |||
| 078c9204af | |||
| 68818b3409 | |||
| 7d4aa34d12 | |||
| 209c3d7d30 | |||
| 2a27e0f467 | |||
| 54ee8a9c69 | |||
| 2b44efd6b3 | |||
| d62c8beb30 | |||
| 155ec08280 | |||
| d46aa81dbe | |||
| 51c0bf27cf | |||
| 43eb4c88c9 | |||
| 06b2d2b416 | |||
| af7580a6a6 | |||
| 1e4375ec8a | |||
| 195247a5c3 | |||
| dd65bc8bc2 | |||
| 196e719358 | |||
| b1c267b179 | |||
| a2679c8dbd | |||
| c9e1816be0 | |||
| a1f0455d5a | |||
| 5b3f4b6104 | |||
| fe4e9d9d3b | |||
| dd051b4d13 | |||
| e7f756555c | |||
| 9488837e9e | |||
| b8c4f1403b | |||
| b88698c2a3 | |||
| c897d5ad0f | |||
| 037f453a75 | |||
| ad3a3c1341 | |||
| ba320f7740 | |||
| f3dbc0b779 | |||
| 0c518ac40e | |||
| ccc0140bba | |||
| bf57118900 | |||
| b80a14f2b1 | |||
| 2c044d0ee4 | |||
| 1450064640 | |||
| 90e19d5099 | |||
| 383124dc36 | |||
| 6d6ce2613a | |||
| 8569264b82 | |||
| 59667abf09 | |||
| 5201637326 | |||
| 417c41c8a0 | |||
| b651ef8617 | |||
| af67894d4e | |||
| 76e17eddd7 | |||
| f8c9c41eb0 | |||
| 40ac173389 | |||
| c6bc7ca6cc | |||
| f01e08aec9 | |||
| faddf5d7b6 | |||
| 81cf2f0ddc | |||
| 198561d15a | |||
| 1e721b699c | |||
| 8f48dfd347 | |||
| bc811a2882 | |||
| bdccbc4c28 | |||
| bfd986fdfd | |||
| a2bd5e01e0 | |||
| 844d227f19 | |||
| 8b1f92e9c4 | |||
| f5834d440b | |||
| f982bf6478 | |||
| 33d7afec71 | |||
| 37ef50f323 | |||
| 4c6acdee3a | |||
| 6beb060e63 | |||
| d11ccba0b7 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -9,4 +9,6 @@ build/
|
||||
release-app/
|
||||
test-app/
|
||||
scripts/apk-channel/
|
||||
app/src/test/java/com/gh/gamecenter
|
||||
app/src/test/java/com/gh/gamecenter
|
||||
app/src/main/assets-debug/
|
||||
app/src/main/assets-release/
|
||||
@ -71,7 +71,7 @@ android_build:
|
||||
exit_codes: 137
|
||||
only:
|
||||
- dev
|
||||
- feat/GHZSCY-5250
|
||||
- release
|
||||
|
||||
# 代码检查
|
||||
sonarqube_analysis:
|
||||
@ -127,6 +127,9 @@ oss-upload&send-email:
|
||||
- sysadm-devops
|
||||
stage: oss-upload&send-email
|
||||
image: hub.shanqu.cc/devops/android-apk-oss-upload:latest
|
||||
id_tokens:
|
||||
VAULT_ID_TOKEN:
|
||||
aud: https://vault.shanqu.cc
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
VAULT_ADDR: https://vault.shanqu.cc # 固定值
|
||||
@ -145,6 +148,7 @@ 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
|
||||
@ -152,4 +156,4 @@ oss-upload&send-email:
|
||||
- /usr/local/bin/python /ci-android-mail-jira-comment.py
|
||||
only:
|
||||
- dev
|
||||
- feat/GHZSCY-5250
|
||||
- release
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -8,3 +8,6 @@
|
||||
[submodule "ndownload"]
|
||||
path = ndownload
|
||||
url = ../../../android/ndownload.git
|
||||
[submodule "vasdk"]
|
||||
path = vasdk
|
||||
url = ../../../sdg/android/vasdk.git
|
||||
|
||||
@ -44,5 +44,4 @@
|
||||
|
||||
### 混淆配置
|
||||
|
||||
* 本项目使用了微信的 [AndResGuard](https://github.com/shwenzhang/AndResGuard) 作为资源混淆压缩方案,新增需要使用 `getIdentifier` 获取的资源文件时需要添加至白名单
|
||||
* 本项目默认使用 R8 作为混淆工具,往 proguard-rules.txt 添加 proguard 新配置项时请检查可用性(如语法等)
|
||||
|
||||
232
app/build.gradle
232
app/build.gradle
@ -3,7 +3,6 @@ apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android' // kotlin
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'AndResGuard'
|
||||
|
||||
import groovy.xml.XmlUtil
|
||||
|
||||
@ -75,7 +74,7 @@ android {
|
||||
versionName rootProject.ext.versionName
|
||||
applicationId rootProject.ext.applicationId
|
||||
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt', rootProject.ext.va_proguard_rules
|
||||
|
||||
String CORE_EVENT_GAME_CATEGORY = ""
|
||||
|
||||
@ -106,6 +105,9 @@ android {
|
||||
buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\""
|
||||
buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\""
|
||||
buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\""
|
||||
// 一体包的32位畅玩游戏助手包名
|
||||
buildConfigField "String", "EXT_PACKAGE_NAME", "\"${rootProject.ext.EXT_PACKAGE_NAME}\""
|
||||
buildConfigField "String", "VA_VERSION_NAME", "\"${rootProject.ext.VA_VERSION}\""
|
||||
}
|
||||
|
||||
// gradle 2.2以上默认同时启用v1和v2(优先用于Android N)
|
||||
@ -126,6 +128,10 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/gradle/incremental.annotation.processors'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
debuggable true
|
||||
@ -164,6 +170,15 @@ android {
|
||||
flavorDimensions("env", "region")
|
||||
|
||||
sourceSets {
|
||||
|
||||
debug {
|
||||
assets.srcDirs += 'src/main/assets-debug'
|
||||
}
|
||||
|
||||
release {
|
||||
assets.srcDirs += 'src/main/assets-release'
|
||||
}
|
||||
|
||||
publish {
|
||||
java.srcDirs = ['src/main/java', "src/default/java"]
|
||||
}
|
||||
@ -303,7 +318,6 @@ dependencies {
|
||||
kuaishouImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/kuaishou/libs')
|
||||
gdtImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/gdt/libs')
|
||||
smImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/sm/libs')
|
||||
testImplementation 'junit:junit:4.12'
|
||||
|
||||
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakcanary}"
|
||||
debugImplementation "com.squareup.leakcanary:leakcanary-android-process:${leakcanary}"
|
||||
@ -348,7 +362,7 @@ dependencies {
|
||||
implementation "com.llew.huawei:verifier:${verifier}"
|
||||
|
||||
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:${bytedanceApplog}"
|
||||
teaImplementation "com.bytedance.applog:RangersAppLog-All-convert:${bytedanceApplog}"
|
||||
teaImplementation "com.bytedance.ads:AppConvert:${bytedanceAppConvert}"
|
||||
|
||||
implementation "net.lingala.zip4j:zip4j:${zip4j}"
|
||||
|
||||
@ -357,7 +371,9 @@ dependencies {
|
||||
|
||||
implementation "com.lg:easyfloat:${easyFloat}"
|
||||
|
||||
implementation "com.lg:apksig:${apksig}"
|
||||
implementation ("com.lg:apksig:${apksig}") {
|
||||
exclude group: 'com.google.protobuf'
|
||||
}
|
||||
|
||||
implementation "com.lg:gid:${gid}"
|
||||
|
||||
@ -369,52 +385,93 @@ dependencies {
|
||||
|
||||
implementation project(':ndownload')
|
||||
implementation project(':vspace-bridge:vspace')
|
||||
implementation(project(':feature:xapk-installer'))
|
||||
|
||||
implementation (project(':module_common')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
|
||||
implementation(project(':module_login')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
implementation(project(':module_setting')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
// implementation(project(':module_setting_compose')) {
|
||||
// exclude group: 'androidx.swiperefreshlayout'
|
||||
// }
|
||||
|
||||
implementation(project(':module_core_feature')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
// implementation(project(':module_feedback')) {
|
||||
// exclude group: 'androidx.swiperefreshlayout'
|
||||
// }
|
||||
implementation(project(':feature:new_feedback',)) {
|
||||
|
||||
implementation(project(':module_setting')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
implementation(project(':module_sensors_data')) {
|
||||
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_message')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
|
||||
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableFeedback) {
|
||||
implementation(project(':feature:new_feedback')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
}
|
||||
// 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.enableMessage) {
|
||||
implementation(project(':module_message')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
}
|
||||
|
||||
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableOaid) {
|
||||
implementation(project(':feature:oaid'))
|
||||
}
|
||||
|
||||
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableFloatingWindow) {
|
||||
implementation(project(':feature:floating-window'))
|
||||
}
|
||||
|
||||
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableSensorData) {
|
||||
implementation(project(':module_sensors_data')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
}
|
||||
|
||||
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableCsjAd) {
|
||||
implementation(project(':feature:csj_ad'))
|
||||
}
|
||||
|
||||
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableQQGame) {
|
||||
implementation(project(':feature:qq_game')) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
}
|
||||
|
||||
if (!gradle.ext.excludeOptionalModules || gradle.ext.enablePush) {
|
||||
def pushProperty = findProperty('BUILD_PUSH_TYPE')
|
||||
// 根据BUILD_PUSH_TYPE决定使用哪个推送SDK,目前默认使用极光推送
|
||||
def pushProject = (pushProperty == null || pushProperty == 'jg')
|
||||
? project(':feature:jg_push') : project(':feature:acloud_push')
|
||||
|
||||
implementation(pushProject) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
}
|
||||
|
||||
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableSentry) {
|
||||
implementation(project(':feature:sentry'))
|
||||
}
|
||||
|
||||
implementation(project(":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'))
|
||||
|
||||
// 根据BUILD_PUSH_TYPE决定使用哪个推送SDK,目前默认使用阿里云推送
|
||||
def pushProject = findProperty('BUILD_PUSH_TYPE') == 'jg'
|
||||
? project(':feature:jg_push') : project(':feature:acloud_push')
|
||||
implementation(pushProject) {
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
}
|
||||
debugImplementation 'com.bytedance.android:shadowhook:1.0.9'
|
||||
debugImplementation 'io.github.shiqos:wytrace:1.0.1'
|
||||
}
|
||||
|
||||
File propFile = file('sign.properties')
|
||||
@ -474,113 +531,6 @@ if (propFile.exists()) {
|
||||
// }.each { t -> t.dependsOn generateMetaJson }
|
||||
//}
|
||||
|
||||
andResGuard {
|
||||
mappingFile = null
|
||||
use7zip = true
|
||||
useSign = true
|
||||
// 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字
|
||||
keepRoot = false
|
||||
// 设置这个值,会把arsc name列混淆成相同的名字,减少string常量池的大小
|
||||
fixedResName = "arg"
|
||||
// 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源
|
||||
mergeDuplicatedRes = true
|
||||
whiteList = [
|
||||
"R.xml.jpush*",
|
||||
"R.drawable.jpush*",
|
||||
"R.layout.jpush*",
|
||||
"R.layout.push*",
|
||||
"R.string.jg*",
|
||||
"R.style.MyDialogStyle",
|
||||
"R.style.JPushTheme",
|
||||
"R.drawable.icon",
|
||||
"R.drawable.ic_bar_back",
|
||||
"R.drawable.toolbar_search_icon",
|
||||
"R.drawable.bg_notification_answer_style_1",
|
||||
"R.drawable.bg_notification_answer_style_2",
|
||||
"R.drawable.bg_notification_article_style_1",
|
||||
"R.drawable.bg_notification_article_style_2",
|
||||
"R.drawable.bg_notification_feedback_style_1",
|
||||
"R.drawable.bg_notification_feedback_style_2",
|
||||
"R.drawable.bg_notification_gift_style_1",
|
||||
"R.drawable.bg_notification_gift_style_2",
|
||||
"R.drawable.bg_notification_login_style_1",
|
||||
"R.drawable.bg_notification_login_style_2",
|
||||
"R.drawable.bg_notification_question_style_1",
|
||||
"R.drawable.bg_notification_question_style_2",
|
||||
"R.drawable.bg_notification_rating_style_1",
|
||||
"R.drawable.bg_notification_rating_style_2",
|
||||
"R.drawable.bg_notification_reserve_game_style_1",
|
||||
"R.drawable.bg_notification_reserve_game_style_2",
|
||||
"R.drawable.bg_notification_video_style_1",
|
||||
"R.drawable.bg_notification_video_style_2",
|
||||
"R.drawable.ic_recommend_activity",
|
||||
"R.drawable.ic_recommend_discount",
|
||||
"R.drawable.ic_recommend_function",
|
||||
"R.drawable.ic_recommend_gift",
|
||||
"R.drawable.ic_recommend_role",
|
||||
"R.drawable.download_button_normal_style",
|
||||
"R.drawable.ic_selector_selected",
|
||||
"R.drawable.ic_selector_default",
|
||||
"R.id.download_speed",
|
||||
"R.id.download_percentage",
|
||||
"R.id.comment",
|
||||
"R.id.vote",
|
||||
"R.id.watermark_hint",
|
||||
"R.id.watermark_sb",
|
||||
"R.id.bottomShareIv",
|
||||
"R.id.bottomShareTv",
|
||||
"R.id.recommendStarPref",
|
||||
"R.id.recommendStar",
|
||||
"R.id.iv_vmode_badge",
|
||||
"R.id.tv_vmode",
|
||||
"R.id.iv_vmode",
|
||||
"R.drawable.help_search_delete",
|
||||
"R.drawable.suggest_type_normal",
|
||||
"R.drawable.suggest_type_crash",
|
||||
"R.drawable.suggest_type_game_question",
|
||||
"R.drawable.suggest_type_game_collect",
|
||||
"R.drawable.suggest_type_function_suggest",
|
||||
"R.drawable.suggest_type_article_collect",
|
||||
"R.drawable.suggest_type_copyright",
|
||||
"R.drawable.news_comment_detail_read",
|
||||
"R.drawable.news_comment_detail_comment",
|
||||
"R.drawable.news_comment_detail_share",
|
||||
"R.drawable.ic_libao",
|
||||
"R.drawable.ic_link",
|
||||
"R.drawable.concern_message_icon",
|
||||
"R.drawable.reuse_blank_hint",
|
||||
"R.drawable.ic_concern",
|
||||
"R.drawable.concern_down",
|
||||
"R.drawable.concern_up",
|
||||
"R.drawable.ic_libao_more",
|
||||
"R.drawable.ic_libao_delete",
|
||||
"R.drawable.ic_dialog_close",
|
||||
"R.drawable.occupy2",
|
||||
"R.drawable.kc_checkbox_unselect",
|
||||
"R.drawable.kc_checkbox_select",
|
||||
"R.drawable.ic_type_unselect",
|
||||
"R.drawable.ic_type_selected",
|
||||
"R.drawable.suggest_add_pic_icon",
|
||||
"R.drawable.icon_pic_add",
|
||||
"R.drawable.ask_search_input_delete",
|
||||
"R.drawable.suggest_pic_delete",
|
||||
"R.id.cardIv",
|
||||
"R.id.cardMask",
|
||||
"R.id.cardGradientMask",
|
||||
"R.id.gameIconIv",
|
||||
"R.id.titleContainer"
|
||||
]
|
||||
compressFilePattern = [
|
||||
"*.png",
|
||||
"*.jpg",
|
||||
"*.jpeg",
|
||||
"*.gif",
|
||||
]
|
||||
sevenzip {
|
||||
artifact = 'io.github.leon406:SevenZip:1.2.22.5'
|
||||
}
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
def variants = null
|
||||
try {
|
||||
|
||||
@ -28,6 +28,9 @@ object GdtHelper {
|
||||
} else {
|
||||
GDTAction.init(application, USER_ACTION_SET_ID, APP_SECRET_ID, channel)
|
||||
}
|
||||
|
||||
GDTAction.start()
|
||||
|
||||
Utils.log("init GdtHelper")
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
BIN
app/src/gdt/libs/GDTActionSDK.min.1.8.9.aar
Normal file
BIN
app/src/gdt/libs/GDTActionSDK.min.1.8.9.aar
Normal file
Binary file not shown.
@ -6,27 +6,37 @@ 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 : IExternalGamesUsage {
|
||||
override fun addInstallExternalGameButton(viewParent: ViewGroup) {
|
||||
class ExternalGameUsage : ITestCase {
|
||||
|
||||
private fun buttonTemplate(viewParent: ViewGroup, id: Int, fn: (LayoutPersonalOtherItemBinding) -> Unit) {
|
||||
val context = viewParent.context
|
||||
viewParent.findViewById<View>(R.id.install_game_from_external) ?: run {
|
||||
viewParent.findViewById<View>(id) ?: run {
|
||||
val binding = LayoutPersonalOtherItemBinding.inflate(LayoutInflater.from(context)).apply {
|
||||
root.id = R.id.install_game_from_external
|
||||
titleTv.text = context.getString(R.string.title_install_external_game)
|
||||
iconIv.setImageResource(R.drawable.ic_personal_my_game)
|
||||
root.setOnClickListener {
|
||||
VHelper.connectService {
|
||||
context.startActivity(
|
||||
InstallExternalGameActivity.getIntent(context)
|
||||
.apply { flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK })
|
||||
}
|
||||
}
|
||||
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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -25,6 +25,11 @@ class ExternalGameAdapter(private val games: List<ExternalGameUiState>, private
|
||||
路径:${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)
|
||||
|
||||
@ -8,4 +8,5 @@ class ExternalGameViewHolder(binding: LayoutExternalGameItemBinding) : RecyclerV
|
||||
val install = binding.btnInstall
|
||||
val uninstall = binding.btnUninstall
|
||||
val start = binding.btnStart
|
||||
val update = binding.btnUpdate
|
||||
}
|
||||
@ -1,7 +1,12 @@
|
||||
package com.gh.vspace.installexternalgames
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Dialog
|
||||
import android.content.ComponentName
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.gamecenter.R
|
||||
@ -16,6 +21,7 @@ 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
|
||||
@ -39,6 +45,19 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
|
||||
private lateinit var dialog: Dialog
|
||||
|
||||
|
||||
private val requestPermissionLauncher = registerForActivityResult<String, Boolean>(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { result ->
|
||||
if (result == true) {
|
||||
// grant
|
||||
mViewModel.scanPaths()
|
||||
} else {
|
||||
// not grant
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setNavigationTitle(getString(com.gh.gamecenter.R.string.title_install_external_game))
|
||||
@ -55,11 +74,30 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
mViewModel.scanPaths()
|
||||
|
||||
|
||||
requestStoragePermission()
|
||||
}
|
||||
|
||||
private fun requestStoragePermission() {
|
||||
when {
|
||||
ContextCompat.checkSelfPermission(
|
||||
requireContext(),
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED -> {
|
||||
mViewModel.scanPaths()
|
||||
}
|
||||
|
||||
shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE) -> {
|
||||
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
|
||||
else -> {
|
||||
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun initView() {
|
||||
dialog = DialogUtils.showWaitDialog(requireContext(), "")
|
||||
mBinding.externalGamesList.let {
|
||||
@ -93,9 +131,11 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
OnItemClickListener.ClickType.CLICK_INSTALL -> {
|
||||
install(externalGameUiState)
|
||||
}
|
||||
|
||||
OnItemClickListener.ClickType.CLICK_UNINSTALL -> {
|
||||
uninstall(externalGameUiState)
|
||||
}
|
||||
|
||||
OnItemClickListener.ClickType.CLICK_START -> {
|
||||
start(externalGameUiState)
|
||||
}
|
||||
@ -103,21 +143,21 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
}
|
||||
|
||||
private fun install(externalGameUiState: ExternalGameUiState) {
|
||||
val bit =
|
||||
externalGameUiState.externalGameEntity.cpuAbi.let { if (it.size == 1 && it.contains("armeabi-v7a")) "32" else "64" }
|
||||
if (VHelper.showDialogIfVSpaceIsNeeded(
|
||||
requireContext(),
|
||||
"",
|
||||
externalGameUiState.externalGameEntity.appName,
|
||||
"",
|
||||
bit = bit
|
||||
)
|
||||
) return
|
||||
dialog.show()
|
||||
externalGameUiState.externalGameEntity.let {
|
||||
val intent = VirtualAppManager.getInstallIntent(context, it.apkPath, it.apkPackageName)
|
||||
requireActivity().startActivity(intent)
|
||||
|
||||
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) {
|
||||
@ -144,7 +184,15 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -24,6 +24,14 @@
|
||||
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"
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
<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>
|
||||
Binary file not shown.
BIN
app/src/kuaishou/libs/channelsdk-0.2.3.aar
Normal file
BIN
app/src/kuaishou/libs/channelsdk-0.2.3.aar
Normal file
Binary file not shown.
@ -9,15 +9,17 @@
|
||||
|
||||
<queries>
|
||||
<package android:name="com.lg.vspace" />
|
||||
<package android:name="com.gh.gamecenter.addon" />
|
||||
</queries>
|
||||
|
||||
<!-- 华为/荣耀角标 -->
|
||||
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE "/>
|
||||
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE " />
|
||||
<uses-permission android:name="com.hihonor.android.launcher.permission.CHANGE_BADGE" />
|
||||
<!-- vivo角标 -->
|
||||
<uses-permission android:name="com.vivo.notification.permission.BADGE_ICON" />
|
||||
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||
<uses-permission
|
||||
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<!-- 允许应用程序访问网络连接 -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
@ -39,7 +41,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" />
|
||||
|
||||
@ -54,6 +56,9 @@
|
||||
<!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<!-- 悬浮窗 -->
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
|
||||
<uses-sdk tools:overrideLibrary="
|
||||
com.shuyu.gsyvideoplayer,
|
||||
com.shuyu.gsyvideoplayer.lib,
|
||||
@ -92,7 +97,33 @@
|
||||
com.tencent.qqmini,
|
||||
com.tencent.qqmini.minigame.external,
|
||||
com.tencent.qqmini.minigame.opensdk,
|
||||
com.tencent.qqmini.union.ad" />
|
||||
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" />
|
||||
|
||||
<!-- 去掉 SDK 一些流氓权限 -->
|
||||
<uses-permission
|
||||
@ -111,6 +142,14 @@
|
||||
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"
|
||||
@ -270,10 +309,6 @@
|
||||
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"
|
||||
@ -298,14 +333,6 @@
|
||||
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" />
|
||||
@ -462,9 +489,6 @@
|
||||
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"
|
||||
@ -530,14 +554,6 @@
|
||||
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" />
|
||||
@ -747,11 +763,11 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qgame.QGameHomeWrapperActivity"
|
||||
android:name="com.gh.gamecenter.minigame.qq.QGameHomeWrapperActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qgame.QGameSearchActivity"
|
||||
android:name="com.gh.gamecenter.minigame.MiniGameSearchActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
@ -770,8 +786,18 @@
|
||||
android:name="com.gh.gamecenter.wrapper.ToolbarWrapperActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity android:name=".forum.home.CommunityActivity"
|
||||
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="${applicationId}.douyinapi.DouYinEntryActivity"-->
|
||||
@ -783,7 +809,8 @@
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
android:grantUriPermissions="true"
|
||||
tools:replace="android:authorities">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
@ -829,6 +856,8 @@
|
||||
|
||||
<service android:name="com.gh.gamecenter.install.InstallService" />
|
||||
|
||||
<service android:name="com.gh.download.suspendwindow.DownloadSuspendWindowService" />
|
||||
|
||||
<receiver
|
||||
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
|
||||
android:exported="false">
|
||||
|
||||
1
app/src/main/assets/lottie/draw_overlay_permission.json
Normal file
1
app/src/main/assets/lottie/draw_overlay_permission.json
Normal file
File diff suppressed because one or more lines are too long
@ -28,7 +28,6 @@ import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.provider.IBeiziAdProvider
|
||||
import com.gh.gamecenter.core.provider.ICsjAdProvider
|
||||
import com.gh.gamecenter.core.utils.CurrentActivityHolder
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
@ -46,14 +45,11 @@ import io.reactivex.schedulers.Schedulers
|
||||
*
|
||||
* 由它来分发功能实现到具体的实现
|
||||
*
|
||||
* 以最复杂的开屏广告为例,有三种实现(1. 自有的广告实现 2. 穿山甲的开屏广告实现 3. Beizi 的开屏广告实现)
|
||||
*
|
||||
* 由于两个广告 SDK 有可能在一次启动中都被使用,所以会根据获取到的广告配置 config 来决定是否需要出是很好两个 SDK
|
||||
* 以开屏广告为例,有两种实现(1. 自有的广告实现 2. 穿山甲的开屏广告实现 )
|
||||
*/
|
||||
object AdDelegateHelper {
|
||||
|
||||
private var mCsjAdImpl: ICsjAdProvider? = null
|
||||
private var mBeiziAdImpl: IBeiziAdProvider? = null
|
||||
|
||||
private val mAdConfigList: ArrayList<AdConfig> by lazy { arrayListOf() }
|
||||
|
||||
@ -65,8 +61,10 @@ object AdDelegateHelper {
|
||||
val vGameLaunchAd: AdConfig?
|
||||
get() = mVGameLaunchAd
|
||||
|
||||
val splashAdDisplayInterval: Int
|
||||
get() = mSplashAd?.ownerAd?.startAd?.displayInterval ?: 3
|
||||
|
||||
private const val AD_SDK_CSJ = "穿山甲"
|
||||
private const val AD_SDK_BEIZI = "倍孜"
|
||||
const val AD_TYPE_SDK = "third_party_ads" // 第三方 SDK 广告
|
||||
const val AD_TYPE_OWNER = "owner_ads" // 自有广告
|
||||
|
||||
@ -80,13 +78,6 @@ object AdDelegateHelper {
|
||||
var gameSearchKeyword = ""
|
||||
|
||||
fun initAdSdk(context: Context) {
|
||||
// 初始化 Beizi
|
||||
if (mBeiziAdImpl == null) {
|
||||
mBeiziAdImpl =
|
||||
ARouter.getInstance().build(RouteConsts.provider.beiziAd).navigation() as? IBeiziAdProvider
|
||||
mBeiziAdImpl?.initSDK(context)
|
||||
}
|
||||
|
||||
// 初始化穿山甲
|
||||
if (mCsjAdImpl == null) {
|
||||
mCsjAdImpl =
|
||||
@ -191,10 +182,11 @@ object AdDelegateHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* 热启动是否需要显示开屏广告
|
||||
* 热启动是否需要显示开屏广告(目前只展示第三方广告)
|
||||
*/
|
||||
private fun shouldShowStartUpAdWhenHotLaunch() =
|
||||
mSplashAd?.displayRule?.hotStartSplashAd?.type == AD_TYPE_SDK && mSplashAd?.hotStartThirdPartyAd != null
|
||||
private fun shouldShowStartUpAdWhenHotLaunch() = (mCsjAdImpl != null)
|
||||
&& mSplashAd?.displayRule?.hotStartSplashAd?.type == AD_TYPE_SDK
|
||||
&& mSplashAd?.hotStartThirdPartyAd != null
|
||||
|
||||
/**
|
||||
* 是否需要显示下载管理广告
|
||||
@ -203,6 +195,10 @@ object AdDelegateHelper {
|
||||
return mDownloadManagerAd != null && !isMatchAdFreeRule(mDownloadManagerAd) && isMatchDownloadManagerAdDisplayRule()
|
||||
}
|
||||
|
||||
fun shouldShowHelperLaunchAd(): Boolean {
|
||||
return mVGameLaunchAd != null && !isMatchAdFreeRule(mVGameLaunchAd) && isMatchAdDisplayRule(mVGameLaunchAd, Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否需要显示游戏搜索广告
|
||||
*/
|
||||
@ -247,10 +243,11 @@ object AdDelegateHelper {
|
||||
/**
|
||||
* 是否大于广告管理展示间隔时长
|
||||
*/
|
||||
private fun isMatchDownloadManagerAdDisplayRule(): Boolean {
|
||||
mDownloadManagerAd?.displayRule?.run {
|
||||
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(Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME, 0L)
|
||||
val lastShowTime = SPUtils.getLong(spKey, 0L)
|
||||
val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60
|
||||
return durationInMinutes > adDisplayInterval
|
||||
} else {
|
||||
@ -402,10 +399,7 @@ object AdDelegateHelper {
|
||||
((mSplashAd?.displayRule?.timeout ?: 3.5F) * 1000).toInt()
|
||||
}
|
||||
|
||||
if (thirdPartyAd.sourceName == AD_SDK_BEIZI) {
|
||||
sdkStartAdContainer.visibility = View.VISIBLE
|
||||
requestBeiziSplashAd(sdkStartAdContainer, adsViewGroup, adViewWidthInPx, adViewHeightInPx, timeout.toLong(), sdkSplashCallback)
|
||||
} else if (thirdPartyAd.sourceName == AD_SDK_CSJ) {
|
||||
if (thirdPartyAd.sourceName == AD_SDK_CSJ) {
|
||||
sdkStartAdContainer.visibility = View.VISIBLE
|
||||
requestCsjSplashAd(
|
||||
activity,
|
||||
@ -452,24 +446,6 @@ object AdDelegateHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Beizi 的开屏广告
|
||||
*/
|
||||
private fun requestBeiziSplashAd(
|
||||
startAdContainer: View,
|
||||
adsFl: FrameLayout,
|
||||
adViewWidthInPx: Int,
|
||||
adViewHeightInPx: Int,
|
||||
timeout: Long,
|
||||
callback: (isSuccess: Boolean) -> Unit,
|
||||
) {
|
||||
if (mBeiziAdImpl == null) {
|
||||
callback.invoke(false)
|
||||
} else {
|
||||
mBeiziAdImpl?.requestSplashAd(startAdContainer, adsFl, adViewWidthInPx, adViewHeightInPx, timeout, callback)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示自有的开屏广告
|
||||
*/
|
||||
@ -550,12 +526,15 @@ object AdDelegateHelper {
|
||||
handler: BaseActivity.BaseHandler,
|
||||
hideCallback: () -> Unit
|
||||
) {
|
||||
val jumpBtn: View = startAdContainer.findViewById(R.id.jumpBtn)
|
||||
val jumpBtn = startAdContainer.findViewById<TextView>(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(
|
||||
@ -563,7 +542,16 @@ object AdDelegateHelper {
|
||||
R.drawable.ic_startup_ad_arrow
|
||||
), null, null
|
||||
)
|
||||
|
||||
adImage.visibleIf(true)
|
||||
ImageUtils.display(adImage, ad.img)
|
||||
|
||||
if (ad.isImageType) {
|
||||
adVideo.visibleIf(false)
|
||||
} else {
|
||||
adVideo.visibleIf(true)
|
||||
adVideo.startPlay(ad.video.url)
|
||||
}
|
||||
startAdContainer.setOnClickListener {
|
||||
// 拦截点击事件传递
|
||||
}
|
||||
@ -676,7 +664,6 @@ object AdDelegateHelper {
|
||||
* 取消开屏广告
|
||||
*/
|
||||
fun cancelSplashAd(context: Context) {
|
||||
mBeiziAdImpl?.cancelSplashAd(context)
|
||||
mCsjAdImpl?.cancelSplashAd(context)
|
||||
}
|
||||
|
||||
|
||||
44
app/src/main/java/com/gh/ad/LaunchAdImpl.kt
Normal file
44
app/src/main/java/com/gh/ad/LaunchAdImpl.kt
Normal file
@ -0,0 +1,44 @@
|
||||
package com.gh.ad
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.provider.ILaunchAd
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
|
||||
@Route(path = RouteConsts.provider.vaAd, name = "畅玩启动页广告")
|
||||
class LaunchAdImpl : ILaunchAd {
|
||||
override fun init(context: Context?) {
|
||||
}
|
||||
|
||||
override fun requestAd(fragment: Fragment, container: ViewGroup, maskView: View) {
|
||||
if (AdDelegateHelper.shouldShowHelperLaunchAd()) {
|
||||
val launchAd = AdDelegateHelper.vGameLaunchAd
|
||||
val showThirdPartyAd = launchAd?.displayRule?.adSource == AdDelegateHelper.AD_TYPE_SDK
|
||||
val thirdPartyAd = launchAd?.thirdPartyAd
|
||||
if (showThirdPartyAd && thirdPartyAd != null) {
|
||||
AdDelegateHelper.requestThirdPartyBannerAd(
|
||||
fragment,
|
||||
container,
|
||||
thirdPartyAd,
|
||||
DisplayUtils.getScreenWidthInDp(fragment.requireActivity()),
|
||||
) { isSuccess ->
|
||||
maskView.goneIf(!isSuccess)
|
||||
if (isSuccess) {
|
||||
SPUtils.setLong(Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME, System.currentTimeMillis())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
78
app/src/main/java/com/gh/ad/SplashAdVideoView.kt
Normal file
78
app/src/main/java/com/gh/ad/SplashAdVideoView.kt
Normal file
@ -0,0 +1,78 @@
|
||||
package com.gh.ad
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.WindowManager
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.video.detail.CustomManager
|
||||
import com.shuyu.gsyvideoplayer.utils.GSYVideoType
|
||||
import com.shuyu.gsyvideoplayer.utils.GSYVideoType.SCREEN_TYPE_FULL
|
||||
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
|
||||
import com.shuyu.gsyvideoplayer.video.base.GSYVideoViewBridge
|
||||
|
||||
class SplashAdVideoView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) :
|
||||
StandardGSYVideoPlayer(context, attrs) {
|
||||
|
||||
fun startPlay(url: String) {
|
||||
GSYVideoType.setShowType(SCREEN_TYPE_FULL)
|
||||
GSYVideoType.setRenderType(GSYVideoType.SUFRACE)
|
||||
CustomManager.getCustomManager(getKey()).isNeedMute = true
|
||||
|
||||
setUp(url, true, "")
|
||||
|
||||
setNeedAutoAdaptation(false)
|
||||
startPlayLogic()
|
||||
}
|
||||
|
||||
override fun getGSYVideoManager(): GSYVideoViewBridge {
|
||||
CustomManager.getCustomManager(getKey()).initContext(context.applicationContext)
|
||||
return CustomManager.getCustomManager(getKey())
|
||||
}
|
||||
|
||||
private fun getKey() = "splash_ad"
|
||||
|
||||
/**
|
||||
* 覆盖父类方法,防止在是视频 Preparing 阶段封面图被隐藏,导致白屏
|
||||
*/
|
||||
override fun changeUiToPreparingShow() = Unit
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.layout_splash_ad_video
|
||||
}
|
||||
|
||||
override fun onAutoCompletion() {
|
||||
setStateAndUi(CURRENT_STATE_AUTO_COMPLETE);
|
||||
|
||||
mSaveChangeViewTIme = 0
|
||||
mCurrentPosition = 0
|
||||
|
||||
if (!mIfCurrentIsFullscreen) {
|
||||
getGSYVideoManager().setLastListener(null)
|
||||
}
|
||||
mAudioManager.abandonAudioFocus(onAudioFocusChangeListener);
|
||||
if (mContext is Activity) {
|
||||
try {
|
||||
(mContext as Activity).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
releaseNetWorkState()
|
||||
|
||||
if (mVideoAllCallBack != null && isCurrentMediaListener()) {
|
||||
mVideoAllCallBack.onAutoComplete(mOriginUrl, mTitle, this)
|
||||
}
|
||||
mHadPlay = false
|
||||
}
|
||||
|
||||
fun clearAll() {
|
||||
GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_DEFAULT)
|
||||
GSYVideoType.setRenderType(GSYVideoType.TEXTURE)
|
||||
release()
|
||||
CustomManager.removeManager(getKey())
|
||||
}
|
||||
}
|
||||
@ -16,15 +16,18 @@ import com.gh.gamecenter.SplashScreenActivity
|
||||
import com.gh.gamecenter.authorization.AuthorizationActivity
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.provider.IHelpAndFeedbackProvider
|
||||
import com.gh.gamecenter.common.utils.PackageFlavorHelper
|
||||
import com.gh.gamecenter.core.provider.IPushProvider
|
||||
import com.gh.gamecenter.login.view.LoginActivity
|
||||
import com.gh.gamecenter.va.VCore
|
||||
import com.gh.gamecenter.login.utils.QuickLoginHelper
|
||||
import com.gh.vspace.VHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
// TODO:移动到对应的模块
|
||||
class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
|
||||
private var isFromBackgroundToForeground = false // 是否后台回到前台
|
||||
private var activityCount = 0
|
||||
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
|
||||
// do nothing
|
||||
@ -32,19 +35,31 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
|
||||
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
GlobalActivityManager.currentActivity = activity
|
||||
activityCount ++
|
||||
if (activityCount == 1 && isFromBackgroundToForeground) {
|
||||
GlobalActivityManager.activityCount ++
|
||||
if (GlobalActivityManager.activityCount == 1 && isFromBackgroundToForeground) {
|
||||
if (AdDelegateHelper.shouldShowStartUpAd(true)
|
||||
&& !HaloApp.getInstance().isSkippingThirdParty
|
||||
&& !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 = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
|
||||
pushProvider?.cleanBadgeNumber(activity.applicationContext)
|
||||
}
|
||||
}
|
||||
if (QuickLoginHelper.isLoginAuthPage(activity)) {
|
||||
QuickLoginHelper.addCustomViewToLoginAuthPage(activity)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResumed(activity: Activity) {
|
||||
@ -76,6 +91,8 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
|
||||
}
|
||||
|
||||
if (activity is AppCompatActivity
|
||||
&& !VCore.getInstance().isLaunchActivity(activity)
|
||||
&& activity !is LoginActivity
|
||||
&& activity !is SplashScreenActivity
|
||||
&& activity !is SkipActivity
|
||||
&& activity !is AuthorizationActivity
|
||||
@ -84,10 +101,6 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
|
||||
}
|
||||
|
||||
XapkInstaller.updateCurrentInstallStatus()
|
||||
|
||||
// 清除桌面角标
|
||||
val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
|
||||
pushProvider?.cleanBadgeNumber(activity.applicationContext)
|
||||
}
|
||||
|
||||
override fun onActivityPaused(activity: Activity) {
|
||||
@ -98,8 +111,8 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
activityCount --
|
||||
isFromBackgroundToForeground = activityCount <= 0
|
||||
GlobalActivityManager.activityCount --
|
||||
isFromBackgroundToForeground = GlobalActivityManager.activityCount <= 0
|
||||
}
|
||||
|
||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
|
||||
@ -107,7 +120,16 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
|
||||
}
|
||||
|
||||
override fun onActivityDestroyed(activity: Activity) {
|
||||
// do nothing
|
||||
if (QuickLoginHelper.isLoginAuthPage(activity)) {
|
||||
QuickLoginHelper.release()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSuggestionActivity(activity: Activity): Boolean {
|
||||
val helpAndFeedbackProvider =
|
||||
ARouter.getInstance().build(RouteConsts.provider.helpAndFeedback)
|
||||
.navigation() as? IHelpAndFeedbackProvider
|
||||
return helpAndFeedbackProvider?.isSuggestionActivity(activity) ?: false
|
||||
}
|
||||
|
||||
}
|
||||
@ -32,9 +32,13 @@ import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.utils.NewFlatLogUtils
|
||||
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
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.core.utils.CurrentActivityHolder
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.entity.SensorsEvent
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
@ -45,6 +49,7 @@ import com.gh.gamecenter.login.user.LoginTag
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.login.user.UserRepository
|
||||
import com.gh.gamecenter.login.utils.LoginHelper
|
||||
import com.gh.gamecenter.login.utils.QuickLoginHelper
|
||||
import com.gh.gamecenter.login.view.LoginActivity
|
||||
import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
|
||||
import com.gh.gamecenter.setting.SettingBridge
|
||||
@ -69,7 +74,7 @@ class DefaultJsApi(
|
||||
private var mFragment: Fragment? = null,
|
||||
private var mBbsId: String? = "",
|
||||
private var mOriginUrl: String? = "",
|
||||
private val mForumName: String? = ""
|
||||
private val mForumName: String? = "",
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@ -89,6 +94,11 @@ class DefaultJsApi(
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun isEnableForceDark(msg: Any): Boolean {
|
||||
return DarkModeUtils.isWebViewForceDarkEnabled
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun isGhzs(msg: Any): String {
|
||||
return "true"
|
||||
@ -129,12 +139,12 @@ class DefaultJsApi(
|
||||
|
||||
@JavascriptInterface
|
||||
fun login(msg: Any) {
|
||||
// if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
|
||||
// QuickLoginHelper.startLogin(context, "浏览器")
|
||||
// } else {
|
||||
if (NetworkUtils.isQuickLoginEnabled(context)) {
|
||||
QuickLoginHelper.startLogin(context, "浏览器")
|
||||
} else {
|
||||
val intent = LoginActivity.getIntent(context, "浏览器")
|
||||
context.startActivity(intent)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -219,7 +229,7 @@ class DefaultJsApi(
|
||||
runOnUiThread {
|
||||
// 若畅玩列表中安装了,优先启动畅玩游戏
|
||||
if (VHelper.isInstalled(packageName)) {
|
||||
if (!VHelper.showDialogIfVSpaceIsNeeded(context, "", "", "", "")) {
|
||||
VHelper.validateVSpaceBeforeAction(context, packageName, null) {
|
||||
VHelper.launch(context, packageName)
|
||||
}
|
||||
} else {
|
||||
@ -333,6 +343,12 @@ class DefaultJsApi(
|
||||
return HaloApp.getInstance().oaid
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getPushId(): String {
|
||||
val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
|
||||
return pushProvider?.getRegistrationId(HaloApp.getInstance()) ?: "unknown"
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun showIncompatibleVersionDialog(msg: Any) {
|
||||
DialogHelper.showUpgradeDialog(context)
|
||||
|
||||
@ -268,10 +268,6 @@ 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 ?: "")
|
||||
|
||||
@ -16,7 +16,7 @@ class ValidateVSpaceHandler : DownloadChainHandler() {
|
||||
}
|
||||
|
||||
if (asVGame) {
|
||||
VHelper.validateVSpaceBeforeAction(context, gameEntity) {
|
||||
VHelper.validateVSpaceBeforeAction(context,gameEntity.getUniquePackageName(), gameEntity) {
|
||||
closure.invoke()
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
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;
|
||||
@ -14,21 +15,27 @@ 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.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.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;
|
||||
|
||||
@ -39,8 +46,11 @@ import org.json.JSONObject;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.SingleSource;
|
||||
import io.reactivex.functions.Function;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
public class Config {
|
||||
@ -68,6 +78,10 @@ public class Config {
|
||||
private static NewApiSettingsEntity.NightMode mNightModeSetting;
|
||||
private static SimulatorEntity mNewSimulatorEntity;
|
||||
private static VSetting mVSetting;
|
||||
private static VNewSetting mVNewSetting;
|
||||
|
||||
private static AppEntity mNew32UpdateEntity;
|
||||
public static BehaviorSubject<VNewSetting> vNewSettingSubject = BehaviorSubject.create();
|
||||
private static GameGuidePopupEntity mGameGuidePopupEntity;
|
||||
private static SharedPreferences mDefaultSharedPreferences;
|
||||
|
||||
@ -77,24 +91,11 @@ public class Config {
|
||||
return !SPUtils.getBoolean(Constants.SP_TEENAGER_MODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* VPN 开关选项是否开启
|
||||
*/
|
||||
public static boolean isVpnOptionEnabled() {
|
||||
if (mNewApiSettingsEntity == null
|
||||
|| mNewApiSettingsEntity.getInstall() == null
|
||||
|| mNewApiSettingsEntity.getInstall().getVpnRequired() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mNewApiSettingsEntity.getInstall().getVpnRequired().getShouldShowVpnOption();
|
||||
}
|
||||
|
||||
public static void setSettings(SettingsEntity settingsEntity) {
|
||||
getPreferences().edit().putString(SETTINGS_KEY, GsonUtils.toJson(settingsEntity)).apply();
|
||||
mSettingsEntity = settingsEntity;
|
||||
|
||||
PackageHelper.refreshList();
|
||||
PackageHelper.refreshPackageNameList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -195,6 +196,27 @@ 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 AppEntity getNew32UpdateEntity() {
|
||||
return mNew32UpdateEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求网络数据,尝试刷新畅玩相关配置
|
||||
*/
|
||||
@ -203,7 +225,6 @@ 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) {
|
||||
@ -215,6 +236,35 @@ public class Config {
|
||||
});
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static GameGuidePopupEntity getGameGuidePopupEntity() {
|
||||
return mGameGuidePopupEntity;
|
||||
@ -238,7 +288,6 @@ 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) {
|
||||
@ -251,7 +300,7 @@ public class Config {
|
||||
edit.apply();
|
||||
|
||||
if (!SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) {
|
||||
EventBus.getDefault().post(new EBReuse("Refresh"));
|
||||
AppExecutor.getUiExecutor().execute(() -> EventBus.getDefault().post(new EBReuse("Refresh")));
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -259,7 +308,6 @@ 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) {
|
||||
@ -269,11 +317,11 @@ public class Config {
|
||||
});
|
||||
|
||||
refreshVSettingEntity();
|
||||
getNewSetting();
|
||||
|
||||
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) {
|
||||
@ -285,7 +333,6 @@ 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) {
|
||||
@ -309,12 +356,13 @@ public class Config {
|
||||
String filterString = UrlFilterUtils.getFilterQuery(
|
||||
"manufacturer", Build.MANUFACTURER,
|
||||
"model", Build.MODEL,
|
||||
"android_sdk_version", String.valueOf(Build.VERSION.SDK_INT));
|
||||
"android_sdk_version", String.valueOf(Build.VERSION.SDK_INT),
|
||||
"rom", MetaUtil.INSTANCE.getRom().name() + " " + MetaUtil.INSTANCE.getRom().getVersionName()
|
||||
);
|
||||
|
||||
RetrofitManager.getInstance()
|
||||
.getNewApi().getNewSettings(PackageUtils.getGhVersionName(), channel, filterString)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BiResponse<NewApiSettingsEntity>() {
|
||||
@Override
|
||||
public void onSuccess(NewApiSettingsEntity data) {
|
||||
@ -323,7 +371,7 @@ public class Config {
|
||||
mNewSimulatorEntity = data.getSimulator();
|
||||
if (HaloApp.getInstance().isNewForThisVersion && mNightModeSetting != null && mNightModeSetting.getInstall()) {
|
||||
DarkModeUtils.INSTANCE.updateFollowSystemDarkModeToSp(true);
|
||||
DarkModeUtils.INSTANCE.initDarkMode();
|
||||
AppExecutor.getUiExecutor().execute(DarkModeUtils.INSTANCE::initDarkMode);
|
||||
}
|
||||
SPUtils.setString(Constants.SP_NEW_API_SETTINGS, GsonUtils.toJson(data));
|
||||
|
||||
@ -331,8 +379,31 @@ public class Config {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ class InstallPermissionDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
if (isXapk) {
|
||||
val xapkUnzipVersions = Config.getSettings()?.permissionPopupAppliedVersions?.xapkUnzip
|
||||
if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
|
||||
if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false || XapkInstaller.systemHasFlaw) {
|
||||
callBack?.invoke(false)
|
||||
return
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
private val mDuration = 3000
|
||||
private var mDisposable: Disposable? = null
|
||||
private var mAdapter: PackageCheckAdapter? = null
|
||||
private var mAllInstalledPackages = PackageHelper.getInstalledPackages(HaloApp.getInstance().application, 0)
|
||||
private var mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
|
||||
var gameEntity: GameEntity? = null
|
||||
var callBack: ConfirmListener? = null
|
||||
|
||||
@ -326,7 +326,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mAllInstalledPackages = PackageHelper.getInstalledPackages(HaloApp.getInstance().application, 0)
|
||||
mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
|
||||
gameEntity?.packageDialog?.let {
|
||||
if (isAllPackageInstalled(mAllInstalledPackages, it)) {
|
||||
callBack?.onConfirm()
|
||||
@ -364,7 +364,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(busFour: EBPackage) {
|
||||
if (busFour.isInstalledOrUninstalled()) {
|
||||
mAllInstalledPackages = PackageHelper.getInstalledPackages(HaloApp.getInstance().application, 0)
|
||||
mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
|
||||
mAdapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
@ -417,7 +417,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
return
|
||||
}
|
||||
|
||||
val allInstalledPackages = PackageHelper.getInstalledPackages(HaloApp.getInstance().application, 0)
|
||||
val allInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
|
||||
if (isAllPackageInstalled(allInstalledPackages, packageDialogEntity)) {
|
||||
callBack.onConfirm()
|
||||
return
|
||||
@ -454,12 +454,12 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
|
||||
private fun checkDetectionsInstalled(
|
||||
allInstalledPackages: List<PackageInfo>,
|
||||
allInstalledPackages: List<String>,
|
||||
packages: ArrayList<String>
|
||||
): Boolean {
|
||||
var isPackagesInstalled = false
|
||||
packages.forEach { packageName ->
|
||||
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
|
||||
val isInstalled = allInstalledPackages.find { it == packageName } != null
|
||||
if (isInstalled) {
|
||||
isPackagesInstalled = true
|
||||
return@forEach
|
||||
@ -470,7 +470,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
|
||||
|
||||
fun isAllPackageInstalled(
|
||||
allInstalledPackages: List<PackageInfo>,
|
||||
allInstalledPackages: List<String>,
|
||||
packageDialogEntity: PackageDialogEntity
|
||||
): Boolean {
|
||||
var isAllInstalled = true
|
||||
|
||||
@ -6,16 +6,16 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
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.base.BaseRecyclerViewHolder
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.common.entity.SimpleGameEntity
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.fromHtml
|
||||
import com.gh.gamecenter.common.view.FixLinearLayoutManager
|
||||
import com.gh.gamecenter.databinding.DialogReserveBinding
|
||||
import com.gh.gamecenter.databinding.DialogReserveItemBinding
|
||||
import com.gh.gamecenter.common.entity.SimpleGameEntity
|
||||
import com.gh.gamecenter.mygame.MyGameActivity
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
|
||||
@ -43,7 +43,7 @@ class ReserveDialog : BaseDialogFragment() {
|
||||
View.VISIBLE
|
||||
} else View.GONE
|
||||
binding.more.setOnClickListener {
|
||||
val intent = MyGameActivity.getIntentWithConfig(requireContext(), 2)
|
||||
val intent = MyGameActivity.getIntentWithConfig(requireContext(), MyGameActivity.RESERVATION_INDEX)
|
||||
startActivity(intent)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import com.aliyun.sls.android.producer.Log
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.loghub.LoghubHelper
|
||||
import com.gh.gamecenter.common.loghub.TLogHubHelper
|
||||
import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet
|
||||
import com.gh.gamecenter.common.utils.toJson
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.lightgame.utils.Utils
|
||||
import com.volcengine.model.tls.LogItem
|
||||
|
||||
/**
|
||||
* A handful tool for committing logs to aliyun loghub.
|
||||
@ -78,19 +78,20 @@ object ExposureManager {
|
||||
|
||||
private fun uploadExposures(eventSet: HashSet<ExposureEvent>, forced: Boolean) {
|
||||
eventSet.forEach {
|
||||
LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced)
|
||||
TLogHubHelper.sendLog(buildLog(it), LOG_STORE)
|
||||
// LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced)
|
||||
// it.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
private fun buildLog(event: ExposureEvent) = LogItem(System.currentTimeMillis()).apply {
|
||||
addContent("__id", event.id)
|
||||
addContent("payload", event.payload.toJson())
|
||||
addContent("event", event.event.toString())
|
||||
addContent("source", eliminateMultipleBrackets(event.source.toJson()))
|
||||
addContent("meta", event.meta.toJson())
|
||||
addContent("real_millisecond", event.timeInMillisecond.toString())
|
||||
addContent(
|
||||
"e-traces", if (event.eTrace != null) {
|
||||
eliminateMultipleBrackets(event.eTrace?.toJson() ?: "")
|
||||
} else ""
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
package com.gh.common.prioritychain
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Handler
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.FrameLayout
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.view.BugFixedPopupWindow
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
@ -19,7 +19,7 @@ import com.gh.gamecenter.wrapper.MainWrapperViewModel
|
||||
class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priority) {
|
||||
|
||||
private var mActivity: Activity? = null
|
||||
private var mBaseHandler: BaseFragment.BaseHandler? = null
|
||||
private var mHandler: Handler? = null
|
||||
private var mGameList: List<GameEntity>? = null
|
||||
private var mViewModel: MainWrapperViewModel? = null
|
||||
|
||||
@ -28,13 +28,13 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
|
||||
*/
|
||||
fun doPreProcess(
|
||||
activity: Activity,
|
||||
baseHandler: BaseFragment.BaseHandler,
|
||||
handler: Handler,
|
||||
gameEntityList: List<GameEntity>?,
|
||||
viewModel: MainWrapperViewModel
|
||||
) {
|
||||
mActivity = activity
|
||||
mGameList = gameEntityList
|
||||
mBaseHandler = baseHandler
|
||||
mHandler = handler
|
||||
mViewModel = viewModel
|
||||
|
||||
if (getStatus() == STATUS_PENDING) {
|
||||
@ -59,7 +59,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
|
||||
val accelerateSet =
|
||||
HashSet(SPUtils.getStringSet(Constants.SP_ACCELERATE_NOTIFICATION_POP_UP_SET))
|
||||
if (!mGameList.isNullOrEmpty() && !accelerateSet.contains(mGameList!![0].messageId)) {
|
||||
showAccelerateNotificationPopupWindow(mActivity!!, mViewModel, mBaseHandler, mGameList!![0]) {
|
||||
showAccelerateNotificationPopupWindow(mActivity!!, mViewModel, mHandler, mGameList!![0]) {
|
||||
processNext()
|
||||
}
|
||||
accelerateSet.add(mGameList!![0].messageId)
|
||||
@ -82,7 +82,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
|
||||
fun showAccelerateNotificationPopupWindow(
|
||||
activity: Activity,
|
||||
viewModel: MainWrapperViewModel?,
|
||||
baseHandler: BaseFragment.BaseHandler?,
|
||||
handler: Handler?,
|
||||
gameEntity: GameEntity?,
|
||||
dismissCallback: (() -> Unit)?
|
||||
) {
|
||||
@ -131,7 +131,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
|
||||
setOnDismissListener {
|
||||
dismissCallback?.invoke()
|
||||
}
|
||||
baseHandler?.postDelayed({ dismiss() }, 5000)
|
||||
handler?.postDelayed({ dismiss() }, 5000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,169 @@
|
||||
package com.gh.common.prioritychain
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Handler
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.PopupWindow
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.view.BugFixedPopupWindow
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.databinding.PopupBottomTabGuideBinding
|
||||
import com.gh.gamecenter.entity.BottomTab
|
||||
|
||||
class BottomTabGuideHandler(priority: Int): PriorityChainHandler(priority) {
|
||||
private var mActivity: Activity? = null
|
||||
private var mHandler: Handler? = null
|
||||
private var mViewPager: ViewGroup? = null
|
||||
private var mGuide: BottomTab.Guide? = null
|
||||
private var mTriangleTransX = 0F
|
||||
private var mGuideTransX = 0F
|
||||
private var mRestWidth = 0F
|
||||
private var mIsCenterPosition = false
|
||||
private var mIsRightPosition = false
|
||||
|
||||
private var mPopupWindow: PopupWindow? = null
|
||||
|
||||
fun doPreProcess(
|
||||
shouldShow: Boolean,
|
||||
activity: Activity? = null,
|
||||
handler: Handler? = null,
|
||||
viewPager: ViewGroup? = null,
|
||||
guide: BottomTab.Guide? = null,
|
||||
triangleTransX: Float = 0F,
|
||||
guideTransX: Float = 0F,
|
||||
restWidth: Float = 0F,
|
||||
isCenterPosition: Boolean = false,
|
||||
isRightPosition: Boolean = false
|
||||
) {
|
||||
mActivity = activity
|
||||
mHandler = handler
|
||||
mViewPager = viewPager
|
||||
mGuide = guide
|
||||
mTriangleTransX = triangleTransX
|
||||
mGuideTransX = guideTransX
|
||||
mRestWidth = restWidth
|
||||
mIsCenterPosition = isCenterPosition
|
||||
mIsRightPosition = isRightPosition
|
||||
|
||||
if (getStatus() == STATUS_PENDING) {
|
||||
if (shouldShow) {
|
||||
updateStatus(STATUS_VALID)
|
||||
process()
|
||||
} else {
|
||||
processNext()
|
||||
}
|
||||
} else {
|
||||
if (shouldShow) {
|
||||
updateStatus(STATUS_VALID)
|
||||
} else {
|
||||
updateStatus(STATUS_INVALID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProcess(): Boolean {
|
||||
when (getStatus()) {
|
||||
STATUS_VALID -> {
|
||||
if (mGuide == null || mActivity == null || mViewPager == null) {
|
||||
processNext()
|
||||
return false
|
||||
}
|
||||
|
||||
val guideSet = HashSet(SPUtils.getStringSet(Constants.SP_BOTTOM_TAB_GUIDE_SET))
|
||||
if (!guideSet.contains(mGuide?.bottomTabId + mGuide?.text)) {
|
||||
mPopupWindow = showBottomTabPopupWindow(
|
||||
mActivity!!,
|
||||
mHandler,
|
||||
mViewPager!!,
|
||||
mGuide!!,
|
||||
mTriangleTransX,
|
||||
mGuideTransX,
|
||||
mRestWidth,
|
||||
mIsCenterPosition,
|
||||
mIsRightPosition
|
||||
) {
|
||||
processNext()
|
||||
}
|
||||
guideSet.add(mGuide?.bottomTabId + mGuide?.text)
|
||||
SPUtils.setStringSet(Constants.SP_BOTTOM_TAB_GUIDE_SET, guideSet)
|
||||
return true
|
||||
} else {
|
||||
processNext()
|
||||
}
|
||||
}
|
||||
|
||||
STATUS_INVALID -> {
|
||||
processNext()
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun dismiss() {
|
||||
if (mPopupWindow?.isShowing == true) {
|
||||
mPopupWindow?.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KEY_BOTTOM_TAB_GUIDE_AUTO_DISMISS = 100
|
||||
private const val AUTO_DISMISS_DELAY_TIME = 5000L
|
||||
|
||||
fun showBottomTabPopupWindow(
|
||||
activity: Activity,
|
||||
handler: Handler?,
|
||||
viewPager: ViewGroup,
|
||||
guide: BottomTab.Guide,
|
||||
triangleTransX: Float,
|
||||
guideTransX: Float,
|
||||
restWidth: Float,
|
||||
isCenterPosition: Boolean,
|
||||
isRightPosition: Boolean,
|
||||
dismissCallback: (() -> Unit)?
|
||||
): PopupWindow {
|
||||
val binding = PopupBottomTabGuideBinding.inflate(LayoutInflater.from(activity))
|
||||
binding.guideTv.text = guide.text
|
||||
binding.guideTriangleIv.translationX = triangleTransX
|
||||
binding.guideTv.translationX = guideTransX
|
||||
binding.guideIconIv.translationX = guideTransX
|
||||
binding.guideTv.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
horizontalBias = if (isCenterPosition) 0.5F else if (isRightPosition) 1F else 0F
|
||||
}
|
||||
|
||||
val popupWindow = BugFixedPopupWindow(
|
||||
binding.root,
|
||||
ConstraintLayout.LayoutParams.MATCH_PARENT,
|
||||
ConstraintLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
popupWindow.contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
|
||||
val measureWidth = popupWindow.contentView.measuredWidth
|
||||
val measureHeight = popupWindow.contentView.measuredHeight
|
||||
if (measureWidth > restWidth) {
|
||||
binding.guideTv.translationX = 0F
|
||||
binding.guideIconIv.translationX = 0F
|
||||
}
|
||||
|
||||
return popupWindow.apply {
|
||||
isFocusable = false
|
||||
isOutsideTouchable = false
|
||||
animationStyle = R.style.popup_window_ease_in_and_out_anim_style
|
||||
setOnDismissListener {
|
||||
dismissCallback?.invoke()
|
||||
}
|
||||
handler?.post {
|
||||
if (!activity.isFinishing) {
|
||||
showAsDropDown(viewPager, 0, 8F.dip2px() - measureHeight)
|
||||
}
|
||||
handler.sendEmptyMessageDelayed(KEY_BOTTOM_TAB_GUIDE_AUTO_DISMISS, AUTO_DISMISS_DELAY_TIME)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@ package com.gh.common.prioritychain
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.gamecenter.floatingwindow.FloatingWindowEntity
|
||||
import com.gh.gamecenter.feature.entity.FloatingWindowEntity
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
|
||||
class CustomFloatingWindowHandler(priority: Int) : PriorityChainHandler(priority) {
|
||||
@ -60,7 +60,7 @@ class CustomFloatingWindowHandler(priority: Int) : PriorityChainHandler(priority
|
||||
when (getStatus()) {
|
||||
STATUS_VALID -> {
|
||||
_showFloatingAction.value = Event(data)
|
||||
processNext()
|
||||
return true
|
||||
// floatingWindowProvider.showFloatingWindowOnly(
|
||||
// mFragment!!,
|
||||
// mRecyclerView!!,
|
||||
@ -79,4 +79,9 @@ class CustomFloatingWindowHandler(priority: Int) : PriorityChainHandler(priority
|
||||
return false
|
||||
}
|
||||
|
||||
fun dismiss() {
|
||||
if (getStatus() == STATUS_HANDLING || getStatus() == STATUS_VALID) {
|
||||
processNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,13 +9,17 @@ import androidx.fragment.app.FragmentActivity
|
||||
import com.gh.common.iinterface.ISuperiorChain
|
||||
import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.gamecenter.SplashAdActivity
|
||||
import com.gh.gamecenter.SplashScreenActivity
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.entity.SimpleGameEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.entity.DialogEntity
|
||||
import com.gh.gamecenter.feature.entity.WelcomeDialogEntity
|
||||
import com.gh.gamecenter.hud.PendingInstallHUDHandler
|
||||
import com.gh.gamecenter.hud.ResumeDownloadHudHandler
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
@ -42,18 +46,21 @@ object GlobalPriorityChainHelper : ISuperiorChain {
|
||||
return activity is FragmentActivity
|
||||
&& !activity.isFinishing
|
||||
&& activity !is SplashScreenActivity
|
||||
&& activity !is SplashAdActivity
|
||||
}
|
||||
|
||||
/**
|
||||
* 预启动所有的优先级弹窗管理链
|
||||
*/
|
||||
fun preStart() {
|
||||
fun preStart(withSpecialDelay: Boolean) {
|
||||
val launchRedirectHandler = LaunchRedirectHandler(-101)
|
||||
val updateDialogHandler = UpdateDialogHandler(-100)
|
||||
val privacyPolicyDialogHandler = PrivacyPolicyDialogHandler(-99)
|
||||
val notificationPermissionDialogHandler = NotificationPermissionDialogHandler(0)
|
||||
val reserveDialogHandler = ReserveDialogHandler(1)
|
||||
val welcomeDialogHandler = WelcomeDialogHandler(2)
|
||||
val pendingInstallHandler = PendingInstallHUDHandler(3)
|
||||
val resumeDownloadHandler = ResumeDownloadHudHandler(4)
|
||||
|
||||
mainChain.addHandler(launchRedirectHandler)
|
||||
mainChain.addHandler(updateDialogHandler)
|
||||
@ -61,11 +68,18 @@ object GlobalPriorityChainHelper : ISuperiorChain {
|
||||
mainChain.addHandler(welcomeDialogHandler)
|
||||
mainChain.addHandler(reserveDialogHandler)
|
||||
mainChain.addHandler(notificationPermissionDialogHandler)
|
||||
mainChain.addHandler(pendingInstallHandler)
|
||||
mainChain.addHandler(resumeDownloadHandler)
|
||||
|
||||
launchRedirectHandler.doPreProcess()
|
||||
updateDialogHandler.doPreProcess()
|
||||
requestOpeningDialogData(welcomeDialogHandler, privacyPolicyDialogHandler)
|
||||
requestReserveDialogData(reserveDialogHandler)
|
||||
|
||||
// 首次启动延迟 300ms,保证请求首次启动时已经获取到了 GID 、 OAID 等标记
|
||||
val requestDelay = if (withSpecialDelay) 300L else 0L
|
||||
AppExecutor.uiExecutor.executeWithDelay({
|
||||
requestOpeningDialogData(welcomeDialogHandler, privacyPolicyDialogHandler)
|
||||
requestReserveDialogData(reserveDialogHandler)
|
||||
}, requestDelay)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,6 +137,17 @@ object GlobalPriorityChainHelper : ISuperiorChain {
|
||||
mainChain.resume()
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加新的 handler 到优先级弹窗管理链 (插队!)
|
||||
*/
|
||||
fun queueNewHandler(handler: PriorityChainHandler) {
|
||||
if (mainChain.isHandlerQueueEmpty()) {
|
||||
observeLifecycle()
|
||||
}
|
||||
|
||||
mainChain.addHandler(handler)
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求首页启动弹窗相关的数据并执行相关 handler 的 preProcess
|
||||
*/
|
||||
|
||||
@ -0,0 +1,297 @@
|
||||
package com.gh.common.prioritychain
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Handler
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.PopupWindow
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.view.BugFixedPopupWindow
|
||||
import com.gh.gamecenter.common.view.NoDefaultMinWidthTabLayout
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.databinding.PopupMultiTabGuideBinding
|
||||
import com.gh.gamecenter.entity.BottomTab
|
||||
import com.gh.gamecenter.wrapper.BaseTabWrapperFragment
|
||||
import com.gh.gamecenter.wrapper.MainWrapperFragment
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayout.TabView
|
||||
|
||||
class MultiTabGuideHandler(priority: Int): PriorityChainHandler(priority) {
|
||||
private var mActivity: Activity? = null
|
||||
private var mHandler: Handler? = null
|
||||
private var mGuide: BottomTab.Guide? = null
|
||||
private var mTabLayout: TabLayout? = null
|
||||
private var mTabView: TabView? = null
|
||||
private var mIsSingleLineTab = false
|
||||
private var mMainWrapperFragment: MainWrapperFragment? = null
|
||||
private var mTabWrapperFragment: BaseTabWrapperFragment? = null
|
||||
|
||||
fun doPreProcess(
|
||||
shouldShow: Boolean,
|
||||
activity: Activity? = null,
|
||||
handler: Handler? = null,
|
||||
guide: BottomTab.Guide? = null,
|
||||
tabLayout: TabLayout? = null,
|
||||
tabView: TabLayout.TabView? = null,
|
||||
isSingleLineTab: Boolean = false,
|
||||
mainWrapperFragment: MainWrapperFragment? = null,
|
||||
tabWrapperFragment: BaseTabWrapperFragment? = null
|
||||
) {
|
||||
mActivity = activity
|
||||
mHandler = handler
|
||||
mGuide = guide
|
||||
mTabLayout = tabLayout
|
||||
mTabView = tabView
|
||||
mIsSingleLineTab = isSingleLineTab
|
||||
mMainWrapperFragment = mainWrapperFragment
|
||||
mTabWrapperFragment = tabWrapperFragment
|
||||
|
||||
if (getStatus() == STATUS_PENDING) {
|
||||
if (shouldShow) {
|
||||
updateStatus(STATUS_VALID)
|
||||
process()
|
||||
} else {
|
||||
processNext()
|
||||
}
|
||||
} else {
|
||||
if (shouldShow) {
|
||||
updateStatus(STATUS_VALID)
|
||||
} else {
|
||||
updateStatus(STATUS_INVALID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProcess(): Boolean {
|
||||
when (getStatus()) {
|
||||
STATUS_VALID -> {
|
||||
if (mGuide == null || mActivity == null || mTabView == null || mTabLayout == null) {
|
||||
processNext()
|
||||
return false
|
||||
}
|
||||
|
||||
return showMultiTabGuide(
|
||||
true,
|
||||
mActivity!!,
|
||||
mHandler,
|
||||
mGuide!!,
|
||||
mTabLayout!!,
|
||||
mTabView!!,
|
||||
mIsSingleLineTab,
|
||||
mMainWrapperFragment,
|
||||
mTabWrapperFragment
|
||||
) {
|
||||
processNext()
|
||||
}
|
||||
}
|
||||
|
||||
STATUS_INVALID -> {
|
||||
processNext()
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAB_GUIDE_TRIANGLE_OFFSET_DP = 5F
|
||||
private const val TAB_GUIDE_START_TRIANGLE_OFFSET_DP = 12F
|
||||
private const val TAB_GUIDE_RIGHT_SIDE_ICON_RIGHT_RESERVED_OFFSET_DP = 51F + TAB_GUIDE_TRIANGLE_OFFSET_DP // 光宝在文案右侧时预留引导到屏幕右侧的距离
|
||||
private const val TAB_GUIDE_RIGHT_SIDE_ICON_LEFT_RESERVED_OFFSET_DP = TAB_GUIDE_START_TRIANGLE_OFFSET_DP + TAB_GUIDE_TRIANGLE_OFFSET_DP // 光宝在文案作侧时预留引导到屏幕右侧的距离
|
||||
|
||||
fun showMultiTabGuide(
|
||||
isImmediately: Boolean,
|
||||
activity: Activity,
|
||||
handler: Handler?,
|
||||
guide: BottomTab.Guide,
|
||||
tabLayout: TabLayout,
|
||||
tabView: TabView,
|
||||
isSingleLineTab: Boolean = false,
|
||||
mainWrapperFragment: MainWrapperFragment? = null,
|
||||
tabWrapperFragment: BaseTabWrapperFragment? = null,
|
||||
dismissCallback: (() -> Unit)? = null
|
||||
): Boolean {
|
||||
val guideSet = HashSet(SPUtils.getStringSet(Constants.SP_MULTI_TAB_NAV_GUIDE_SET))
|
||||
val hasShownGuide = guideSet.contains(guide.multiTabId + guide.text)
|
||||
val isCurrentBottomTab = mainWrapperFragment == null || guide.bottomTabId == mainWrapperFragment.currentTab?.id
|
||||
if (!hasShownGuide && isCurrentBottomTab) {
|
||||
val screenWidth = DisplayUtils.getScreenWidth(activity)
|
||||
val outLocation = IntArray(2)
|
||||
tabView.getLocationOnScreen(outLocation)
|
||||
val tabViewCenterPosX = outLocation.first() + tabView.width / 2F
|
||||
val iconLeftMaxPosX = if (isSingleLineTab) tabLayout.width else tabLayout.width - TAB_GUIDE_RIGHT_SIDE_ICON_LEFT_RESERVED_OFFSET_DP.dip2px()
|
||||
val iconRightMaxPosX = if (isSingleLineTab) tabLayout.width else tabLayout.width - TAB_GUIDE_RIGHT_SIDE_ICON_RIGHT_RESERVED_OFFSET_DP.dip2px()
|
||||
val isIconLeftValid = tabViewCenterPosX <= iconLeftMaxPosX
|
||||
val isIconRightValid = tabViewCenterPosX <= iconRightMaxPosX
|
||||
val isTabViewShowOnScreen = tabViewCenterPosX > 0 && (isIconLeftValid || isIconRightValid)
|
||||
val isTabLayoutScrollStateIdle = (tabLayout as? NoDefaultMinWidthTabLayout)?.isScrollStateIdle == true
|
||||
if (isTabViewShowOnScreen && isTabLayoutScrollStateIdle) {
|
||||
val trianglePosX = tabViewCenterPosX - TAB_GUIDE_TRIANGLE_OFFSET_DP.dip2px()
|
||||
val guideStartPosX = trianglePosX - TAB_GUIDE_START_TRIANGLE_OFFSET_DP.dip2px()
|
||||
val xoff = tabView.width / 2 - TAB_GUIDE_START_TRIANGLE_OFFSET_DP.dip2px() - TAB_GUIDE_TRIANGLE_OFFSET_DP.dip2px()
|
||||
val restGuideWidth = screenWidth - guideStartPosX
|
||||
|
||||
showMultiTabPopupWindow(
|
||||
activity,
|
||||
handler,
|
||||
guide,
|
||||
tabView,
|
||||
xoff,
|
||||
screenWidth,
|
||||
restGuideWidth,
|
||||
isIconRightValid,
|
||||
dismissCallback
|
||||
)
|
||||
guideSet.add(guide.multiTabId + guide.text)
|
||||
SPUtils.setStringSet(Constants.SP_MULTI_TAB_NAV_GUIDE_SET, guideSet)
|
||||
|
||||
return true
|
||||
} else if (isImmediately) {
|
||||
(tabLayout as? NoDefaultMinWidthTabLayout)?.let {
|
||||
it.onScrollListener = object :
|
||||
NoDefaultMinWidthTabLayout.OnScrollListener() {
|
||||
override fun onScrollStateChanged(view: NoDefaultMinWidthTabLayout, scrollState: Int) {
|
||||
if (scrollState == SCROLL_STATE_IDLE) {
|
||||
showMultiTabGuideIfTabViewShow(
|
||||
activity,
|
||||
handler,
|
||||
guide,
|
||||
it,
|
||||
tabView,
|
||||
isSingleLineTab,
|
||||
mainWrapperFragment
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isImmediately && !isCurrentBottomTab) {
|
||||
tabWrapperFragment?.setResumeAndPauseListener {
|
||||
if (it) {
|
||||
handler?.post {
|
||||
(tabLayout as? NoDefaultMinWidthTabLayout)?.let { tl ->
|
||||
showMultiTabGuideIfBottomTabShow(
|
||||
activity,
|
||||
handler,
|
||||
guide,
|
||||
tl,
|
||||
tabView,
|
||||
isSingleLineTab,
|
||||
mainWrapperFragment,
|
||||
tabWrapperFragment
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dismissCallback?.invoke()
|
||||
return false
|
||||
}
|
||||
|
||||
fun showMultiTabGuideIfTabViewShow(
|
||||
activity: Activity,
|
||||
handler: Handler?,
|
||||
guide: BottomTab.Guide,
|
||||
tabLayout: NoDefaultMinWidthTabLayout,
|
||||
tabView: TabView,
|
||||
isSingleLineTab: Boolean = false,
|
||||
mainWrapperFragment: MainWrapperFragment?
|
||||
) {
|
||||
if (showMultiTabGuide(
|
||||
false,
|
||||
activity,
|
||||
handler,
|
||||
guide,
|
||||
tabLayout,
|
||||
tabView,
|
||||
isSingleLineTab,
|
||||
mainWrapperFragment
|
||||
)
|
||||
) {
|
||||
tabLayout.onScrollListener = null
|
||||
}
|
||||
}
|
||||
|
||||
fun showMultiTabGuideIfBottomTabShow(
|
||||
activity: Activity,
|
||||
handler: Handler?,
|
||||
guide: BottomTab.Guide,
|
||||
tabLayout: NoDefaultMinWidthTabLayout,
|
||||
tabView: TabView,
|
||||
isSingleLineTab: Boolean = false,
|
||||
mainWrapperFragment: MainWrapperFragment?,
|
||||
tabWrapperFragment: BaseTabWrapperFragment?
|
||||
) {
|
||||
if (showMultiTabGuide(
|
||||
false,
|
||||
activity,
|
||||
handler,
|
||||
guide,
|
||||
tabLayout,
|
||||
tabView,
|
||||
isSingleLineTab,
|
||||
mainWrapperFragment,
|
||||
tabWrapperFragment
|
||||
)
|
||||
) {
|
||||
tabWrapperFragment?.setResumeAndPauseListener(null)
|
||||
}
|
||||
}
|
||||
|
||||
fun showMultiTabPopupWindow(
|
||||
activity: Activity,
|
||||
handler: Handler?,
|
||||
guide: BottomTab.Guide,
|
||||
tabView: TabView,
|
||||
xoff: Int,
|
||||
screenWidth: Int,
|
||||
restGuideWidth: Float,
|
||||
isIconRight: Boolean,
|
||||
dismissCallback: (() -> Unit)?
|
||||
): PopupWindow {
|
||||
val binding = PopupMultiTabGuideBinding.inflate(LayoutInflater.from(activity))
|
||||
binding.guideTv.text = guide.text
|
||||
binding.guideTriangleIv.translationX = 12F.dip2px().toFloat()
|
||||
binding.guideTv.setPadding(if (isIconRight) 8F.dip2px() else 52F.dip2px(), 0, if (isIconRight) 52F.dip2px() else 8F.dip2px(), 0)
|
||||
binding.guideIconIv.goneIf(!isIconRight)
|
||||
binding.guideIconFlipIv.goneIf(isIconRight)
|
||||
|
||||
val popupWindow = BugFixedPopupWindow(
|
||||
binding.root,
|
||||
ConstraintLayout.LayoutParams.WRAP_CONTENT,
|
||||
ConstraintLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
popupWindow.contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
|
||||
val measureWidth = popupWindow.contentView.measuredWidth
|
||||
if (measureWidth >= screenWidth) {
|
||||
popupWindow.width = screenWidth
|
||||
binding.guideTriangleIv.translationX += screenWidth - restGuideWidth
|
||||
} else if (measureWidth > restGuideWidth) {
|
||||
binding.guideTriangleIv.translationX += measureWidth - restGuideWidth
|
||||
}
|
||||
|
||||
return popupWindow.apply {
|
||||
isTouchable = false
|
||||
isFocusable = false
|
||||
isOutsideTouchable = true
|
||||
animationStyle = R.style.popup_window_ease_in_and_out_anim_style
|
||||
setOnDismissListener {
|
||||
dismissCallback?.invoke()
|
||||
}
|
||||
handler?.post {
|
||||
if (!activity.isFinishing) {
|
||||
showAsDropDown(tabView, xoff, (-25F).dip2px())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.gh.common.prioritychain
|
||||
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.gh.common.util.PackageHelper
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
|
||||
class RequestInstalledListPermissionHandler : PriorityChainHandler(-1000) {
|
||||
|
||||
init {
|
||||
updateStatus(STATUS_VALID)
|
||||
}
|
||||
|
||||
override fun onProcess(): Boolean {
|
||||
val currentActivity = GlobalActivityManager.currentActivity ?: return false
|
||||
|
||||
if (currentActivity !is FragmentActivity) return false
|
||||
|
||||
PackageHelper.showGetInstallAppsListDialogAndRequestPermissionIfNeeded(
|
||||
activity = currentActivity,
|
||||
ignorePermanentlyDenied = true
|
||||
) {
|
||||
processNext()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@ -7,6 +7,7 @@ import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.core.provider.IAppProvider
|
||||
import com.gh.gamecenter.core.provider.IFlavorProvider
|
||||
import com.gh.gamecenter.va.VCore
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
@Route(path = RouteConsts.provider.app, name = "Application暴露服务")
|
||||
@ -83,7 +84,13 @@ class AppProviderImpl : IAppProvider {
|
||||
return HaloApp.getInstance().isBrandNewInstall
|
||||
}
|
||||
|
||||
override fun setSkippingThirdParty(isSkippingThirdParty: Boolean) {
|
||||
HaloApp.getInstance().isSkippingThirdParty = isSkippingThirdParty
|
||||
override fun setDisableSplashAdTemporarily(isDisable: Boolean) {
|
||||
HaloApp.getInstance().isDisableSplashAdTemporarily = isDisable
|
||||
}
|
||||
|
||||
override fun getPluginVersion(): String = VCore.getInstance().getPluginVersion()
|
||||
|
||||
override fun initImageLoaderIfNeeded() {
|
||||
HaloApp.getInstance().initFresco()
|
||||
}
|
||||
}
|
||||
@ -32,5 +32,6 @@ class BuildConfigImpl : IBuildConfigProvider {
|
||||
override fun getVApiHost(): String = BuildConfig.VAPI_HOST
|
||||
|
||||
override fun getVDevApiHost(): String = BuildConfig.DEV_VAPI_HOST
|
||||
|
||||
override fun getLogProducerProject(): String = BuildConfig.LOG_HUB_PROJECT
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
package com.gh.common.provider
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.ConcernContentUtils
|
||||
import com.gh.common.view.ImageContainerView
|
||||
import com.gh.gamecenter.ImageViewerActivity.Companion.getIntent
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.toArrayList
|
||||
import com.gh.gamecenter.core.provider.IConcernArticleUtilsProvider
|
||||
import com.gh.gamecenter.databinding.RecyclerGameArticleBinding
|
||||
import com.gh.gamecenter.R
|
||||
|
||||
@Route(path = RouteConsts.provider.concernContentUtils, name = "ConcernContentUtils暴露服务")
|
||||
class ConcernArticleUtilsProviderImpl : IConcernArticleUtilsProvider {
|
||||
override fun addContentPic(
|
||||
context: Context,
|
||||
linearLayout: LinearLayout,
|
||||
list: List<String>,
|
||||
entrance: String,
|
||||
width: Int
|
||||
) {
|
||||
ConcernContentUtils.addContentPic(context, linearLayout, list, entrance, width)
|
||||
}
|
||||
|
||||
override fun createArticleBinding(parent: ViewGroup): ViewBinding {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
return RecyclerGameArticleBinding.inflate(inflater, parent, false)
|
||||
}
|
||||
|
||||
override fun initArticleStyle(binding: ViewBinding) {
|
||||
if (binding is RecyclerGameArticleBinding) {
|
||||
val context = binding.root.context
|
||||
binding.root
|
||||
.setBackground(ContextCompat.getDrawable(context, R.drawable.reuse_listview_item_style))
|
||||
binding.tvGameName.setTextColor(ContextCompat.getColor(context, R.color.text_primary))
|
||||
binding.tvTime.setTextColor(ContextCompat.getColor(context, R.color.text_tertiary))
|
||||
binding.tvTitle.setTextColor(ContextCompat.getColor(context, R.color.text_primary))
|
||||
binding.tvDescription.setTextColor(ContextCompat.getColor(context, R.color.text_secondary))
|
||||
binding.tvComment.setTextColor(ContextCompat.getColor(context, R.color.text_tertiary))
|
||||
binding.tvShare.setTextColor(ContextCompat.getColor(context, R.color.text_tertiary))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getIvIcon(binding: ViewBinding): View =
|
||||
(binding as RecyclerGameArticleBinding).ivIcon
|
||||
|
||||
override fun getTvGameName(binding: ViewBinding): TextView =
|
||||
(binding as RecyclerGameArticleBinding).tvGameName
|
||||
|
||||
override fun getTvTime(binding: ViewBinding): TextView = (binding as RecyclerGameArticleBinding).tvTime
|
||||
|
||||
override fun getTvTitle(binding: ViewBinding): TextView = (binding as RecyclerGameArticleBinding).tvTitle
|
||||
|
||||
override fun getTvDescription(binding: ViewBinding): TextView =
|
||||
(binding as RecyclerGameArticleBinding).tvDescription
|
||||
|
||||
override fun bindImgs(binding: ViewBinding, img: List<String>) {
|
||||
if (binding is RecyclerGameArticleBinding) {
|
||||
val images = img.map {
|
||||
ImageContainerView.ImageContainerData.ImageInfo(it, 3, 2)
|
||||
}
|
||||
val imageContainerData =
|
||||
ImageContainerView.ImageContainerData("", false, images, show = images.isNotEmpty())
|
||||
binding.ivImagesContainer.bindData(imageContainerData,
|
||||
object : ImageContainerView.OnImageContainerEventListener {
|
||||
override fun onImageClick(
|
||||
images: List<String>,
|
||||
position: Int,
|
||||
imageViewList: ArrayList<SimpleDraweeView>
|
||||
) {
|
||||
val checkIntent = getIntent(
|
||||
binding.root.context,
|
||||
images.toArrayList(),
|
||||
position,
|
||||
imageViewList,
|
||||
""
|
||||
)
|
||||
binding.root.context.startActivity(checkIntent)
|
||||
}
|
||||
|
||||
override fun onVideoCLick(videoId: String) = Unit
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTvComment(binding: ViewBinding): TextView = (binding as RecyclerGameArticleBinding).tvComment
|
||||
|
||||
override fun getTvShare(binding: ViewBinding): TextView = (binding as RecyclerGameArticleBinding).tvShare
|
||||
|
||||
override fun init(context: Context?) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
package com.gh.common.provider
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.LinearLayout
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.gh.common.util.ConcernContentUtils
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.core.provider.IConcernContentUtilsProvider
|
||||
|
||||
@Route(path = RouteConsts.provider.concernContentUtils, name = "ConcernContentUtils暴露服务")
|
||||
class ConcernContentUtilsProviderImpl : IConcernContentUtilsProvider {
|
||||
override fun addContentPic(
|
||||
context: Context,
|
||||
linearLayout: LinearLayout,
|
||||
list: List<String>,
|
||||
entrance: String,
|
||||
width: Int
|
||||
) {
|
||||
ConcernContentUtils.addContentPic(context, linearLayout, list, entrance, width)
|
||||
}
|
||||
|
||||
|
||||
override fun init(context: Context?) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.gh.common.provider
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.core.provider.IConcernGiftPackUtilsProvider
|
||||
import com.gh.gamecenter.databinding.RecyclerGiftPackBinding
|
||||
|
||||
@Route(path = RouteConsts.provider.concernGiftPackUtils, name = "ConcernGiftPackUtils暴露服务")
|
||||
class ConcernGiftPackUtilsProviderImpl : IConcernGiftPackUtilsProvider {
|
||||
override fun createBinding(parent: ViewGroup): ViewBinding {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
return RecyclerGiftPackBinding.inflate(inflater, parent, false)
|
||||
.also {
|
||||
it.gCode.goneIf(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun initStyle(viewBinding: ViewBinding) {
|
||||
with(viewBinding as RecyclerGiftPackBinding) {
|
||||
val context = root.context
|
||||
tvGameName.setTextColor(R.color.text_primary.toColor(context))
|
||||
tvTime.setTextColor(R.color.text_tertiary.toColor(context))
|
||||
tvGiftPackName.setTextColor(R.color.text_primary.toColor(context))
|
||||
tvGiftPackContent.setTextColor(R.color.text_secondary.toColor(context))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getIvGameIcon(viewBinding: ViewBinding) =
|
||||
(viewBinding as RecyclerGiftPackBinding).ivIcon
|
||||
|
||||
override fun getTvGameName(viewBinding: ViewBinding) =
|
||||
(viewBinding as RecyclerGiftPackBinding).tvGameName
|
||||
|
||||
override fun getTvTime(viewBinding: ViewBinding) =
|
||||
(viewBinding as RecyclerGiftPackBinding).tvTime
|
||||
|
||||
override fun getTvGiftPackName(viewBinding: ViewBinding) =
|
||||
(viewBinding as RecyclerGiftPackBinding).tvGiftPackName
|
||||
|
||||
override fun getTvGiftPackContent(viewBinding: ViewBinding) =
|
||||
(viewBinding as RecyclerGiftPackBinding).tvGiftPackContent
|
||||
|
||||
override fun init(context: Context?) {
|
||||
// Do Nothing
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.gh.common.provider
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.core.provider.IConcernShareNewsProvider
|
||||
import com.gh.gamecenter.newsdetail.NewsShareDialog
|
||||
|
||||
@Route(path = RouteConsts.provider.concernShareNews, name = "ConcernShareNews暴露服务")
|
||||
class ConcernShareNewsProviderImpl : IConcernShareNewsProvider {
|
||||
override fun share(activity: AppCompatActivity, shortId: String?, id: String?, gameIcon: String?, title: String?) {
|
||||
NewsShareDialog.show(activity, shortId, id, gameIcon, title)
|
||||
}
|
||||
|
||||
override fun init(context: Context?) {
|
||||
// Do Nothing
|
||||
}
|
||||
}
|
||||
@ -100,6 +100,10 @@ class ConfigProviderImpl : IConfigProvider {
|
||||
return Config.getNightModeSetting()?.setting ?: false
|
||||
}
|
||||
|
||||
override fun isJiguangSwitch(): Boolean {
|
||||
return Config.getNewApiSettingsEntity()?.jiguangSwitch ?: false
|
||||
}
|
||||
|
||||
override fun init(context: Context?) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.provider
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
@ -69,10 +70,18 @@ class DirectProviderImpl : IDirectProvider {
|
||||
DirectUtils.directToAmway(context, fixedTopAmwayCommentId, entrance, path)
|
||||
}
|
||||
|
||||
override fun directToQGame(context: Context) {
|
||||
override fun directToQQGameHome(context: Context) {
|
||||
return DirectUtils.directToQGameHome(context)
|
||||
}
|
||||
|
||||
override fun directToQQGameById(activity: Activity, qqAppId: String) {
|
||||
DirectUtils.directToQQGameById(activity, qqAppId)
|
||||
}
|
||||
|
||||
override fun directToWechatGameById(activity: Activity, qqAppId: String) {
|
||||
DirectUtils.directToWechatGameById(activity, qqAppId)
|
||||
}
|
||||
|
||||
override fun directToExternalBrowser(context: Context, url: String) {
|
||||
DirectUtils.directToExternalBrowser(context, url)
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package com.gh.common.provider
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.gamecenter.common.avoidcallback.Callback
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.core.provider.IEntranceUtilsProvider
|
||||
|
||||
@ -17,6 +19,14 @@ class EntranceUtilsProviderImpl : IEntranceUtilsProvider {
|
||||
EntranceUtils.saveShortcut(activityName, bundle)
|
||||
}
|
||||
|
||||
override fun jumpActivityWithCallback(context: Context, bundle: Bundle, callback: () -> Unit) {
|
||||
EntranceUtils.jumpActivity(context, null, bundle, object : Callback {
|
||||
override fun onActivityResult(resultCode: Int, data: Intent?) {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun init(context: Context?) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
package com.gh.common.provider
|
||||
|
||||
import android.content.Context
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.core.provider.IMiniGameRecentlyPlayedProvider
|
||||
import com.gh.gamecenter.minigame.MiniGameRecentlyPlayUseCase
|
||||
|
||||
@Route(path = RouteConsts.provider.miniGameRecentPlayed, name = "MiniGameRecentlyPlayed暴露服务")
|
||||
class MiniGameRecentlyPlayedProviderImpl : IMiniGameRecentlyPlayedProvider {
|
||||
override fun clearMiniGameRecentlyPlayed(gameType: String) {
|
||||
MiniGameRecentlyPlayUseCase.clearRecentlyPlayedMiniGameList(gameType)
|
||||
}
|
||||
|
||||
override fun refreshQQMiniRecentPlayed() {
|
||||
MiniGameRecentlyPlayUseCase.loadRecentlyPlayedMiniGameList(Constants.QQ_MINI_GAME)
|
||||
}
|
||||
|
||||
override fun init(context: Context?) {
|
||||
// no implement
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,7 @@ class PackageUtilsProviderImpl : IPackageUtilsProvider {
|
||||
}
|
||||
|
||||
override fun getInstalledPackages(context: Context, flag: Int): List<PackageInfo> {
|
||||
return PackageHelper.getInstalledPackages(context, flag)
|
||||
return PackageHelper.getInstalledPackageInfoList(context, flag)
|
||||
}
|
||||
|
||||
override fun getApkSignatureByPackageName(context: Context, packageName: String): Array<String> {
|
||||
|
||||
@ -19,8 +19,10 @@ import com.gh.gamecenter.databinding.DialogArchiveLoadingBinding
|
||||
import com.gh.gamecenter.entity.ArchiveEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.va.VCore
|
||||
import com.gh.vspace.VArchiveHelper
|
||||
import com.gh.vspace.VHelper
|
||||
import com.gh.vspace.VHelper.is32
|
||||
import com.lg.download.DownloadError
|
||||
import com.lg.download.DownloadStatus
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
@ -50,8 +52,6 @@ object ArchiveDownloadButtonHelper {
|
||||
}
|
||||
downloadBtn.setOnClickListener {
|
||||
when {
|
||||
// 检查是否已安装畅玩助手
|
||||
!VHelper.isVSpaceInstalled(context) -> showVSpaceTipDialog(context, gameEntity)
|
||||
// 检查是否已安装游戏
|
||||
!VHelper.isInstalled(packageName) -> {
|
||||
// 检查游戏是否在安装中
|
||||
@ -273,14 +273,19 @@ object ArchiveDownloadButtonHelper {
|
||||
R.string.archive_apply.toResString(),
|
||||
R.string.cancel.toResString(),
|
||||
{
|
||||
applyArchive(context, entrance, packageName, config, archiveEntity, gameEntity)
|
||||
NewFlatLogUtils.logCloudArchiveApplyDialogRelated("cloud_save_overwrite_dialog_click", "使用")
|
||||
SensorsBridge.trackEvent(
|
||||
"CloudSaveOverwriteDialogClick",
|
||||
"game_id", gameEntity?.id ?: "",
|
||||
"game_name", gameEntity?.name ?: "",
|
||||
"button_name", "使用"
|
||||
)
|
||||
if(gameEntity.is32() && VHelper.isInnerInstalled(packageName) && !VCore.getInstance().isExtPackageInstalled()) {
|
||||
// 32位的游戏 并且 32位畅玩没有安装 并且 一体化
|
||||
VHelper.newCwValidateVspaceBeforeAction(context, gameEntity) {}
|
||||
} else {
|
||||
applyArchive(context, entrance, packageName, config, archiveEntity, gameEntity)
|
||||
NewFlatLogUtils.logCloudArchiveApplyDialogRelated("cloud_save_overwrite_dialog_click", "使用")
|
||||
SensorsBridge.trackEvent(
|
||||
"CloudSaveOverwriteDialogClick",
|
||||
"game_id", gameEntity?.id ?: "",
|
||||
"game_name", gameEntity?.name ?: "",
|
||||
"button_name", "使用"
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
NewFlatLogUtils.logCloudArchiveApplyDialogRelated("cloud_save_overwrite_dialog_click", "取消")
|
||||
|
||||
@ -1,14 +1,21 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts;
|
||||
import com.gh.gamecenter.login.view.LoginActivity;
|
||||
import com.gh.gamecenter.common.utils.NetworkUtils;
|
||||
import com.gh.gamecenter.core.utils.CurrentActivityHolder;
|
||||
import com.gh.gamecenter.login.user.UserManager;
|
||||
import com.gh.gamecenter.login.utils.QuickLoginHelper;
|
||||
import com.gh.gamecenter.login.view.LoginActivity;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
|
||||
|
||||
/**
|
||||
* Created by khy on 28/06/17.
|
||||
@ -22,15 +29,15 @@ public class CheckLoginUtils {
|
||||
LogUtils.login("dialog", null, entrance);
|
||||
LogUtils.login("activity", null, entrance);
|
||||
|
||||
// if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
|
||||
// startQuickLogin(context, entrance);
|
||||
// } else {
|
||||
// 有可能App未启动
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
|
||||
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
|
||||
EntranceUtils.jumpActivity(context, bundle);
|
||||
// }
|
||||
if (NetworkUtils.isQuickLoginEnabled(context)) {
|
||||
startQuickLogin(context, entrance, null);
|
||||
} else {
|
||||
// 有可能App未启动
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
|
||||
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
|
||||
EntranceUtils.jumpActivity(context, bundle);
|
||||
}
|
||||
} else {
|
||||
if (listener != null) {
|
||||
listener.onLogin();
|
||||
@ -38,16 +45,16 @@ public class CheckLoginUtils {
|
||||
}
|
||||
}
|
||||
|
||||
// private static void startQuickLogin(Context context, String entrance) {
|
||||
// // 需要确保传入的 context 不为 application
|
||||
// if (!(context instanceof Activity)) {
|
||||
// context = CurrentActivityHolder.getCurrentActivity();
|
||||
// }
|
||||
//
|
||||
// if (context != null) {
|
||||
// QuickLoginHelper.startLogin(context, entrance);
|
||||
// }
|
||||
// }
|
||||
private static void startQuickLogin(Context context, String entrance, Function0<Unit> callback) {
|
||||
// 需要确保传入的 context 不为 application
|
||||
if (!(context instanceof Activity)) {
|
||||
context = CurrentActivityHolder.getCurrentActivity();
|
||||
}
|
||||
|
||||
if (context != null) {
|
||||
QuickLoginHelper.startLogin(context, entrance, callback);
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkLogin(final Context context, Bundle nextToBundle, boolean isTriggerNextStep, String entrance, OnLoginListener listener) {
|
||||
if (!isLogin()) {
|
||||
@ -55,15 +62,25 @@ public class CheckLoginUtils {
|
||||
LogUtils.login("dialog", null, entrance);
|
||||
LogUtils.login("activity", null, entrance);
|
||||
|
||||
// 有可能App未启动
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
|
||||
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
|
||||
EntranceUtils.jumpActivity(context, nextToBundle, bundle, (resultCode, data) -> {
|
||||
if (isTriggerNextStep && listener != null && isLogin()) {
|
||||
listener.onLogin();
|
||||
}
|
||||
});
|
||||
if (NetworkUtils.isQuickLoginEnabled(context)) {
|
||||
startQuickLogin(context, entrance, () -> {
|
||||
if (isTriggerNextStep && listener != null && isLogin()) {
|
||||
listener.onLogin();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
// 有可能App未启动
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
|
||||
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
|
||||
EntranceUtils.jumpActivity(context, nextToBundle, bundle, (resultCode, data) -> {
|
||||
if (isTriggerNextStep && listener != null && isLogin()) {
|
||||
listener.onLogin();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
if (listener != null) {
|
||||
listener.onLogin();
|
||||
|
||||
@ -7,8 +7,8 @@ import android.widget.LinearLayout;
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.gh.gamecenter.ImageViewerActivity;
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils;
|
||||
import com.gh.gamecenter.common.utils.ImageUtils;
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -121,5 +121,4 @@ public class ConcernContentUtils {
|
||||
}
|
||||
return imageView;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,17 +1,14 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts;
|
||||
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
|
||||
import com.gh.gamecenter.common.utils.NetworkUtils;
|
||||
import com.gh.gamecenter.feature.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.NewsDetailEntity;
|
||||
import com.gh.gamecenter.feature.utils.PlatformUtils;
|
||||
import com.gh.gamecenter.manager.DataCollectionManager;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -32,7 +29,7 @@ public class DataCollectionUtils {
|
||||
map.put("type", android.os.Build.MODEL);
|
||||
map.put("system", android.os.Build.VERSION.SDK_INT + "=" + android.os.Build.VERSION.RELEASE);
|
||||
// WIFI实时
|
||||
DataCollectionManager.onEvent(context, "error", map, NetworkUtils.isWifiConnected(context));
|
||||
DataCollectionManager.onEvent(context, "error", map, true);
|
||||
}
|
||||
|
||||
// 上传下载数据(开始、完成)
|
||||
|
||||
@ -9,19 +9,18 @@ import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.alibaba.android.arouter.launcher.ARouter;
|
||||
import com.gh.ad.AdDelegateHelper;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager;
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity;
|
||||
import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.common.constant.RouteConsts;
|
||||
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse;
|
||||
import com.gh.gamecenter.common.utils.ExtensionsKt;
|
||||
import com.gh.gamecenter.core.AppExecutor;
|
||||
import com.gh.gamecenter.core.provider.ISentryProvider;
|
||||
import com.gh.gamecenter.core.utils.GsonUtils;
|
||||
import com.gh.gamecenter.core.utils.MtaHelper;
|
||||
import com.gh.gamecenter.core.utils.SPUtils;
|
||||
import com.gh.gamecenter.core.utils.SentryHelper;
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper;
|
||||
import com.gh.gamecenter.login.entity.IdCardEntity;
|
||||
import com.gh.gamecenter.login.entity.UserInfoEntity;
|
||||
import com.gh.gamecenter.provider.GhContentProvider;
|
||||
@ -32,12 +31,7 @@ import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.config.CommonDebug;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import io.sentry.Sentry;
|
||||
import io.sentry.android.core.SentryAndroid;
|
||||
import kotlin.Pair;
|
||||
|
||||
/**
|
||||
* Created by LGT on 2016/6/15.
|
||||
@ -61,92 +55,58 @@ public class DataUtils {
|
||||
}
|
||||
|
||||
private static void initSentry(Context context, String channel) {
|
||||
SentryAndroid.init(context, options -> {
|
||||
// Sentry 疯狂报 ANR (很大一部分还是莫名奇妙的 ANR)严重影响到其它闪退日志的收集
|
||||
// 这里将它局限到只有官网渠道的包才统计 ANR
|
||||
if ("GH_206".equals(channel) || "GH_BETA".equals(channel) || com.gh.gamecenter.common.BuildConfig.BUILD_TIME != 0) {
|
||||
options.setAnrEnabled(true);
|
||||
options.setAnrTimeoutIntervalMillis(6000);
|
||||
} else {
|
||||
options.setAnrEnabled(false);
|
||||
}
|
||||
|
||||
options.setDebug(BuildConfig.DEBUG);
|
||||
options.setEnableAutoSessionTracking(true);
|
||||
options.setEnvironment(BuildConfig.FLAVOR);
|
||||
options.setEnableSystemEventBreadcrumbs(false);
|
||||
options.setDsn("https://6b1caf0d17c1408e8680f3f73ff80bd0@sentry.shanqu.cc/22");
|
||||
|
||||
options.setBeforeSend((event, hint) -> {
|
||||
if (BuildConfig.DEBUG) {
|
||||
return null;
|
||||
} else {
|
||||
return event;
|
||||
}
|
||||
});
|
||||
|
||||
options.setBeforeBreadcrumb(((breadcrumb, hint) -> {
|
||||
if ("ui.lifecycle".equals(breadcrumb.getCategory()) && "started".equals(breadcrumb.getData("state")) && GlobalActivityManager.INSTANCE.getCurrentActivity() instanceof BaseActivity) {
|
||||
Pair<String, String> businessId = ((BaseActivity) GlobalActivityManager.INSTANCE.getCurrentActivity()).getBusinessId();
|
||||
if (businessId != null) {
|
||||
breadcrumb.setData("businessId1", businessId.component1());
|
||||
breadcrumb.setData("businessId2", businessId.component2());
|
||||
}
|
||||
}
|
||||
return breadcrumb;
|
||||
}));
|
||||
});
|
||||
|
||||
Sentry.configureScope(scope -> {
|
||||
if (com.gh.gamecenter.common.BuildConfig.BUILD_TIME != 0L) {
|
||||
scope.setTag("alias", "内测版" + BuildConfig.VERSION_NAME);
|
||||
} else {
|
||||
scope.setTag("alias", "正式版" + BuildConfig.VERSION_NAME);
|
||||
scope.setTag("channel", channel);
|
||||
}
|
||||
});
|
||||
ISentryProvider sentryProvider = (ISentryProvider) ARouter.getInstance().build(RouteConsts.provider.sentry).navigation();
|
||||
if (sentryProvider != null) {
|
||||
sentryProvider.init(context, channel, BuildConfig.FLAVOR, BuildConfig.VERSION_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
public static void getGid() {
|
||||
GidHelper.getInstance().registerDevice(HaloApp.getInstance().getApplication(), new GidCallback() {
|
||||
@Override
|
||||
public void onSuccess(String gid) {
|
||||
Utils.log("Gid", gid);
|
||||
PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit().putString(Constants.DEVICE_KEY, gid).apply();
|
||||
// 默认用 APP 级已存储的 GID 来使用,不使用外部 GID
|
||||
String savedGid = SPUtils.getString(Constants.GID);
|
||||
if (!TextUtils.isEmpty(savedGid)) {
|
||||
HaloApp.getInstance().setGid(savedGid);
|
||||
onGidReceived(savedGid);
|
||||
} else {
|
||||
GidHelper.getInstance().registerDevice(HaloApp.getInstance().getApplication(), new GidCallback() {
|
||||
@Override
|
||||
public void onSuccess(String gid) {
|
||||
Utils.log("Gid", gid);
|
||||
PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit().putString(Constants.DEVICE_KEY, gid).apply();
|
||||
|
||||
// 默认用 APP 级已存储的 GID 来使用,不使用外部 GID
|
||||
String savedGid = SPUtils.getString(Constants.GID);
|
||||
if (!TextUtils.isEmpty(savedGid)) {
|
||||
gid = savedGid;
|
||||
} else {
|
||||
SPUtils.setString(Constants.GID, gid);
|
||||
|
||||
onGidReceived(gid);
|
||||
}
|
||||
|
||||
HaloApp.getInstance().setGid(gid);
|
||||
|
||||
// 更新广告配置
|
||||
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
|
||||
|
||||
getDeviceCertification(gid);
|
||||
|
||||
// 避免初始化顺序问题导致 MetaUtil 一直持有空的 gid
|
||||
MetaUtil.INSTANCE.refreshMeta();
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(GhContentProvider.KEY_GID, gid);
|
||||
values.put(GhContentProvider.KEY_ANDROID_ID, MetaUtil.getBase64EncodedAndroidId());
|
||||
try {
|
||||
HaloApp.getInstance().getContentResolver().insert(Uri.parse("content://com.gh.gamecenter.provider/device"), values);
|
||||
} catch (Exception exception) {
|
||||
SentryHelper.INSTANCE.onEvent("DEVICE_INSERT_ERROR", "exception_digest", exception.getLocalizedMessage());
|
||||
exception.printStackTrace();
|
||||
@Override
|
||||
public void onFailure(String s) {
|
||||
// 更新广告配置
|
||||
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(String s) {
|
||||
// 更新广告配置
|
||||
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
|
||||
private static void onGidReceived(String gid) {
|
||||
HaloApp.getInstance().setGid(gid);
|
||||
// 更新广告配置
|
||||
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
|
||||
|
||||
getDeviceCertification(gid);
|
||||
|
||||
// 避免初始化顺序问题导致 MetaUtil 一直持有空的 gid
|
||||
MetaUtil.INSTANCE.refreshMeta();
|
||||
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(GhContentProvider.KEY_GID, gid);
|
||||
values.put(GhContentProvider.KEY_ANDROID_ID, MetaUtil.getBase64EncodedAndroidId());
|
||||
try {
|
||||
HaloApp.getInstance().getContentResolver().insert(Uri.parse("content://com.gh.gamecenter.provider/device"), values);
|
||||
} catch (Exception exception) {
|
||||
SentryHelper.INSTANCE.onEvent("DEVICE_INSERT_ERROR", "exception_digest", exception.getLocalizedMessage());
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.filter.RegionSetting;
|
||||
import com.gh.common.filter.RegionSettingHelper;
|
||||
import com.gh.common.repository.ReservationRepository;
|
||||
@ -19,6 +18,7 @@ import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.common.entity.LinkEntity;
|
||||
import com.gh.gamecenter.common.utils.ExtensionsKt;
|
||||
import com.gh.gamecenter.core.utils.SPUtils;
|
||||
import com.gh.gamecenter.core.utils.SpeedUtils;
|
||||
import com.gh.gamecenter.feature.entity.GameEntity;
|
||||
import com.gh.gamecenter.feature.entity.PluginLocation;
|
||||
import com.gh.gamecenter.feature.view.DownloadButton;
|
||||
@ -48,11 +48,6 @@ public class DetailDownloadUtils {
|
||||
GameEntity gameEntity = viewHolder.getGameEntity();
|
||||
String downloadAddWord = gameEntity.getDownloadAddWord();
|
||||
|
||||
// 隐藏下载按钮上的畅玩文案
|
||||
if (viewHolder.getOverlayTv() != null) {
|
||||
viewHolder.getOverlayTv().setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// 多版本下载箭头
|
||||
if (viewHolder.getMultiVersionDownloadTv() != null) {
|
||||
viewHolder.getMultiVersionDownloadTv().setVisibility(View.GONE);
|
||||
@ -117,17 +112,6 @@ public class DetailDownloadUtils {
|
||||
}
|
||||
}
|
||||
|
||||
// 更新默认的下载按钮
|
||||
updateWithSingleApk(
|
||||
gameEntity,
|
||||
viewHolder,
|
||||
viewHolder.getDownloadPb(),
|
||||
downloadAddWord,
|
||||
showVGame,
|
||||
showDualDownloadButton,
|
||||
downloadEntity
|
||||
);
|
||||
|
||||
if (showDualDownloadButton) {
|
||||
// 双下载按钮时更新占位的下载按钮
|
||||
updateWithSingleApk(
|
||||
@ -140,6 +124,17 @@ public class DetailDownloadUtils {
|
||||
downloadEntity
|
||||
);
|
||||
}
|
||||
|
||||
// 更新默认的下载按钮
|
||||
updateWithSingleApk(
|
||||
gameEntity,
|
||||
viewHolder,
|
||||
viewHolder.getDownloadPb(),
|
||||
downloadAddWord,
|
||||
showVGame,
|
||||
showDualDownloadButton,
|
||||
downloadEntity
|
||||
);
|
||||
} else {
|
||||
// 游戏包含多 APK 的情况
|
||||
viewHolder.getMultiVersionDownloadTv().setText("选择下载你的版本" + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord));
|
||||
@ -192,49 +187,53 @@ public class DetailDownloadUtils {
|
||||
Context context = viewHolder.getContext();
|
||||
TextView overlayTv = viewHolder.getOverlayTv();
|
||||
|
||||
String status = GameUtils.getDownloadBtnText(context, gameEntity, false, showAsVGame, PluginLocation.only_game);
|
||||
boolean containsAddWord = !TextUtils.isEmpty(downloadAddWord); // 是否存在下载补充文案
|
||||
|
||||
// 根据游戏实体获取下载按钮文案
|
||||
String rawBtnText = GameUtils.getDownloadBtnText(context, gameEntity, false, showAsVGame, PluginLocation.only_game);
|
||||
|
||||
if (showAsVGame) {
|
||||
// 显示为畅玩游戏
|
||||
if (context.getString(R.string.launch).equals(status)) {
|
||||
if (context.getString(R.string.launch).equals(rawBtnText)) {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
|
||||
} else {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
|
||||
}
|
||||
|
||||
String btnText;
|
||||
String decoratedBtnText;
|
||||
// 双下载按钮时,显示特殊样式
|
||||
if (showDualDownloadButton
|
||||
&& (context.getString(R.string.launch).equals(status) || context.getString(R.string.install).equals(status) || context.getString(R.string.smooth).equals(status) || context.getString(R.string.update).equals(status))) {
|
||||
if (context.getString(R.string.smooth).equals(status)) {
|
||||
btnText = context.getString(R.string.download_v);
|
||||
} else if (context.getString(R.string.update).equals(status)) {
|
||||
btnText = context.getString(R.string.update_v);
|
||||
&& (context.getString(R.string.launch).equals(rawBtnText) || context.getString(R.string.install).equals(rawBtnText) || context.getString(R.string.smooth).equals(rawBtnText) || context.getString(R.string.update).equals(rawBtnText))) {
|
||||
if (context.getString(R.string.smooth).equals(rawBtnText)) {
|
||||
decoratedBtnText = context.getString(R.string.download_v);
|
||||
} else if (context.getString(R.string.update).equals(rawBtnText)) {
|
||||
decoratedBtnText = context.getString(R.string.update_v);
|
||||
} else {
|
||||
btnText = context.getString(R.string.launch_v);
|
||||
decoratedBtnText = context.getString(R.string.launch_v);
|
||||
}
|
||||
|
||||
if (overlayTv != null && downloadButton.getVisibility() != View.GONE) {
|
||||
overlayTv.setVisibility(View.VISIBLE);
|
||||
overlayTv.setText(btnText);
|
||||
overlayTv.setText(decoratedBtnText);
|
||||
downloadButton.setText("");
|
||||
}
|
||||
} else {
|
||||
btnText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : downloadAddWord) + getDownloadSizeText(viewHolder);
|
||||
decoratedBtnText = rawBtnText + (containsAddWord? "" : downloadAddWord) + getWrappedDownloadSizeText(viewHolder);
|
||||
|
||||
if (overlayTv != null && downloadButton.getVisibility() != View.GONE) {
|
||||
if (context.getString(R.string.launch).equals(status)
|
||||
|| context.getString(R.string.install).equals(status)) {
|
||||
if (context.getString(R.string.launch).equals(rawBtnText)
|
||||
|| context.getString(R.string.install).equals(rawBtnText)) {
|
||||
overlayTv.setVisibility(View.VISIBLE);
|
||||
overlayTv.setText("启动(畅玩)");
|
||||
} else {
|
||||
overlayTv.setVisibility(View.GONE);
|
||||
downloadButton.setText(btnText);
|
||||
downloadButton.setText(decoratedBtnText);
|
||||
}
|
||||
} else {
|
||||
if (overlayTv != null) {
|
||||
overlayTv.setVisibility(View.GONE);
|
||||
}
|
||||
downloadButton.setText(btnText);
|
||||
downloadButton.setText(decoratedBtnText);
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,11 +246,11 @@ public class DetailDownloadUtils {
|
||||
}
|
||||
} else {
|
||||
// 非畅玩,显示为普通游戏
|
||||
if (context.getString(R.string.pluggable).equals(status)) {
|
||||
if (context.getString(R.string.pluggable).equals(rawBtnText)) {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.PLUGIN);
|
||||
} else if (context.getString(R.string.launch).equals(status)) {
|
||||
} else if (context.getString(R.string.launch).equals(rawBtnText)) {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
|
||||
} else if (context.getString(R.string.install).equals(status)) {
|
||||
} else if (context.getString(R.string.install).equals(rawBtnText)) {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_NORMAL);
|
||||
} else {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
|
||||
@ -271,48 +270,78 @@ public class DetailDownloadUtils {
|
||||
}
|
||||
}
|
||||
|
||||
String btnText;
|
||||
String extraBtnText;
|
||||
String decoratedBtnText;
|
||||
String localBtnText;
|
||||
boolean useAlternativeTextStyle = false; // 是否使用带图标的文案,仅不包含补充文案时使用且
|
||||
|
||||
// 更新下载按钮文案
|
||||
if (viewHolder.isNewsDetail()) {
|
||||
btnText = status;
|
||||
extraBtnText = status;
|
||||
} else if (context.getString(R.string.pluggable).equals(status)) {
|
||||
btnText = "升级" + (TextUtils.isEmpty(downloadAddWord) ? "" : "至" + downloadAddWord) + getDownloadSizeText(viewHolder);
|
||||
extraBtnText = "升级" + (TextUtils.isEmpty(downloadAddWord) ? "" : "至" + downloadAddWord);
|
||||
} else if (context.getString(R.string.launch).equals(status)) {
|
||||
btnText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord);
|
||||
extraBtnText = context.getString(R.string.launch_local);
|
||||
} else if (context.getString(R.string.attempt).equals(status)) {
|
||||
btnText = status + getDownloadSizeText(viewHolder);
|
||||
extraBtnText = status;
|
||||
decoratedBtnText = rawBtnText;
|
||||
localBtnText = rawBtnText;
|
||||
} else if (context.getString(R.string.pluggable).equals(rawBtnText)) {
|
||||
decoratedBtnText = "升级" + (!containsAddWord ? "" : "至" + downloadAddWord) + getWrappedDownloadSizeText(viewHolder);
|
||||
localBtnText = "升级" + (!containsAddWord ? "" : "至" + downloadAddWord);
|
||||
} else if (context.getString(R.string.launch).equals(rawBtnText)) {
|
||||
decoratedBtnText = rawBtnText + (!containsAddWord ? "" : "-" + downloadAddWord);
|
||||
localBtnText = context.getString(R.string.launch_local);
|
||||
} else if (context.getString(R.string.attempt).equals(rawBtnText)) {
|
||||
decoratedBtnText = context.getString(R.string.attempt);
|
||||
localBtnText = rawBtnText;
|
||||
if (showDualDownloadButton
|
||||
&& viewHolder.getLocalDownloadContainer() != null
|
||||
&& viewHolder.getLocalDownloadContainer().getVisibility() == View.VISIBLE) {
|
||||
viewHolder.getLocalDownloadSizeTv().setVisibility(View.VISIBLE);
|
||||
} else if (viewHolder.getOverlayTv() != null) {
|
||||
useAlternativeTextStyle = true;
|
||||
}
|
||||
} else if (context.getString(R.string.install).equals(status)) {
|
||||
btnText = context.getString(R.string.install);
|
||||
extraBtnText = context.getString(R.string.install_local);
|
||||
} else if (context.getString(R.string.update).equals(status)) {
|
||||
btnText = context.getString(R.string.update);
|
||||
extraBtnText = context.getString(R.string.update_local);
|
||||
} else if (context.getString(R.string.install).equals(rawBtnText)) {
|
||||
decoratedBtnText = context.getString(R.string.install);
|
||||
localBtnText = context.getString(R.string.install_local);
|
||||
} else if (context.getString(R.string.update).equals(rawBtnText)) {
|
||||
decoratedBtnText = context.getString(R.string.update);
|
||||
localBtnText = context.getString(R.string.update_local);
|
||||
if (showDualDownloadButton
|
||||
&& viewHolder.getLocalDownloadContainer() != null
|
||||
&& viewHolder.getLocalDownloadContainer().getVisibility() == View.VISIBLE) {
|
||||
viewHolder.getLocalDownloadSizeTv().setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
btnText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : downloadAddWord) + getDownloadSizeText(viewHolder);
|
||||
extraBtnText = context.getString(R.string.download_local);
|
||||
if (containsAddWord) {
|
||||
decoratedBtnText = rawBtnText + downloadAddWord + getWrappedDownloadSizeText(viewHolder);
|
||||
} else {
|
||||
decoratedBtnText = rawBtnText;
|
||||
}
|
||||
localBtnText = context.getString(R.string.download_local);
|
||||
if (showDualDownloadButton
|
||||
&& viewHolder.getLocalDownloadContainer() != null
|
||||
&& viewHolder.getLocalDownloadContainer().getVisibility() == View.VISIBLE) {
|
||||
viewHolder.getLocalDownloadSizeTv().setVisibility(View.VISIBLE);
|
||||
} else if (viewHolder.getOverlayTv() != null && !containsAddWord) {
|
||||
useAlternativeTextStyle = true;
|
||||
}
|
||||
}
|
||||
downloadButton.setText(btnText);
|
||||
|
||||
if (useAlternativeTextStyle) {
|
||||
downloadButton.setText("");
|
||||
viewHolder.getOverlayTv().setText(decoratedBtnText);
|
||||
viewHolder.getOverlayTv().setVisibility(View.VISIBLE);
|
||||
viewHolder.getOverlayTv().setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_special_download, 0, 0, 0);
|
||||
if (viewHolder.getExtraOverlayTv() != null) {
|
||||
viewHolder.getExtraOverlayTv().setVisibility(View.VISIBLE);
|
||||
viewHolder.getExtraOverlayTv().setText(gameEntity.getApk().get(0).getSize());
|
||||
}
|
||||
} else {
|
||||
if (viewHolder.getOverlayTv() != null && !showDualDownloadButton) {
|
||||
viewHolder.getOverlayTv().setVisibility(View.GONE);
|
||||
if (viewHolder.getExtraOverlayTv() != null) {
|
||||
viewHolder.getExtraOverlayTv().setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
downloadButton.setText(decoratedBtnText);
|
||||
}
|
||||
|
||||
if (viewHolder.getLocalDownloadTitleTv() != null) {
|
||||
viewHolder.getLocalDownloadTitleTv().setText(extraBtnText);
|
||||
viewHolder.getLocalDownloadTitleTv().setText(localBtnText);
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,10 +378,13 @@ public class DetailDownloadUtils {
|
||||
if (overlayTv != null
|
||||
&& downloadEntity.getStatus() != DownloadStatus.done) {
|
||||
overlayTv.setVisibility(View.GONE);
|
||||
if (viewHolder.getExtraOverlayTv() != null) {
|
||||
viewHolder.getExtraOverlayTv().setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
if (showAsVGame) {
|
||||
updateVStyleDownloadButton(viewHolder, downloadButton, downloadEntity, status);
|
||||
updateVStyleDownloadButton(viewHolder, downloadButton, downloadEntity, rawBtnText);
|
||||
} else {
|
||||
updateDefaultStyleDownloadButton(context, viewHolder, downloadButton, gameEntity, downloadEntity);
|
||||
}
|
||||
@ -441,7 +473,7 @@ public class DetailDownloadUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String getDownloadSizeText(DetailViewHolder viewHolder) {
|
||||
private static String getWrappedDownloadSizeText(DetailViewHolder viewHolder) {
|
||||
return String.format("(%s)", viewHolder.getGameEntity().getApk().isEmpty() ? "" : viewHolder.getGameEntity().getApk().get(0).getSize());
|
||||
}
|
||||
|
||||
@ -452,7 +484,7 @@ public class DetailDownloadUtils {
|
||||
switch (downloadEntity.getStatus()) {
|
||||
case redirected:
|
||||
case downloading:
|
||||
downloadButton.setText("游戏加载中 " + downloadEntity.getPercent() + "%");
|
||||
downloadButton.setText(SpeedUtils.getSpeed(downloadEntity.getSpeed()));
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_NORMAL);
|
||||
break;
|
||||
case waiting:
|
||||
@ -466,11 +498,13 @@ public class DetailDownloadUtils {
|
||||
case diskisfull:
|
||||
case diskioerror:
|
||||
case pause:
|
||||
downloadButton.setText("继续加载 " + downloadEntity.getPercent() + "%");
|
||||
String pausedText = viewHolder.getContext().getString(R.string.paused);
|
||||
downloadButton.setText(getValidProgress(downloadEntity) + "% " + pausedText);
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_NORMAL);
|
||||
break;
|
||||
case done:
|
||||
if (!status.contains("更新")) {
|
||||
String updateText = viewHolder.getContext().getString(R.string.update);
|
||||
if (!status.contains(updateText)) {
|
||||
if (VHelper.isInstalled(downloadEntity.getPackageName())) {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
|
||||
} else {
|
||||
@ -510,8 +544,9 @@ public class DetailDownloadUtils {
|
||||
case diskisfull:
|
||||
case diskioerror:
|
||||
case overflow:
|
||||
String downloadingText = "游戏加载中 " + downloadEntity.getPercent() + "%";
|
||||
String resumeText = "继续加载 " + downloadEntity.getPercent() + "%";
|
||||
String pausedText = context.getString(R.string.paused);
|
||||
String downloadingText = SpeedUtils.getSpeed(downloadEntity.getSpeed());
|
||||
String resumeText = getValidProgress(downloadEntity) + "% " + pausedText;
|
||||
downloadButton.setText((downloadEntity.getStatus() == DownloadStatus.downloading || downloadEntity.getStatus() == DownloadStatus.redirected) ? downloadingText : resumeText);
|
||||
if (downloadEntity.isPluggable() && PackagesManager.isInstalled(downloadEntity.getPackageName())) {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN);
|
||||
@ -561,6 +596,10 @@ public class DetailDownloadUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static int getValidProgress(DownloadEntity downloadEntity) {
|
||||
return (int) Math.ceil(downloadEntity.getPercent());
|
||||
}
|
||||
|
||||
private static boolean handleDownloadButtonAsXapk(DownloadEntity downloadEntity, DownloadButton downloadButton) {
|
||||
String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);
|
||||
|
||||
|
||||
@ -633,7 +633,19 @@ public class DialogUtils {
|
||||
|
||||
binding.gameIcon.displayGameIcon(gameEntity);
|
||||
binding.gameNameTv.setText(context.getString(R.string.dialog_land_page_address_hint, gameEntity.getName()));
|
||||
binding.closeIv.setOnClickListener(v -> dialog.dismiss());
|
||||
|
||||
AtomicBoolean dismissByButton = new AtomicBoolean(false);
|
||||
|
||||
binding.closeIv.setOnClickListener(v -> {
|
||||
dismissByButton.set(true);
|
||||
SensorsBridge.INSTANCE.trackJumpLandPageAddressDialogClick(
|
||||
"取消",
|
||||
gameEntity.getId(),
|
||||
gameEntity.getName() != null ? gameEntity.getName() : "",
|
||||
gameEntity.getCategoryChinese()
|
||||
);
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
binding.urlTv.setText(gameEntity.getLandPageAddressDialog().getLink());
|
||||
|
||||
@ -643,10 +655,28 @@ public class DialogUtils {
|
||||
|
||||
binding.downloadBtn.setText(downloadText);
|
||||
binding.downloadBtn.setOnClickListener(v -> {
|
||||
dismissByButton.set(true);
|
||||
SensorsBridge.INSTANCE.trackJumpLandPageAddressDialogClick(
|
||||
"前往第三方网站下载游戏",
|
||||
gameEntity.getId(),
|
||||
gameEntity.getName() != null ? gameEntity.getName() : "",
|
||||
gameEntity.getCategoryChinese()
|
||||
);
|
||||
listener.onConfirm();
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.setOnDismissListener(dialog1 -> {
|
||||
if (!dismissByButton.get()) {
|
||||
SensorsBridge.INSTANCE.trackJumpLandPageAddressDialogClick(
|
||||
"关闭弹窗",
|
||||
gameEntity.getId(),
|
||||
gameEntity.getName() != null ? gameEntity.getName() : "",
|
||||
gameEntity.getCategoryChinese()
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Window window = dialog.getWindow();
|
||||
if (window != null) {
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
@ -655,6 +685,12 @@ public class DialogUtils {
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
|
||||
SensorsBridge.INSTANCE.trackJumpLandPageAddressDialogShow(
|
||||
gameEntity.getId(),
|
||||
gameEntity.getName() != null ? gameEntity.getName() : "",
|
||||
gameEntity.getCategoryChinese()
|
||||
);
|
||||
}
|
||||
|
||||
public static void showGameH5DownloadDialog(Context context, GameEntity gameEntity, RegionSetting.GameH5Download gameH5Download) {
|
||||
|
||||
@ -10,6 +10,7 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.os.bundleOf
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.exposure.ExposureManager.log
|
||||
@ -18,8 +19,6 @@ import com.gh.common.util.EntranceUtils.jumpActivity
|
||||
import com.gh.common.util.EntranceUtils.jumpActivityCompat
|
||||
import com.gh.gamecenter.*
|
||||
import com.gh.gamecenter.amway.AmwayActivity
|
||||
import com.gh.gamecenter.catalog.CatalogActivity
|
||||
import com.gh.gamecenter.category.CategoryDirectoryActivity
|
||||
import com.gh.gamecenter.category2.CategoryV2Activity
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity_TabLayout
|
||||
@ -43,11 +42,13 @@ import com.gh.gamecenter.feature.entity.MeEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
|
||||
import com.gh.gamecenter.feature.exposure.ExposureType
|
||||
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
|
||||
import com.gh.gamecenter.feature.provider.IConcernInfoProvider
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailActivity
|
||||
import com.gh.gamecenter.forum.home.CommunityActivity
|
||||
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity
|
||||
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailActivity
|
||||
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailFragment
|
||||
import com.gh.gamecenter.game.commoncollection.detail.CustomCommonCollectionDetailActivity
|
||||
import com.gh.gamecenter.game.upload.GameSubmissionActivity
|
||||
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
|
||||
@ -63,6 +64,9 @@ import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
|
||||
import com.gh.gamecenter.help.HelpAndFeedbackBridge
|
||||
import com.gh.gamecenter.libao.LibaoDetailActivity
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.minigame.MiniGameRecentlyPlayUseCase
|
||||
import com.gh.gamecenter.minigame.MiniGameSearchActivity
|
||||
import com.gh.gamecenter.minigame.qq.QGameHomeWrapperActivity
|
||||
import com.gh.gamecenter.newsdetail.NewsDetailActivity
|
||||
import com.gh.gamecenter.personalhome.UserHomeActivity
|
||||
import com.gh.gamecenter.personalhome.background.PersonalityBackgroundActivity
|
||||
@ -73,9 +77,6 @@ import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
|
||||
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
|
||||
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
|
||||
import com.gh.gamecenter.qgame.QGameHomeWrapperActivity
|
||||
import com.gh.gamecenter.qgame.QGameSearchActivity
|
||||
import com.gh.gamecenter.qgame.QGameViewModel
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.servers.GameServerTestActivity
|
||||
import com.gh.gamecenter.servers.GameServersActivity
|
||||
@ -95,6 +96,8 @@ import com.gh.vspace.VDownloadManagerActivity
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.halo.assistant.fragment.WebFragment
|
||||
import com.lightgame.utils.Utils
|
||||
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram
|
||||
import com.tencent.mm.opensdk.openapi.WXAPIFactory
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import retrofit2.HttpException
|
||||
@ -108,8 +111,14 @@ import kotlin.math.roundToInt
|
||||
object DirectUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun directToLinkPage(context: Context, linkEntity: LinkEntity, entrance: String, path: String, sourceEntrance: String = "") {
|
||||
directToLinkPage(context, linkEntity, entrance, path, null, sourceEntrance)
|
||||
fun directToLinkPage(
|
||||
context: Context,
|
||||
linkEntity: LinkEntity,
|
||||
entrance: String,
|
||||
path: String,
|
||||
sourceEntrance: String = ""
|
||||
) {
|
||||
directToLinkPage(context, linkEntity, entrance, path, null, sourceEntrance)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@ -140,14 +149,12 @@ object DirectUtils {
|
||||
"qqqun",
|
||||
"tag",
|
||||
"all_community_article",
|
||||
"category",
|
||||
"block",
|
||||
"column_collection",
|
||||
"server",
|
||||
"top_game_comment",
|
||||
"wechat_bind",
|
||||
"video",
|
||||
"catalog",
|
||||
"category_v2",
|
||||
"common_collection",
|
||||
"game_list",
|
||||
@ -243,7 +250,7 @@ object DirectUtils {
|
||||
path
|
||||
)
|
||||
|
||||
HOST_WEB, HOST_WEB_INURL, HOST_WEB_AL -> {
|
||||
HOST_WEB, HOST_WEB_INURL, HOST_WEB_AL, HOST_QA_CONTENT -> {
|
||||
when {
|
||||
linkEntity.link!!.contains("v.douyin") && PackageHelper.localPackageNameSet.contains("com.ss.android.ugc.aweme") -> {
|
||||
directDouyin(context, "1402577827140941")
|
||||
@ -274,10 +281,6 @@ object DirectUtils {
|
||||
)
|
||||
)
|
||||
|
||||
"category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!)
|
||||
|
||||
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
|
||||
|
||||
"category_v2" -> directCategoryV2(
|
||||
context,
|
||||
linkEntity.link!!,
|
||||
@ -343,9 +346,9 @@ object DirectUtils {
|
||||
|
||||
"feedback" -> directToFeedback(context, linkEntity.name, false, "", false, false, entrance)
|
||||
|
||||
"qa", "qa_content", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
|
||||
"qa", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
|
||||
|
||||
"qa_list" -> directToHelpAndFeedback(context)
|
||||
"qa_list" -> directToHelpAndFeedback(context, bundleOf(KEY_ENTRANCE to entrance))
|
||||
|
||||
"qa_collection", "Q&A合集" -> directToQaCollection(
|
||||
context, linkEntity.text
|
||||
@ -470,22 +473,28 @@ object DirectUtils {
|
||||
"column_test_v2" -> context.startActivity(
|
||||
GameServerTestV2Activity.getIntent(
|
||||
context,
|
||||
linkEntity.link ?: "none",
|
||||
entrance,
|
||||
exposureEvent
|
||||
)
|
||||
)
|
||||
|
||||
"qq_mini_game_column" -> directToQGameHome(context)
|
||||
ColumnCollectionDetailFragment.TYPE_QQ_MINI_GAME_COLUMN -> directToQGameHome(context)
|
||||
|
||||
// QQ游戏专题详情页
|
||||
"qq_mini_game_column_detail" -> {
|
||||
ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN, ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN -> {
|
||||
val subjectType = if (linkEntity.type == ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN) {
|
||||
SubjectData.SubjectType.QQ_GAME
|
||||
} else {
|
||||
SubjectData.SubjectType.WECHAT_GAME
|
||||
}
|
||||
directToSubject(
|
||||
context = context,
|
||||
id = linkEntity.link ?: "",
|
||||
subjectName = linkEntity.text,
|
||||
entrance = BaseActivity.mergeEntranceAndPath(entrance, path),
|
||||
exposureEvent = exposureEvent,
|
||||
isQQMiniGame = true
|
||||
subjectType = subjectType
|
||||
)
|
||||
}
|
||||
|
||||
@ -536,6 +545,10 @@ object DirectUtils {
|
||||
}
|
||||
}
|
||||
|
||||
"wechat_game" -> linkEntity.link?.let {
|
||||
MiniGameItemHelper.launchMiniGame(it, Constants.WECHAT_MINI_GAME)
|
||||
}
|
||||
|
||||
"" -> {
|
||||
// do nothing
|
||||
}
|
||||
@ -774,7 +787,12 @@ object DirectUtils {
|
||||
}
|
||||
}
|
||||
if (traceEvent != null) {
|
||||
val clickEvent = createEvent(GameEntity(id = id, name = name), traceEvent.source, appendTrace(traceEvent), ExposureType.CLICK)
|
||||
val clickEvent = createEvent(
|
||||
GameEntity(id = id, name = name),
|
||||
traceEvent.source,
|
||||
appendTrace(traceEvent),
|
||||
ExposureType.CLICK
|
||||
)
|
||||
log(clickEvent)
|
||||
bundle.putParcelable(KEY_TRACE_EVENT, clickEvent)
|
||||
}
|
||||
@ -837,12 +855,12 @@ object DirectUtils {
|
||||
subjectName: String? = "",
|
||||
entrance: String? = null,
|
||||
exposureEvent: ExposureEvent? = null,
|
||||
isQQMiniGame: Boolean = false,
|
||||
subjectType: SubjectData.SubjectType = SubjectData.SubjectType.NORMAL
|
||||
) {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
val subjectData =
|
||||
SubjectData(subjectId = id, subjectName = subjectName, isOrder = false, isQQMiniGame = isQQMiniGame)
|
||||
SubjectData(subjectId = id, subjectName = subjectName, isOrder = false, subjectType = subjectType)
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, SubjectActivity::class.java.name)
|
||||
bundle.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, subjectData)
|
||||
@ -899,12 +917,16 @@ object DirectUtils {
|
||||
qaContentId: String? = "",
|
||||
isPlugin: Boolean = false,
|
||||
isSmoothGame: Boolean = false,
|
||||
gameId: String? = "",
|
||||
gameName: String? = "",
|
||||
entrance: String? = null
|
||||
) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putBoolean(KEY_PLUGIN, isPlugin)
|
||||
bundle.putBoolean(KEY_SMOOTH_GAME, isSmoothGame)
|
||||
bundle.putString(KEY_GAME_ID, gameId)
|
||||
bundle.putString(KEY_GAME_NAME, gameName)
|
||||
if (isPlugin) {
|
||||
bundle.putString(KEY_HIDE_SUGGEST_HINT, "【插件问题】")
|
||||
}
|
||||
@ -991,7 +1013,13 @@ object DirectUtils {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToQuestionDetail(context: Context, id: String, entrance: String? = null, path: String? = null, sourceEntrance: String = "") {
|
||||
fun directToQuestionDetail(
|
||||
context: Context,
|
||||
id: String,
|
||||
entrance: String? = null,
|
||||
path: String? = null,
|
||||
sourceEntrance: String = ""
|
||||
) {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
@ -1387,47 +1415,6 @@ object DirectUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转分类
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directCategoryDirectory(
|
||||
context: Context,
|
||||
categoryId: String,
|
||||
categoryTitle: String,
|
||||
entrance: String? = null,
|
||||
path: String? = ""
|
||||
) {
|
||||
if (categoryId.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, CategoryDirectoryActivity::class.java.name)
|
||||
bundle.putString(KEY_CATEGORY_ID, categoryId)
|
||||
bundle.putString(KEY_CATEGORY_TITLE, categoryTitle)
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转新分类
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directCatalog(
|
||||
context: Context,
|
||||
catalogId: String,
|
||||
catalogTitle: String,
|
||||
entrance: String? = null,
|
||||
path: String? = "",
|
||||
) {
|
||||
if (catalogId.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, CatalogActivity::class.java.name)
|
||||
bundle.putString(KEY_CATALOG_ID, catalogId)
|
||||
bundle.putString(KEY_CATALOG_TITLE, catalogTitle)
|
||||
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转新分类2.0
|
||||
*/
|
||||
@ -1935,7 +1922,7 @@ object DirectUtils {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToQGameSearch(
|
||||
fun directToMiniGameSearch(
|
||||
context: Context,
|
||||
hint: String,
|
||||
sourceEntrance: String,
|
||||
@ -1947,7 +1934,7 @@ object DirectUtils {
|
||||
searchBoxPattern: String = ""
|
||||
) {
|
||||
context.startActivity(
|
||||
QGameSearchActivity.getIntent(
|
||||
MiniGameSearchActivity.getIntent(
|
||||
context,
|
||||
hint,
|
||||
sourceEntrance,
|
||||
@ -1963,11 +1950,10 @@ object DirectUtils {
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun directToQGameById(
|
||||
fun directToQQGameById(
|
||||
activity: Activity,
|
||||
qqGameId: String
|
||||
qqAppId: String
|
||||
) {
|
||||
|
||||
if (activity !is AppCompatActivity || activity.supportFragmentManager.isDestroyed) {
|
||||
ToastUtils.toast("启动QQ小游戏失败,请稍后再试")
|
||||
return
|
||||
@ -1988,25 +1974,40 @@ object DirectUtils {
|
||||
val qGameProvider = ARouter
|
||||
.getInstance()
|
||||
.build(RouteConsts.provider.qGame)
|
||||
.navigation() as IQGameProvider<*>
|
||||
qGameProvider.setLoginInfo(activity, userId, userName, userToken)
|
||||
qGameProvider.launchGame(activity, qqGameId) { _, _ ->
|
||||
RetrofitManager
|
||||
.getInstance()
|
||||
.newApi
|
||||
.postQGamePlay(qqGameId, userId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
QGameViewModel.notifyQGameSubjectUpdate() // 通知QQ小游戏首页列表刷新
|
||||
},
|
||||
{}
|
||||
) // 秒玩记录上报
|
||||
.navigation() as? IQGameProvider
|
||||
qGameProvider?.setLoginInfo(activity, userId, userName, userToken)
|
||||
qGameProvider?.launchGame(activity, qqAppId) { _, _ ->
|
||||
MiniGameRecentlyPlayUseCase.submitRecentPlayedQGame(qqAppId, userId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun directToWechatGameById(
|
||||
activity: Activity,
|
||||
wechatAppId: String,
|
||||
) {
|
||||
|
||||
val wxApiProxy = WXAPIFactory.createWXAPI(
|
||||
activity,
|
||||
Config.WECHAT_APPID
|
||||
)
|
||||
if (!wxApiProxy.isWXAppInstalled) {
|
||||
ToastUtils.toast("请安装微信客户端")
|
||||
return
|
||||
}
|
||||
|
||||
wxApiProxy.sendReq(
|
||||
WXLaunchMiniProgram.Req().apply {
|
||||
userName = wechatAppId
|
||||
path = Constants.WECHAT_MINI_GAME_PCS
|
||||
miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE;
|
||||
}
|
||||
)
|
||||
|
||||
MiniGameRecentlyPlayUseCase.submitRecentPlayedWGame(wechatAppId, HaloApp.getInstance().gid)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToMessageCenter(defaultTabIndex: Int) {
|
||||
ARouter.getInstance().build(RouteConsts.activity.messageWrapperActivity)
|
||||
@ -2082,7 +2083,7 @@ object DirectUtils {
|
||||
)
|
||||
)
|
||||
|
||||
BottomTab.SearchStyle.TYPE_QQ_MINI_GAME -> directToQGameSearch(
|
||||
BottomTab.SearchStyle.TYPE_MINI_GAME -> directToMiniGameSearch(
|
||||
context,
|
||||
"请输入小游戏关键词",
|
||||
sourceEntrance,
|
||||
|
||||
@ -27,7 +27,6 @@ import com.gh.download.server.BrowserInstallHelper
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.callback.CancelListener
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
@ -41,6 +40,7 @@ import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
|
||||
import com.gh.gamecenter.teenagermode.TeenagerModeActivity
|
||||
import com.gh.vspace.VHelper
|
||||
import com.lightgame.download.DownloadConfig
|
||||
@ -247,9 +247,8 @@ object DownloadItemUtils {
|
||||
}
|
||||
return
|
||||
}
|
||||
if (gameEntity.isQQMiniGame()) {
|
||||
val isQQMiniGameOffShelve = gameEntity.qqMiniGameAppStatus == 1 // QQ小游戏是否下架
|
||||
if (isQQMiniGameOffShelve) {
|
||||
if (gameEntity.isMiniGame()) {
|
||||
if (gameEntity.isMiniGameOffShelve()) {
|
||||
downloadBtn.apply {
|
||||
isClickable = false
|
||||
text = context.getString(R.string.off_shelve)
|
||||
@ -844,12 +843,11 @@ object DownloadItemUtils {
|
||||
}
|
||||
return
|
||||
}
|
||||
if (gameEntity.isQQMiniGame()) {
|
||||
if (gameEntity.isMiniGame()) {
|
||||
downloadBtn.setOnClickListener {
|
||||
NewFlatLogUtils.logQGameClick(gameEntity.qqMiniGameAppId, gameEntity.name)
|
||||
GlobalActivityManager.currentActivity?.let { activity ->
|
||||
DirectUtils.directToQGameById(activity, gameEntity.qqMiniGameAppId)
|
||||
}
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
|
||||
clickCallback?.onCallback()
|
||||
allStateClickCallback?.onCallback()
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -1164,7 +1162,11 @@ object DownloadItemUtils {
|
||||
isSubscribe,
|
||||
traceEvent
|
||||
)
|
||||
ToastUtils.toast(gameEntity.name + "已加入下载队列")
|
||||
if (asVGame) {
|
||||
ToastUtils.toast(gameEntity.name + "已加入加载队列")
|
||||
} else {
|
||||
ToastUtils.toast(gameEntity.name + "已加入下载队列")
|
||||
}
|
||||
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
|
||||
val toast = context.getString(R.string.unsupported_browser_install_hint)
|
||||
AppExecutor.uiExecutor.executeWithDelay({
|
||||
|
||||
@ -499,7 +499,7 @@ object DownloadObserver {
|
||||
"game_name", downloadEntity.name,
|
||||
"game_id", downloadEntity.gameId,
|
||||
"game_type", downloadEntity.categoryChinese,
|
||||
"game_schema_type", if (downloadEntity.getMetaExtra(VHelper.KEY_BIT) == "32") "32位" else "64位",
|
||||
"game_schema_type", if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
*kvs
|
||||
)
|
||||
} else if (downloadEntity.gameId == Constants.HALO_FUN_GAME_ID) {
|
||||
@ -508,11 +508,18 @@ object DownloadObserver {
|
||||
"space_schema_type",
|
||||
if (downloadEntity.packageName == VHelper.VSPACE_32BIT_PACKAGENAME) "32位" else "64位"
|
||||
)
|
||||
} else if(downloadEntity.gameId == Constants.HALO_FUN_NEW_32_GAME_ID) {
|
||||
SensorsBridge.trackEvent(
|
||||
"HaloFunDownloadDone",
|
||||
"space_schema_type",
|
||||
"32位(新)"
|
||||
)
|
||||
}
|
||||
|
||||
if (downloadEntity.gameId != Constants.GHZS_GAME_ID
|
||||
&& downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) != Constants.SIMULATOR_DOWNLOAD
|
||||
&& downloadEntity.gameId != Constants.HALO_FUN_GAME_ID
|
||||
&& downloadEntity.gameId != Constants.HALO_FUN_NEW_32_GAME_ID
|
||||
) {
|
||||
val trackJson = downloadEntity.customPageTrackDataJson
|
||||
val kvs = if (!trackJson.isNullOrBlank()) {
|
||||
@ -527,7 +534,7 @@ object DownloadObserver {
|
||||
"game_name", downloadEntity.meta[Constants.GAME_NAME] ?: "",
|
||||
"game_type", downloadEntity.meta[Constants.GAME_CATEGORY_IN_CHINESE] ?: "",
|
||||
"game_label", downloadEntity.tags.joinToString(","),
|
||||
"game_schema_type", if (downloadEntity.getMetaExtra(VHelper.KEY_BIT) == "32") "32位" else "64位",
|
||||
"game_schema_type", if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
|
||||
"page_name", getCurrentPageEntity().pageName,
|
||||
"page_id", getCurrentPageEntity().pageId,
|
||||
"page_business_id", getCurrentPageEntity().pageBusinessId,
|
||||
|
||||
@ -282,7 +282,7 @@ object GameActivityDownloadHelper {
|
||||
location: String,
|
||||
traceEvent: ExposureEvent
|
||||
) {
|
||||
VHelper.validateVSpaceBeforeAction(context, gameEntity) {
|
||||
VHelper.validateVSpaceBeforeAction(context,gameEntity.getUniquePackageName(), gameEntity) {
|
||||
GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
|
||||
DialogUtils.checkDownload(
|
||||
context,
|
||||
|
||||
@ -49,13 +49,8 @@ public class InstallUtils {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == INSTALL_WHAT && packageManager != null) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
List<PackageInfo> packageInfos = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
list.add(packageInfo.packageName);
|
||||
}
|
||||
}
|
||||
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
|
||||
ArrayList<String> list = new ArrayList<>(packageNameList);
|
||||
if (installMap != null && installMap.size() != 0) {
|
||||
ArrayList<String> keys = new ArrayList<>();
|
||||
for (String packageName : installMap.keySet()) {
|
||||
|
||||
@ -768,10 +768,10 @@ public class LibaoUtils {
|
||||
}
|
||||
|
||||
public static boolean isAppInstalled(Context context, String packageName) {
|
||||
List<PackageInfo> pinfo = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
|
||||
if (pinfo != null) {
|
||||
for (int i = 0; i < pinfo.size(); i++) {
|
||||
String pn = pinfo.get(i).packageName;
|
||||
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
|
||||
if (packageNameList != null) {
|
||||
for (int i = 0; i < packageNameList.size(); i++) {
|
||||
String pn = packageNameList.get(i);
|
||||
if (pn.equals(packageName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -734,18 +734,6 @@ public class LogUtils {
|
||||
LoghubUtils.log(object, LOG_STORE_EVENT, false);
|
||||
}
|
||||
|
||||
public static void logNewCatalogAppearanceEvent(String entrance, String key) {
|
||||
logCatalogEvent("access_to_classification", entrance, key, -1, -1, -1, -1);
|
||||
}
|
||||
|
||||
public static void logSubCatalogClickEvent(String entrance, String key, int seq1) {
|
||||
logCatalogEvent("click_first_classification", entrance, key, seq1, -1, -1, -1);
|
||||
}
|
||||
|
||||
public static void logSubCatalogContentClickEvent(String entrance, String key, int seq1, int seq2) {
|
||||
logCatalogEvent("click_secondary_classification", entrance, key, seq1, seq2, -1, -1);
|
||||
}
|
||||
|
||||
public static void logSpecialCatalogContentClickEvent(String entrance, String key, int seq1, int seqContent) {
|
||||
logCatalogEvent("click_content", entrance, key, seq1, -1, seqContent, -1);
|
||||
}
|
||||
|
||||
@ -93,12 +93,13 @@ object NewFlatLogUtils {
|
||||
|
||||
// 畅玩助手更新弹窗展示事件
|
||||
@JvmStatic
|
||||
fun logHaloFunUpdateDialogShow(gameId: String, gameName: String, gameArchitecture: String) {
|
||||
fun logHaloFunUpdateDialogShow(gameId: String, gameName: String, gameArchitecture: String, targetVaVersion: String) {
|
||||
val json = json {
|
||||
KEY_EVENT to "halo_fun_update_dialog_show"
|
||||
"game_id" to gameId
|
||||
"game_name" to gameName
|
||||
"game_architecture" to gameArchitecture
|
||||
"target_va_version" to targetVaVersion
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
@ -142,12 +143,13 @@ object NewFlatLogUtils {
|
||||
|
||||
// 畅玩助手更新弹窗点击事件
|
||||
@JvmStatic
|
||||
fun logHaloFunUpdateDialogClick(dialogType: String, buttonType: String, architecture: String) {
|
||||
fun logHaloFunUpdateDialogClick(dialogType: String, buttonType: String, architecture: String, targetVaVersion: String) {
|
||||
val json = json {
|
||||
KEY_EVENT to "halo_fun_update_dialog_click"
|
||||
"dialog_type" to dialogType
|
||||
KEY_BUTTON_TYPE to buttonType
|
||||
"architecture" to architecture
|
||||
"target_va_version" to targetVaVersion
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
@ -2007,29 +2009,6 @@ object NewFlatLogUtils {
|
||||
log(json, "event", false)
|
||||
}
|
||||
|
||||
// vpn 弹窗显示
|
||||
fun logVpnHintDialogShow(gameId: String, gameName: String) {
|
||||
val json = json {
|
||||
KEY_EVENT to "vpn_pre_access_dialog_show"
|
||||
KEY_GAME_ID to gameId
|
||||
KEY_GAME_NAME to gameName
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json, "event", false)
|
||||
}
|
||||
|
||||
// vpn 弹窗点击
|
||||
fun logVpnHintDialogClick(gameId: String, gameName: String, button: String) {
|
||||
val json = json {
|
||||
KEY_EVENT to "vpn_pre_access_dialog_click"
|
||||
KEY_GAME_ID to gameId
|
||||
KEY_GAME_NAME to gameName
|
||||
"button" to button
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json, "event", false)
|
||||
}
|
||||
|
||||
// 谷歌框架弹窗显示
|
||||
fun logGAppsDialogShowed(gameId: String, gameName: String) {
|
||||
val json = json {
|
||||
@ -2600,17 +2579,6 @@ object NewFlatLogUtils {
|
||||
log(json)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logQGameClick(qqGameId: String, qqGameName: String?) {
|
||||
val json = json {
|
||||
KEY_EVENT to "qq_game_click"
|
||||
"qq_game_id" to qqGameId
|
||||
"qq_game_name" to qqGameName ?: ""
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
}
|
||||
|
||||
// 点击个人主页的认证文案事件
|
||||
@JvmStatic
|
||||
fun logClickAuthText(linkType: String, linkId: String, linkText: String, userId: String, text: String) {
|
||||
|
||||
240
app/src/main/java/com/gh/common/util/PackageChangeHelper.kt
Normal file
240
app/src/main/java/com/gh/common/util/PackageChangeHelper.kt
Normal file
@ -0,0 +1,240 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.download.PackageObserver
|
||||
import com.gh.gamecenter.DownloadManagerActivity
|
||||
import com.gh.gamecenter.common.utils.NewFlatLogUtils
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.core.utils.CurrentActivityHolder
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.hud.HeadUpDisplayHelper
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.gh.gamecenter.packagehelper.PackageRepository
|
||||
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.hud.HeadUpDisplayLogHelper
|
||||
import com.lightgame.utils.Utils
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
object PackageChangeHelper : DefaultLifecycleObserver {
|
||||
|
||||
private const val TAG = "PackageChangeHelper"
|
||||
|
||||
private const val INSTALL_PENDING = 1
|
||||
private const val UNINSTALL_PENDING = 2
|
||||
private const val UPDATE_PENDING = 3
|
||||
|
||||
// <包名,pending 类型,应用版本> Triple
|
||||
private var pendingPackageTriple: Triple<String, Int, String>? = null
|
||||
private var pendingGhId: String? = null
|
||||
|
||||
private var pendingHUDShowed: Boolean = false
|
||||
|
||||
/**
|
||||
* 添加一个等待中,待确定是否已成功安装的应用
|
||||
*/
|
||||
fun addInstallPendingPackage(packageName: String) {
|
||||
val installData = PackagesManager.getInstalledData(packageName)
|
||||
|
||||
if (installData == null) {
|
||||
Utils.log(TAG, "添加了: $packageName 包名等待安装成功")
|
||||
|
||||
pendingHUDShowed = false
|
||||
pendingPackageTriple = Triple(packageName, INSTALL_PENDING, "")
|
||||
} else {
|
||||
Utils.log(TAG, "添加了: $packageName 包名等待安装更新成功")
|
||||
|
||||
val ghId = PackageUtils.getGhId(packageName)
|
||||
|
||||
// 记录光环插件相关信息,用于安装成功后的处理
|
||||
if (ghId != null) {
|
||||
pendingGhId = ghId.toString()
|
||||
}
|
||||
|
||||
pendingHUDShowed = false
|
||||
pendingPackageTriple = Triple(packageName, UPDATE_PENDING, installData.version)
|
||||
}
|
||||
}
|
||||
|
||||
fun isInstallPendingPackage(packageName: String): Boolean {
|
||||
return pendingPackageTriple?.first == packageName
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个等待中,待确定是否已成功卸载的应用
|
||||
*/
|
||||
fun addUninstallPendingPackage(packageName: String) {
|
||||
Utils.log(TAG, "添加了: $packageName 包名等待卸载成功")
|
||||
pendingPackageTriple = Triple(packageName, UNINSTALL_PENDING, "")
|
||||
}
|
||||
|
||||
override fun onResume(owner: LifecycleOwner) {
|
||||
super.onResume(owner)
|
||||
|
||||
if (pendingPackageTriple != null) {
|
||||
val packageName = pendingPackageTriple?.first ?: return
|
||||
val isInstallPending = pendingPackageTriple?.second == INSTALL_PENDING
|
||||
val isUninstallPending = pendingPackageTriple?.second == UNINSTALL_PENDING
|
||||
val isUpdatePending = pendingPackageTriple?.second == UPDATE_PENDING
|
||||
|
||||
val pendingVersion = pendingPackageTriple?.third ?: ""
|
||||
|
||||
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
|
||||
val isInstalled = installedVersionName != null
|
||||
|
||||
if (isInstallPending) {
|
||||
if (isInstalled) {
|
||||
pendingPackageTriple = null
|
||||
pendingGhId = null
|
||||
|
||||
PackageRepository.addInstalledGame(packageName)
|
||||
|
||||
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
|
||||
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
|
||||
|
||||
performInstallSuccessAction(packageName)
|
||||
} else {
|
||||
// 任务不存在了,将等待更新安装结果的 triple 置为 null
|
||||
if (DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) == null) {
|
||||
pendingPackageTriple = null
|
||||
} else {
|
||||
showHUDIfNeeded(packageName)
|
||||
}
|
||||
}
|
||||
} else if (isUninstallPending && !isInstalled) {
|
||||
pendingPackageTriple = null
|
||||
pendingGhId = null
|
||||
|
||||
// 从额外的包名白名单移除,下次启动时不再查询此包的安装情况
|
||||
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = false)
|
||||
|
||||
performUninstallSuccessAction(packageName)
|
||||
} else if (isUpdatePending) {
|
||||
val isUpdateValid = if (installedVersionName != pendingVersion) {
|
||||
true
|
||||
} else {
|
||||
!pendingGhId.isNullOrEmpty() && pendingGhId != PackageUtils.getGhId(packageName).toString()
|
||||
}
|
||||
|
||||
pendingPackageTriple = null
|
||||
pendingGhId = null
|
||||
|
||||
if (isUpdateValid) {
|
||||
performUninstallSuccessAction(packageName)
|
||||
performInstallSuccessAction(packageName)
|
||||
} else {
|
||||
// 任务不存在了,将等待更新安装结果的 triple 置为 null
|
||||
if (DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) == null) {
|
||||
pendingPackageTriple = null
|
||||
} else {
|
||||
showHUDIfNeeded(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
|
||||
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showHUDIfNeeded(packageName: String) {
|
||||
if (pendingHUDShowed) return
|
||||
|
||||
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) ?: return
|
||||
val activity = CurrentActivityHolder.getCurrentActivity() ?: return
|
||||
if (activity is DownloadManagerActivity) return
|
||||
|
||||
pendingHUDShowed = true
|
||||
HeadUpDisplayHelper.showHUD(activity,
|
||||
downloadEntity.icon ?: "",
|
||||
activity.getString(R.string.hud_has_pending_install_game),
|
||||
activity.getString(R.string.hud_head_to_download_manager),
|
||||
showingCallback = {
|
||||
HeadUpDisplayLogHelper.trackInstallationShow(downloadEntity, "游戏下载")
|
||||
},
|
||||
clickedCallback = {
|
||||
DirectUtils.directToDownloadManager(activity, "HUD")
|
||||
HeadUpDisplayLogHelper.trackInstallationClick(downloadEntity, "游戏下载")
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 对外暴露的方法,用于添加一个安装成功的应用
|
||||
* @param packageName 包名
|
||||
* @param cachedGameEntity 缓存的 GameEntity,用于快速更新状态
|
||||
*/
|
||||
fun addInstall(packageName: String, cachedGameEntity: GameEntity? = null) {
|
||||
performInstallSuccessAction(packageName, cachedGameEntity)
|
||||
}
|
||||
|
||||
/**
|
||||
* 对外暴露的方法,用于添加一个卸载成功的应用
|
||||
* @param packageName 包名
|
||||
* @param cachedGameEntity 缓存的 GameEntity,用于快速更新状态
|
||||
*/
|
||||
fun addUpdate(packageName: String, cachedGameEntity: GameEntity? = null) {
|
||||
performUninstallSuccessAction(packageName)
|
||||
performInstallSuccessAction(packageName, cachedGameEntity)
|
||||
}
|
||||
|
||||
/**
|
||||
* 对应包名安装成功后的操作,继承至 PackageChangeBroadcastObserver
|
||||
* @param packageName 包名
|
||||
* @param cachedGameEntity 缓存的 GameEntity,用于快速更新状态
|
||||
* @param withLog 是否需要记录日志
|
||||
*/
|
||||
private fun performInstallSuccessAction(
|
||||
packageName: String,
|
||||
cachedGameEntity: GameEntity? = null,
|
||||
withLog: Boolean = true
|
||||
) {
|
||||
Utils.log(TAG, "安装了: $packageName 包名的程序")
|
||||
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName)
|
||||
val gameId = if (downloadEntity != null && downloadEntity.gameId != null) downloadEntity.gameId else ""
|
||||
val gameName = if (downloadEntity != null && downloadEntity.name != null) downloadEntity.name else ""
|
||||
|
||||
if (withLog) {
|
||||
NewFlatLogUtils.logGameInstallComplete(gameId, gameName)
|
||||
SensorsBridge.trackInstallGameFinish(gameId, gameName)
|
||||
}
|
||||
|
||||
InstallUtils.getInstance().removeInstall(packageName)
|
||||
PackageHelper.refreshLocalPackageList()
|
||||
|
||||
val versionName = PackageUtils.getVersionNameByPackageName(packageName)
|
||||
val installEb = EBPackage(EBPackage.TYPE_INSTALLED, packageName, versionName)
|
||||
|
||||
PackageObserver.onPackageChanged(installEb, cachedGameEntity)
|
||||
EventBus.getDefault().post(installEb)
|
||||
}
|
||||
|
||||
fun addUninstall(packageName: String) {
|
||||
performUninstallSuccessAction(packageName)
|
||||
}
|
||||
|
||||
/**
|
||||
* 对应包名卸载成功后的操作,继承至 PackageChangeBroadcastObserver
|
||||
*/
|
||||
private fun performUninstallSuccessAction(packageName: String, withLog: Boolean = true) {
|
||||
Utils.log(TAG, "卸载了: $packageName 包名的程序")
|
||||
val install = PackagesManager.getInstalledData(packageName)
|
||||
val gameId = if (install?.id != null) install.id else ""
|
||||
val gameName = if (install?.name != null) install.name else ""
|
||||
|
||||
if (withLog) {
|
||||
NewFlatLogUtils.logGameUninstallComplete(gameId!!, gameName!!)
|
||||
SensorsBridge.trackUnloadGameFinish(gameId, gameName)
|
||||
}
|
||||
|
||||
InstallUtils.getInstance().removeUninstall(packageName)
|
||||
PackageHelper.refreshLocalPackageList()
|
||||
|
||||
val uninstallEb = EBPackage(EBPackage.TYPE_UNINSTALLED, packageName, "")
|
||||
PackageObserver.onPackageChanged(uninstallEb)
|
||||
EventBus.getDefault().post(uninstallEb)
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,21 +1,39 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PermissionInfo
|
||||
import android.os.Build
|
||||
import android.os.Process
|
||||
import android.provider.Settings
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.gamecenter.common.utils.PermissionHelper.isGetInstalledListPermissionDisabled
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.DialogHelper
|
||||
import com.gh.gamecenter.common.utils.PermissionHelper
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.toJson
|
||||
import com.gh.gamecenter.common.utils.toObject
|
||||
import com.gh.gamecenter.core.GHThreadFactory
|
||||
import com.gh.gamecenter.core.runOnUiThread
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.entity.WhitePackageListEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.SettingsEntity
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.gh.gamecenter.packagehelper.PackageRepository
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.*
|
||||
import java.util.HashMap
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
@ -23,16 +41,43 @@ object PackageHelper {
|
||||
|
||||
private const val TAG = "PackageHelper"
|
||||
|
||||
private const val SP_GET_INSTALLED_API_AGREED = "get_installed_api_agreed"
|
||||
private const val SP_GET_INSTALLED_PACKAGES_AGREED = "get_installed_packages_agreed" // 用户是否同意使用已安装应用列表 API
|
||||
|
||||
private const val SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API =
|
||||
"get_installed_packages_by_alternative_api" // 是否使用另类方式获取已安装应用列表
|
||||
|
||||
private const val SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE =
|
||||
"user_used_get_installed_api_switch_package" // 用户是否使用过含有已安装应用列表获取开关的包
|
||||
|
||||
private const val SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST =
|
||||
"additional_whitelist_package_name_list" // 额外的白名单包名列表 (曾经更正为已安装的包名列表)
|
||||
|
||||
private const val UNKNOWN = -1
|
||||
private const val UNSUPPORTED = 0
|
||||
private const val SUPPORTED = 1
|
||||
|
||||
private var lastInstalledPackageListTime = 0L
|
||||
private var installedPackageList: List<PackageInfo> = arrayListOf()
|
||||
private var isGetInstalledPackagesApiAgreed = false
|
||||
private var isGetInstalledListPermissionSupported = UNKNOWN // 设备是否支持禁用获取已安装应用列表。-1 代表支持情况未知,0 代表不支持, 1 代表支持
|
||||
private const val ENABLED = 2
|
||||
private const val DISABLED = 3
|
||||
|
||||
private var lastSuccessfullyGetInstalledPackagesTimeMills = 0L
|
||||
private var cachedInstalledPackageInfoList: List<PackageInfo> = arrayListOf() // 缓存的已安装应用列表
|
||||
private var cachedInstalledPackageNameList: List<String> = arrayListOf() // 缓存的已安装应用包名列表
|
||||
private var additionalWhiteListPackageNameSet: HashSet<String> = hashSetOf()
|
||||
|
||||
private var isGetInstalledPackagesAgreed = false // 用户是否已经同意使用已安装应用列表
|
||||
private var isGetInstalledPackagesAgreedRequired = UNKNOWN // 需要用户手动授权才获取已安装应用列表的功能的开关
|
||||
private var isGetInstalledPackagesPermissionSupported = UNKNOWN // 设备是否支持禁用获取已安装应用列表
|
||||
|
||||
private var useAlternativeWayToGetInstalledPackages = false
|
||||
|
||||
private var cachedPkgNameAndGameEntityMap = HashMap<String, GameEntity>() // 缓存的状态异常包名和游戏实体的映射 (用于免接口请求更新状态)
|
||||
|
||||
private val packageExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_PACKAGE_THREAD")) }
|
||||
|
||||
private var uploadUIDGapLog = true
|
||||
|
||||
// 光环运行的环境是否为默认的 UID (0)
|
||||
private val isRunningOnDefaultUid by lazy { Process.myUid() / 100000 == 0 }
|
||||
|
||||
// 评论黑名单包名列表,避免用户安装了 Xposed Installer 这样的工具,也能在包含该安装包的游戏详情页评论
|
||||
private var _commentPackageNameBlackList = arrayListOf<String>()
|
||||
@ -50,6 +95,10 @@ object PackageHelper {
|
||||
private var _relatedPackageList = arrayListOf<SettingsEntity.GameWithPackages>()
|
||||
val relatedPackageList: ArrayList<SettingsEntity.GameWithPackages> = _relatedPackageList
|
||||
|
||||
// 接口控制的已安装应用列表获取开关状态 (UI 显示)
|
||||
private var _installedPackageApiSwitchStatusLiveData = MutableLiveData<Boolean>()
|
||||
val installedPackageApiSwitchStatusLiveData: LiveData<Boolean> = _installedPackageApiSwitchStatusLiveData
|
||||
|
||||
// 本地已安装包的列表
|
||||
var localPackageNameSet = hashSetOf<String>()
|
||||
get() {
|
||||
@ -61,6 +110,67 @@ object PackageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否需要忽略接口控制的已安装应用列表获取开关
|
||||
* 用于覆盖安装首次启动时的检查 https://jira.shanqu.cc/browse/GHZSCY-5694
|
||||
*/
|
||||
fun checkIfGetInstalledApiSwitchShouldBeIgnored(context: Context) {
|
||||
val userHasUsedGetInstalledApiSwitchPackage =
|
||||
SPUtils.getBoolean(SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE, false)
|
||||
if (!userHasUsedGetInstalledApiSwitchPackage) {
|
||||
val isSupportGetInstalledAppsPermission = isSupportGetInstalledAppsPermission(context)
|
||||
|
||||
if (!isSupportGetInstalledAppsPermission) {
|
||||
if (isRunningOnDefaultUid) {
|
||||
// 设备不支持动态管理获取已安装应用列表,忽略接口控制,使用另类方式获取已安装应用列表
|
||||
updateUseAlternativeWayToGetInstalledPackages()
|
||||
}
|
||||
onGetInstalledPackagesAgreed()
|
||||
} else if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
|
||||
if (isRunningOnDefaultUid) {
|
||||
// 设备支持动态管理获取已安装应用列表但已经授权,忽略接口控制,使用另类方式获取已安装应用列表
|
||||
updateUseAlternativeWayToGetInstalledPackages()
|
||||
}
|
||||
onGetInstalledPackagesAgreed()
|
||||
}
|
||||
|
||||
SPUtils.getBoolean(SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE, true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包名白名单列表(为了在没有已安装应用列表获取能力的时候也能正常判断更新、插件化)
|
||||
* @param additionalWhiteList 额外的已安装白名单
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
fun getPackagesWhiteList(additionalWhiteList: HashSet<String>) {
|
||||
RetrofitManager.getInstance().newApi.installWhitelist
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : BiResponse<WhitePackageListEntity>() {
|
||||
override fun onSuccess(data: WhitePackageListEntity) {
|
||||
val installedWhiteList = hashSetOf<String>()
|
||||
|
||||
if (additionalWhiteList.isNotEmpty()) {
|
||||
installedWhiteList.addAll(additionalWhiteList)
|
||||
}
|
||||
|
||||
data.data?.let {
|
||||
installedWhiteList.addAll(it)
|
||||
}
|
||||
|
||||
addInstalledButMissingPackages(installedWhiteList)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
|
||||
if (additionalWhiteList.isNotEmpty()) {
|
||||
addInstalledButMissingPackages(additionalWhiteList)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun refreshLocalPackageList() {
|
||||
localPackageNameSet = getAllPackageName(HaloApp.getInstance().application)
|
||||
@ -68,7 +178,7 @@ object PackageHelper {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun refreshList() {
|
||||
fun refreshPackageNameList() {
|
||||
Config.getSettings()?.gameCommentBlackList?.let { _commentPackageNameBlackList = ArrayList(it) }
|
||||
Config.getSettings()?.gameDownloadBlackList?.let { _downloadPackageNameBlackList = ArrayList(it) }
|
||||
Config.getSettings()?.gamePackageMatch?.let { _relatedPackageList = ArrayList(it) }
|
||||
@ -87,12 +197,10 @@ object PackageHelper {
|
||||
private fun getAllPackageName(context: Context): HashSet<String> {
|
||||
val set = HashSet<String>()
|
||||
return try {
|
||||
val packageInfos = getInstalledPackages(context, 0)
|
||||
for (packageInfo in packageInfos) {
|
||||
if (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0) {
|
||||
if (context.packageName != packageInfo.packageName) {
|
||||
set.add(packageInfo.packageName)
|
||||
}
|
||||
val packageNameList = getInstalledPackageNameList(context, 0)
|
||||
for (packageName in packageNameList) {
|
||||
if (context.packageName != packageName) {
|
||||
set.add(packageName)
|
||||
}
|
||||
}
|
||||
set
|
||||
@ -106,78 +214,275 @@ object PackageHelper {
|
||||
* 弃用已安装列表缓存
|
||||
*/
|
||||
fun dumpInstalledListCache() {
|
||||
lastInstalledPackageListTime = 0
|
||||
lastSuccessfullyGetInstalledPackagesTimeMills = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 在超时后,若后台没有开启获取已安装应用列表的功能,回落到以接口不控制的方式获取已安装应用列表
|
||||
*/
|
||||
fun ignoreInstalledPackageApiSwitchAfterTimeout(timeout: Long) {
|
||||
CoroutineScope(SupervisorJob()).launch {
|
||||
delay(timeout)
|
||||
if (isGetInstalledPackagesAgreedRequired == UNKNOWN && !isGetInstalledPackagesAgreed()) {
|
||||
Utils.log(TAG, "后台没有开启获取已安装应用列表的功能,超时后回落到以接口不控制的方式获取已安装应用列表")
|
||||
updateIsGetInstalledPackagesApiAgreedRequired(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新已安装应用列表获取开关状态
|
||||
*/
|
||||
fun updateIsGetInstalledPackagesApiAgreedRequired(isEnabled: Boolean) {
|
||||
Utils.log(TAG, "updateIsGetInstalledPackagesApiAgreedRequired 入参为 $isEnabled")
|
||||
|
||||
// 状态不变,无需更新
|
||||
if ((isEnabled == true && isGetInstalledPackagesAgreedRequired == ENABLED)
|
||||
|| (isEnabled == false && isGetInstalledPackagesAgreedRequired == DISABLED)
|
||||
) {
|
||||
Utils.log(TAG, "isGetInstalledPackagesApiAgreedRequired 状态不变,无需更新")
|
||||
return
|
||||
}
|
||||
|
||||
// 若用户已经同意使用了,无需更新
|
||||
if (isGetInstalledPackagesAgreed()) {
|
||||
Utils.log(TAG, "用户已经同意使用了,无需再更新已安装应用列表获取开关状态")
|
||||
return
|
||||
}
|
||||
|
||||
if (isEnabled) {
|
||||
Utils.log(TAG, "开启获取已安装应用列表限制")
|
||||
|
||||
additionalWhiteListPackageNameSet =
|
||||
SPUtils.getString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST).toObject() ?: hashSetOf()
|
||||
|
||||
Utils.log(TAG, "额外的白名单为 $additionalWhiteListPackageNameSet")
|
||||
|
||||
getPackagesWhiteList(additionalWhiteListPackageNameSet)
|
||||
_installedPackageApiSwitchStatusLiveData.postValue(true)
|
||||
isGetInstalledPackagesAgreedRequired = ENABLED
|
||||
} else {
|
||||
Utils.log(TAG, "不开启获取已安装应用列表限制")
|
||||
|
||||
isGetInstalledPackagesAgreedRequired = DISABLED
|
||||
|
||||
if (isRunningOnDefaultUid) {
|
||||
// 启用另类获取已安装应用列表的 API
|
||||
updateUseAlternativeWayToGetInstalledPackages()
|
||||
}
|
||||
|
||||
onGetInstalledPackagesAgreed()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户是否已经允许了调用获取已安装应用列表接口
|
||||
* 优先用内存的值,没有再从 SP 中获取并更新
|
||||
*/
|
||||
fun isGetInstalledPackagesApiAgreed(): Boolean {
|
||||
return isGetInstalledPackagesApiAgreed
|
||||
|| (SPUtils.getBoolean(SP_GET_INSTALLED_API_AGREED).also { isGetInstalledPackagesApiAgreed = it })
|
||||
fun isGetInstalledPackagesAgreed(): Boolean {
|
||||
return isGetInstalledPackagesAgreed
|
||||
|| (SPUtils.getBoolean(SP_GET_INSTALLED_PACKAGES_AGREED).also { isGetInstalledPackagesAgreed = it })
|
||||
}
|
||||
|
||||
/**
|
||||
* 同意使用已安装应用列表 API
|
||||
* 用户是否已经使用另类方式获取已安装应用列表
|
||||
*/
|
||||
fun agreeOnGetInstalledPackagesApi() {
|
||||
isGetInstalledPackagesApiAgreed = true
|
||||
SPUtils.setBoolean(SP_GET_INSTALLED_API_AGREED, true)
|
||||
private fun isUseAlternativeWayToGetInstalledPackages(): Boolean {
|
||||
return useAlternativeWayToGetInstalledPackages
|
||||
|| (SPUtils.getBoolean(SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API)
|
||||
.also { useAlternativeWayToGetInstalledPackages = it })
|
||||
}
|
||||
|
||||
private fun updateUseAlternativeWayToGetInstalledPackages() {
|
||||
// 启用另类获取已安装应用列表的 API
|
||||
useAlternativeWayToGetInstalledPackages = true
|
||||
SPUtils.setBoolean(SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API, true)
|
||||
}
|
||||
|
||||
fun isGetInstalledPackagesAgreedRequired(): Boolean {
|
||||
return isGetInstalledPackagesAgreedRequired == ENABLED
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已安装应用列表
|
||||
*/
|
||||
fun getInstalledPackages(context: Context?, flags: Int): List<PackageInfo> {
|
||||
Utils.log(TAG, "即将获取已安装应用列表")
|
||||
fun getInstalledPackageInfoList(context: Context?, flags: Int): List<PackageInfo> {
|
||||
return getInstalledListInternal(context, flags, false).first
|
||||
}
|
||||
|
||||
// Utils.log(TAG, "即将获取已安装应用列表" + Thread.currentThread().getStackTrace().contentToString().replace( ',', '\n' ))
|
||||
/**
|
||||
* 获取已安装应用包名列表
|
||||
*/
|
||||
fun getInstalledPackageNameList(context: Context?, flags: Int): List<String> {
|
||||
return getInstalledListInternal(context, flags, true).second
|
||||
}
|
||||
|
||||
private fun getInstalledListInternal(context: Context?,
|
||||
flags: Int,
|
||||
packageNameOnly: Boolean): Pair<List<PackageInfo>, List<String>> {
|
||||
Utils.log(TAG, "即将获取已安装应用列表,仅获取包名 $packageNameOnly")
|
||||
|
||||
// 用户未同意使用已安装应用列表 API,返回空列表
|
||||
if (!isGetInstalledPackagesApiAgreed()) {
|
||||
if (!isGetInstalledPackagesAgreed()) {
|
||||
Utils.log(TAG, "用户未同意使用已安装应用列表 API,返回空列表")
|
||||
return installedPackageList
|
||||
return Pair(cachedInstalledPackageInfoList, cachedInstalledPackageNameList)
|
||||
}
|
||||
|
||||
// 简单 debounce 过于频繁的获取已安装应用列表调用
|
||||
if (System.currentTimeMillis() - lastInstalledPackageListTime < 3000 && installedPackageList.isNotEmpty()) {
|
||||
Utils.log(TAG, "使用了缓存的已安装应用列表")
|
||||
return installedPackageList
|
||||
if (System.currentTimeMillis() - lastSuccessfullyGetInstalledPackagesTimeMills < 20 * 1000) {
|
||||
// 时间间隔合适且对应的列表不为空,直接返回对应的缓存列表数据
|
||||
if ((packageNameOnly && cachedInstalledPackageNameList.isNotEmpty())
|
||||
|| (!packageNameOnly && cachedInstalledPackageInfoList.isNotEmpty())
|
||||
) {
|
||||
Utils.log(TAG, "使用了缓存的已安装应用列表")
|
||||
return Pair(cachedInstalledPackageInfoList, cachedInstalledPackageNameList)
|
||||
}
|
||||
}
|
||||
|
||||
var shouldGetNewInstalledPackagedList = false
|
||||
|
||||
// 当前设备是否支持限制获取已安装应用列表的功能
|
||||
if (isSupportGetInstalledAppsPermission(context!!)) {
|
||||
Utils.log(TAG, "当前设备支持限制获取已安装应用列表的功能")
|
||||
Utils.log(TAG, "当前设备支持动态管理获取已安装应用列表的功能")
|
||||
// 当前设备是否支持禁用了获取已安装应用列表
|
||||
if (!isGetInstalledListPermissionDisabled(context)) {
|
||||
Utils.log(TAG, "当前设备没有限制获取已安装应用列表的功能")
|
||||
if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
|
||||
Utils.log(TAG, "当前设备支持动态管理但没有限制获取已安装应用列表的功能")
|
||||
shouldGetNewInstalledPackagedList = true
|
||||
} else {
|
||||
Utils.log(TAG, "当前设备已限制获取已安装应用列表的功能")
|
||||
Utils.log(TAG, "当前设备支持动态管理且已限制获取已安装应用列表的功能")
|
||||
}
|
||||
} else {
|
||||
Utils.log(TAG, "当前设备不支持限制获取已安装应用列表的功能")
|
||||
Utils.log(TAG, "当前设备不支持动态管理获取已安装应用列表的功能")
|
||||
shouldGetNewInstalledPackagedList = true
|
||||
}
|
||||
|
||||
if (shouldGetNewInstalledPackagedList) {
|
||||
lastInstalledPackageListTime = System.currentTimeMillis()
|
||||
installedPackageList = getInstalledPackagesInternal(context, flags)
|
||||
lastSuccessfullyGetInstalledPackagesTimeMills = System.currentTimeMillis()
|
||||
|
||||
if (packageNameOnly) {
|
||||
cachedInstalledPackageNameList = getInstalledPackageNameListInternal(context, flags)
|
||||
Utils.log(TAG, "获取已安装应用列表成功,数量为 ${cachedInstalledPackageNameList.size}")
|
||||
} else {
|
||||
cachedInstalledPackageInfoList = getInstalledPackageInfoListInternal(context, flags)
|
||||
Utils.log(TAG, "获取已安装应用列表成功,数量为 ${cachedInstalledPackageInfoList.size}")
|
||||
}
|
||||
}
|
||||
|
||||
return installedPackageList
|
||||
return Pair(cachedInstalledPackageInfoList, cachedInstalledPackageNameList)
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示获取已安装应用列表的对话框并请求权限
|
||||
*/
|
||||
fun showGetInstallAppsListDialogAndRequestPermissionIfNeeded(
|
||||
activity: FragmentActivity,
|
||||
ignorePermanentlyDenied: Boolean = false,
|
||||
resultClosure: (Boolean) -> Unit
|
||||
) {
|
||||
|
||||
if (isSupportGetInstalledAppsPermission(activity)) {
|
||||
// 若系统已经授予了获取应用列表的权限,直接执行授权成功回调
|
||||
if (!PermissionHelper.isGetInstalledListPermissionDisabled(activity)) {
|
||||
onGetInstalledPackagesAgreed()
|
||||
resultClosure.invoke(true)
|
||||
return
|
||||
}
|
||||
|
||||
PermissionHelper.showGetInstalledAppsListPermissionDialog(
|
||||
activity = activity,
|
||||
requestPermission = true,
|
||||
ignorePermanentlyDenied = ignorePermanentlyDenied
|
||||
) { isGranted ->
|
||||
if (isGranted) {
|
||||
SensorsBridge.trackInstalledListPermissionsResult("成功")
|
||||
onGetInstalledPackagesAgreed()
|
||||
resultClosure.invoke(true)
|
||||
|
||||
trackInstalledListAfterDelay()
|
||||
} else {
|
||||
resultClosure.invoke(false)
|
||||
SensorsBridge.trackInstalledListPermissionsResult("拒绝")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val hintDialog = PermissionHelper.showGetInstalledAppsListPermissionDialog(
|
||||
activity = activity,
|
||||
requestPermission = false,
|
||||
) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
SensorsBridge.trackInstalledListPermissionsCustomDialogShow()
|
||||
|
||||
val noticeDialog = DialogHelper.showGuideDialog(
|
||||
context = activity,
|
||||
title = "权限申请",
|
||||
content = "是否允许“光环助手”获取已安装的应用信息",
|
||||
confirmText = "开启",
|
||||
cancelText = "拒绝",
|
||||
confirmClickCallback = {
|
||||
SensorsBridge.trackInstalledListPermissionsCustomClick("开启")
|
||||
onGetInstalledPackagesAgreed()
|
||||
resultClosure.invoke(true)
|
||||
|
||||
trackInstalledListAfterDelay()
|
||||
},
|
||||
cancelClickCallback = {
|
||||
resultClosure.invoke(false)
|
||||
SensorsBridge.trackInstalledListPermissionsCustomClick("拒绝")
|
||||
}
|
||||
)
|
||||
|
||||
noticeDialog?.setOnDismissListener {
|
||||
hintDialog?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行用户授权获取已安装应用列表的操作
|
||||
*/
|
||||
private fun onGetInstalledPackagesAgreed() {
|
||||
isGetInstalledPackagesAgreed = true
|
||||
SPUtils.setBoolean(SP_GET_INSTALLED_PACKAGES_AGREED, true)
|
||||
|
||||
_installedPackageApiSwitchStatusLiveData.postValue(false)
|
||||
|
||||
// 进行包名初始化相关的操作
|
||||
initPackageRelatedData()
|
||||
}
|
||||
|
||||
/**
|
||||
* 进行包名初始化相关的操作
|
||||
*/
|
||||
fun initPackageRelatedData() {
|
||||
PackageRepository.initData()
|
||||
refreshLocalPackageList()
|
||||
refreshPackageNameList()
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟5秒后上报已安装应用列表
|
||||
*/
|
||||
private fun trackInstalledListAfterDelay() {
|
||||
CoroutineScope(SupervisorJob()).launch {
|
||||
delay(5000)
|
||||
SensorsBridge.trackNumberOfInstalledList(localPackageNameSet.size, localPackageNameSet)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否支持动态获取已安装应用列表权限
|
||||
*/
|
||||
fun isSupportGetInstalledAppsPermission(context: Context): Boolean {
|
||||
if (isUseAlternativeWayToGetInstalledPackages()) {
|
||||
// 已经使用另类获取已安装应用列表形式,强制判定为不支持动态获取已安装应用列表权限
|
||||
return false
|
||||
}
|
||||
|
||||
// 若存在缓存,直接返回缓存结果。
|
||||
if (isGetInstalledListPermissionSupported != UNKNOWN) {
|
||||
return isGetInstalledListPermissionSupported != UNSUPPORTED
|
||||
if (isGetInstalledPackagesPermissionSupported != UNKNOWN) {
|
||||
return isGetInstalledPackagesPermissionSupported != UNSUPPORTED
|
||||
}
|
||||
|
||||
try {
|
||||
@ -185,7 +490,7 @@ object PackageHelper {
|
||||
val flag =
|
||||
Settings.Secure.getInt(context.contentResolver, "oem_installed_apps_runtime_permission_enable", 0)
|
||||
if (flag == 1) {
|
||||
isGetInstalledListPermissionSupported = SUPPORTED
|
||||
isGetInstalledPackagesPermissionSupported = SUPPORTED
|
||||
return true
|
||||
}
|
||||
|
||||
@ -194,62 +499,323 @@ object PackageHelper {
|
||||
val permissionInfo = packageManager.getPermissionInfo("com.android.permission.GET_INSTALLED_APPS", 0)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
if (permissionInfo.protection == PermissionInfo.PROTECTION_DANGEROUS) {
|
||||
isGetInstalledListPermissionSupported = SUPPORTED
|
||||
isGetInstalledPackagesPermissionSupported = SUPPORTED
|
||||
return true
|
||||
} else {
|
||||
isGetInstalledListPermissionSupported = UNSUPPORTED
|
||||
isGetInstalledPackagesPermissionSupported = UNSUPPORTED
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
isGetInstalledListPermissionSupported = UNSUPPORTED
|
||||
isGetInstalledPackagesPermissionSupported = UNSUPPORTED
|
||||
return false
|
||||
}
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
isGetInstalledListPermissionSupported = UNSUPPORTED
|
||||
isGetInstalledPackagesPermissionSupported = UNSUPPORTED
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在5.1系统手机使用PackageManager获取已安装应用容易发生Package manager has died异常
|
||||
* https://stackoverflow.com/questions/13235793/transactiontoolargeeception-when-trying-tÏo-get-a-list-of-applications-installed/30062632#30062632
|
||||
* 确保指定包名的应用在已安装了的情况下能正常收录
|
||||
*/
|
||||
private fun getInstalledPackagesInternal(context: Context, flags: Int): List<PackageInfo> {
|
||||
Utils.log(TAG, "调用系统 API 获取已安装应用列表")
|
||||
fun addInstalledButMissingPackages(packageNameSet: HashSet<String>) {
|
||||
Utils.log(TAG, "addInstalledButMissingPackages 检查已安装但未收录的应用")
|
||||
|
||||
val installedPackageNameSet: HashSet<String> = hashSetOf()
|
||||
|
||||
for (packageName in packageNameSet) {
|
||||
val installedPkgNameExistInMemory = PackagesManager.isInstalled(packageName)
|
||||
val packageNameInstalledOnDevice = PackageUtils.getVersionNameByPackageName(packageName) != null
|
||||
|
||||
if (!installedPkgNameExistInMemory && packageNameInstalledOnDevice) {
|
||||
installedPackageNameSet.add(packageName)
|
||||
}
|
||||
|
||||
if (!packageNameInstalledOnDevice) {
|
||||
additionalWhiteListPackageNameSet.remove(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toJson())
|
||||
|
||||
Utils.log(TAG, "addInstalledButMissingPackages 需要请求接口获取的包数量为 ${installedPackageNameSet.size}")
|
||||
|
||||
PackageRepository.addInstalledGames(
|
||||
pkgNameList = ArrayList(installedPackageNameSet),
|
||||
updateInstallStatus = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新额外的白名单包名列表
|
||||
* @param packageName 包名
|
||||
* @param isAdd 是否添加
|
||||
*/
|
||||
fun updateAdditionalWhiteListPackageName(packageName: String, isAdd: Boolean) {
|
||||
val isUpdated = if (isAdd) {
|
||||
additionalWhiteListPackageNameSet.add(packageName)
|
||||
} else {
|
||||
additionalWhiteListPackageNameSet.remove(packageName)
|
||||
}
|
||||
|
||||
Utils.log(
|
||||
TAG,
|
||||
"updateAdditionalWhiteListPackageName 更新额外的白名单包名列表 $isAdd $packageName ,结果是 $isUpdated"
|
||||
)
|
||||
|
||||
if (isUpdated) {
|
||||
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toJson())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新安装状态异常 (适用于仅存在包名信息的列表)
|
||||
*/
|
||||
fun refreshWrongInstallStatus(packageNameSet: MutableSet<String>) {
|
||||
packageExecutor.execute {
|
||||
Utils.log(TAG, "refreshWrongInstallStatus 检查安装状态异常的应用")
|
||||
|
||||
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
|
||||
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
|
||||
|
||||
for (packageName in packageNameSet) {
|
||||
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
|
||||
|
||||
if (PackagesManager.isInstalled(packageName)
|
||||
&& installedVersionName == null
|
||||
) {
|
||||
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
|
||||
} else if (PackagesManager.isInstalled(packageName)
|
||||
&& installedVersionName != null
|
||||
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
|
||||
) {
|
||||
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
Utils.log(
|
||||
TAG,
|
||||
"refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}"
|
||||
)
|
||||
Utils.log(
|
||||
TAG,
|
||||
"refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}"
|
||||
)
|
||||
|
||||
runOnUiThread {
|
||||
if (uninstalledButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
|
||||
for (packageName in uninstalledButKeepingWrongStatusPackageNameSet) {
|
||||
PackageChangeHelper.addUninstall(packageName)
|
||||
additionalWhiteListPackageNameSet.remove(packageName)
|
||||
}
|
||||
|
||||
SPUtils.setString(
|
||||
SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST,
|
||||
additionalWhiteListPackageNameSet.toString()
|
||||
)
|
||||
}
|
||||
|
||||
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
|
||||
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
|
||||
PackageChangeHelper.addUpdate(packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新安装状态异常 (适用于存在游戏信息的列表)
|
||||
*/
|
||||
fun refreshWrongInstallStatus(gameEntityList: ArrayList<GameEntity>) {
|
||||
packageExecutor.execute {
|
||||
Utils.log(TAG, "refreshWrongInstallStatus 检查安装状态异常的应用")
|
||||
|
||||
val installedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
|
||||
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
|
||||
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
|
||||
|
||||
for (game in gameEntityList) {
|
||||
for (apk in game.getApk()) {
|
||||
val packageName = apk.packageName
|
||||
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
|
||||
|
||||
if (!PackagesManager.isInstalled(packageName)
|
||||
&& installedVersionName != null
|
||||
) {
|
||||
cachedPkgNameAndGameEntityMap.put(packageName, game)
|
||||
installedButKeepingWrongStatusPackageNameSet.add(packageName)
|
||||
} else if (PackagesManager.isInstalled(packageName)
|
||||
&& installedVersionName == null
|
||||
) {
|
||||
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
|
||||
} else if (PackagesManager.isInstalled(packageName)
|
||||
&& installedVersionName != null
|
||||
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
|
||||
&& !PackagesManager.isCanUpdate(game.id, packageName, false)
|
||||
) {
|
||||
cachedPkgNameAndGameEntityMap.put(packageName, game)
|
||||
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Utils.log(
|
||||
TAG,
|
||||
"refreshWrongInstallStatus 需要更新已安装状态的包数量为 ${installedButKeepingWrongStatusPackageNameSet.size}"
|
||||
)
|
||||
Utils.log(
|
||||
TAG,
|
||||
"refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}"
|
||||
)
|
||||
Utils.log(
|
||||
TAG,
|
||||
"refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}"
|
||||
)
|
||||
|
||||
runOnUiThread {
|
||||
if (installedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
|
||||
for (packageName in installedButKeepingWrongStatusPackageNameSet) {
|
||||
PackageChangeHelper.addInstall(packageName, cachedPkgNameAndGameEntityMap.remove(packageName))
|
||||
additionalWhiteListPackageNameSet.add(packageName)
|
||||
}
|
||||
|
||||
SPUtils.setString(
|
||||
SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST,
|
||||
additionalWhiteListPackageNameSet.toString()
|
||||
)
|
||||
}
|
||||
|
||||
if (uninstalledButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
|
||||
for (packageName in uninstalledButKeepingWrongStatusPackageNameSet) {
|
||||
PackageChangeHelper.addUninstall(packageName)
|
||||
additionalWhiteListPackageNameSet.remove(packageName)
|
||||
}
|
||||
|
||||
SPUtils.setString(
|
||||
SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST,
|
||||
additionalWhiteListPackageNameSet.toString()
|
||||
)
|
||||
}
|
||||
|
||||
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
|
||||
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
|
||||
PackageChangeHelper.addUpdate(packageName, cachedPkgNameAndGameEntityMap.remove(packageName))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInstalledPackageInfoListInternal(
|
||||
context: Context,
|
||||
flags: Int
|
||||
): List<PackageInfo> {
|
||||
return if (isUseAlternativeWayToGetInstalledPackages()) {
|
||||
Utils.log(TAG, "调用另类系统 API 获取已安装应用列表")
|
||||
getInstalledPackageByAlternative(context)
|
||||
} else {
|
||||
Utils.log(TAG, "调用默认系统 API 获取已安装应用列表")
|
||||
getInstalledPackageByDefault(context, flags)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInstalledPackageNameListInternal(
|
||||
context: Context,
|
||||
flags: Int
|
||||
): List<String> {
|
||||
if (isUseAlternativeWayToGetInstalledPackages()) {
|
||||
Utils.log(TAG, "调用另类系统 API 获取已安装应用包名列表")
|
||||
return getInstalledPackageNameByAlternative(context)
|
||||
} else {
|
||||
Utils.log(TAG, "调用默认系统 API 获取已安装应用包名列表")
|
||||
val packageInfoList = getInstalledPackageByDefault(context, flags)
|
||||
val packageList = arrayListOf<String>()
|
||||
for (packageInfo in packageInfoList) {
|
||||
if (context.packageName != packageInfo.packageName) {
|
||||
packageList.add(packageInfo.packageName)
|
||||
}
|
||||
}
|
||||
return packageList
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInstalledPackageByDefault(context: Context, flags: Int): List<PackageInfo> {
|
||||
val pm = context.packageManager
|
||||
try {
|
||||
return pm.getInstalledPackages(flags)
|
||||
} catch (ignored: java.lang.Exception) {
|
||||
//we don't care why it didn't succeed. We'll do it using an alternative way instead
|
||||
}
|
||||
// use fallback:
|
||||
val process: Process
|
||||
val result: MutableList<PackageInfo> = java.util.ArrayList()
|
||||
var bufferedReader: BufferedReader? = null
|
||||
try {
|
||||
process = Runtime.getRuntime().exec("pm list packages")
|
||||
bufferedReader = BufferedReader(InputStreamReader(process.inputStream))
|
||||
var line: String
|
||||
while ((bufferedReader.readLine().also { line = it }) != null) {
|
||||
val packageName = line.substring(line.indexOf(':') + 1)
|
||||
val packageInfo = pm.getPackageInfo(packageName, flags)
|
||||
result.add(packageInfo)
|
||||
}
|
||||
process.waitFor()
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
if (e is InterruptedException) {
|
||||
Thread.currentThread().interrupt()
|
||||
}
|
||||
} finally {
|
||||
if (bufferedReader != null) try {
|
||||
bufferedReader.close()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
return arrayListOf()
|
||||
}
|
||||
|
||||
private fun getInstalledPackageByAlternative(context: Context): ArrayList<PackageInfo> {
|
||||
val packageManager = context.getPackageManager()
|
||||
val packageList = arrayListOf<PackageInfo>()
|
||||
var packagesArray: Array<String>? = null
|
||||
var uid = android.os.Process.FIRST_APPLICATION_UID
|
||||
|
||||
while (uid <= android.os.Process.LAST_APPLICATION_UID) {
|
||||
try {
|
||||
packagesArray = packageManager.getPackagesForUid(uid)
|
||||
if (packagesArray != null && packagesArray.isNotEmpty()) {
|
||||
for (packageName in packagesArray) {
|
||||
try {
|
||||
val packageInfo = packageManager.getPackageInfo(packageName, 0)
|
||||
if (packageInfo == null) {
|
||||
break
|
||||
}
|
||||
|
||||
packageList.add(packageInfo)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (securityException: SecurityException) {
|
||||
securityException.printStackTrace()
|
||||
}
|
||||
uid++
|
||||
}
|
||||
|
||||
return packageList
|
||||
}
|
||||
|
||||
private fun getInstalledPackageNameByAlternative(context: Context): ArrayList<String> {
|
||||
val packageManager = context.getPackageManager()
|
||||
val packageList = arrayListOf<String>()
|
||||
var packagesArray: Array<String>? = null
|
||||
var uid = android.os.Process.FIRST_APPLICATION_UID
|
||||
|
||||
var lastValidUid = 0
|
||||
|
||||
while (uid <= android.os.Process.LAST_APPLICATION_UID) {
|
||||
try {
|
||||
packagesArray = packageManager.getPackagesForUid(uid)
|
||||
if (packagesArray != null && packagesArray.isNotEmpty()) {
|
||||
lastValidUid = uid
|
||||
|
||||
for (packageName in packagesArray) {
|
||||
packageList.add(packageName)
|
||||
}
|
||||
}
|
||||
} catch (securityException: SecurityException) {
|
||||
securityException.printStackTrace()
|
||||
}
|
||||
uid++
|
||||
}
|
||||
|
||||
if (HaloApp.getInstance().isNewForThisVersion && uploadUIDGapLog) {
|
||||
// 仅应用该版本第一次启动的第一次方法调用上报日志
|
||||
uploadUIDGapLog = false
|
||||
|
||||
val uidGap = (android.os.Process.LAST_APPLICATION_UID - lastValidUid) / 100 * 100
|
||||
SentryHelper.onEvent("UID_GAP", "gap", uidGap.toString())
|
||||
}
|
||||
|
||||
return packageList
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,7 +6,6 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.FileProvider
|
||||
import com.gh.common.dialog.InstallPermissionDialogFragment
|
||||
@ -20,15 +19,18 @@ import com.gh.gamecenter.core.utils.CurrentActivityHolder
|
||||
import com.gh.gamecenter.core.utils.MD5Utils
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.install.InstallService
|
||||
import com.gh.gamecenter.vpn.VpnHelper
|
||||
import com.gh.vspace.VHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.utils.AppManager
|
||||
import com.lightgame.utils.Utils
|
||||
import java.io.File
|
||||
|
||||
// TODO 将弹窗改成以责任链模式来处理
|
||||
object PackageInstaller {
|
||||
|
||||
private val listeners = mutableListOf<OnInstallListener>()
|
||||
|
||||
/**
|
||||
* 为了兼容java代码
|
||||
*/
|
||||
@ -59,7 +61,7 @@ object PackageInstaller {
|
||||
val isDownloadAsVGame = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.VGAME
|
||||
|| downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.DUAL_DOWNLOAD_VGAME
|
||||
|
||||
val currentActivity = CurrentActivityHolder.getCurrentActivity() ?: return
|
||||
val currentActivity = AppManager.getInstance().currentActivity() ?: return
|
||||
|
||||
if (!ignoreAsVGame && isDownloadAsVGame) {
|
||||
VHelper.install(currentActivity, downloadEntity)
|
||||
@ -108,6 +110,12 @@ object PackageInstaller {
|
||||
return
|
||||
}
|
||||
|
||||
val packageName = downloadEntity?.packageName ?: PackageUtils.getPackageNameByPath(context, pkgPath)
|
||||
|
||||
packageName?.let {
|
||||
PackageChangeHelper.addInstallPendingPackage(packageName)
|
||||
}
|
||||
|
||||
try {
|
||||
// 判断是否需要使用浏览器来进行安装
|
||||
if (BrowserInstallHelper.isUseBrowserToInstallEnabled()
|
||||
@ -118,13 +126,14 @@ object PackageInstaller {
|
||||
}
|
||||
|
||||
if (PackageUtils.isCanLaunchSetup(context, pkgPath)) {
|
||||
val currentActivity = CurrentActivityHolder.getCurrentActivity()
|
||||
|
||||
if (VpnHelper.shouldUseVpn() && currentActivity is AppCompatActivity) {
|
||||
turnOnVpnThenInstall(currentActivity, pkgPath, downloadEntity)
|
||||
} else {
|
||||
install(context, pkgPath)
|
||||
}
|
||||
installWithPureModeHandled(
|
||||
context,
|
||||
pkgPath,
|
||||
downloadEntity?.packageName,
|
||||
downloadEntity?.gameId ?: "unknown",
|
||||
downloadEntity?.name ?: "unknown",
|
||||
downloadEntity?.categoryChinese ?: "unknown"
|
||||
)
|
||||
} else {
|
||||
if (isPluggin) {
|
||||
DialogHelper.showPluginDialog(
|
||||
@ -154,10 +163,26 @@ object PackageInstaller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理纯净模式后的安装
|
||||
*/
|
||||
private fun installWithPureModeHandled(
|
||||
context: Context,
|
||||
pkgPath: String,
|
||||
pkgName: String?,
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameType: String,
|
||||
) {
|
||||
PureModeHelper.handlePureModeIfNeeded(context, gameId, gameName, gameType) {
|
||||
install(context, pkgPath, pkgName)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 最终执行安装的方法
|
||||
*/
|
||||
private fun install(context: Context, pkgPath: String) {
|
||||
private fun install(context: Context, pkgPath: String, pkgName: String?) {
|
||||
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
|
||||
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU && Build.MANUFACTURER.lowercase().contains("xiaomi")) {
|
||||
@ -168,10 +193,13 @@ object PackageInstaller {
|
||||
|
||||
val installIntent = getInstallIntent(context, pkgPath)
|
||||
context.startActivity(installIntent)
|
||||
|
||||
dispatchOnInstallListener(pkgPath, pkgName)
|
||||
}
|
||||
|
||||
fun installMultiple(
|
||||
context: Context,
|
||||
pkgName: String,
|
||||
pkgPath: String,
|
||||
sessionId: Int = -1
|
||||
) {
|
||||
@ -194,6 +222,24 @@ object PackageInstaller {
|
||||
val pendingIntent = PendingIntent.getActivity(context, sessionId, intent, flags)
|
||||
// 提交数据流并执行安装
|
||||
session.commit(pendingIntent.intentSender)
|
||||
|
||||
dispatchOnInstallListener(pkgName, pkgPath)
|
||||
}
|
||||
|
||||
fun registerOnInstallListener(listener: OnInstallListener) {
|
||||
if (!listeners.contains(listener)) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
}
|
||||
|
||||
fun unregisterOnInstallListener(listener: OnInstallListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
private fun dispatchOnInstallListener(pkgPath: String, pkgName: String?) {
|
||||
for (listener in listeners) {
|
||||
listener.onInstalling(pkgName, pkgPath)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -250,6 +296,8 @@ object PackageInstaller {
|
||||
fun uninstallForPackageName(context: Context, pkn: String?) {
|
||||
if (pkn.isNullOrEmpty()) return
|
||||
|
||||
PackageChangeHelper.addUninstallPendingPackage(pkn)
|
||||
|
||||
val uninstallIntent = Intent()
|
||||
uninstallIntent.action = Intent.ACTION_DELETE
|
||||
uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
@ -283,82 +331,8 @@ object PackageInstaller {
|
||||
return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis())
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动 VPN 然后安装应用 (若没有授权会先提醒授权 VPN ,若拒绝授权会回落到直接执行安装)
|
||||
*/
|
||||
private fun turnOnVpnThenInstall(currentActivity: AppCompatActivity,
|
||||
pkgPath: String,
|
||||
downloadEntity: DownloadEntity?) {
|
||||
if (VpnHelper.isVpnPermissionGranted(currentActivity) == true) {
|
||||
VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
|
||||
if (shouldShowVpnError) {
|
||||
ToastUtils.toast("安装防护功能启动失败")
|
||||
}
|
||||
install(currentActivity, pkgPath)
|
||||
}
|
||||
} else {
|
||||
val isTheFirstTimeToShowVpnHintDialog = VpnHelper.isTheFistTimeToShowVpnHintDialog()
|
||||
|
||||
downloadEntity?.let {
|
||||
NewFlatLogUtils.logVpnHintDialogShow(it.gameId, it.name)
|
||||
}
|
||||
|
||||
// 将 VPN 提示弹窗标记为已读(已读后的下一次显示"不再提醒"按钮)
|
||||
VpnHelper.setVpnHintDialogShowed()
|
||||
if (!VpnHelper.shouldShowVpnHintDialog()) {
|
||||
VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
|
||||
if (shouldShowVpnError) {
|
||||
ToastUtils.toast("安装防护功能启动失败")
|
||||
}
|
||||
install(currentActivity, pkgPath)
|
||||
}
|
||||
} else {
|
||||
DialogHelper.showGuideDialog(
|
||||
context = currentActivity,
|
||||
title = "开启安装防护",
|
||||
content = "建议您开启安装防护功能,该功能有助于帮助您更快的完成安装,避免因提示和置换导致的重复下载等问题,安装防护功能需要获取您的VPN权限",
|
||||
confirmText = "立即授权开启防护",
|
||||
cancelText = "不再提醒",
|
||||
confirmClickCallback = {
|
||||
VpnHelper.ignoreVpnHintDialog()
|
||||
VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
|
||||
if (shouldShowVpnError) {
|
||||
ToastUtils.toast("安装防护功能启动失败")
|
||||
}
|
||||
install(currentActivity, pkgPath)
|
||||
}
|
||||
|
||||
downloadEntity?.let {
|
||||
NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "立即授权")
|
||||
}
|
||||
},
|
||||
cancelClickCallback = {
|
||||
VpnHelper.ignoreVpnFunction()
|
||||
install(currentActivity, pkgPath)
|
||||
downloadEntity?.let {
|
||||
NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "不再提醒")
|
||||
}
|
||||
},
|
||||
extraConfig = DialogHelper.Config(
|
||||
showCloseIcon = true,
|
||||
showAlternativeCancelStyle = !isTheFirstTimeToShowVpnHintDialog
|
||||
),
|
||||
uiModificationCallback = { binding ->
|
||||
binding.cancelTv.visibility = View.GONE
|
||||
binding.closeContainer.setOnClickListener {
|
||||
binding.markDismissByTouchInside()
|
||||
|
||||
install(currentActivity, pkgPath)
|
||||
binding.dismiss()
|
||||
|
||||
downloadEntity?.let {
|
||||
NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "关闭按钮")
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
interface OnInstallListener {
|
||||
fun onInstalling(packageName: String?, packagePath: String)
|
||||
}
|
||||
|
||||
}
|
||||
@ -7,14 +7,12 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.content.pm.Signature;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@ -29,12 +27,11 @@ import com.gh.common.xapk.XapkInstaller;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.common.utils.ExtensionsKt;
|
||||
import com.gh.gamecenter.common.utils.PermissionHelper;
|
||||
import com.gh.gamecenter.core.utils.MD5Utils;
|
||||
import com.gh.gamecenter.core.utils.SentryHelper;
|
||||
import com.gh.gamecenter.feature.entity.ApkEntity;
|
||||
import com.gh.gamecenter.feature.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.GameUpdateEntity;
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.gh.vspace.VHelper;
|
||||
import com.gh.vspace.db.VGameEntity;
|
||||
@ -48,12 +45,10 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
@ -74,7 +69,7 @@ public class PackageUtils {
|
||||
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).applicationInfo.sourceDir;
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
// do nothing
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -312,7 +307,7 @@ public class PackageUtils {
|
||||
return new String[]{null, null};
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
// do nothing
|
||||
}
|
||||
return new String[]{null, null};
|
||||
}
|
||||
@ -592,7 +587,7 @@ public class PackageUtils {
|
||||
.getPackageInfo(packageName, 0);
|
||||
return packageInfo.firstInstallTime;
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
// do nothing
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -619,7 +614,7 @@ public class PackageUtils {
|
||||
return HaloApp.getInstance().getApplication().getPackageManager()
|
||||
.getPackageInfo(BuildConfig.APPLICATION_ID, 0).lastUpdateTime;
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
// do nothing
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -633,7 +628,7 @@ public class PackageUtils {
|
||||
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName;
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
// do nothing
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -646,7 +641,7 @@ public class PackageUtils {
|
||||
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionCode;
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
// do nothing
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -660,70 +655,38 @@ public class PackageUtils {
|
||||
PackageManager packageManager = context.getApplicationContext().getPackageManager();
|
||||
return packageManager.getApplicationIcon(packageName);
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
// do nothing
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* 获取所有已安装的软件的包名、版本(非系统应用)
|
||||
* 获取所有已安装的软件的包名(包括系统应用)
|
||||
*/
|
||||
public static ArrayList<String> getAllPackageName(Context context) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
List<PackageInfo> packageInfos = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
if (!context.getPackageName().equals(packageInfo.packageName)) {
|
||||
list.add(packageInfo.packageName);
|
||||
}
|
||||
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
|
||||
for (String packageName : packageNameList) {
|
||||
if (!context.getPackageName().equals(packageName)) {
|
||||
list.add(packageName);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static ArrayList<String> getAllPackageNameIncludeGh(Context context) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
List<PackageInfo> packageInfos = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
list.add(packageInfo.packageName);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/*
|
||||
* 获取所有已安装的软件的包名(包括系统应用)
|
||||
*/
|
||||
public static ArrayList<String> getAllPackageNameIncludeSystemApps(Context context) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
List<PackageInfo> packageInfos = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
list.add(packageInfo.packageName);
|
||||
}
|
||||
return list;
|
||||
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
|
||||
return new ArrayList<>(packageNameList);
|
||||
}
|
||||
|
||||
public static JSONArray getAppList(Context context) {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
try {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
List<PackageInfo> packageInfos = PackageHelper.INSTANCE.getInstalledPackages(context, 0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
// 这里的 pm.getApplicationLabel 有极小机率会返回 null 值 (明明方法标示了返回值 nonnull)
|
||||
// Attempt to invoke interface method 'java.lang.String java.lang.CharSequence.toString()' on a null object reference
|
||||
// 所以要是为空就 continue,忽略掉它
|
||||
if (pm.getApplicationLabel(packageInfo.applicationInfo) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
jsonObject.put("name", pm.getApplicationLabel(packageInfo.applicationInfo).toString());
|
||||
jsonObject.put("package", packageInfo.packageName);
|
||||
jsonObject.put("version", packageInfo.versionName);
|
||||
jsonArray.put(jsonObject);
|
||||
}
|
||||
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
|
||||
for (String packageName : packageNameList) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("package", packageName);
|
||||
jsonArray.put(jsonObject);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@ -5,12 +5,12 @@ import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
|
||||
import com.gh.gamecenter.common.retrofit.JSONObjectResponse;
|
||||
import com.gh.gamecenter.common.retrofit.Response;
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.walkud.rom.checker.RomIdentifier;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
@ -37,7 +37,7 @@ public class PostCommentUtils {
|
||||
device.put("model", Build.MODEL);
|
||||
device.put("manufacturer", Build.MANUFACTURER);
|
||||
device.put("android_version", android.os.Build.VERSION.RELEASE);
|
||||
device.put("rom", RomIdentifier.getRom().name() + " " + RomIdentifier.getRom().getVersionName());
|
||||
device.put("rom", MetaUtil.INSTANCE.getRom().name() + " " + MetaUtil.INSTANCE.getRom().getVersionName());
|
||||
content.put("device", device);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
342
app/src/main/java/com/gh/common/util/PureModeHelper.kt
Normal file
342
app/src/main/java/com/gh/common/util/PureModeHelper.kt
Normal file
@ -0,0 +1,342 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.Settings
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.gamecenter.common.utils.DialogHelper
|
||||
import com.gh.gamecenter.entity.NewApiSettingsEntity
|
||||
import com.lightgame.utils.Utils
|
||||
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.enlargeTouchArea
|
||||
import com.gh.gamecenter.common.utils.setDrawableEnd
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
|
||||
/**
|
||||
* 处理厂商纯净/安全模式的辅助类
|
||||
*/
|
||||
object PureModeHelper {
|
||||
|
||||
private const val TAG = "PureModeHelper"
|
||||
|
||||
private const val HW = "HUAWEI"
|
||||
|
||||
private const val HW_PURE_MODE_STATE = "pure_mode_state"
|
||||
private const val HW_PURE_ENHANCED_MODE_STATE = "pure_enhanced_mode_state"
|
||||
|
||||
private const val HW_PURE_MODE = "harmony_os_pure_mode"
|
||||
private const val HW_PURE_ENHANCED_MODE = "harmony_os_pure_enhanced_mode"
|
||||
|
||||
private const val SP_USER_IGNORE_GUIDE = "user_ignore_guide"
|
||||
|
||||
private const val SWITCH_EXIST = 1
|
||||
private const val SWITCH_ON = 0
|
||||
private const val SWITCH_OFF = -1
|
||||
|
||||
private var isThisDeviceUsingEnhancedMode = false // 当前设备是否是增强纯净模式
|
||||
|
||||
fun handlePureModeIfNeeded(
|
||||
context: Context,
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameType: String,
|
||||
callback: () -> Unit
|
||||
) {
|
||||
// 用户忽略提醒,不再走下面的逻辑
|
||||
if (SPUtils.getBoolean(SP_USER_IGNORE_GUIDE, false)) {
|
||||
callback()
|
||||
return
|
||||
}
|
||||
|
||||
// 仅适用于华为手机
|
||||
val manufacturer = android.os.Build.MANUFACTURER
|
||||
if (manufacturer != HW) {
|
||||
callback.invoke()
|
||||
return
|
||||
}
|
||||
|
||||
val solidContext = DialogHelper.checkDialogContext(context)
|
||||
|
||||
if (solidContext == null) {
|
||||
callback.invoke()
|
||||
return
|
||||
}
|
||||
|
||||
if (readState(solidContext, HW_PURE_ENHANCED_MODE_STATE) == SWITCH_ON) {
|
||||
Utils.log(TAG, "增强纯净模式开启!")
|
||||
isThisDeviceUsingEnhancedMode = true
|
||||
|
||||
val pureModeGuide =
|
||||
Config.getNewApiSettingsEntity()?.install?.guides?.firstOrNull { it.type == HW_PURE_ENHANCED_MODE }
|
||||
|
||||
if (pureModeGuide != null) {
|
||||
showHWHintDialog(solidContext, pureModeGuide, gameId, gameName, gameType, true, callback)
|
||||
} else {
|
||||
callback.invoke()
|
||||
}
|
||||
} else if (readState(solidContext, HW_PURE_ENHANCED_MODE_STATE) != SWITCH_EXIST
|
||||
&& readState(solidContext, HW_PURE_MODE_STATE) == SWITCH_ON
|
||||
) {
|
||||
Utils.log(TAG, "纯净模式开启!")
|
||||
isThisDeviceUsingEnhancedMode = false
|
||||
|
||||
val pureModeGuide =
|
||||
Config.getNewApiSettingsEntity()?.install?.guides?.firstOrNull { it.type == HW_PURE_MODE }
|
||||
|
||||
if (pureModeGuide != null) {
|
||||
showHWHintDialog(solidContext, pureModeGuide, gameId, gameName, gameType, false, callback)
|
||||
} else {
|
||||
callback.invoke()
|
||||
}
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showHWHintDialog(
|
||||
context: Context,
|
||||
guide: NewApiSettingsEntity.Guide,
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameType: String,
|
||||
isEnhancedMode: Boolean,
|
||||
callback: () -> Unit
|
||||
) {
|
||||
var isIgnored = false
|
||||
|
||||
if (context is Activity) {
|
||||
if (context.isFinishing) {
|
||||
callback.invoke()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
trackDialogShow(isEnhancedMode, gameId, gameName, gameType)
|
||||
|
||||
DialogHelper.showGuideDialog(
|
||||
context = context,
|
||||
title = guide.title,
|
||||
content = guide.content,
|
||||
confirmText = guide.buttonTextSettingJump,
|
||||
cancelText = guide.buttonTextClose,
|
||||
uiModificationCallback = { binding ->
|
||||
binding.hintTv.buildSpannableString {
|
||||
addText(guide.linkTextPrefix)
|
||||
addText(guide.linkText) {
|
||||
setColor(ColorResId(R.color.text_theme))
|
||||
onClick(false) {
|
||||
binding.extraHintIv.performClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.extraHintIv.setImageResource(R.drawable.ic_home_head_arrow)
|
||||
binding.extraHintIv.setOnClickListener {
|
||||
directToLink(
|
||||
context,
|
||||
guide,
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
isEnhancedMode,
|
||||
isIgnored
|
||||
)
|
||||
}
|
||||
binding.extraHintIv.enlargeTouchArea()
|
||||
binding.extraHintIv.visibility = View.VISIBLE
|
||||
binding.hintTv.visibility = View.VISIBLE
|
||||
binding.selectorContainer.visibility = if (guide.dialogFrequency == "once") View.VISIBLE else View.GONE
|
||||
binding.selectorContainer.setOnClickListener {
|
||||
binding.selectorContainer.isChecked = !binding.selectorContainer.isChecked
|
||||
isIgnored = binding.selectorContainer.isChecked
|
||||
}
|
||||
|
||||
binding.confirmTv.setOnClickListener {
|
||||
toHWPureModeSetting(context)
|
||||
trackDialogClicked(
|
||||
isEnhancedMode = isEnhancedMode,
|
||||
gameId = gameId,
|
||||
gameName = gameName,
|
||||
gameType = gameType,
|
||||
buttonName = guide.buttonTextSettingJump,
|
||||
isIgnored = isIgnored
|
||||
)
|
||||
}
|
||||
|
||||
// 监听是否已授权,授权后自动调起安装并 dismiss dialog
|
||||
if (context is AppCompatActivity) {
|
||||
val lifecycle = context.lifecycle
|
||||
lifecycle.addObserver(object : DefaultLifecycleObserver {
|
||||
override fun onResume(owner: LifecycleOwner) {
|
||||
val granted = (isThisDeviceUsingEnhancedMode && readState(context, HW_PURE_ENHANCED_MODE_STATE) != SWITCH_ON)
|
||||
|| (!isThisDeviceUsingEnhancedMode && readState(context, HW_PURE_MODE_STATE) != SWITCH_ON)
|
||||
|
||||
if (granted) {
|
||||
binding.dialog.dismiss()
|
||||
callback.invoke()
|
||||
lifecycle.removeObserver(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
super.onDestroy(owner)
|
||||
|
||||
lifecycle.removeObserver(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
confirmClickCallback = {
|
||||
// do nothing, 上面 setOnClickListener 处理了
|
||||
},
|
||||
cancelClickCallback = {
|
||||
if (guide.dialogFrequency == "once" && isIgnored) {
|
||||
SPUtils.setBoolean(SP_USER_IGNORE_GUIDE, true)
|
||||
}
|
||||
trackDialogClicked(
|
||||
isEnhancedMode = isEnhancedMode,
|
||||
gameId = gameId,
|
||||
gameName = gameName,
|
||||
gameType = gameType,
|
||||
buttonName = guide.buttonTextClose,
|
||||
isIgnored = isIgnored
|
||||
)
|
||||
callback()
|
||||
},
|
||||
touchOutsideCallback = {
|
||||
if (guide.dialogFrequency == "once" && isIgnored) {
|
||||
SPUtils.setBoolean(SP_USER_IGNORE_GUIDE, true)
|
||||
}
|
||||
trackDialogClicked(
|
||||
isEnhancedMode = isEnhancedMode,
|
||||
gameId = gameId,
|
||||
gameName = gameName,
|
||||
gameType = gameType,
|
||||
buttonName = "关闭弹窗",
|
||||
isIgnored = isIgnored
|
||||
)
|
||||
callback()
|
||||
},
|
||||
extraConfig = DialogHelper.Config(centerTitle = true)
|
||||
)
|
||||
}
|
||||
|
||||
private fun directToLink(
|
||||
context: Context,
|
||||
guide: NewApiSettingsEntity.Guide,
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameType: String,
|
||||
isEnhancedMode: Boolean,
|
||||
isIgnored: Boolean
|
||||
) {
|
||||
DirectUtils.directToLinkPage(context, guide.link, "纯净模式弹窗", "")
|
||||
trackDialogClicked(
|
||||
isEnhancedMode,
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"跳转链接",
|
||||
isIgnored,
|
||||
guide.link.link ?: "",
|
||||
guide.link.type ?: "",
|
||||
guide.link.text ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
private fun trackDialogShow(
|
||||
isEnhancedMode: Boolean,
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameType: String
|
||||
) {
|
||||
if (isEnhancedMode) {
|
||||
SensorsBridge.trackAddedProtectionDialogShow(
|
||||
gameId = gameId,
|
||||
gameName = gameName,
|
||||
gameType = gameType
|
||||
)
|
||||
} else {
|
||||
SensorsBridge.trackPureModeDialogShow(
|
||||
gameId = gameId,
|
||||
gameName = gameName,
|
||||
gameType = gameType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun trackDialogClicked(
|
||||
isEnhancedMode: Boolean,
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameType: String,
|
||||
buttonName: String,
|
||||
isIgnored: Boolean,
|
||||
linkId: String? = null,
|
||||
linkType: String? = null,
|
||||
linkText: String? = null
|
||||
) {
|
||||
if (isEnhancedMode) {
|
||||
SensorsBridge.trackAddedProtectionDialogClick(
|
||||
gameId = gameId,
|
||||
gameName = gameName,
|
||||
gameType = gameType,
|
||||
buttonName = buttonName,
|
||||
isIgnored = isIgnored,
|
||||
linkId = linkId ?: "",
|
||||
linkType = linkType ?: "",
|
||||
linkText = linkText ?: ""
|
||||
)
|
||||
} else {
|
||||
SensorsBridge.trackPureModeDialogClick(
|
||||
gameId = gameId,
|
||||
gameName = gameName,
|
||||
gameType = gameType,
|
||||
buttonName = buttonName,
|
||||
isIgnored = isIgnored,
|
||||
linkId = linkId ?: "",
|
||||
linkType = linkType ?: "",
|
||||
linkText = linkText ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun toHWPureModeSetting(context: Context) {
|
||||
try {
|
||||
val intent = Intent()
|
||||
intent.setPackage("com.huawei.security.privacycenter")
|
||||
intent.setAction("com.huawei.securitycenter.PURE_MODE_ACTIVITY")
|
||||
intent.putExtra("intent_from_settings", true)
|
||||
context.startActivity(intent)
|
||||
} catch (_: Exception) {
|
||||
toSystemSettings(context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun toSystemSettings(context: Context) {
|
||||
try {
|
||||
val intent = Intent(Settings.ACTION_SETTINGS)
|
||||
context.startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun readState(context: Context, key: String): Int {
|
||||
try {
|
||||
val result = Settings.Secure.getInt(context.getContentResolver(), key, SWITCH_OFF)
|
||||
Utils.log(TAG, "readState $key state >>> $result")
|
||||
return result
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return SWITCH_OFF
|
||||
}
|
||||
|
||||
}
|
||||
@ -3,12 +3,12 @@ package com.gh.common.util
|
||||
import android.annotation.SuppressLint
|
||||
import com.gh.gamecenter.common.entity.SignatureEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toJson
|
||||
import com.gh.gamecenter.common.utils.toObject
|
||||
import com.gh.gamecenter.core.utils.MD5Utils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
/**
|
||||
* 存储光环网游使用的签名
|
||||
@ -24,7 +24,7 @@ object SignatureRepository {
|
||||
RetrofitManager.getInstance()
|
||||
.newApi
|
||||
.ghSignature
|
||||
.compose(singleToMain())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : BiResponse<ArrayList<SignatureEntity>>() {
|
||||
override fun onSuccess(data: ArrayList<SignatureEntity>) {
|
||||
signDigestList = ArrayList()
|
||||
|
||||
@ -27,8 +27,8 @@ import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
|
||||
|
||||
object SyncDataBetweenPageHelper {
|
||||
|
||||
private const val REQUEST_CODE_TAG = "REQUEST_CODE_TAG"
|
||||
private const val DATA_POSITION_TAG = "DATA_POSITION_TAG"
|
||||
const val REQUEST_CODE_TAG = "REQUEST_CODE_TAG"
|
||||
const val DATA_POSITION_TAG = "DATA_POSITION_TAG"
|
||||
private const val DEFAULT_NUMBER = -1111
|
||||
|
||||
fun startActivityForResult(context: Context, intent: Intent, requestCode: Int, dataPosition: Int) {
|
||||
|
||||
@ -2,15 +2,16 @@ package com.gh.common.util
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.iinterface.ISuperiorChain
|
||||
import com.gh.gamecenter.amway.AmwayFragment
|
||||
import com.gh.gamecenter.category2.CategoryV2Fragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.provider.IHelpAndFeedbackProvider
|
||||
import com.gh.gamecenter.discovery.DiscoveryFragment
|
||||
import com.gh.gamecenter.entity.SubjectData
|
||||
import com.gh.gamecenter.feedback.view.help.HelpAndFeedbackFragment
|
||||
import com.gh.gamecenter.feedback.view.qa.HelpContainerFragment
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailFragment
|
||||
import com.gh.gamecenter.forum.home.CommunityHomeFragment
|
||||
import com.gh.gamecenter.fragment.ReloadFragment
|
||||
@ -62,7 +63,8 @@ object ViewPagerFragmentHelper {
|
||||
const val TYPE_GAME_LIST = "game_list" // 游戏单广场
|
||||
const val TYPE_FEEDBACK = "feedback" // 帮助与反馈
|
||||
const val TYPE_COLUMN = "column" // 游戏专题详情页
|
||||
const val TYPE_QQ_MINI_GAME_COLUMN = "qq_mini_game_column_detail" // QQ游戏专题详情页
|
||||
const val TYPE_QQ_MINI_GAME_COLUMN = "qq_mini_game_column_detail" // QQ小游戏专题详情页
|
||||
const val TYPE_WECHAT_GAME_COLUMN = "wechat_game_column_detail" // 微信小游戏专题详情页
|
||||
const val TYPE_COLUMN_COLLECTION = "column_collection" // 专题合集详情页
|
||||
const val TYPE_SERVER = "server" // 开服表
|
||||
const val TYPE_COLUMN_TEST = "column_test_v2" // 新游开测
|
||||
@ -124,7 +126,15 @@ object ViewPagerFragmentHelper {
|
||||
}
|
||||
// 帮助与反馈
|
||||
TYPE_FEEDBACK -> {
|
||||
HelpAndFeedbackFragment().with(bundle)
|
||||
val helpAndFeedbackProvider =
|
||||
ARouter.getInstance().build(RouteConsts.provider.helpAndFeedback)
|
||||
.navigation() as? IHelpAndFeedbackProvider
|
||||
if (helpAndFeedbackProvider != null) {
|
||||
helpAndFeedbackProvider.getHelpAndFeedbackFragment().with(bundle)
|
||||
} else {
|
||||
// 纯粹是占位用的 fragment
|
||||
AmwayFragment().with(bundle)
|
||||
}
|
||||
}
|
||||
// 帖子
|
||||
TYPE_COMMUNITY_ARTICLE -> {
|
||||
@ -151,11 +161,16 @@ object ViewPagerFragmentHelper {
|
||||
className = GameCollectionSquareFragment::class.java.name
|
||||
}
|
||||
// 游戏专题详情页/QQ游戏专题详情页
|
||||
TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN -> {
|
||||
TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN, TYPE_WECHAT_GAME_COLUMN -> {
|
||||
val subjectType = when(entity.type) {
|
||||
TYPE_QQ_MINI_GAME_COLUMN -> SubjectData.SubjectType.QQ_GAME
|
||||
TYPE_WECHAT_GAME_COLUMN -> SubjectData.SubjectType.WECHAT_GAME
|
||||
else -> SubjectData.SubjectType.NORMAL
|
||||
}
|
||||
className = SubjectFragment::class.java.name
|
||||
bundle.putParcelable(
|
||||
EntranceConsts.KEY_SUBJECT_DATA,
|
||||
SubjectData(entity.link, entity.text, false, isQQMiniGame = entity.type == "qq_mini_game_column_detail")
|
||||
SubjectData(entity.link, entity.text, false, subjectType = subjectType)
|
||||
)
|
||||
bundle.putBoolean(EntranceConsts.KEY_SHOW_DOWNLOAD_MENU, !isTabWrapper)
|
||||
}
|
||||
@ -175,6 +190,8 @@ object ViewPagerFragmentHelper {
|
||||
// 新游开测
|
||||
TYPE_COLUMN_TEST -> {
|
||||
className = GameServerTestV2Fragment::class.java.name
|
||||
bundle.putString(EntranceConsts.KEY_ID, entity.link)
|
||||
bundle.putString(EntranceConsts.KEY_NAME, entity.text)
|
||||
}
|
||||
// 分类2.0
|
||||
TYPE_CATEGORY_V2 -> {
|
||||
@ -227,9 +244,15 @@ object ViewPagerFragmentHelper {
|
||||
}
|
||||
// QA
|
||||
TYPE_QA -> {
|
||||
className = HelpContainerFragment::class.java.name
|
||||
bundle.putString(EntranceConsts.KEY_QA_ID, entity.link)
|
||||
bundle.putString(EntranceConsts.KEY_NAVIGATION_TITLE, entity.text)
|
||||
val helpAndFeedbackProvider =
|
||||
ARouter.getInstance().build(RouteConsts.provider.helpAndFeedback)
|
||||
.navigation() as? IHelpAndFeedbackProvider
|
||||
|
||||
helpAndFeedbackProvider?.let {
|
||||
className = it.getHelpContainerFragmentClass()
|
||||
bundle.putString(EntranceConsts.KEY_QA_ID, entity.link)
|
||||
bundle.putString(EntranceConsts.KEY_NAVIGATION_TITLE, entity.text)
|
||||
}
|
||||
}
|
||||
// 资讯中心
|
||||
TYPE_ARTICLE_CENTER -> {
|
||||
|
||||
@ -31,7 +31,7 @@ class CustomExoPlayerCacheManager : ICacheManager {
|
||||
mediaPlayer.setDataSource(context, Uri.parse(url), header)
|
||||
}
|
||||
|
||||
override fun clearCache(context: Context, cachePath: File, url: String) {
|
||||
override fun clearCache(context: Context, cachePath: File?, url: String) {
|
||||
ExoSourceManager.clearCache(context, cachePath, url)
|
||||
}
|
||||
|
||||
|
||||
@ -156,8 +156,8 @@ class CustomIjkExo2MediaPlayer : AbstractMediaPlayer(), Player.EventListener, An
|
||||
|
||||
override fun setDataSource(context: Context?, uri: Uri) {
|
||||
dataSource = uri.toString()
|
||||
// mediaSource = exoHelper?.getMediaSource(dataSource, isPreview, isCache, isLooping, cacheDir, overrideExtension)
|
||||
mediaSource = DefaultMediaSourceFactory(context!!).createMediaSource(MediaItem.fromUri(uri))
|
||||
mediaSource = exoHelper?.getMediaSource(dataSource, isPreview, isCache, isLooping, cacheDir, overrideExtension)
|
||||
// mediaSource = DefaultMediaSourceFactory(context!!).createMediaSource(MediaItem.fromUri(uri))
|
||||
}
|
||||
|
||||
override fun setDataSource(fd: FileDescriptor?) {
|
||||
@ -265,7 +265,9 @@ class CustomIjkExo2MediaPlayer : AbstractMediaPlayer(), Player.EventListener, An
|
||||
internalPlayer?.release()
|
||||
internalPlayer = null
|
||||
|
||||
exoHelper?.release()
|
||||
// exoHelper?.release() 调用的是 ExoSourceManager 的 release 方法,会废弃掉全局唯一的 SimpleCache 实例
|
||||
// 导致其他地方使用 SimpleCache 时会出现异常,无法正常播放
|
||||
// exoHelper?.release()
|
||||
|
||||
surface = null
|
||||
dataSource = null
|
||||
|
||||
@ -1,331 +0,0 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.setDrawableEnd
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.visibleIf
|
||||
import com.gh.gamecenter.entity.CatalogEntity
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
|
||||
class CatalogFilterView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private var mTypeTv: TextView
|
||||
private var mCatalogTv: TextView
|
||||
private var mSizeTv: TextView
|
||||
private var mTypeContainer: View
|
||||
private var mCatalogContainer: View
|
||||
private var mSizeContainer: View
|
||||
|
||||
private var mTypeFilterArray = ArrayList<SortType>()
|
||||
private var mCatalogFilterArray = ArrayList<CatalogEntity.SubCatalogEntity>()
|
||||
private var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
|
||||
|
||||
private var mOnCatalogFilterSetupListener: OnCatalogFilterSetupListener? = null
|
||||
|
||||
private var mTypePopupWindow: PopupWindow? = null
|
||||
private var mCatalogPopupWindow: PopupWindow? = null
|
||||
private var mSizePopupWindow: PopupWindow? = null
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.layout_catalog_filter, this)
|
||||
|
||||
mTypeTv = findViewById(R.id.type_tv)
|
||||
mCatalogTv = findViewById(R.id.catalog_tv)
|
||||
mSizeTv = findViewById(R.id.size_tv)
|
||||
mTypeContainer = findViewById(R.id.container_type)
|
||||
mCatalogContainer = findViewById(R.id.container_catalog)
|
||||
mSizeContainer = findViewById(R.id.container_size)
|
||||
|
||||
mTypeContainer.setOnClickListener {
|
||||
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
|
||||
}
|
||||
|
||||
mCatalogContainer.setOnClickListener {
|
||||
showSelectCatalogPopupWindow(this, mCatalogTv, mCatalogTv.text.toString())
|
||||
}
|
||||
|
||||
mSizeContainer.setOnClickListener {
|
||||
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun setTypeList(switch: CatalogEntity.CatalogSwitch) {
|
||||
switch.run {
|
||||
if ("on" == hotSort) mTypeFilterArray.add(SortType.RECOMMENDED)
|
||||
if ("on" == newSort) mTypeFilterArray.add(SortType.NEWEST)
|
||||
if ("on" == starSort) mTypeFilterArray.add(SortType.RATING)
|
||||
}
|
||||
if (mTypeFilterArray.isNotEmpty()) mTypeTv.text = mTypeFilterArray[0].value
|
||||
}
|
||||
|
||||
fun setCatalogList(subCatalogList: List<CatalogEntity.SubCatalogEntity>, initCatalogName: String) {
|
||||
mCatalogFilterArray = ArrayList(subCatalogList)
|
||||
mCatalogTv.text = initCatalogName
|
||||
}
|
||||
|
||||
fun setOnConfigSetupListener(onCatalogFilterSetupListener: OnCatalogFilterSetupListener) {
|
||||
mOnCatalogFilterSetupListener = onCatalogFilterSetupListener
|
||||
}
|
||||
|
||||
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
|
||||
if (highlightIt) {
|
||||
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
|
||||
targetTextView.setTextColor(Color.WHITE)
|
||||
} else {
|
||||
targetTextView.background = null
|
||||
targetTextView.setTextColor(R.color.text_757575.toColor(context))
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectTypePopupWindow(containerView: View, typeTv: TextView, typeText: String) {
|
||||
typeTv.setTextColor(R.color.text_theme.toColor(context))
|
||||
typeTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
|
||||
|
||||
val inflater = LayoutInflater.from(typeTv.context)
|
||||
val layout = inflater.inflate(R.layout.layout_filter_size, null)
|
||||
val popupWindow = PopupWindow(
|
||||
layout,
|
||||
LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.WRAP_CONTENT
|
||||
).apply { mTypePopupWindow = this }
|
||||
|
||||
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
|
||||
val backgroundView = layout.findViewById<View>(R.id.background)
|
||||
|
||||
backgroundView.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
for (type in mTypeFilterArray) {
|
||||
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
|
||||
|
||||
// 单列 3 个,强行设置宽度为屏幕的 1/3
|
||||
val width = typeTv.context.resources.displayMetrics.widthPixels / 3
|
||||
val height = item.layoutParams.height
|
||||
|
||||
item.layoutParams = ViewGroup.LayoutParams(width, height)
|
||||
flexboxLayout.addView(item)
|
||||
|
||||
val tv = item.findViewById<TextView>(R.id.size_tv)
|
||||
tv.text = type.value
|
||||
|
||||
toggleHighlightedTextView(tv, typeText == type.value)
|
||||
|
||||
tv.tag = type.value
|
||||
|
||||
item.setOnClickListener {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
popupWindow.dismiss()
|
||||
typeTv.text = type.value
|
||||
|
||||
mOnCatalogFilterSetupListener?.onSetupSortType(type)
|
||||
}
|
||||
}
|
||||
|
||||
popupWindow.setOnDismissListener {
|
||||
typeTv.setTextColor(R.color.text_757575.toColor(context))
|
||||
typeTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
|
||||
mTypePopupWindow = null
|
||||
}
|
||||
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.isFocusable = true
|
||||
popupWindow.animationStyle = 0
|
||||
popupWindow.showAsDropDown(containerView, 0, 0)
|
||||
}
|
||||
|
||||
private fun showSelectCatalogPopupWindow(containerView: View, catalogTv: TextView, catalogText: String) {
|
||||
catalogTv.setTextColor(R.color.text_theme.toColor(context))
|
||||
catalogTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
|
||||
|
||||
val inflater = LayoutInflater.from(catalogTv.context)
|
||||
val layout = inflater.inflate(R.layout.layout_filter_size, null)
|
||||
val popupWindow = PopupWindow(
|
||||
layout,
|
||||
LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.WRAP_CONTENT
|
||||
).apply { mCatalogPopupWindow = this }
|
||||
|
||||
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
|
||||
val backgroundView = layout.findViewById<View>(R.id.background)
|
||||
|
||||
backgroundView.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
for (entity in mCatalogFilterArray) {
|
||||
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
|
||||
|
||||
// 单列 3 个,强行设置宽度为屏幕的 1/3
|
||||
val width = catalogTv.context.resources.displayMetrics.widthPixels / 3
|
||||
val height = item.layoutParams.height
|
||||
|
||||
item.layoutParams = ViewGroup.LayoutParams(width, height)
|
||||
flexboxLayout.addView(item)
|
||||
|
||||
val tv = item.findViewById<TextView>(R.id.size_tv)
|
||||
val iv = item.findViewById<ImageView>(R.id.recommend_iv)
|
||||
tv.text = entity.name
|
||||
iv.visibleIf(entity.recommended)
|
||||
|
||||
toggleHighlightedTextView(tv, catalogText == entity.name)
|
||||
|
||||
tv.tag = entity.name
|
||||
|
||||
item.setOnClickListener {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
popupWindow.dismiss()
|
||||
catalogTv.text = entity.name
|
||||
|
||||
mOnCatalogFilterSetupListener?.onSetupSortCatalog(entity)
|
||||
}
|
||||
}
|
||||
|
||||
popupWindow.setOnDismissListener {
|
||||
catalogTv.setTextColor(R.color.text_757575.toColor(context))
|
||||
catalogTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
|
||||
mCatalogPopupWindow = null
|
||||
}
|
||||
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.isFocusable = true
|
||||
popupWindow.animationStyle = 0
|
||||
popupWindow.showAsDropDown(containerView, 0, 0)
|
||||
}
|
||||
|
||||
private fun showSelectSizePopupWindow(containerView: View, sizeTv: TextView, sizeText: String) {
|
||||
sizeTv.setTextColor(R.color.text_theme.toColor(context))
|
||||
sizeTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
|
||||
|
||||
val inflater = LayoutInflater.from(sizeTv.context)
|
||||
val layout = inflater.inflate(R.layout.layout_filter_size, null)
|
||||
val popupWindow = PopupWindow(
|
||||
layout,
|
||||
LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.WRAP_CONTENT
|
||||
).apply { mSizePopupWindow = this }
|
||||
|
||||
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
|
||||
val backgroundView = layout.findViewById<View>(R.id.background)
|
||||
|
||||
sizeFilterArray = if (sizeFilterArray == null) {
|
||||
getDefaultSizeFilterArray()
|
||||
} else {
|
||||
sizeFilterArray?.apply {
|
||||
if (firstOrNull()?.text != "全部大小") {
|
||||
add(0, SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backgroundView.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
for (size in sizeFilterArray!!) {
|
||||
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
|
||||
|
||||
// 单列 3 个,强行设置宽度为屏幕的 1/3
|
||||
val width = sizeTv.context.resources.displayMetrics.widthPixels / 3
|
||||
val height = item.layoutParams.height
|
||||
|
||||
item.layoutParams = ViewGroup.LayoutParams(width, height)
|
||||
flexboxLayout.addView(item)
|
||||
|
||||
val tv = item.findViewById<TextView>(R.id.size_tv)
|
||||
tv.text = size.text
|
||||
|
||||
toggleHighlightedTextView(tv, sizeText == size.text)
|
||||
|
||||
tv.tag = size.text
|
||||
|
||||
item.setOnClickListener {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
popupWindow.dismiss()
|
||||
sizeTv.text = size.text
|
||||
|
||||
mOnCatalogFilterSetupListener?.onSetupSortSize(size)
|
||||
}
|
||||
}
|
||||
|
||||
popupWindow.setOnDismissListener {
|
||||
sizeTv.setTextColor(R.color.text_757575.toColor(context))
|
||||
sizeTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
|
||||
mSizePopupWindow = null
|
||||
}
|
||||
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.isFocusable = true
|
||||
popupWindow.animationStyle = 0
|
||||
popupWindow.showAsDropDown(containerView, 0, 0)
|
||||
}
|
||||
|
||||
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
|
||||
return arrayListOf<SubjectSettingEntity.Size>().apply {
|
||||
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
|
||||
add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下"))
|
||||
add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M"))
|
||||
add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M"))
|
||||
add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G"))
|
||||
add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上"))
|
||||
}
|
||||
}
|
||||
|
||||
fun setRootBackgroundColor(@ColorInt color: Int) {
|
||||
findViewById<View>(R.id.config_controller).setBackgroundColor(color)
|
||||
}
|
||||
|
||||
fun setItemTextColor(@ColorInt color: Int) {
|
||||
mTypeTv.setTextColor(color)
|
||||
mCatalogTv.setTextColor(color)
|
||||
mSizeTv.setTextColor(color)
|
||||
}
|
||||
|
||||
fun updatePopupWindow() {
|
||||
when {
|
||||
mTypePopupWindow != null && mTypePopupWindow!!.isShowing -> {
|
||||
mTypePopupWindow?.dismiss()
|
||||
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
|
||||
}
|
||||
|
||||
mCatalogPopupWindow != null && mCatalogPopupWindow!!.isShowing -> {
|
||||
mCatalogPopupWindow?.dismiss()
|
||||
showSelectCatalogPopupWindow(this, mCatalogTv, mCatalogTv.text.toString())
|
||||
}
|
||||
|
||||
mSizePopupWindow != null && mSizePopupWindow!!.isShowing -> {
|
||||
mSizePopupWindow?.dismiss()
|
||||
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnCatalogFilterSetupListener {
|
||||
fun onSetupSortSize(sortSize: SubjectSettingEntity.Size)
|
||||
fun onSetupSortType(sortType: SortType)
|
||||
fun onSetupSortCatalog(sortCatalog: CatalogEntity.SubCatalogEntity)
|
||||
}
|
||||
|
||||
enum class SortType(val value: String) {
|
||||
RECOMMENDED("热门推荐"),
|
||||
NEWEST("最新上线"),
|
||||
RATING("最高评分")
|
||||
}
|
||||
}
|
||||
@ -6,25 +6,21 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.get
|
||||
import com.facebook.drawee.drawable.ScalingUtils
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.ImageViewerActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.debounceActionWithInterval
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.toResString
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.TopCutProcess
|
||||
import com.gh.gamecenter.databinding.ItemCommunityImageBinding
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.feature.entity.CommunityVideoEntity
|
||||
import com.gh.gamecenter.feature.entity.ImageInfo
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
|
||||
class ImageContainerView : LinearLayout {
|
||||
private var mAnswerEntity: AnswerEntity? = null
|
||||
|
||||
private var data: ImageContainerData? = null
|
||||
|
||||
//三图默认宽度
|
||||
private var mDefaultWidth = 0f
|
||||
@ -41,9 +37,6 @@ class ImageContainerView : LinearLayout {
|
||||
//长图比例
|
||||
private var mLongPictureRatio = 9 / 18f
|
||||
|
||||
private var mEntrance = ""
|
||||
private var mPath = ""
|
||||
|
||||
//图片之间的间距
|
||||
private val mItemSpace = 4f.dip2px()
|
||||
private var mOffset = 0
|
||||
@ -51,6 +44,8 @@ class ImageContainerView : LinearLayout {
|
||||
|
||||
private val imageViewList = arrayListOf<SimpleDraweeView>()
|
||||
|
||||
private var onImageContainerEventListener: OnImageContainerEventListener? = null
|
||||
|
||||
constructor(context: Context) : this(context, null)
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||
@ -75,40 +70,34 @@ class ImageContainerView : LinearLayout {
|
||||
calculateWidth()
|
||||
}
|
||||
|
||||
fun bindData(entity: AnswerEntity, entrance: String = "", path: String = "", imageClick: (() -> Unit)? = null) {
|
||||
fun bindData(
|
||||
data: ImageContainerData,
|
||||
listener: OnImageContainerEventListener? = null
|
||||
) {
|
||||
this.data = data
|
||||
onImageContainerEventListener = listener
|
||||
imageViewList.clear()
|
||||
if (entity.id != mAnswerEntity?.id) {
|
||||
removeAllViews()
|
||||
}
|
||||
mAnswerEntity = entity
|
||||
mEntrance = entrance
|
||||
mPath = path
|
||||
removeAllViews()
|
||||
index = 0
|
||||
if ((entity.user.id == UserManager.getInstance().userId && entity.videos.isNotEmpty()) ||
|
||||
(entity.user.id != UserManager.getInstance().userId && entity.getPassVideos().isNotEmpty()) ||
|
||||
entity.images.isNullOrEmpty()
|
||||
) {
|
||||
if (!data.show) {
|
||||
visibility = View.GONE
|
||||
return
|
||||
}
|
||||
visibility = View.VISIBLE
|
||||
if (mAnswerEntity?.type == "community_article") {
|
||||
if (data.isPostCard) {
|
||||
//若文章内容含有图片及视频,则信息流卡片,仅展示图片,且标题后带有‘有视频’标签
|
||||
//若文章内容仅含有图片,则信息流卡片,仅展示图片,无标签
|
||||
//若文章内容仅含有视频,则信息流卡片,仅展示视频,无标签
|
||||
when {
|
||||
entity.images.isNotEmpty() -> {
|
||||
val imagesInfo = entity.imagesInfo
|
||||
val images = entity.images.take(3)
|
||||
images.forEachIndexed { index, url ->
|
||||
val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0
|
||||
val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0
|
||||
bindImage(url, width, height, images.size == 1, imageClick)
|
||||
}
|
||||
data.images.isNotEmpty() -> {
|
||||
data.images.take(3)
|
||||
.forEach {
|
||||
bindImage(it.url, it.width, it.height, data.images.size == 1)
|
||||
}
|
||||
}
|
||||
|
||||
entity.getPassVideos().isNotEmpty() -> {
|
||||
val video = entity.getPassVideos()[0]
|
||||
data.video != null -> {
|
||||
val video = data.video
|
||||
bindVideo(video, video.width, video.height, true)
|
||||
}
|
||||
|
||||
@ -120,28 +109,22 @@ class ImageContainerView : LinearLayout {
|
||||
//若问答内容含有图片及视频,则信息流卡片,同时展示图片及视频,且参考以往排序逻辑(视频优先放置第一位),无标签
|
||||
//若问答内容仅含有图片,则信息流卡片,仅展示图片,无标签
|
||||
//若问答内容仅含有视频,则信息流卡片,仅展示视频,无标签
|
||||
if (entity.getPassVideos().isNotEmpty()) {
|
||||
val video = entity.getPassVideos()[0]
|
||||
bindVideo(video, video.width, video.height, mAnswerEntity?.images.isNullOrEmpty())
|
||||
entity.images.take(2).forEachIndexed { index, url ->
|
||||
val imagesInfo = entity.imagesInfo
|
||||
val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0
|
||||
val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0
|
||||
bindImage(url, width, height, false, imageClick)
|
||||
if (data.video != null) {
|
||||
val video = data.video
|
||||
bindVideo(video, video.width, video.height, data.images.isNullOrEmpty())
|
||||
data.images.take(2).forEach {
|
||||
bindImage(it.url, it.width, it.height, false)
|
||||
}
|
||||
} else {
|
||||
val images = entity.images.take(3)
|
||||
images.forEachIndexed { index, url ->
|
||||
val imagesInfo = entity.imagesInfo
|
||||
val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0
|
||||
val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0
|
||||
bindImage(url, width, height, images.size == 1, imageClick)
|
||||
}
|
||||
data.images.take(3)
|
||||
.forEach {
|
||||
bindImage(it.url, it.width, it.height, data.images.size == 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindVideo(video: CommunityVideoEntity, width: Int, height: Int, isChangeRatio: Boolean) {
|
||||
private fun bindVideo(video: ImageContainerData.VideoInfo, width: Int, height: Int, isChangeRatio: Boolean) {
|
||||
val oldView = if (childCount == 0 || index >= childCount) null else getChildAt(index)
|
||||
val binding = if (oldView != null) {
|
||||
ItemCommunityImageBinding.bind(oldView)
|
||||
@ -158,16 +141,7 @@ class ImageContainerView : LinearLayout {
|
||||
displayImage(binding, video.poster, width.toFloat(), height.toFloat(), isChangeRatio, true)
|
||||
binding.root.setOnClickListener {
|
||||
debounceActionWithInterval(it.id, 1000) {
|
||||
if (mAnswerEntity == null) return@debounceActionWithInterval
|
||||
val videoEntity = mAnswerEntity!!.getPassVideos().firstOrNull()
|
||||
DirectUtils.directToVideoDetail(
|
||||
context,
|
||||
videoEntity?.id ?: "",
|
||||
VideoDetailContainerViewModel.Location.VIDEO_HOT.value,
|
||||
showComment = false,
|
||||
entrance = mEntrance,
|
||||
path = mPath
|
||||
)
|
||||
onImageContainerEventListener?.onVideoCLick(video.id)
|
||||
}
|
||||
}
|
||||
index++
|
||||
@ -177,8 +151,7 @@ class ImageContainerView : LinearLayout {
|
||||
url: String,
|
||||
width: Int,
|
||||
height: Int,
|
||||
isChangeRatio: Boolean,
|
||||
imageClick: (() -> Unit)?
|
||||
isChangeRatio: Boolean
|
||||
) {
|
||||
val oldView = if (childCount == 0 || index >= childCount) null else getChildAt(index)
|
||||
val binding = if (oldView != null) {
|
||||
@ -195,25 +168,21 @@ class ImageContainerView : LinearLayout {
|
||||
binding.videoPlay.visibility = View.GONE
|
||||
displayImage(binding, url, width.toFloat(), height.toFloat(), isChangeRatio)
|
||||
binding.root.setOnClickListener {
|
||||
if (mAnswerEntity?.status == "pending" || mAnswerEntity?.status == "fail") return@setOnClickListener
|
||||
imageClick?.invoke()
|
||||
if (data?.status == "pending" || data?.status == "fail") return@setOnClickListener
|
||||
debounceActionWithInterval(it.id, 1000) {
|
||||
if (mAnswerEntity == null) return@debounceActionWithInterval
|
||||
val position = if (mAnswerEntity?.type == "community_article") {
|
||||
binding.root.tag as Int
|
||||
} else {
|
||||
if (mAnswerEntity!!.getPassVideos()
|
||||
.isNullOrEmpty()
|
||||
) binding.root.tag as Int else (binding.root.tag as Int) - 1
|
||||
data?.run {
|
||||
val position = if (isPostCard) {
|
||||
binding.root.tag as Int
|
||||
} else {
|
||||
if (video == null) binding.root.tag as Int else (binding.root.tag as Int) - 1
|
||||
}
|
||||
onImageContainerEventListener?.onImageClick(
|
||||
images.map(ImageContainerData.ImageInfo::url),
|
||||
position,
|
||||
imageViewList
|
||||
)
|
||||
}
|
||||
if (mAnswerEntity?.communityId.isNullOrEmpty()) {
|
||||
mAnswerEntity?.communityId = mAnswerEntity?.bbs?.id
|
||||
}
|
||||
val intent = ImageViewerActivity.getIntent(
|
||||
context, mAnswerEntity!!.images as ArrayList<String>, position, imageViewList,
|
||||
if (mAnswerEntity?.type == "community_article") mAnswerEntity else null, mEntrance, true
|
||||
)
|
||||
context.startActivity(intent)
|
||||
|
||||
}
|
||||
}
|
||||
index++
|
||||
@ -279,7 +248,7 @@ class ImageContainerView : LinearLayout {
|
||||
}
|
||||
|
||||
binding.pendingView.run {
|
||||
when (mAnswerEntity?.status) {
|
||||
when (data?.status) {
|
||||
"pending" -> {
|
||||
visibility = View.VISIBLE
|
||||
text = R.string.pending_status.toResString()
|
||||
@ -297,7 +266,7 @@ class ImageContainerView : LinearLayout {
|
||||
}
|
||||
|
||||
|
||||
val imageCount = mAnswerEntity?.images?.size ?: 0
|
||||
val imageCount = data?.images?.size ?: 0
|
||||
if (!isVideo && index == 2 && imageCount > 3) {
|
||||
binding.labelIcon.visibility = View.GONE
|
||||
binding.durationOrNumTv.visibility = View.VISIBLE
|
||||
@ -308,4 +277,80 @@ class ImageContainerView : LinearLayout {
|
||||
if (index != 0) params.leftMargin = mItemSpace
|
||||
binding.root.layoutParams = params
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val COMMUNITY_ARTICLE = "community_article"
|
||||
|
||||
fun AnswerEntity.toImageContainerData(): ImageContainerData {
|
||||
val imageInfoList = arrayListOf<ImageContainerData.ImageInfo>()
|
||||
images.forEachIndexed { index, url ->
|
||||
if (index < 3) {
|
||||
imageInfoList.add(ImageContainerData.ImageInfo(url))
|
||||
}
|
||||
}
|
||||
imageInfoList.forEachIndexed { index, imageInfo ->
|
||||
val item = imagesInfo.getOrNull(index)
|
||||
if (item != null) {
|
||||
imageInfo.width = item.width
|
||||
imageInfo.height = item.height
|
||||
}
|
||||
}
|
||||
val video =
|
||||
getPassVideos().firstOrNull()?.let {
|
||||
ImageContainerData.VideoInfo(
|
||||
it.id,
|
||||
it.duration,
|
||||
it.poster,
|
||||
it.width,
|
||||
it.height
|
||||
)
|
||||
}
|
||||
val show = !((user.id == UserManager.getInstance().userId && videos.isNotEmpty())
|
||||
|| (user.id != UserManager.getInstance().userId && getPassVideos().isNotEmpty())
|
||||
|| images.isNullOrEmpty())
|
||||
return ImageContainerData(
|
||||
status = status,
|
||||
isPostCard = type == COMMUNITY_ARTICLE,
|
||||
images = imageInfoList,
|
||||
video = video,
|
||||
show
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class ImageContainerData(
|
||||
val status: String,
|
||||
val isPostCard: Boolean, // 是否是帖子卡片
|
||||
val images: List<ImageInfo>,
|
||||
val video: VideoInfo? = null,
|
||||
val show: Boolean
|
||||
) {
|
||||
|
||||
data class ImageInfo(
|
||||
val url: String,
|
||||
var width: Int = 0,
|
||||
var height: Int = 0
|
||||
)
|
||||
|
||||
data class VideoInfo(
|
||||
val id: String,
|
||||
val duration: String,
|
||||
val poster: String,
|
||||
var width: Int = 0,
|
||||
var height: Int = 0,
|
||||
)
|
||||
}
|
||||
|
||||
interface OnImageContainerEventListener {
|
||||
|
||||
fun onImageClick(
|
||||
images: List<String>,
|
||||
position: Int,
|
||||
imageViewList: ArrayList<SimpleDraweeView>
|
||||
)
|
||||
|
||||
fun onVideoCLick(videoId: String)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.widget.FrameLayout
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
||||
class InterceptTouchContainView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.children
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.visibleIf
|
||||
|
||||
/**
|
||||
* 单游戏卡片标签样式专用
|
||||
* 根据宽度展示标签个数,最多展示三个标签
|
||||
*/
|
||||
class SingleCardTagContainerView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
) : LinearLayout(context, attrs) {
|
||||
|
||||
private val childViews = arrayListOf<TextView>()
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||
children.forEach {
|
||||
// 父容器不限制子View的宽度
|
||||
it.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
|
||||
super.onLayout(changed, l, t, r, b)
|
||||
// 如果有显示不完整的标签,直接隐藏
|
||||
children.forEach {
|
||||
it.visibleIf(it.right <= width)
|
||||
}
|
||||
}
|
||||
|
||||
fun setData(tags: List<String>) {
|
||||
removeAllViews()
|
||||
tags.forEachIndexed { index, tag ->
|
||||
if (index < 3) {
|
||||
// 缓存子View 避免频繁创建新View
|
||||
val tvTag = childViews.getOrNull(index) ?: TextView(context).also { childViews.add(it) }
|
||||
if (index == 0) {
|
||||
tvTag.text = tag
|
||||
} else {
|
||||
tvTag.text = "$DELIMITER$tag"
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
tvTag.setTextAppearance(R.style.TextCaption2)
|
||||
} else {
|
||||
tvTag.setTextAppearance(context, R.style.TextCaption2)
|
||||
}
|
||||
tvTag.setTextColor(R.color.text_tertiary.toColor(context))
|
||||
addView(tvTag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DELIMITER = "·"
|
||||
}
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.category.CategoryListActivity
|
||||
import com.gh.gamecenter.entity.CategoryEntity
|
||||
|
||||
class SubCategoryView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
|
||||
LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
var leftTv: TextView
|
||||
var centerTv: TextView
|
||||
var rightTv: TextView
|
||||
|
||||
var leftDivider: View
|
||||
var rightDivider: View
|
||||
|
||||
var primeCategory: CategoryEntity? = null
|
||||
var categoryTitle: String? = ""
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.layout_sub_category, this)
|
||||
|
||||
leftTv = findViewById(R.id.tv_left_sub_category)
|
||||
centerTv = findViewById(R.id.tv_center_sub_category)
|
||||
rightTv = findViewById(R.id.tv_right_sub_category)
|
||||
|
||||
leftDivider = findViewById(R.id.divider_left)
|
||||
rightDivider = findViewById(R.id.divider_right)
|
||||
}
|
||||
|
||||
fun setLeftCategory(category: CategoryEntity) {
|
||||
setCategory(leftTv, category)
|
||||
}
|
||||
|
||||
fun setCenterCategory(category: CategoryEntity) {
|
||||
setCategory(centerTv, category)
|
||||
leftDivider.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun setRightCategory(category: CategoryEntity) {
|
||||
setCategory(rightTv, category)
|
||||
rightDivider.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun setCategory(tv: TextView, category: CategoryEntity) {
|
||||
tv.text = category.name
|
||||
tv.setOnClickListener {
|
||||
tv.context.startActivity(
|
||||
CategoryListActivity.getIntent(
|
||||
tv.context,
|
||||
categoryTitle!!,
|
||||
primeCategory!!,
|
||||
category.name!!
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,8 +6,12 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.text.underline
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.activityresult.ActResultRequest
|
||||
@ -37,6 +41,14 @@ object XapkDialogHelper {
|
||||
|
||||
val previousShowedDialog = mUnzipFailureDialogRef?.get()
|
||||
|
||||
val useRebootStyle = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||
|
||||
val content = if (useRebootStyle) {
|
||||
"未授权允许未知来源安装、数据包格式、设备兼容性…等均可能导致解压失败。"
|
||||
} else {
|
||||
"未授权允许未知来源安装、数据包格式、设备兼容性…等均可能导致解压失败。\n如果开启权限后仍未能解决,请提交反馈帮助我们改进。"
|
||||
}
|
||||
|
||||
if (previousShowedDialog != null
|
||||
&& previousShowedDialog.isShowing
|
||||
&& context == previousShowedDialog.ownerActivity
|
||||
@ -48,9 +60,9 @@ object XapkDialogHelper {
|
||||
val dialog = DialogHelper.showGuideDialog(
|
||||
context = context,
|
||||
title = "",
|
||||
content = "未授权允许未知来源安装、数据包格式、设备兼容性…等均可能导致解压失败。\n如果开启权限后仍未能解决,请提交反馈帮助我们改进。",
|
||||
content = content,
|
||||
confirmText = "开启权限",
|
||||
cancelText = "提交反馈",
|
||||
cancelText = if (useRebootStyle) "重启助手" else "提交反馈",
|
||||
confirmClickCallback = {
|
||||
if (context is AppCompatActivity) {
|
||||
val intent = PermissionHelper.getToInstallPermissionSettingIntent(context)
|
||||
@ -83,11 +95,7 @@ object XapkDialogHelper {
|
||||
)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val pm = context.packageManager
|
||||
val restartIntent = pm.getLaunchIntentForPackage(context.packageName)
|
||||
val mainIntent = Intent.makeRestartActivityTask(restartIntent!!.component)
|
||||
context.startActivity(mainIntent)
|
||||
Runtime.getRuntime().exit(0)
|
||||
restart(context)
|
||||
} else {
|
||||
XapkInstaller.install(context, downloadEntity, true)
|
||||
}
|
||||
@ -100,27 +108,22 @@ object XapkDialogHelper {
|
||||
}
|
||||
},
|
||||
cancelClickCallback = {
|
||||
val hint = "游戏安装包解压失败,问题反馈:"
|
||||
HelpAndFeedbackBridge.startSuggestionActivity(
|
||||
context,
|
||||
SuggestType.GAME,
|
||||
null,
|
||||
hint,
|
||||
SimpleGameEntity(downloadEntity.gameId, downloadEntity.name, downloadEntity.icon)
|
||||
)
|
||||
NewFlatLogUtils.logXApkUnzipFailedDialogClick(
|
||||
"提交反馈",
|
||||
false,
|
||||
downloadEntity.gameId,
|
||||
downloadEntity.name
|
||||
)
|
||||
if (useRebootStyle) {
|
||||
// 记录应用重启前需要重解压的信息
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, context.javaClass.name)
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, downloadEntity.url)
|
||||
|
||||
SensorsBridge.trackGameDecompressionFailedDialogClick(
|
||||
buttonName = "提交反馈",
|
||||
downloadEntity.gameId,
|
||||
downloadEntity.name,
|
||||
downloadEntity.categoryChinese
|
||||
)
|
||||
SensorsBridge.trackGameDecompressionFailedDialogClick(
|
||||
buttonName = "重启助手",
|
||||
downloadEntity.gameId,
|
||||
downloadEntity.name,
|
||||
downloadEntity.categoryChinese
|
||||
)
|
||||
|
||||
restart(context)
|
||||
} else {
|
||||
doFeedback(context, downloadEntity)
|
||||
}
|
||||
},
|
||||
uiModificationCallback = { binding ->
|
||||
binding.headIv.setBackgroundResource(R.drawable.dialog_unzip_failure_head_background)
|
||||
@ -146,6 +149,30 @@ object XapkDialogHelper {
|
||||
)
|
||||
binding.dismiss()
|
||||
}
|
||||
if (useRebootStyle) {
|
||||
val spannableString = SpannableStringBuilder()
|
||||
.append("未能解决问题?点击 ")
|
||||
.underline { append("提交反馈") }
|
||||
.append(" ")
|
||||
binding.alternativeCancelTv.visibility = View.VISIBLE
|
||||
binding.alternativeCancelTv.text = spannableString
|
||||
binding.alternativeCancelTv.setTextColor(R.color.text_secondary.toColor(context))
|
||||
binding.alternativeCancelTv.setDrawableEnd(R.drawable.ic_right_arrow_xapk)
|
||||
binding.alternativeCancelTv.setOnClickListener {
|
||||
doFeedback(context, downloadEntity)
|
||||
}
|
||||
|
||||
binding.hintTv.text = "开启权限后请务必重启光环助手,再进行安装"
|
||||
binding.hintTv.setTextColor(R.color.text_theme.toColor(context))
|
||||
binding.hintTv.setTextAppearance(R.style.TextCaption1)
|
||||
binding.hintTv.visibility = View.VISIBLE
|
||||
binding.hintTv.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
topMargin = 8F.dip2px()
|
||||
}
|
||||
binding.confirmTv.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
topMargin = 16F.dip2px()
|
||||
}
|
||||
}
|
||||
},
|
||||
touchOutsideCallback = {
|
||||
SensorsBridge.trackGameDecompressionFailedDialogClick(
|
||||
@ -164,4 +191,37 @@ object XapkDialogHelper {
|
||||
mUnzipFailureDialogRef = WeakReference(dialog)
|
||||
}
|
||||
|
||||
private fun restart(context: Context) {
|
||||
val pm = context.packageManager
|
||||
val restartIntent = pm.getLaunchIntentForPackage(context.packageName)
|
||||
val mainIntent = Intent.makeRestartActivityTask(restartIntent!!.component)
|
||||
context.startActivity(mainIntent)
|
||||
Runtime.getRuntime().exit(0)
|
||||
}
|
||||
|
||||
private fun doFeedback(context: Context, downloadEntity: DownloadEntity) {
|
||||
val hint = "游戏安装包解压失败,问题反馈:"
|
||||
|
||||
HelpAndFeedbackBridge.startSuggestionActivity(
|
||||
context,
|
||||
SuggestType.GAME,
|
||||
null,
|
||||
hint,
|
||||
SimpleGameEntity(downloadEntity.gameId, downloadEntity.name, downloadEntity.icon?: "")
|
||||
)
|
||||
NewFlatLogUtils.logXApkUnzipFailedDialogClick(
|
||||
"提交反馈",
|
||||
false,
|
||||
downloadEntity.gameId,
|
||||
downloadEntity.name
|
||||
)
|
||||
|
||||
SensorsBridge.trackGameDecompressionFailedDialogClick(
|
||||
buttonName = "提交反馈",
|
||||
downloadEntity.gameId,
|
||||
downloadEntity.name,
|
||||
downloadEntity.categoryChinese
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,10 +6,7 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.Settings
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.dialog.ManagerAllFilesPermissionDialogFragment
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.DownloadNotificationHelper
|
||||
import com.gh.common.util.PackageInstaller
|
||||
@ -19,15 +16,17 @@ import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.utils.CurrentActivityHolder
|
||||
import com.gh.gamecenter.core.utils.SentryHelper
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper
|
||||
import com.gh.gamecenter.xapk.XApkUnZipper
|
||||
import com.gh.gamecenter.xapk.core.XApkFile
|
||||
import com.gh.gamecenter.xapk.core.XApkUnZipCallback
|
||||
import com.gh.gamecenter.xapk.core.XApkUnZipEntry
|
||||
import com.gh.gamecenter.xapk.core.XApkUnZipOutputFactory
|
||||
import com.gh.gamecenter.xapk.io.*
|
||||
import com.gh.gamecenter.xapk.io.NonSplitApksOutput
|
||||
import com.gh.gamecenter.xapk.io.OBBFileOutput
|
||||
import com.gh.gamecenter.xapk.io.SplitApksOutput
|
||||
import com.gh.gamecenter.xapk.io.XApkFileOutput
|
||||
import com.gh.gamecenter.xapk.pi.IPackageInstaller
|
||||
import com.gh.ndownload.NDataChanger
|
||||
import com.halo.assistant.HaloApp
|
||||
@ -48,8 +47,6 @@ import java.util.*
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
|
||||
private const val XAPK_PACKAGE_PATH_TAG = "xapk_package_path"
|
||||
|
||||
const val XAPK_EXTENSION_NAME = "xapk"
|
||||
|
||||
// 通过解压过程存放于 DownloadEntity meta
|
||||
@ -59,12 +56,21 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
const val XAPK_DATA_EXTENSION_NAME = "obb"
|
||||
const val PACKAGE_EXTENSION_NAME = "apk"
|
||||
|
||||
// 系统是否有 obb 访问漏洞
|
||||
val systemHasFlaw by lazy {
|
||||
val systemMatched = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
|
||||
val rootPath = Environment.getExternalStorageDirectory().path
|
||||
val fileListMatched = File(rootPath, "Android").list().contentEquals(File(rootPath, "\u200bAndroid").list())
|
||||
|
||||
systemMatched && fileListMatched
|
||||
}
|
||||
|
||||
private const val GUIDE_TYPE_MIUI_OPTIMIZATION = "miui_optimization"
|
||||
private const val MIUI_OPTIMIZATION_WARNING_DIALOG_ENTRANCE = "MIUI优化关闭提示弹窗"
|
||||
|
||||
private var mContext = HaloApp.getInstance().application.applicationContext
|
||||
|
||||
private val mXApkUnZipper = XApkUnZipper(this)
|
||||
private val mXApkUnZipper = XApkUnZipper(this, useFlawToUnzip = systemHasFlaw)
|
||||
.also {
|
||||
it.registerCallback(this)
|
||||
}
|
||||
@ -114,7 +120,7 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
return
|
||||
}
|
||||
|
||||
if (checkPermission(downloadEntity, showUnzipToast)) {
|
||||
PermissionHelper.checkManageAllFilesOrStoragePermissionBeforeAction(context) {
|
||||
DownloadManager.getInstance().getDownloadEntitySnapshot(downloadEntity.url, downloadEntity.gameId)
|
||||
?.let {
|
||||
unzipXapkFile(it)
|
||||
@ -129,23 +135,6 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPermission(downloadEntity: DownloadEntity, showUnzipToast: Boolean = false): Boolean {
|
||||
// 安卓11以上系统需要开启所有文件访问权限
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
|
||||
&& !Environment.isExternalStorageManager()) {
|
||||
CurrentActivityHolder.getCurrentActivity()?.let {
|
||||
ManagerAllFilesPermissionDialogFragment.show(it as AppCompatActivity) {
|
||||
unzipXapkFile(downloadEntity)
|
||||
if (showUnzipToast) {
|
||||
Utils.toast(mContext, "解压过程请勿退出光环助手!")
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun unzipXapkFile(downloadEntity: DownloadEntity) {
|
||||
mXApkUnZipper.unzip(
|
||||
XApkUnZipEntry(
|
||||
@ -362,7 +351,7 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
|
||||
mPendingSessionInfoMap[downloadEntity.path] = XapkPendingSessionInfo(downloadEntity.path, sessionId)
|
||||
AppExecutor.ioExecutor.execute {// 有可能卡顿造成anr
|
||||
PackageInstaller.installMultiple(applicationContext, downloadEntity.path, sessionId)
|
||||
PackageInstaller.installMultiple(applicationContext, downloadEntity.packageName, downloadEntity.path, sessionId)
|
||||
NDataChanger.notifyDataChanged(downloadEntity)
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,8 +10,8 @@ import com.gh.gamecenter.common.exposure.meta.MetaUtil
|
||||
import com.gh.gamecenter.common.exposure.meta.MetaUtil.getMeta
|
||||
import com.gh.gamecenter.common.loghub.LoghubUtils
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.SentryHelper
|
||||
import com.gh.ndownload.NDataChanger
|
||||
import com.gh.ndownload.NDownloadBridge
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadConfig
|
||||
import com.lightgame.download.DownloadEntity
|
||||
@ -124,6 +124,7 @@ object DownloadDataHelper {
|
||||
val payloadObject = JSONObject()
|
||||
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
|
||||
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
|
||||
payloadObject.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
|
||||
payloadObject.put("game_id", downloadEntity.gameId)
|
||||
payloadObject.put("gameName", downloadEntity.name)
|
||||
payloadObject.put("platform", downloadEntity.platform)
|
||||
@ -212,6 +213,7 @@ object DownloadDataHelper {
|
||||
|
||||
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
|
||||
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
|
||||
payloadObject.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
|
||||
payloadObject.put("game_id", downloadEntity.gameId)
|
||||
payloadObject.put("gameName", downloadEntity.name)
|
||||
payloadObject.put("platform", downloadEntity.platform)
|
||||
@ -251,6 +253,7 @@ object DownloadDataHelper {
|
||||
|
||||
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
|
||||
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
|
||||
payloadObject.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
|
||||
payloadObject.put("game_id", downloadEntity.gameId)
|
||||
payloadObject.put("gameName", downloadEntity.name)
|
||||
payloadObject.put("platform", downloadEntity.platform)
|
||||
@ -315,6 +318,7 @@ object DownloadDataHelper {
|
||||
|
||||
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
|
||||
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
|
||||
payloadObject.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
|
||||
payloadObject.put("game_id", downloadEntity.gameId)
|
||||
payloadObject.put("gameName", downloadEntity.name)
|
||||
payloadObject.put("platform", downloadEntity.platform)
|
||||
@ -357,6 +361,7 @@ object DownloadDataHelper {
|
||||
sheet = JSONObject()
|
||||
sheet.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
|
||||
sheet.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
|
||||
sheet.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
|
||||
sheet.put("game_id", downloadEntity.gameId)
|
||||
sheet.put("platform", downloadEntity.platform)
|
||||
sheet.put("package", downloadEntity.packageName)
|
||||
@ -376,6 +381,7 @@ object DownloadDataHelper {
|
||||
"path",
|
||||
downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown"
|
||||
) // 初始化记录的 path 为空
|
||||
sheet.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
|
||||
sheet.put("total_size", downloadEntity.size / 1024 / 1024) // 初始化记录的 total_size 有可能为0
|
||||
sheet.put("progress_size", downloadEntity.progress / 1024 - progressSize)
|
||||
sheet.put("current_progress_size", downloadEntity.progress / 1024)
|
||||
|
||||
@ -20,9 +20,9 @@ import com.gh.gamecenter.common.utils.ExtensionsKt;
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge;
|
||||
import com.gh.gamecenter.core.AppExecutor;
|
||||
import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.core.GHThreadFactory;
|
||||
import com.gh.gamecenter.feature.entity.TagStyleEntity;
|
||||
import com.gh.gamecenter.feature.entity.CustomPageTrackData;
|
||||
import com.gh.gamecenter.feature.entity.TagStyleEntity;
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
@ -34,20 +34,13 @@ import com.gh.common.util.LunchType;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager;
|
||||
import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
|
||||
import com.gh.gamecenter.common.utils.DeviceUtils;
|
||||
import com.gh.gamecenter.common.utils.ExtensionsKt;
|
||||
import com.gh.gamecenter.common.utils.FileUtils;
|
||||
import com.gh.gamecenter.common.utils.NetworkUtils;
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge;
|
||||
import com.gh.gamecenter.core.AppExecutor;
|
||||
import com.gh.gamecenter.core.utils.AppDebugConfig;
|
||||
import com.gh.gamecenter.core.utils.GsonUtils;
|
||||
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
|
||||
import com.gh.gamecenter.core.utils.SPUtils;
|
||||
import com.gh.gamecenter.core.utils.SentryHelper;
|
||||
import com.gh.gamecenter.download.DownloadedGameIdAndPackageNameDao;
|
||||
import com.gh.gamecenter.entity.GameUpdateEntity;
|
||||
import com.gh.gamecenter.entity.HomePluggableFilterEntity;
|
||||
@ -55,7 +48,7 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus;
|
||||
import com.gh.gamecenter.feature.entity.ApkEntity;
|
||||
import com.gh.gamecenter.feature.entity.GameEntity;
|
||||
import com.gh.gamecenter.feature.entity.PluginLocation;
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent;
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper;
|
||||
import com.gh.gamecenter.login.user.UserManager;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.gh.gamecenter.packagehelper.PackageRepository;
|
||||
@ -64,7 +57,6 @@ import com.gh.ndownload.NDownloadBridge;
|
||||
import com.gh.ndownload.NDownloadService;
|
||||
import com.gh.vspace.VHelper;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.download.ConnectionUtils;
|
||||
import com.lightgame.download.DataWatcher;
|
||||
import com.lightgame.download.DownloadConfig;
|
||||
import com.lightgame.download.DownloadDao;
|
||||
@ -85,6 +77,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class DownloadManager implements DownloadStatusListener {
|
||||
@ -111,6 +105,9 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
|
||||
private final Set<String> mUpdateMarks;
|
||||
|
||||
private final ExecutorService packageExecutor
|
||||
= Executors.newSingleThreadExecutor(new GHThreadFactory("GH_DOWNLOAD_MANAGER_THREAD"));
|
||||
|
||||
@Override
|
||||
public void onTaskCancelled(DownloadEntity entity) {
|
||||
EBDownloadStatus status = new EBDownloadStatus("delete", entity.getName(),
|
||||
@ -179,9 +176,6 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
|
||||
mUpdateMarks = SPUtils.getStringSet(UPDATE_IS_READ_MARK);
|
||||
|
||||
// 只有下载模块需要这坨东西,因此移动到这里初始化
|
||||
ConnectionUtils.initHttpsUrlConnection(mContext);
|
||||
|
||||
updateDownloadMetaMap();
|
||||
|
||||
lastTimeMap = new ArrayMap<>();
|
||||
@ -304,7 +298,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
// 下载模拟器游戏配置文件,地址是 "模拟器游戏类型根目录/cheat/"
|
||||
if (!TextUtils.isEmpty(gameEntity.getSimulatorGameConfig())) {
|
||||
String configFilePath = SimulatorGameManager.getPathByType(gameEntity.getSimulatorType()) + "/cheat/" + apkEntity.getPackageName() + ".ini";
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
getInstance().packageExecutor.execute(() -> {
|
||||
FileUtils.downloadFile(gameEntity.getSimulatorGameConfig(), configFilePath);
|
||||
});
|
||||
}
|
||||
@ -362,9 +356,10 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE, Constants.VGAME);
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, DownloadConfig.KEY_PROGRESS_CALLBACK_INTERVAL, "200");
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, VHelper.KEY_REQUIRED_G_APPS, gameEntity.getGAppsSwitch());
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, VHelper.KEY_BIT, apkEntity.getBit());
|
||||
}
|
||||
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.KEY_BIT, apkEntity.getBit());
|
||||
|
||||
// 记录是否为双下载按钮模式
|
||||
if (isDualDownloadTypeEnabled) {
|
||||
if (asVGame) {
|
||||
@ -547,6 +542,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
checkDownloadEntryRecordValidate(url);
|
||||
if (isDownloadCompleted(url)) {
|
||||
downloadEntity.setStatus(DownloadStatus.done);
|
||||
mDownloadDao.newOrUpdate(downloadEntity);
|
||||
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
|
||||
} else if (!isTaskDownloading(url)) {
|
||||
DownloadEntity daoEntity = mDownloadDao.get(downloadEntity.getUrl());
|
||||
@ -661,7 +657,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
* @return 下载任务快照列表
|
||||
*/
|
||||
@NonNull
|
||||
private ArrayList<DownloadEntity> getAllDownloadEntitySnapshots() {
|
||||
public ArrayList<DownloadEntity> getAllDownloadEntitySnapshots() {
|
||||
return mDownloadDao.getAllSnapshots();
|
||||
}
|
||||
|
||||
@ -917,7 +913,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
DownloadEntity entry = mDownloadDao.getSnapshot(url);
|
||||
DownloadDataSimpleHelper.INSTANCE.removeDownloadSimpleEntity(url);
|
||||
if (entry != null) {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
getInstance().packageExecutor.execute(() -> {
|
||||
NDownloadBridge.INSTANCE.cancel(url);
|
||||
|
||||
mDownloadDao.delete(url);
|
||||
@ -959,7 +955,6 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
|
||||
// 改任务队列的状态
|
||||
NDataChanger.INSTANCE.getDownloadingTaskUrlSet().remove(entry.getUrl());
|
||||
NDataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl());
|
||||
if (!cancelSilently) {
|
||||
NDataChanger.INSTANCE.notifyDataChanged(entry);
|
||||
onTaskCancelled(entry);
|
||||
@ -972,9 +967,9 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
* 暂停所有正在下载的任务
|
||||
*/
|
||||
public void pauseAll() {
|
||||
synchronized (NDataChanger.INSTANCE.getDownloadEntries()) {
|
||||
for (DownloadEntity entity : NDataChanger.INSTANCE.getDownloadEntries().values()) {
|
||||
pause(entity.getUrl());
|
||||
synchronized (NDataChanger.INSTANCE.getDownloadingTaskUrlSet()) {
|
||||
for (String url : NDataChanger.INSTANCE.getDownloadingTaskUrlSet()) {
|
||||
pause(url);
|
||||
}
|
||||
}
|
||||
Utils.log(DownloadManager.class.getSimpleName(), "pause all");
|
||||
@ -985,7 +980,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
*/
|
||||
public void pause(String url) {
|
||||
checkDownloadEntryRecordValidate(url);
|
||||
DownloadEntity entry = NDataChanger.INSTANCE.getDownloadEntries().get(url);
|
||||
DownloadEntity entry = getDownloadEntitySnapshot(url);
|
||||
if (entry != null) {
|
||||
startDownloadService(entry, DownloadStatus.pause);
|
||||
put(url, System.currentTimeMillis());
|
||||
@ -1001,19 +996,21 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
* 3.检查是否显示下载通知栏
|
||||
*/
|
||||
public void initDownloadService() {
|
||||
final Set<String> urlSet = NDataChanger.INSTANCE.getDownloadingTaskUrlSet();
|
||||
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
|
||||
if (!urlSet.contains(downloadEntity.getUrl())
|
||||
&& (downloadEntity.getStatus().equals(DownloadStatus.downloading)
|
||||
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
|
||||
downloadEntity.setStatus(DownloadStatus.subscribe);
|
||||
mDownloadDao.newOrUpdate(downloadEntity);
|
||||
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
|
||||
packageExecutor.execute(() -> {
|
||||
final Set<String> urlSet = NDataChanger.INSTANCE.getDownloadingTaskUrlSet();
|
||||
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
|
||||
if (!urlSet.contains(downloadEntity.getUrl())
|
||||
&& (downloadEntity.getStatus().equals(DownloadStatus.downloading)
|
||||
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
|
||||
downloadEntity.setStatus(DownloadStatus.subscribe);
|
||||
mDownloadDao.newOrUpdate(downloadEntity);
|
||||
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startDownloadService();
|
||||
checkAndRetryDownload();
|
||||
startDownloadService();
|
||||
checkAndRetryDownload(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1104,13 +1101,15 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
/**
|
||||
* 检查并尝试重试下载
|
||||
*/
|
||||
public void checkAndRetryDownload() {
|
||||
public void checkAndRetryDownload(boolean includePausedTask) {
|
||||
if (!NetworkUtils.isWifiConnected(mContext)) return;
|
||||
|
||||
for (DownloadEntity downloadEntity : DownloadManager.getInstance().getAllDownloadEntityExcludeDoneTask()) {
|
||||
if (DownloadStatus.neterror.equals(downloadEntity.getStatus())
|
||||
|| DownloadStatus.timeout.equals(downloadEntity.getStatus())
|
||||
|| DownloadStatus.subscribe.equals(downloadEntity.getStatus())) {
|
||||
|| DownloadStatus.subscribe.equals(downloadEntity.getStatus())
|
||||
|| (includePausedTask && DownloadStatus.pause.equals(downloadEntity.getStatus()))
|
||||
) {
|
||||
DownloadManager.getInstance().put(downloadEntity.getUrl(), System.currentTimeMillis());
|
||||
Message msg = Message.obtain();
|
||||
msg.what = DownloadConfig.CONTINUE_DOWNLOAD_AUTO_TASK;
|
||||
@ -1215,7 +1214,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
* 标记下载已完成的任务为已读 (用于下载管理页入口的 toolbar 红点显示)
|
||||
*/
|
||||
public void markDownloadedTaskAsRead() {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
getInstance().packageExecutor.execute(() -> {
|
||||
boolean markHasChanged = false;
|
||||
|
||||
List<DownloadEntity> all = getAllDownloadEntityExcludeSilentTask();
|
||||
@ -1255,7 +1254,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
* 更改下载中任务的已读状态(用于下载页及外部toolbar)
|
||||
*/
|
||||
private void markDownloadingTaskAsReadOrUnread(boolean isRead) {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
getInstance().packageExecutor.execute(() -> {
|
||||
boolean markHasChanged = false;
|
||||
|
||||
List<DownloadEntity> all = getAllDownloadEntityExcludeSilentTask();
|
||||
@ -1286,7 +1285,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
* 标记可用更新为已读 (用于下载管理页入口的 toolbar 红点显示)
|
||||
*/
|
||||
public void markUpdatableTaskAsRead() {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
getInstance().packageExecutor.execute(() -> {
|
||||
boolean markHasChanged = false;
|
||||
|
||||
ArrayList<GameUpdateEntity> updates = PackageRepository.INSTANCE.getGameUpdate();
|
||||
@ -1385,7 +1384,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
* 手动触发下载 LiveData 变更
|
||||
*/
|
||||
public void notifyDownloadLiveDataChanged() {
|
||||
AppExecutor.getIoExecutor().execute(() -> mDownloadEntityListLiveData.postValue(getAllDownloadEntity()));
|
||||
getInstance().packageExecutor.execute(() -> mDownloadEntityListLiveData.postValue(getAllDownloadEntity()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -14,12 +14,13 @@ import com.gh.gamecenter.common.retrofit.EmptyResponse
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.utils.NewFlatLogUtils
|
||||
import com.gh.gamecenter.core.runOnIoThread
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.core.utils.ThirdPartyPackageHelper
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.gamecenter.entity.GameDigestEntity
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.utils.ConcernUtils
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
@ -55,7 +56,7 @@ object PackageObserver {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun onPackageChanged(busFour: EBPackage) {
|
||||
fun onPackageChanged(busFour: EBPackage, cachedGameEntity: GameEntity? = null) {
|
||||
val application = HaloApp.getInstance().application
|
||||
val packageName = busFour.packageName
|
||||
val versionName = busFour.versionName
|
||||
@ -99,7 +100,7 @@ object PackageObserver {
|
||||
if (EBPackage.TYPE_INSTALLED == busFour.type) {
|
||||
if (!busFour.isVGame) {
|
||||
// 非畅玩游戏才执行下面的代码
|
||||
mPackageViewModel.addInstalledGame(packageName)
|
||||
mPackageViewModel.addInstalledGame(packageName, cachedGameEntity)
|
||||
BrowserInstallHelper.onApkInstalled(mDownloadEntity?.path)
|
||||
}
|
||||
|
||||
@ -153,7 +154,7 @@ object PackageObserver {
|
||||
}
|
||||
}
|
||||
|
||||
runOnIoThread { postNewlyInstalledApp(gameId, packageName) }
|
||||
AppExecutor.logExecutor.execute { postNewlyInstalledApp(gameId, packageName) }
|
||||
}
|
||||
|
||||
if (EBPackage.TYPE_UNINSTALLED == busFour.type) {
|
||||
|
||||
@ -24,6 +24,7 @@ import com.gh.gamecenter.common.base.fragment.BaseDraggableDialogFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.observeNonNull
|
||||
import com.gh.gamecenter.common.utils.safelyGetInRelease
|
||||
import com.gh.gamecenter.common.utils.throwExceptionInDebug
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.utils.TimeElapsedHelper
|
||||
@ -181,7 +182,7 @@ class DownloadDialog : BaseDraggableDialogFragment() {
|
||||
AppExecutor.uiExecutor.executeWithDelay({
|
||||
recyclerView.adapter?.let {
|
||||
for (i in 0 until it.itemCount) {
|
||||
val apkEntity = itemList[i].normal ?: continue
|
||||
val apkEntity = itemList.safelyGetInRelease(i)?.normal ?: continue
|
||||
val apkCollection = apkEntity.apkCollection
|
||||
val platformName = platformList[0].name
|
||||
val packageName = platformList[0].packageName
|
||||
|
||||
@ -4,10 +4,12 @@ import android.content.Context
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.callback.OnViewClickListener
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.*
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
@ -100,7 +102,16 @@ class DownloadDialogAdapter(
|
||||
DirectUtils.directToQa(mContext, data.linkText, data.linkId)
|
||||
}
|
||||
"qa_collection" -> {
|
||||
DirectUtils.directToHelpAndFeedback(mContext, isPlugin = true)
|
||||
DirectUtils.directToQaCollection(mContext, data.linkText, data.linkId)
|
||||
}
|
||||
"qa_list" -> {
|
||||
DirectUtils.directToHelpAndFeedback(
|
||||
mContext, bundleOf(
|
||||
EntranceConsts.KEY_ENTRANCE to "选择下载加速版本-常见问题",
|
||||
EntranceConsts.KEY_GAME_ID to viewModel.gameEntity.id,
|
||||
EntranceConsts.KEY_GAME_NAME to viewModel.gameEntity.name
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
//Utils.toast(mContext, "暂不支持类型:" + data.linkType)
|
||||
|
||||
@ -61,7 +61,7 @@ object BrowserInstallHelper {
|
||||
}
|
||||
|
||||
else -> {
|
||||
val allInstalledPackageList = PackageUtils.getAllPackageNameIncludeSystemApps(mContext)
|
||||
val allInstalledPackageList = PackageUtils.getAllPackageName(mContext)
|
||||
|
||||
if (allInstalledPackageList.isNotEmpty()) {
|
||||
mValidInstalledPackageList = allInstalledPackageList
|
||||
|
||||
@ -10,6 +10,9 @@ import com.gh.gamecenter.common.utils.updateStatusBarColor
|
||||
import com.gh.gamecenter.entity.SubjectRecommendEntity
|
||||
import com.gh.gamecenter.game.GameFragment
|
||||
|
||||
/**
|
||||
* 板块
|
||||
*/
|
||||
class BlockActivity : DownloadToolbarActivity() {
|
||||
|
||||
companion object {
|
||||
|
||||
@ -14,6 +14,7 @@ import com.halo.assistant.fragment.ApkCleanerFragment;
|
||||
|
||||
/**
|
||||
* Created by khy on 2017/1/24.
|
||||
* 清理安装包
|
||||
*/
|
||||
@Route(path = RouteConsts.activity.cleanApkActivity)
|
||||
public class CleanApkActivity extends ToolBarActivity {
|
||||
|
||||
@ -16,6 +16,7 @@ import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created by khy on 18/07/17.
|
||||
* 我的收藏
|
||||
*/
|
||||
public class CollectionActivity extends ToolBarActivity {
|
||||
@Override
|
||||
|
||||
@ -23,6 +23,9 @@ import java.lang.ref.SoftReference;
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* 裁剪图片
|
||||
*/
|
||||
public class CropImageActivity extends ToolBarActivity {
|
||||
|
||||
protected CropImageCustom mCropImageCustom;
|
||||
|
||||
@ -24,7 +24,7 @@ import com.halo.assistant.HaloApp
|
||||
|
||||
/**
|
||||
* Created by khy on 2017/3/24.
|
||||
* 游戏详情适配器
|
||||
* 游戏详情页
|
||||
*/
|
||||
class GameDetailActivity : DownloadToolbarActivity() {
|
||||
|
||||
|
||||
@ -44,6 +44,7 @@ import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.entity.SensorsEvent
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.utils.ImageUtils.getIdealImageUrl
|
||||
@ -103,6 +104,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
private var mInitialPosition = 0
|
||||
private var mUseEnterAndExitAnimation = false
|
||||
private var mShowSaveBtn = false
|
||||
private var mSaveBtnText = ""
|
||||
private var mAnswerEntity: AnswerEntity? = null
|
||||
private var mIsFromImageContainerView = false
|
||||
|
||||
@ -126,6 +128,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
private var mTranslationY = 0f
|
||||
private var mTargetCenterX = 0f
|
||||
private var mTargetCenterY = 0f
|
||||
private var mSaveSensorsEvent: SensorsEvent? = null
|
||||
|
||||
override fun getLayoutId() = R.layout.activity_viewimage
|
||||
|
||||
@ -157,6 +160,8 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
mInitialPosition = it.getInt(EntranceConsts.KEY_CURRENT, 0)
|
||||
}
|
||||
mShowSaveBtn = it.getBoolean(KEY_SHOW_SAVE)
|
||||
mSaveBtnText = it.getString(KEY_SAVE_TEXT, "")
|
||||
mSaveSensorsEvent = it.getParcelable(KEY_SAVE_SENSORS_EVENT)
|
||||
mUseEnterAndExitAnimation = it.getBoolean(KEY_USE_ENTER_AND_EXIT_ANIMATION)
|
||||
mAnswerEntity = it.getParcelable(AnswerEntity::class.java.name)
|
||||
mOriginLeftList = it.getIntegerArrayList(KEY_LEFT)
|
||||
@ -172,6 +177,9 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
}
|
||||
|
||||
mSavePicBtn.visibleIf(mShowSaveBtn)
|
||||
if (mSaveBtnText.isNotEmpty()) {
|
||||
mBinding.btnSavePic.text = mSaveBtnText
|
||||
}
|
||||
mArticleDetailBtn.visibleIf(mAnswerEntity != null)
|
||||
mIndicatorMask.goneIf(mUrlList?.size == 1)
|
||||
mIndicatorTv.text = String.format("%d/%d", mInitialPosition + 1, mUrlList!!.size)
|
||||
@ -217,6 +225,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
}
|
||||
|
||||
mSavePicBtn.setOnClickListener {
|
||||
mSaveSensorsEvent?.let { SensorsBridge.trackEvent(it) }
|
||||
checkStoragePermissionBeforeAction {
|
||||
mBigImageView?.currentImageFile?.run {
|
||||
ImageUtils.saveImageToFile(this, mFinalUrl)
|
||||
@ -789,7 +798,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
} else {
|
||||
rawUrl
|
||||
}
|
||||
var compressedStandardImageUrl: String? = if (!mShowBase64Image && rawUrl.contains("ghzs")) {
|
||||
var compressedStandardImageUrl: String? = if (!mShowBase64Image && rawUrl.contains("ghzs") && !rawUrl.contains("x-oss-process")) {
|
||||
// 用 oss.jpeg 加上 limit 以后会出现双指放大的情况
|
||||
rawUrl + Config.getSettings()?.image?.oss?.gif
|
||||
} else {
|
||||
@ -838,6 +847,8 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
mFinalUrl = finalUrl ?: ""
|
||||
|
||||
imageView.setImageLoaderCallback(object : SimpleImageLoader() {
|
||||
var tryCount = 0
|
||||
|
||||
override fun onSuccess(image: File) {
|
||||
if (finalUrl != mUrlList!![position]) {
|
||||
val options = BitmapFactory.Options()
|
||||
@ -858,6 +869,15 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFail(error: java.lang.Exception?) {
|
||||
super.onFail(error)
|
||||
// 加载压缩图片失败时尝试加载原图
|
||||
if (finalUrl != rawUrl && tryCount == 0) {
|
||||
loadImage(thumbnailImageUrl, rawUrl, imageView)
|
||||
tryCount ++
|
||||
}
|
||||
}
|
||||
})
|
||||
loadImage(thumbnailImageUrl, compressedStandardImageUrl, imageView)
|
||||
|
||||
@ -935,8 +955,10 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
|
||||
private const val KEY_BASE64 = "base64"
|
||||
private const val KEY_SHOW_SAVE = "showSave"
|
||||
private const val KEY_SAVE_TEXT = "saveText"
|
||||
private const val KEY_USE_ENTER_AND_EXIT_ANIMATION = "use_enter_and_exit_animation"
|
||||
private const val KEY_IS_FROM_IMAGE_CONTAINER_VIEW = "is_from_image_container_view"
|
||||
private const val KEY_SAVE_SENSORS_EVENT = "save_sensors_event"
|
||||
|
||||
private const val KEY_LEFT = "left"
|
||||
private const val KEY_TOP = "top"
|
||||
@ -958,6 +980,27 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
return getIntent(context, list, position, null, entrance, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getSingleIntent(
|
||||
context: Context,
|
||||
url: String,
|
||||
isShowSaveBtn: Boolean,
|
||||
saveBtnText: String? = null,
|
||||
entrance: String? = null,
|
||||
saveSensorsEvent: SensorsEvent? = null
|
||||
): Intent {
|
||||
return getIntent(
|
||||
context,
|
||||
arrayListOf(url),
|
||||
0,
|
||||
null,
|
||||
entrance,
|
||||
isShowSaveBtn,
|
||||
saveBtnText = saveBtnText,
|
||||
saveSensorsEvent = saveSensorsEvent
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getIntent(
|
||||
context: Context,
|
||||
@ -994,7 +1037,9 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
entrance: String?,
|
||||
isShowSaveBtn: Boolean,
|
||||
answerEntity: AnswerEntity? = null,
|
||||
isFromICV: Boolean = false
|
||||
isFromICV: Boolean = false,
|
||||
saveBtnText: String? = null,
|
||||
saveSensorsEvent: SensorsEvent? = null
|
||||
): Intent {
|
||||
val intent = Intent(context, ImageViewerActivity::class.java)
|
||||
intent.putExtra(EntranceConsts.KEY_URL_LIST, list)
|
||||
@ -1003,6 +1048,8 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
intent.putExtra(AnswerEntity::class.java.name, answerEntity)
|
||||
intent.putExtra(EntranceConsts.KEY_ENTRANCE, entrance)
|
||||
intent.putExtra(KEY_IS_FROM_IMAGE_CONTAINER_VIEW, isFromICV)
|
||||
saveBtnText?.let { intent.putExtra(KEY_SAVE_TEXT, it) }
|
||||
saveSensorsEvent?.let { intent.putExtra(KEY_SAVE_SENSORS_EVENT, saveSensorsEvent) }
|
||||
|
||||
if (originalViewList != null) {
|
||||
val leftList = arrayListOf<Int>()
|
||||
|
||||
@ -16,6 +16,7 @@ import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/12/12.
|
||||
* 礼包中心
|
||||
*/
|
||||
@Deprecated
|
||||
public class LibaoActivity extends ToolBarActivity {
|
||||
|
||||
@ -43,6 +43,7 @@ import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import com.gh.ad.AdDelegateHelper;
|
||||
import com.gh.ad.SplashAdVideoView;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.filter.RegionSettingHelper;
|
||||
import com.gh.common.history.HistoryDatabase;
|
||||
@ -89,16 +90,16 @@ import com.gh.gamecenter.core.utils.DisplayUtils;
|
||||
import com.gh.gamecenter.core.utils.GsonUtils;
|
||||
import com.gh.gamecenter.core.utils.MtaHelper;
|
||||
import com.gh.gamecenter.core.utils.SPUtils;
|
||||
import com.gh.gamecenter.core.utils.SentryHelper;
|
||||
import com.gh.gamecenter.core.utils.ToastUtils;
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils;
|
||||
import com.gh.gamecenter.entity.StartupAdEntity;
|
||||
import com.gh.gamecenter.feature.entity.GameEntity;
|
||||
import com.gh.gamecenter.feature.utils.PlatformUtils;
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper;
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageShareRepository;
|
||||
import com.gh.gamecenter.home.skip.PackageSkipActivity;
|
||||
import com.gh.gamecenter.login.user.UserManager;
|
||||
import com.gh.gamecenter.manager.DataCollectionManager;
|
||||
import com.gh.gamecenter.login.utils.QuickLoginHelper;
|
||||
import com.gh.gamecenter.packagehelper.PackageViewModel;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.gh.gamecenter.room.AppDatabase;
|
||||
@ -129,13 +130,15 @@ import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.SingleSource;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.functions.Function;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.HttpException;
|
||||
@ -145,7 +148,7 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
public static final String SHOW_AD = "show_ad";
|
||||
public static final int COUNTDOWN_AD = 100;
|
||||
public static final int COUNTDOWN_MAX_COUNT = 3;
|
||||
private int mCountdownMaxCount = 3;
|
||||
private int mCountdownCount = 0;
|
||||
|
||||
private static final String CURRENT_PAGE = "current_page";
|
||||
@ -252,9 +255,6 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
// 必须放在这里,否则会导致获取 baseActivity 不是本应用包名
|
||||
DownloadManager.getInstance().initDownloadService();
|
||||
|
||||
ReservationRepository.refreshReservations();
|
||||
|
||||
// 跳转至其它页面
|
||||
@ -281,13 +281,12 @@ public class MainActivity extends BaseActivity {
|
||||
Config.getGhzsSettings();
|
||||
} else if (Config.getVSettingEntity() == null) {
|
||||
Config.refreshVSettingEntity();
|
||||
} else if (Config.getVNewSettingEntity() == null) {
|
||||
Config.getNewSetting();
|
||||
}
|
||||
|
||||
// 耗时操作
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
// 上传数据
|
||||
DataCollectionManager.getInstance().upload();
|
||||
|
||||
// 初始化PlatformUtils
|
||||
PlatformUtils.getInstance(getApplicationContext());
|
||||
|
||||
@ -318,7 +317,7 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
mMainWrapperViewModel.requestAllDialogData();
|
||||
|
||||
// QuickLoginHelper.getPhoneInfo();
|
||||
QuickLoginHelper.preLogin(this);
|
||||
|
||||
// TODO 搞清楚为什么这里要获取微信相关配置
|
||||
WechatBindHelper.getWechatConfig(null);
|
||||
@ -506,6 +505,11 @@ public class MainActivity extends BaseActivity {
|
||||
float screenHeightInDp = DisplayUtils.px2dip(this, screenHeightInPx);
|
||||
|
||||
if (startAdContainer != null && sdkStartAdContainer != null && adsFl != null) {
|
||||
mCountdownMaxCount = AdDelegateHelper.INSTANCE.getSplashAdDisplayInterval();
|
||||
TextView jumpBtn = findViewById(R.id.jumpBtn);
|
||||
if (jumpBtn != null) {
|
||||
jumpBtn.setText(getString(R.string.splash_jump, mCountdownMaxCount));
|
||||
}
|
||||
AdDelegateHelper.requestSplashAd(
|
||||
this,
|
||||
screenWidthInPx,
|
||||
@ -535,7 +539,7 @@ public class MainActivity extends BaseActivity {
|
||||
super.handleMessage(msg);
|
||||
if (msg.what == COUNTDOWN_AD) {
|
||||
mCountdownCount++;
|
||||
if (COUNTDOWN_MAX_COUNT < mCountdownCount) {
|
||||
if (mCountdownMaxCount < mCountdownCount) {
|
||||
AdDelegateHelper.INSTANCE.setShowingSplashAd(false);
|
||||
hideSplashAd();
|
||||
|
||||
@ -555,8 +559,11 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
} else {
|
||||
TextView jumpBtn = findViewById(R.id.jumpBtn);
|
||||
jumpBtn.setText(String.format(Locale.CHINA, "跳过 %d", COUNTDOWN_MAX_COUNT - mCountdownCount));
|
||||
mBaseHandler.sendEmptyMessageDelayed(COUNTDOWN_AD, 1000);
|
||||
jumpBtn.setText(getString(R.string.splash_jump, mCountdownMaxCount - mCountdownCount));
|
||||
Message newMsg = Message.obtain();
|
||||
newMsg.what = COUNTDOWN_AD;
|
||||
newMsg.obj = msg.obj;
|
||||
mBaseHandler.sendMessageDelayed(newMsg, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -580,6 +587,11 @@ public class MainActivity extends BaseActivity {
|
||||
getIntent().putExtra(SHOW_AD, false);
|
||||
View startAdContainer = findViewById(R.id.startAdContainer);
|
||||
if (startAdContainer != null) {
|
||||
// 如果有播放开屏视频广告,需要及时释放
|
||||
SplashAdVideoView adVideoView = startAdContainer.findViewById(R.id.ad_video);
|
||||
if (adVideoView != null) {
|
||||
adVideoView.clearAll();
|
||||
}
|
||||
startAdContainer.setVisibility(View.GONE);
|
||||
ExtensionsKt.removeFromParent(startAdContainer, true);
|
||||
}
|
||||
@ -735,14 +747,11 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
ToastUtils.showToast("游戏启动中,请稍后~");
|
||||
handler.postDelayed(() -> {
|
||||
VHelper.postOnInitialized(() -> {
|
||||
if (VHelper.isInstalled(gamePackageName)) {
|
||||
VHelper.launch(this, gamePackageName, false, true);
|
||||
} else {
|
||||
ToastUtils.showToast("应用已被卸载!");
|
||||
}
|
||||
return null;
|
||||
});
|
||||
if (VHelper.isInnerInstalled(gamePackageName)) {
|
||||
launchGame(gamePackageName).invoke();
|
||||
} else {
|
||||
VHelper.postOnInitialized(launchGame(gamePackageName));
|
||||
}
|
||||
}, 500);
|
||||
break;
|
||||
case KEY_MARKET_DETAILS:
|
||||
@ -760,6 +769,19 @@ public class MainActivity extends BaseActivity {
|
||||
}, 500);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Function0<Unit> launchGame(String gamePackageName) {
|
||||
return () -> {
|
||||
if (!VHelper.isInnerInstalled(gamePackageName) && !VHelper.isInstalled(gamePackageName)) {
|
||||
ToastUtils.showToast("应用已被卸载!");
|
||||
} else {
|
||||
VHelper.shortcutLaunch();
|
||||
VHelper.launch(this, gamePackageName, false, true);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用跳转
|
||||
*/
|
||||
@ -785,7 +807,7 @@ public class MainActivity extends BaseActivity {
|
||||
public void onFailure(@Nullable HttpException e) {
|
||||
super.onFailure(e);
|
||||
try {
|
||||
ErrorHelper.handleErrorWithCustomizedHandler(MainActivity.this, e.response().errorBody().string(), false, "", "", "内容实名", null, null, code -> {
|
||||
ErrorHelper.handleErrorWithCustomizedHandler(MainActivity.this, e.response().errorBody().string(), false, "", "", "内容实名", null, null, code -> {
|
||||
if (code == 404001) {
|
||||
if (mShouldShowAd) {
|
||||
AppExecutor.getUiExecutor().executeWithDelay(() -> {
|
||||
@ -877,13 +899,6 @@ public class MainActivity extends BaseActivity {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
// 上传数据
|
||||
DataCollectionManager.getInstance().statClickData();
|
||||
super.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NotNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
@ -927,6 +942,8 @@ public class MainActivity extends BaseActivity {
|
||||
Config.getGhzsSettings();
|
||||
} else if (Config.getVSettingEntity() == null) {
|
||||
Config.refreshVSettingEntity();
|
||||
} else if (Config.getVNewSettingEntity() == null) {
|
||||
Config.getNewSetting();
|
||||
}
|
||||
|
||||
mPackageViewModel.checkData();
|
||||
@ -937,8 +954,10 @@ public class MainActivity extends BaseActivity {
|
||||
// 接收登录和登出更新事件统计的 Meta
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(EBReuse reuse) {
|
||||
if (reuse.getType().equals(LOGIN_TAG) || reuse.getType().equals(LOGOUT_TAG)) {
|
||||
boolean isLoginEvent = reuse.getType().equals(LOGIN_TAG);
|
||||
if (isLoginEvent || reuse.getType().equals(LOGOUT_TAG)) {
|
||||
MetaUtil.INSTANCE.refreshMeta();
|
||||
VHelper.INSTANCE.updateAuthorizeInfo(isLoginEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.db.ISearchHistoryDao
|
||||
import com.gh.gamecenter.db.SearchHistoryDao
|
||||
import com.gh.gamecenter.eventbus.EBSearch
|
||||
import com.gh.gamecenter.search.SearchDefaultFragment
|
||||
@ -29,6 +30,9 @@ import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* 游戏搜索页
|
||||
*/
|
||||
open class SearchActivity : BaseActivity() {
|
||||
|
||||
lateinit var searchEt: EditText
|
||||
@ -36,7 +40,7 @@ open class SearchActivity : BaseActivity() {
|
||||
lateinit var backBtn: RelativeLayout
|
||||
private lateinit var deleteIv: ImageView
|
||||
|
||||
private var mDao: SearchHistoryDao? = null
|
||||
protected val mDao: ISearchHistoryDao by lazy { provideDao() }
|
||||
|
||||
protected var mSearchKey: String? = null
|
||||
protected var mIsAutoSearchDisabled: Boolean = false
|
||||
@ -75,7 +79,6 @@ open class SearchActivity : BaseActivity() {
|
||||
val searchImmediately = intent.getBooleanExtra(KEY_SEARCH_IMMEDIATELY, false)
|
||||
var ignoreTextChanges = savedInstanceState != null
|
||||
|
||||
mDao = SearchHistoryDao(this)
|
||||
mPublishSubject = PublishSubject.create()
|
||||
|
||||
mPublishSubject!!
|
||||
@ -99,7 +102,7 @@ open class SearchActivity : BaseActivity() {
|
||||
searchEt.hint = hint
|
||||
if (searchImmediately) {
|
||||
mDisplayType = GAME_DETAIL
|
||||
mDao?.add(hint)
|
||||
mDao.add(hint)
|
||||
search(SearchType.DEFAULT, hint)
|
||||
}
|
||||
} else {
|
||||
@ -187,12 +190,12 @@ open class SearchActivity : BaseActivity() {
|
||||
mIsAutoSearchDisabled = false
|
||||
}
|
||||
|
||||
private fun handleAutoSearch(key: String?) {
|
||||
protected open fun handleAutoSearch(key: String?) {
|
||||
val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
|
||||
if (newSearchKey.isEmpty()) {
|
||||
val hint = searchEt.hint.toString()
|
||||
if (!TextUtils.isEmpty(hint) && HINT_TEXT != hint) {
|
||||
mDao?.add(hint)
|
||||
mDao.add(hint)
|
||||
search(SearchType.DEFAULT, hint)
|
||||
}
|
||||
} else {
|
||||
@ -210,7 +213,7 @@ open class SearchActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDefaultSearch(key: String?) {
|
||||
protected open fun handleDefaultSearch(key: String?) {
|
||||
mSearchKey = key
|
||||
searchEt.setText(key)
|
||||
searchEt.setSelection(searchEt.text.length)
|
||||
@ -227,14 +230,14 @@ open class SearchActivity : BaseActivity() {
|
||||
// MtaHelper.onEvent("游戏搜索", "默认搜索", key)
|
||||
}
|
||||
|
||||
private fun handleHotSearch(key: String?) {
|
||||
protected open fun handleHotSearch(key: String?) {
|
||||
mSearchKey = key
|
||||
searchEt.setText(key)
|
||||
searchEt.setSelection(searchEt.text.length)
|
||||
updateDisplayType(GAME_DETAIL)
|
||||
}
|
||||
|
||||
private fun handleHistorySearch(key: String?) {
|
||||
protected open fun handleHistorySearch(key: String?) {
|
||||
mSearchKey = key
|
||||
searchEt.setText(key)
|
||||
searchEt.setSelection(searchEt.text.length)
|
||||
@ -251,12 +254,12 @@ open class SearchActivity : BaseActivity() {
|
||||
// MtaHelper.onEvent("游戏搜索", "历史搜索", key)
|
||||
}
|
||||
|
||||
private fun handleManualSearch() {
|
||||
protected open fun handleManualSearch() {
|
||||
val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
|
||||
if (newSearchKey.isEmpty()) {
|
||||
val hint = searchEt.hint.toString()
|
||||
if (!TextUtils.isEmpty(hint) && HINT_TEXT != hint) {
|
||||
mDao?.add(hint)
|
||||
mDao.add(hint)
|
||||
search(SearchType.DEFAULT, hint)
|
||||
}
|
||||
} else if (newSearchKey != mSearchKey || mDisplayType != GAME_DETAIL) {
|
||||
@ -270,7 +273,7 @@ open class SearchActivity : BaseActivity() {
|
||||
mSourceEntrance
|
||||
)
|
||||
|
||||
mDao?.add(mSearchKey)
|
||||
mDao.add(mSearchKey)
|
||||
updateDisplayType(GAME_DETAIL)
|
||||
} else {
|
||||
toast("请输入搜索内容")
|
||||
@ -280,6 +283,8 @@ open class SearchActivity : BaseActivity() {
|
||||
// MtaHelper.onEvent("游戏搜索", "主动搜索", newSearchKey)
|
||||
}
|
||||
|
||||
protected open fun provideDao(): ISearchHistoryDao = SearchHistoryDao(this)
|
||||
|
||||
open fun updateDisplayType(type: DisplayType) {
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
when (type) {
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
package com.gh.gamecenter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
|
||||
import com.halo.assistant.fragment.user.SelectPortraitFragment;
|
||||
|
||||
/**
|
||||
* Created by khy on 2017/2/10.
|
||||
*/
|
||||
public class SelectUserIconActivity extends ToolBarActivity {
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context) {
|
||||
return getTargetIntent(context, SelectUserIconActivity.class, SelectPortraitFragment.class);
|
||||
}
|
||||
|
||||
}
|
||||
@ -48,6 +48,7 @@ import io.reactivex.functions.Consumer;
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/11/7.
|
||||
* 分享卡片
|
||||
*/
|
||||
public class ShareCardPicActivity extends ToolBarActivity {
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ import com.tencent.tauth.Tencent;
|
||||
|
||||
/**
|
||||
* Created by khy on 2017/2/6.
|
||||
* 分享光环
|
||||
*/
|
||||
public class ShareGhActivity extends ToolBarActivity {
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import com.gh.gamecenter.common.base.activity.ToolBarActivity
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.amway.AmwaySuccessFragment
|
||||
import com.gh.gamecenter.gamedetail.LibaoListFragment
|
||||
import com.halo.assistant.fragment.SwitchInstallMethodFragment
|
||||
import com.halo.assistant.fragment.user.ManuallyRealNameFragment
|
||||
import com.halo.assistant.fragment.user.RealNameInfoFragment
|
||||
@ -29,12 +30,14 @@ class ShellActivity : ToolBarActivity() {
|
||||
private fun handleIntent(bundle: Bundle?) {
|
||||
// We parse the bundle to fragment to let fragment get data from bundle itself to survive configuration changes.
|
||||
val intentType = Type.fromString(bundle?.getString(INTENT_TYPE) ?: "")
|
||||
val extraData = bundle?.getBundle(EntranceConsts.KEY_DATA)
|
||||
|
||||
when (intentType) {
|
||||
Type.AMWAY_SUCCESS -> startFragment(AmwaySuccessFragment().with(bundle))
|
||||
Type.SWITCH_INSTALL_METHOD -> startFragment(SwitchInstallMethodFragment())
|
||||
Type.REAL_NAME_INFO -> startFragment(RealNameInfoFragment().with(bundle))
|
||||
Type.MANUALLY_REAL_NAME -> startFragment(ManuallyRealNameFragment().with(bundle?.getBundle(EntranceConsts.KEY_DATA)))
|
||||
Type.MANUALLY_REAL_NAME -> startFragment(ManuallyRealNameFragment().with(extraData))
|
||||
Type.SIMPLE_LIBAO_LIST -> startFragment(LibaoListFragment.newInstance(extraData))
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +71,8 @@ class ShellActivity : ToolBarActivity() {
|
||||
AMWAY_SUCCESS("amway_success"),
|
||||
SWITCH_INSTALL_METHOD("switch_install_method"),
|
||||
REAL_NAME_INFO("real_name_info"),
|
||||
MANUALLY_REAL_NAME("manually_real_name");
|
||||
MANUALLY_REAL_NAME("manually_real_name"),
|
||||
SIMPLE_LIBAO_LIST("simple_libao_list");
|
||||
|
||||
companion object {
|
||||
fun fromString(typeString: String): Type {
|
||||
|
||||
@ -3,8 +3,8 @@ package com.gh.gamecenter;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.ENTRANCE_BROWSER;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.ENTRANCE_PUSH;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ANSWER;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ARCHIVE_LOGIN;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ARTICLE;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_CATEGORY;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COLUMN;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COLUMN_COLLECTION;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COMMUNITY;
|
||||
@ -14,6 +14,7 @@ import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_DOWNLOAD;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_GAME;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_GAME_COLLECTION_DETAIL;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_GAME_COLLECTION_SQUARE;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_INSTALL;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_INVOKE_ONLY;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_LIBAO;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ;
|
||||
@ -21,6 +22,7 @@ import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_GAME;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_GROUP;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_QUN;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QUESTION;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_RESTART_GAME;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_SUGGESTION;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_TOOLBOX;
|
||||
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_UPLOAD_VIDEO;
|
||||
@ -54,22 +56,30 @@ import androidx.annotation.Nullable;
|
||||
import com.gh.common.util.CheckLoginUtils;
|
||||
import com.gh.common.util.DirectUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity;
|
||||
import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts;
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity;
|
||||
import com.gh.gamecenter.common.entity.LinkEntity;
|
||||
import com.gh.gamecenter.common.entity.SimpleGameEntity;
|
||||
import com.gh.gamecenter.core.utils.GsonUtils;
|
||||
import com.gh.gamecenter.core.utils.ToastUtils;
|
||||
import com.gh.gamecenter.entity.SubjectData;
|
||||
import com.gh.gamecenter.entity.SubjectRecommendEntity;
|
||||
import com.gh.gamecenter.entity.VideoLinkEntity;
|
||||
import com.gh.gamecenter.feature.utils.PlatformUtils;
|
||||
import com.gh.gamecenter.login.view.LoginActivity;
|
||||
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper;
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel;
|
||||
import com.gh.gamecenter.video.videomanager.VideoManagerActivity;
|
||||
import com.gh.vspace.VHelper;
|
||||
import com.gh.vspace.shortcut.OnCreateShortcutResult;
|
||||
import com.gh.vspace.shortcut.ShortcutManager;
|
||||
import com.gh.vspace.shortcut.ShortcutPermissionTipsDialog;
|
||||
import com.lightgame.config.CommonDebug;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.muugi.shortcut.core.Executor;
|
||||
|
||||
@ -113,6 +123,7 @@ public class SkipActivity extends BaseActivity {
|
||||
String platform = uri.getQueryParameter(KEY_PLATFORM);
|
||||
String platformName = PlatformUtils.getInstance(this).getPlatformName(platform);
|
||||
String gameId = uri.getQueryParameter(EntranceConsts.KEY_GAMEID);
|
||||
String gameName = uri.getQueryParameter(KEY_GAME_NAME);
|
||||
String packageMd5 = uri.getQueryParameter(EntranceConsts.KEY_PACKAGE_MD5);
|
||||
String isQaFeedbackString = uri.getQueryParameter(EntranceConsts.KEY_IS_QA_FEEDBACK);
|
||||
String suggestionType = uri.getQueryParameter(KEY_TYPE);
|
||||
@ -152,7 +163,7 @@ public class SkipActivity extends BaseActivity {
|
||||
DirectUtils.directToGameDetail(this, path, "", entrance, "true".equals(uri.getQueryParameter("auto_download")), to, null);
|
||||
break;
|
||||
case HOST_COLUMN:
|
||||
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), entrance, null, false);
|
||||
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), entrance, null, SubjectData.SubjectType.NORMAL);
|
||||
break;
|
||||
case HOST_SUGGESTION:
|
||||
if (!TextUtils.isEmpty(qaId)) {
|
||||
@ -214,7 +225,7 @@ public class SkipActivity extends BaseActivity {
|
||||
String categoryId = uri.getQueryParameter("category_id");
|
||||
String link = uri.getQueryParameter("link");
|
||||
gameId = uri.getQueryParameter("gameId");
|
||||
String gameName = uri.getQueryParameter("gameName");
|
||||
gameName = uri.getQueryParameter("gameName");
|
||||
String tagActivityId = uri.getQueryParameter("tagActivityId");
|
||||
String tagActivityName = uri.getQueryParameter("tagActivityName");
|
||||
VideoLinkEntity linkEntity = new VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName);
|
||||
@ -303,10 +314,6 @@ public class SkipActivity extends BaseActivity {
|
||||
DirectUtils.directToCommunityColumn(this, community, columnId, entrance, "");
|
||||
break;
|
||||
|
||||
case HOST_CATEGORY:
|
||||
title = uri.getQueryParameter("title");
|
||||
DirectUtils.directCategoryDirectory(this, path, title, entrance, pathName);
|
||||
break;
|
||||
case HOST_COLUMN_COLLECTION:
|
||||
DirectUtils.directToColumnCollection(this, path, -1, entrance, "", "", "", "", null,false);
|
||||
break;
|
||||
@ -385,9 +392,9 @@ public class SkipActivity extends BaseActivity {
|
||||
break;
|
||||
case EntranceConsts.HOST_HELP_AND_FEEDBACK:
|
||||
if ("vgame".equals(suggestionType)) {
|
||||
DirectUtils.directToHelpAndFeedback(this, content, isQaFeedback, qaContentId, false, true, entrance);
|
||||
DirectUtils.directToHelpAndFeedback(this, content, isQaFeedback, qaContentId, false, true, gameId, gameName, "畅玩游戏悬浮窗");
|
||||
} else {
|
||||
DirectUtils.directToHelpAndFeedback(this, content, isQaFeedback, qaContentId, true, false, entrance);
|
||||
DirectUtils.directToHelpAndFeedback(this, content, isQaFeedback, qaContentId, true, false, gameId, gameName, "插件端悬浮窗");
|
||||
}
|
||||
break;
|
||||
case HOST_GAME_COLLECTION_DETAIL:
|
||||
@ -401,10 +408,38 @@ public class SkipActivity extends BaseActivity {
|
||||
try {
|
||||
JSONObject extJsonObject = new JSONObject(extJson);
|
||||
String qqGameId = extJsonObject.optString("aid");
|
||||
DirectUtils.directToQGameById(this, qqGameId);
|
||||
MiniGameItemHelper.INSTANCE.launchMiniGame(qqGameId, Constants.QQ_MINI_GAME);
|
||||
} catch (JSONException ignored) {
|
||||
}
|
||||
break;
|
||||
case HOST_ARCHIVE_LOGIN:
|
||||
String gamePkg = uri.getQueryParameter(EntranceConsts.KEY_GAME_PKG);
|
||||
if(CheckLoginUtils.isLogin()) {
|
||||
VHelper.INSTANCE.updateAuthorizeInfo(true);
|
||||
} else {
|
||||
Bundle newBundle = new Bundle();
|
||||
newBundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
|
||||
EntranceUtils.jumpActivity(this, null, newBundle, (resultCode, data) -> {
|
||||
if(CheckLoginUtils.isLogin()) {
|
||||
VHelper.INSTANCE.updateAuthorizeInfo(true);
|
||||
}
|
||||
VHelper.launch(this, gamePkg, false, false);
|
||||
finish();
|
||||
});
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case HOST_RESTART_GAME:
|
||||
String restartGamePkg = uri.getQueryParameter(EntranceConsts.KEY_GAME_PKG);
|
||||
VHelper.launch(this, restartGamePkg, false, true);
|
||||
break;
|
||||
case HOST_INSTALL:
|
||||
String packageName = uri.getQueryParameter("package_name");
|
||||
DownloadEntity downloadEntity = DownloadManager
|
||||
.getInstance()
|
||||
.getDownloadEntitySnapshotByPackageName(packageName);
|
||||
PackageInstaller.install(this, downloadEntity);
|
||||
break;
|
||||
default:
|
||||
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
|
||||
return;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user