Compare commits
533 Commits
video_only
...
v4.7.1-291
| Author | SHA1 | Date | |
|---|---|---|---|
| 4771c79fa9 | |||
| 3458a5d7f3 | |||
| 5bc7c333d8 | |||
| c7a24555a2 | |||
| e19a678699 | |||
| 278dcc33be | |||
| 87be3bed61 | |||
| 078b102152 | |||
| 85e97bc64d | |||
| 951ac06948 | |||
| 92cdb6fdbb | |||
| cb0dd1d082 | |||
| 276655a8ec | |||
| df8b612188 | |||
| 4d413eb1f2 | |||
| d496ab0283 | |||
| b519ff6aac | |||
| 8c05d2be8a | |||
| 23dd89198b | |||
| 6569ab2d33 | |||
| 1bead6a756 | |||
| c0df3af298 | |||
| 267363f46d | |||
| 44cf54aee6 | |||
| 322d7117f8 | |||
| c8684f837a | |||
| 9e5ecf1520 | |||
| 2df94dddc5 | |||
| 1731980e88 | |||
| f789f0cb73 | |||
| d043a89f3e | |||
| 4ab0f066df | |||
| 096679029b | |||
| 2634228d21 | |||
| a33784221d | |||
| 2ef7216bda | |||
| 2554fab389 | |||
| a4e3121489 | |||
| 8dfde8ddd0 | |||
| 63403c7c29 | |||
| aa9269aecc | |||
| 489e7105bb | |||
| 8dbc407503 | |||
| 3e032fa540 | |||
| 3df381b255 | |||
| 7c59181bc6 | |||
| 9244a65371 | |||
| a7b8b678f7 | |||
| 9877d4d51e | |||
| 32b4570738 | |||
| af3fdb3cfb | |||
| 5ce992ee63 | |||
| ba17019428 | |||
| f77087907f | |||
| 3080f59ef6 | |||
| 74b1f388e2 | |||
| dcbc2fe352 | |||
| b892c58c52 | |||
| 0a455c7b09 | |||
| 7a254c4609 | |||
| 4f08a4b9d2 | |||
| 75670b7801 | |||
| af386f6bdc | |||
| ff813d8784 | |||
| dba87fe09c | |||
| cf13003c2a | |||
| 7fe337c557 | |||
| 1902ed29c1 | |||
| a67927e9e7 | |||
| 33b6835ae6 | |||
| 1ca6a2c795 | |||
| 372230092a | |||
| 2ee1db1074 | |||
| caabf416bb | |||
| d33d0e98c9 | |||
| a4a029f31e | |||
| 3b8d34f8c3 | |||
| 2368e268bf | |||
| 6390198899 | |||
| 4a6aef4caa | |||
| 91529f51a3 | |||
| 57096b2b08 | |||
| 40f1f57844 | |||
| b9da7fbcb8 | |||
| 7138177df2 | |||
| aa4cf291dc | |||
| 8f4c1651a3 | |||
| 30a6cfd7d9 | |||
| c1abb977bf | |||
| fef633e9d8 | |||
| 5207b5675c | |||
| b7059abcee | |||
| 45a84fc45c | |||
| cf96b00036 | |||
| 49dacc472d | |||
| 72d069ad7e | |||
| 2f49e05891 | |||
| fd2d277470 | |||
| fc52694fdc | |||
| 7123b3d59a | |||
| 7684c247bf | |||
| f2b9d26e8a | |||
| 6d5d407aa8 | |||
| 338de605ec | |||
| 53930b0257 | |||
| 34d5e2cc29 | |||
| 591a694bdf | |||
| 9fd9a4ebcc | |||
| f2712c3db7 | |||
| 61c2c7b218 | |||
| 8a54c47d9e | |||
| 7f60a575a4 | |||
| eb2dd7c6b8 | |||
| ae8433d8bd | |||
| 7ec4ba6582 | |||
| 190434a855 | |||
| 4b82e40eb4 | |||
| d8e858ddb8 | |||
| 9b8c8f328d | |||
| bebdbe64cd | |||
| a0555d6ffc | |||
| d6674efe4a | |||
| 20235c6908 | |||
| bc155d580c | |||
| 9cf852b490 | |||
| f32bc837b4 | |||
| 36efcdb75a | |||
| a232ef9d03 | |||
| 05b90bd5b4 | |||
| bc382e6f31 | |||
| 116d71bb9c | |||
| 2aadb78301 | |||
| 22801846e4 | |||
| f9f6886250 | |||
| 30c8d4db02 | |||
| 08a5ea100e | |||
| db33ed0d0d | |||
| fd424b0204 | |||
| c1bf0a628f | |||
| 086bf75314 | |||
| af31fdc562 | |||
| 99e0a2e0a2 | |||
| 069d0db00e | |||
| 68f1343c93 | |||
| fbe25c9099 | |||
| 9b893bcb42 | |||
| 5182d4cd8d | |||
| cce077de96 | |||
| 03092a0ec1 | |||
| 4906ecc06b | |||
| 7a831ce646 | |||
| 290a26c4e2 | |||
| 571080b1e5 | |||
| d9567138ee | |||
| 4a31f74dcb | |||
| 79cf96b161 | |||
| 7fdd4dbf04 | |||
| 8eeeb5de60 | |||
| 150109cef4 | |||
| 7e7cc38d6d | |||
| b3df30680e | |||
| f73048d3a5 | |||
| c540c14e1c | |||
| f216bf4097 | |||
| a42bcbd160 | |||
| bc6786b21e | |||
| 47e357143c | |||
| 74eb8ad0e8 | |||
| d2fc927ffb | |||
| db4b049591 | |||
| 86db2b5688 | |||
| baa1c9f9e5 | |||
| be3a3e82af | |||
| 120ea26455 | |||
| fc476ca889 | |||
| fc36ce6a03 | |||
| 0a1d330c2f | |||
| e5ec42576c | |||
| b57f74a411 | |||
| cb3884ea2e | |||
| 0cb3184e35 | |||
| 76c5009fbc | |||
| 312ec153f1 | |||
| 1ef79df4c5 | |||
| d7a809f8a6 | |||
| ebadeeb873 | |||
| 55155ee8ae | |||
| be98a6b6d6 | |||
| e2f396f8c7 | |||
| 2a8024368a | |||
| 0cd025b42d | |||
| d6adda78c4 | |||
| 99708d7801 | |||
| 584986a9d5 | |||
| 507da05841 | |||
| 72a8fe4764 | |||
| f9f23f6324 | |||
| e2964f93c7 | |||
| cb2a9a3ca0 | |||
| ea68941bb9 | |||
| b598d331d4 | |||
| d7b876bfed | |||
| 6aca60080a | |||
| 59d76688b9 | |||
| 8e5e677228 | |||
| dd1bfcaddd | |||
| f4c66e1ab7 | |||
| 6ebdf6e42a | |||
| 4c01dd442b | |||
| ac226e3301 | |||
| 569f1b8cf1 | |||
| 46f5da88a6 | |||
| f5b876b018 | |||
| c5df856023 | |||
| 4f775847dc | |||
| f53710fdf5 | |||
| 80c56def08 | |||
| a1d88d999e | |||
| fbc6f6adaa | |||
| e7c55b2467 | |||
| 2c45bb1da9 | |||
| 173825dc74 | |||
| a63e28809b | |||
| 0eb8cb6e66 | |||
| e1514e2b25 | |||
| bef0da821b | |||
| 54741729f3 | |||
| e2640c22f8 | |||
| 2f16d5ba99 | |||
| 1d5301f887 | |||
| cc09c702f7 | |||
| 6b2a88766e | |||
| 0eb629fe67 | |||
| 44c398c9fb | |||
| 96122c5919 | |||
| bd4c438036 | |||
| adc8648f5a | |||
| 8eb3922a33 | |||
| 30743bb015 | |||
| 853f51ad0e | |||
| 763aad99ee | |||
| 2ed2317b02 | |||
| 0663f3eb2b | |||
| 11a2eeae7a | |||
| 8c2619bb22 | |||
| 46320fe07d | |||
| 1ee933b115 | |||
| 1d9152ca1a | |||
| 81ebf21bb9 | |||
| dd4bf98f28 | |||
| ba3a06da43 | |||
| 6fe096383c | |||
| d16f99958f | |||
| 5fa3aa42dc | |||
| f4f28a2daa | |||
| 3c1cd14bdc | |||
| 6dcc251312 | |||
| f692aa4bff | |||
| 7cde55ebe0 | |||
| 94eba08af4 | |||
| 2bf207661c | |||
| 2fff7f60c2 | |||
| 1b3c93ebb5 | |||
| 5b529b044e | |||
| 91f417f479 | |||
| fc0bf595bd | |||
| c0f6499577 | |||
| b9bef384f1 | |||
| 58bfae2fdb | |||
| d2c2fff884 | |||
| ab178c47b5 | |||
| 40be004376 | |||
| 0b501c9ce1 | |||
| cff82379f5 | |||
| 825503bd58 | |||
| 77a715a4bd | |||
| 78b233c506 | |||
| a6e799bb9a | |||
| b65992099a | |||
| 3d1a5f52bf | |||
| 82d0d5745c | |||
| fe7968cb32 | |||
| 94c503af74 | |||
| bdd9815ffc | |||
| 693acceca8 | |||
| 90971bc299 | |||
| e5b3613348 | |||
| 652ca8f69c | |||
| f15e351c1e | |||
| 47c81c3dac | |||
| 7453a61e4f | |||
| 911f6397e8 | |||
| 8d21a4f774 | |||
| 991c54b680 | |||
| 48dcb5089b | |||
| 461efe7101 | |||
| 0735161a20 | |||
| 093c1e2b15 | |||
| 7d0e02c899 | |||
| 8294913f04 | |||
| e811c4f90b | |||
| 69e248b389 | |||
| 43f6bfc4c2 | |||
| c8b81ab56a | |||
| aa41fd98e8 | |||
| ff6c4c2de9 | |||
| 136761d2f7 | |||
| 9374fc5264 | |||
| 324aaa5056 | |||
| f22afbd819 | |||
| e149231cb2 | |||
| 9c8155ddf8 | |||
| dd95419a36 | |||
| 870b10dd13 | |||
| 637b426649 | |||
| ee8ce87e28 | |||
| a944a7f730 | |||
| fdbb16b45f | |||
| 29bc098dcf | |||
| b2433cf13a | |||
| e908e23bb2 | |||
| 1a4dc827b5 | |||
| 9fd5e65fa2 | |||
| 5405dcd30e | |||
| 5c35f7fe5d | |||
| fc907a398f | |||
| 1b8dc6eba0 | |||
| c17a36c866 | |||
| a29cf832f1 | |||
| c9a628a5e9 | |||
| 165ba01afd | |||
| a39a8c2cce | |||
| 4002f138bb | |||
| 48fdb38902 | |||
| 38a3120ea1 | |||
| c0e370dfd2 | |||
| e4765089fa | |||
| 721e73ca1e | |||
| e406c90027 | |||
| e7c4886219 | |||
| 80a2e4f336 | |||
| 9f5940c6f6 | |||
| 0d9a4baf32 | |||
| 3a9132ff8c | |||
| d01fda44b3 | |||
| 02a6ec9f7d | |||
| c779d775e3 | |||
| 3fbcd33f98 | |||
| dbcdd7f3cc | |||
| 69d9854b44 | |||
| 2020033bc0 | |||
| dc2c8e590c | |||
| b115db51e9 | |||
| 5246d6e743 | |||
| b20d598751 | |||
| 85e9799f20 | |||
| 6b533c8d09 | |||
| 2797135db4 | |||
| 7507a027da | |||
| 7d194c7078 | |||
| 9873ae8946 | |||
| a5ef80ba33 | |||
| dfdd12bf18 | |||
| 9daf01d9a5 | |||
| ee7ed1fed2 | |||
| 08474a660e | |||
| d8dfe00057 | |||
| 6bd175f72b | |||
| 72b6b3042a | |||
| 3317b178ac | |||
| c86e7ba6ee | |||
| 14c5e4e963 | |||
| 6db8179f4d | |||
| 65c2571329 | |||
| 4810803988 | |||
| f3f030edb1 | |||
| 2ac2a3bf48 | |||
| cd104e4688 | |||
| e2de8cfb47 | |||
| c9f9451dee | |||
| 73c39edd3f | |||
| 7f739798ab | |||
| e41cf76d26 | |||
| 113d446e47 | |||
| 882ac7d67d | |||
| d94be8092b | |||
| b9138ae810 | |||
| 715cecd44b | |||
| dd756fce00 | |||
| 56a003704d | |||
| 50421e0b70 | |||
| 9f0d00f793 | |||
| a56fd8ff18 | |||
| f86fc7b0e1 | |||
| e6197776ca | |||
| 0415ae261b | |||
| d5313c7f98 | |||
| 360231e01f | |||
| 4d86d6f96b | |||
| dd03daae84 | |||
| 5d285fd60e | |||
| 7d4206bcd8 | |||
| a816636d9a | |||
| c6a5522b35 | |||
| 8b888f0ab4 | |||
| ef41a3aea5 | |||
| ba2206931f | |||
| ef4b7b28d8 | |||
| 4a5f12d341 | |||
| ced96f5f70 | |||
| 4180d87b36 | |||
| 2b7f802584 | |||
| 3e9a348019 | |||
| 9725402623 | |||
| 9827b04057 | |||
| b3052485f5 | |||
| d3dc09d377 | |||
| 58905c14a8 | |||
| aadbbbf2ea | |||
| 5256a9b267 | |||
| 0ded7b33f2 | |||
| cdc3158f30 | |||
| 06de179c9e | |||
| f32dc628ef | |||
| 62e371c928 | |||
| 84bcc481af | |||
| 085ddd4ea6 | |||
| b3e859678e | |||
| 7f586fbf13 | |||
| 9dab3dd263 | |||
| 3ee30f05f0 | |||
| 69c8c51000 | |||
| 28742f54bb | |||
| f62751423d | |||
| b0b699679e | |||
| 3c55284d86 | |||
| b6ae508cf0 | |||
| c13ee31ece | |||
| c87a1ba56e | |||
| 9f07cc7720 | |||
| 7bdfe7cef3 | |||
| 667126f92c | |||
| 0409d33d5e | |||
| 14e8285c0f | |||
| c7d63f9df1 | |||
| e2d9ad07d1 | |||
| 9287b6ac4c | |||
| 450da5e0db | |||
| 0397092414 | |||
| ddc515b490 | |||
| a6edde7853 | |||
| 80282f7bcc | |||
| 664df5cb44 | |||
| 8396a55ed2 | |||
| 5ee3f597bd | |||
| 9c8bd9f85e | |||
| 4321e0a33c | |||
| 6f75229209 | |||
| d6bd561e58 | |||
| c957d7585c | |||
| db0e92fd68 | |||
| 992446cf70 | |||
| dcfa52b05a | |||
| 2a06c41dca | |||
| 24214c5d6b | |||
| c839eff88d | |||
| 663505fdc9 | |||
| 641a820ea5 | |||
| bb3f888f88 | |||
| 75bdf6f251 | |||
| 0cacc15e7d | |||
| e4c2ac0aae | |||
| 7acf4c5941 | |||
| 8b22361213 | |||
| a1dee46436 | |||
| 49bf8c9e30 | |||
| 407686ca5b | |||
| 89b7b45ba0 | |||
| b00e7a2826 | |||
| 383d6e7700 | |||
| edce98e4c6 | |||
| a2c3873c8d | |||
| 7990353d08 | |||
| a7b138b2b2 | |||
| 951768e070 | |||
| 69f29fe83b | |||
| 88e28b2388 | |||
| 538bc6f97c | |||
| b1940125f4 | |||
| e1f8e293c2 | |||
| 0a49f27ed2 | |||
| 5dc7badc97 | |||
| d185d39985 | |||
| d9c98d39b5 | |||
| 6949f2b2ff | |||
| 2141440ec4 | |||
| 464c212638 | |||
| dbe74b2091 | |||
| ba55a5a61c | |||
| 452a94f4a2 | |||
| 310be97fe4 | |||
| 2fc45777e4 | |||
| da283fc1f6 | |||
| fee4e4635c | |||
| ebcd50cdee | |||
| cd922dd286 | |||
| 97598d7330 | |||
| 0db59a56d0 | |||
| bee3f5957e | |||
| 65d4b43c9c | |||
| 41f510d333 | |||
| 64d5af036c | |||
| b4c827bddf | |||
| caf3dfa9ee | |||
| c5c10ab208 | |||
| c2251e1ad6 | |||
| bd6d51dab3 | |||
| 1cf9bfcca3 | |||
| 992ec7bfe8 | |||
| cc39bfd06c | |||
| 15d0ad6f49 | |||
| a2e2379073 | |||
| d2431ed8ff | |||
| 80818dee55 | |||
| f2d0916a16 | |||
| 2fa84e0ce1 | |||
| c9f5cfd4aa | |||
| d6c1f692be | |||
| 12e6fb8330 | |||
| ad857d4500 | |||
| 43d8d24c1c | |||
| a34ee5a753 | |||
| ca39f723e1 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,5 +7,6 @@ local.properties
|
||||
captures/
|
||||
build/
|
||||
release-app/
|
||||
test-app/
|
||||
scripts/apk-channel/
|
||||
app/src/test/java/com/gh/gamecenter
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,4 +1,4 @@
|
||||
[submodule "libraries/LGLibrary"]
|
||||
path = libraries/LGLibrary
|
||||
url = git@gitlab.ghzs.com:android/common-library.git
|
||||
url = git@git.ghzs.com:android/common-library.git
|
||||
branch = master
|
||||
|
||||
180
app/build.gradle
180
app/build.gradle
@ -2,9 +2,9 @@ apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android' // kotlin
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: "com.gh.gamecenter.plugin"
|
||||
|
||||
// apkChannelPackage
|
||||
apply plugin: 'channel'
|
||||
import groovy.xml.XmlUtil
|
||||
|
||||
//apply from: 'tinker-support.gradle'
|
||||
|
||||
@ -18,6 +18,10 @@ android {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
viewBinding {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
@ -32,6 +36,10 @@ android {
|
||||
javaMaxHeapSize "4g"
|
||||
}
|
||||
|
||||
aaptOptions {
|
||||
additionalParameters "--no-version-vectors"
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
|
||||
multiDexEnabled true
|
||||
@ -57,7 +65,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-legacy.txt', 'proguard-fresco.txt'
|
||||
|
||||
/**
|
||||
* All third-party appid/appkey
|
||||
@ -125,15 +133,27 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "nonsense"
|
||||
flavorDimensions("env")
|
||||
|
||||
sourceSets {
|
||||
publish {
|
||||
java.srcDirs = ['src/main/java']
|
||||
}
|
||||
internal {
|
||||
java.srcDirs = ['src/main/java']
|
||||
}
|
||||
tea {
|
||||
java.srcDirs = ['src/main/java', 'src/tea/java']
|
||||
}
|
||||
gdt {
|
||||
java.srcDirs = ['src/main/java', 'src/gdt/java']
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 多渠道打包,渠道请参考"channel.txt"文件,所有渠道值均通过java code设置
|
||||
*/
|
||||
productFlavors {
|
||||
// publish release host
|
||||
publish {
|
||||
dimension "nonsense"
|
||||
dimension "env"
|
||||
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
|
||||
|
||||
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
|
||||
@ -144,7 +164,7 @@ android {
|
||||
}
|
||||
// internal test dev host
|
||||
internal {
|
||||
dimension "nonsense"
|
||||
dimension "env"
|
||||
versionNameSuffix "-debug"
|
||||
|
||||
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
|
||||
@ -155,26 +175,35 @@ android {
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEV_UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${DEV_BUGLY_APPID}\""
|
||||
}
|
||||
|
||||
tea {
|
||||
dimension "env"
|
||||
|
||||
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
|
||||
|
||||
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
|
||||
|
||||
manifestPlaceholders.put("APPLOG_SCHEME","rangersapplog.byAx6uYt".toLowerCase())
|
||||
}
|
||||
|
||||
gdt {
|
||||
dimension "env"
|
||||
|
||||
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
|
||||
|
||||
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apkChannelPackage
|
||||
channel {
|
||||
//多渠道包的输出目录,默认为new File(project.buildDir,"channel")
|
||||
baseOutputDir = new File(project.buildDir, "channel")
|
||||
//多渠道包的命名规则,默认为:${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}
|
||||
apkNameFormat = '${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}'
|
||||
}
|
||||
|
||||
rebuildChannel {
|
||||
// baseDebugApk = 已有Debug APK
|
||||
// baseReleaseApk = 已有Release APK
|
||||
// //默认为new File(project.buildDir, "rebuildChannel/debug")
|
||||
// debugOutputDir = Debug渠道包输出目录
|
||||
// //默认为new File(project.buildDir, "rebuildChannel/release")
|
||||
// releaseOutputDir = Release渠道包输出目录
|
||||
}
|
||||
|
||||
repositories {
|
||||
flatDir {
|
||||
dirs 'libs', 'libs/aars'
|
||||
@ -184,6 +213,7 @@ repositories {
|
||||
dependencies {
|
||||
|
||||
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
|
||||
gdtImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/gdt/libs')
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
|
||||
@ -194,8 +224,8 @@ dependencies {
|
||||
debugImplementation "com.gu.android:toolargetool:${toolargetool}"
|
||||
debugImplementation "com.github.nichbar:WhatTheStack:$whatTheStack"
|
||||
|
||||
implementation "androidx.core:core:${core}"
|
||||
implementation "androidx.fragment:fragment:${fragment}"
|
||||
implementation "androidx.core:core-ktx:${core}"
|
||||
implementation "androidx.fragment:fragment-ktx:${fragment}"
|
||||
implementation "androidx.multidex:multidex:${multiDex}"
|
||||
implementation "androidx.appcompat:appcompat:${appCompat}"
|
||||
implementation "androidx.cardview:cardview:${cardView}"
|
||||
@ -216,8 +246,10 @@ dependencies {
|
||||
implementation "com.kyleduo.switchbutton:library:${switchButton}"
|
||||
|
||||
implementation "com.facebook.fresco:fresco:${fresco}"
|
||||
implementation "com.facebook.fresco:animated-gif:${fresco}"
|
||||
implementation "com.facebook.fresco:animated-gif-lite:${fresco}"
|
||||
implementation "com.facebook.fresco:animated-drawable:${fresco}"
|
||||
implementation "com.facebook.fresco:animated-webp:${fresco}"
|
||||
implementation "com.facebook.fresco:webpsupport:${fresco}"
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:${okHttp}"
|
||||
|
||||
@ -285,11 +317,11 @@ dependencies {
|
||||
implementation "com.ethanhua:skeleton:${skeleton}"
|
||||
implementation "io.supercharge:shimmerlayout:${shimmerlayout}"
|
||||
implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:${mta}"
|
||||
implementation "com.walkud.rom.checker:RomChecker:${romChecker}"
|
||||
implementation "com.github.nichbar:AndroidRomChecker:${romChecker}"
|
||||
|
||||
debugImplementation "com.github.nichbar.chucker:library:$chucker"
|
||||
releaseImplementation "com.github.nichbar.chucker:library-no-op:$chucker"
|
||||
// implementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog"
|
||||
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog"
|
||||
// implementation "com.bytedance.ies.ugc.aweme:opensdk-china-external:$bytedanceAweme"
|
||||
// implementation "com.bytedance.ies.ugc.aweme:opensdk-common:$bytedanceAweme"
|
||||
|
||||
@ -299,13 +331,22 @@ dependencies {
|
||||
|
||||
implementation "net.lingala.zip4j:zip4j:${zip4j}"
|
||||
|
||||
implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
|
||||
// plugin 需要字符串,故不能用值
|
||||
implementation "io.sentry:sentry-android:3.2.0"
|
||||
|
||||
// implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
|
||||
implementation("com.github.nichbar.BigImageViewer:BigImageViewer:$bigImageViewer", {
|
||||
exclude group: 'com.squareup.okhttp3'
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
exclude group: 'com.github.bumptech.glide'
|
||||
exclude group: 'com.facebook.fresco'
|
||||
})
|
||||
implementation "com.github.nichbar.BigImageViewer:FrescoImageLoader:$bigImageViewer"
|
||||
implementation "com.github.nichbar.BigImageViewer:FrescoImageViewFactory:$bigImageViewer"
|
||||
implementation "com.github.PhilJay:MPAndroidChart:${chart}"
|
||||
|
||||
implementation "com.github.hsiafan:apk-parser:$apkParser"
|
||||
|
||||
implementation project(':libraries:LGLibrary')
|
||||
// implementation project(':libraries:MTA')
|
||||
implementation project(':libraries:QQShare')
|
||||
@ -371,3 +412,78 @@ if (propFile.exists()) {
|
||||
// task.name.startsWith('merge') && task.name.endsWith('Resources')
|
||||
// }.each { t -> t.dependsOn generateMetaJson }
|
||||
//}
|
||||
|
||||
|
||||
project.afterEvaluate {
|
||||
def variants = null
|
||||
try {
|
||||
variants = android.applicationVariants
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace()
|
||||
try {
|
||||
variants = android.libraryVariants
|
||||
} catch (Throwable tt) {
|
||||
tt.printStackTrace()
|
||||
}
|
||||
}
|
||||
if (variants != null) {
|
||||
variants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
def task = output.processManifestProvider.get()
|
||||
if (task == null) {
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* 为 Manifest 的 Activity 的 configChanges 添加自己手动处理 configurationChanges 配置 [https://developer.android.com/guide/topics/resources/runtime-changes]
|
||||
* AGP 4.1.0 从 ProcessManifest task 里拿 manifest 的 API 变更调整可以参考这里 [https://github.com/Tencent/tinker/pull/1476/commits/d71645729b13d545ca4ba6826f93fbf558751434]
|
||||
* (搞半天还是不会抽离方法,有空再把 gradle 改成用 kotlin 实现吧)
|
||||
*/
|
||||
task.doLast {
|
||||
def manifestFile = new File(multiApkManifestOutputDirectory.get().asFile, "AndroidManifest.xml")
|
||||
if (manifestFile == null || !manifestFile.exists()) {
|
||||
return
|
||||
}
|
||||
def parser = new XmlSlurper(false, true)
|
||||
def manifest = parser.parse(manifestFile)
|
||||
def app = manifest.'application'[0]
|
||||
app.'activity'.each { act ->
|
||||
String value = act.attributes()['android:configChanges']
|
||||
if (value == null || value.isEmpty()) {
|
||||
value = "keyboardHidden|orientation|screenSize|screenLayout|density|fontScale|locale"
|
||||
act.attributes()['androidconfigChanges'] = value
|
||||
} else {
|
||||
String[] valueSplit = value.split("\\|")
|
||||
if (!valueSplit.contains("keyboardHidden")) {
|
||||
value += "|keyboardHidden"
|
||||
}
|
||||
if (!valueSplit.contains("orientation")) {
|
||||
value += "|orientation"
|
||||
}
|
||||
if (!valueSplit.contains("screenSize")) {
|
||||
value += "|screenSize"
|
||||
}
|
||||
if (!valueSplit.contains("screenLayout")) {
|
||||
value += "|screenLayout"
|
||||
}
|
||||
if (!valueSplit.contains("density")) {
|
||||
value += "|density"
|
||||
}
|
||||
if (!valueSplit.contains("fontScale")) {
|
||||
value += "|fontScale"
|
||||
}
|
||||
if (!valueSplit.contains("locale")) {
|
||||
value += "|locale"
|
||||
}
|
||||
act.attributes()['android:configChanges'] = value
|
||||
}
|
||||
}
|
||||
|
||||
def tmpManifest = XmlUtil.serialize(manifest).replaceAll("androidconfigChanges", "android:configChanges")
|
||||
manifest = parser.parseText(tmpManifest)
|
||||
manifestFile.setText(XmlUtil.serialize(manifest), "utf-8")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
271
app/proguard-rules-legacy.txt
Normal file
271
app/proguard-rules-legacy.txt
Normal file
@ -0,0 +1,271 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in C:\Android\sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
#--------- remove logs start ----------------
|
||||
-assumenosideeffects class com.lightgame.config.CommonDebug {
|
||||
private static String getLogTag(...);
|
||||
private static String getMethodName();
|
||||
public static void logMethodName(...);
|
||||
public static void logParams(...);
|
||||
public static void logFields(...);
|
||||
public static void logMethodWithParams(...);
|
||||
}
|
||||
#-assumenosideeffects class com.lightgame.config.CommonDebug {*;}
|
||||
|
||||
#-dontoptimize
|
||||
#--------- remove logs end ----------------
|
||||
|
||||
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod
|
||||
-dontwarn InnerClasses
|
||||
|
||||
# OrmLite uses reflection
|
||||
-keep class com.j256.**
|
||||
-keepclassmembers class com.j256.** { *; }
|
||||
-keep enum com.j256.**
|
||||
-keepclassmembers enum com.j256.** { *; }
|
||||
-keep interface com.j256.**
|
||||
-keepclassmembers interface com.j256.** { *; }
|
||||
-dontwarn com.j256.**
|
||||
|
||||
#okhttp3
|
||||
-dontwarn com.squareup.okhttp3.**
|
||||
-dontwarn okio.**
|
||||
-keep class com.squareup.okhttp3.** { *;}
|
||||
|
||||
# stetho
|
||||
-keep class com.facebook.stetho.** { *; }
|
||||
-dontwarn com.facebook.stetho.**
|
||||
|
||||
# Retrofit 2.2
|
||||
# Platform calls Class.forName on types which do not exist on Android to determine platform.
|
||||
-dontnote retrofit2.Platform
|
||||
# Platform used when running on Java 8 VMs. Will not be used at runtime.
|
||||
-dontwarn retrofit2.Platform$Java8
|
||||
# Retain generic type information for use by reflection by converters and adapters.
|
||||
-keepattributes Signature
|
||||
# Retain declared checked exceptions for use by a Proxy instance.
|
||||
-keepattributes Exceptions
|
||||
|
||||
# Retrofit 2.X
|
||||
## https://square.github.io/retrofit/ ##
|
||||
|
||||
-dontwarn retrofit2.**
|
||||
-keep class retrofit2.** { *; }
|
||||
-keepattributes Signature
|
||||
-keepattributes Exceptions
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
@retrofit2.http.* <methods>;
|
||||
}
|
||||
|
||||
|
||||
# rxjava
|
||||
-keep class rx.schedulers.Schedulers {
|
||||
public static <methods>;
|
||||
}
|
||||
-keep class rx.schedulers.ImmediateScheduler {
|
||||
public <methods>;
|
||||
}
|
||||
-keep class rx.schedulers.TestScheduler {
|
||||
public <methods>;
|
||||
}
|
||||
-keep class rx.schedulers.Schedulers {
|
||||
public static ** test();
|
||||
}
|
||||
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
|
||||
long producerIndex;
|
||||
long consumerIndex;
|
||||
}
|
||||
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
|
||||
long producerNode;
|
||||
long consumerNode;
|
||||
}
|
||||
-dontwarn rx.internal.util.**
|
||||
|
||||
## AutoScrollViewPager
|
||||
-keep class cn.trinea.android.** { *; }
|
||||
-keepclassmembers class cn.trinea.android.** { *; }
|
||||
-dontwarn cn.trinea.android.**
|
||||
|
||||
## butterknife
|
||||
# Retain generated class which implement Unbinder.
|
||||
#-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
|
||||
#
|
||||
## Prevent obfuscation of types which use ButterKnife annotations since the simple name
|
||||
## is used to reflectively look up the generated ViewBinding.
|
||||
#-keep class butterknife.*
|
||||
#-keepclasseswithmembernames class * { @butterknife.* <methods>; }
|
||||
#-keepclasseswithmembernames class * { @butterknife.* <fields>; }
|
||||
|
||||
-dontwarn butterknife.internal.**
|
||||
-keep class **$$ViewInjector { *; }
|
||||
-keepnames class * { @butterknife.InjectView *;}
|
||||
-dontwarn butterknife.Views$InjectViewProcessor
|
||||
-dontwarn com.gc.materialdesign.views.**
|
||||
|
||||
# eventbus
|
||||
-keepattributes *Annotation*
|
||||
-keepclassmembers class ** {
|
||||
@org.greenrobot.eventbus.Subscribe <methods>;
|
||||
}
|
||||
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
|
||||
|
||||
# Only required if you use AsyncExecutor
|
||||
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
|
||||
<init>(java.lang.Throwable);
|
||||
}
|
||||
|
||||
# weiboSdk
|
||||
-keep class com.sina.weibo.sdk.** { *; }
|
||||
-dontwarn android.webkit.WebView
|
||||
-dontwarn android.webkit.WebViewClient
|
||||
|
||||
# app models
|
||||
-keep class com.gh.common.view.** {*;}
|
||||
-keep class com.gh.gamecenter.db.info.** {*;}
|
||||
-keep class com.gh.gamecenter.entity.** {*;}
|
||||
-keep class com.gh.gamecenter.qa.entity.** {*;}
|
||||
-keep class com.gh.gamecenter.retrofit.** {*;}
|
||||
-keep class com.gh.gamecenter.eventbus.** {*;}
|
||||
-keep class com.gh.gamecenter.video.detail.** {*;}
|
||||
-keep class * extends rx.Subscriber
|
||||
|
||||
#---------------------------------webview------------------------------------
|
||||
-keepclassmembers class * extends android.webkit.WebViewClient {
|
||||
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
|
||||
public boolean *(android.webkit.WebView, java.lang.String);
|
||||
}
|
||||
-keepclassmembers class * extends android.webkit.WebViewClient {
|
||||
public void *(android.webkit.WebView, java.lang.String);
|
||||
}
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
|
||||
##---------------Begin: proguard configuration for Gson ----------
|
||||
# Gson uses generic type information stored in a class file when working with fields. Proguard
|
||||
# removes such information by default, so configure it to keep all of it.
|
||||
-keepattributes Signature
|
||||
|
||||
# For using GSON @Expose annotation
|
||||
-keepattributes *Annotation*
|
||||
|
||||
# Gson specific classes
|
||||
-keep class sun.misc.Unsafe { *; }
|
||||
#-keep class com.google.gson.stream.** { *; }
|
||||
|
||||
# Prevent proguard from stripping interface information from TypeAdapterFactory,
|
||||
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
|
||||
-keep class * implements com.google.gson.TypeAdapterFactory
|
||||
-keep class * implements com.google.gson.JsonSerializer
|
||||
-keep class * implements com.google.gson.JsonDeserializer
|
||||
|
||||
-keepclassmembers enum * { *; }
|
||||
|
||||
##---------------End: proguard configuration for Gson ----------
|
||||
|
||||
# ------ bugly ---------
|
||||
-dontwarn com.tencent.bugly.**
|
||||
-keep public class com.tencent.bugly.**{*;}
|
||||
|
||||
# easypermission
|
||||
-keepclassmembers class * {
|
||||
@pub.devrel.easypermissions.AfterPermissionGranted <methods>;
|
||||
}
|
||||
|
||||
# 重命名文件为SourceFile,再配合mapping符号表,可以拿到真实的类名
|
||||
-renamesourcefileattribute SourceFile
|
||||
# 保留源文件行号
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
-ignorewarnings
|
||||
|
||||
-keep @androidx.annotation.Keep class *
|
||||
-keepclassmembers class ** {
|
||||
@androidx.annotation.Keep *;
|
||||
}
|
||||
|
||||
-keep class com.gh.loghub.** { *; }
|
||||
|
||||
### greenDAO 3
|
||||
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
|
||||
public static java.lang.String TABLENAME;
|
||||
}
|
||||
-keep class **$Properties
|
||||
-keep class org.greenrobot.greendao.** { *; }
|
||||
# If you do not use SQLCipher:
|
||||
-dontwarn org.greenrobot.greendao.database.**
|
||||
# If you do not use RxJava:
|
||||
-dontwarn rx.**
|
||||
-dontwarn org.greenrobot.greendao.rx.**
|
||||
-dontwarn org.greenrobot.greendao.**
|
||||
|
||||
### fastJson
|
||||
-dontwarn com.alibaba.fastjson.**
|
||||
-keep class com.alibaba.fastjson.** { *; }
|
||||
-keepattributes Signature
|
||||
-keepattributes Annotation
|
||||
|
||||
### 广点通
|
||||
-dontwarn com.qq.gdt.action.**
|
||||
-keep class com.qq.gdt.action.** {*;}
|
||||
|
||||
### AndroidX
|
||||
-keep class androidx.core.app.CoreComponentFactory { *; }
|
||||
|
||||
#阿里云上传
|
||||
-keep class com.alibaba.sdk.android.oss.** { *; }
|
||||
-dontwarn okio.**
|
||||
-dontwarn org.apache.commons.codec.binary.**
|
||||
|
||||
#视频相关
|
||||
-keep class com.shuyu.gsyvideoplayer.video.** { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.video.**
|
||||
-keep class com.shuyu.gsyvideoplayer.video.base.** { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.video.base.**
|
||||
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.utils.**
|
||||
-keep class tv.danmaku.ijk.** { *; }
|
||||
-dontwarn tv.danmaku.ijk.**
|
||||
-keep public class * extends android.view.View{
|
||||
*** get*();
|
||||
void set*(***);
|
||||
public <init>(android.content.Context);
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
#穿山甲
|
||||
-keep class com.bytedance.sdk.openadsdk.** { *; }
|
||||
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
|
||||
-keep class com.pgl.sys.ces.* {*;}
|
||||
|
||||
-keep class com.gyf.immersionbar.* {*;}
|
||||
-dontwarn com.gyf.immersionbar.**
|
||||
|
||||
-keep class com.taobao.securityjni.**{*;}
|
||||
-keep class com.taobao.wireless.security.**{*;}
|
||||
-keep class com.ut.secbody.**{*;}
|
||||
-keep class com.taobao.dp.**{*;}
|
||||
-keep class com.alibaba.wireless.security.**{*;}
|
||||
|
||||
-keep class com.alibaba.sdk.android.**{*;}
|
||||
-keep class com.ut.**{*;}
|
||||
-keep class com.ta.**{*;}
|
||||
|
||||
-keep class com.gh.gamecenter.GdtHelper { *; }
|
||||
-keep class com.gh.gamecenter.TeaHelper { *; }
|
||||
@ -1,20 +1,3 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in C:\Android\sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
#--------- remove logs start ----------------
|
||||
-assumenosideeffects class com.lightgame.config.CommonDebug {
|
||||
@ -26,126 +9,62 @@
|
||||
public static void logMethodWithParams(...);
|
||||
}
|
||||
|
||||
#-assumenosideeffects class com.lightgame.config.CommonDebug {*;}
|
||||
|
||||
#-dontoptimize
|
||||
-assumenosideeffects class com.lightgame.utils.Utils {
|
||||
public static void log(...);
|
||||
}
|
||||
#--------- remove logs end ----------------
|
||||
|
||||
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod
|
||||
-dontwarn InnerClasses
|
||||
# TODO Dicard sourceFile in final release build but remain in internal build.
|
||||
-renamesourcefileattribute SourceFile
|
||||
# Keep Attribute
|
||||
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod,SourceFile,LineNumberTable
|
||||
|
||||
# OrmLite uses reflection
|
||||
-keep class com.j256.**
|
||||
-keepclassmembers class com.j256.** { *; }
|
||||
-keep enum com.j256.**
|
||||
-keepclassmembers enum com.j256.** { *; }
|
||||
-keep interface com.j256.**
|
||||
-keepclassmembers interface com.j256.** { *; }
|
||||
# OrmLite
|
||||
-keep class com.j256.*
|
||||
-keepclassmembers class com.j256.* { *; }
|
||||
-keep enum com.j256.*
|
||||
-keepclassmembers enum com.j256.* { *; }
|
||||
-keep interface com.j256.*
|
||||
-keepclassmembers interface com.j256.* { *; }
|
||||
-dontwarn com.j256.**
|
||||
|
||||
#okhttp3
|
||||
-dontwarn com.squareup.okhttp3.**
|
||||
-dontwarn okio.**
|
||||
-keep class com.squareup.okhttp3.** { *;}
|
||||
|
||||
# stetho
|
||||
-keep class com.facebook.stetho.** { *; }
|
||||
-dontwarn com.facebook.stetho.**
|
||||
|
||||
# Retrofit 2.2
|
||||
# Platform calls Class.forName on types which do not exist on Android to determine platform.
|
||||
-dontnote retrofit2.Platform
|
||||
# Platform used when running on Java 8 VMs. Will not be used at runtime.
|
||||
-dontwarn retrofit2.Platform$Java8
|
||||
# Retain generic type information for use by reflection by converters and adapters.
|
||||
-keepattributes Signature
|
||||
# Retain declared checked exceptions for use by a Proxy instance.
|
||||
-keepattributes Exceptions
|
||||
|
||||
# Retrofit 2.X
|
||||
## https://square.github.io/retrofit/ ##
|
||||
|
||||
-dontwarn retrofit2.**
|
||||
-keep class retrofit2.** { *; }
|
||||
-keepattributes Signature
|
||||
-keepattributes Exceptions
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
@retrofit2.http.* <methods>;
|
||||
}
|
||||
|
||||
|
||||
# rxjava
|
||||
-keep class rx.schedulers.Schedulers {
|
||||
public static <methods>;
|
||||
}
|
||||
-keep class rx.schedulers.ImmediateScheduler {
|
||||
public <methods>;
|
||||
}
|
||||
-keep class rx.schedulers.TestScheduler {
|
||||
public <methods>;
|
||||
}
|
||||
-keep class rx.schedulers.Schedulers {
|
||||
public static ** test();
|
||||
}
|
||||
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
|
||||
long producerIndex;
|
||||
long consumerIndex;
|
||||
}
|
||||
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
|
||||
long producerNode;
|
||||
long consumerNode;
|
||||
}
|
||||
-dontwarn rx.internal.util.**
|
||||
|
||||
## AutoScrollViewPager
|
||||
-keep class cn.trinea.android.** { *; }
|
||||
-keepclassmembers class cn.trinea.android.** { *; }
|
||||
### AutoScrollViewPager
|
||||
-keep class cn.trinea.android.* { *; }
|
||||
-keepclassmembers class cn.trinea.android.* { *; }
|
||||
-dontwarn cn.trinea.android.**
|
||||
|
||||
## butterknife
|
||||
# Retain generated class which implement Unbinder.
|
||||
#-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
|
||||
#
|
||||
## Prevent obfuscation of types which use ButterKnife annotations since the simple name
|
||||
## is used to reflectively look up the generated ViewBinding.
|
||||
#-keep class butterknife.*
|
||||
#-keepclasseswithmembernames class * { @butterknife.* <methods>; }
|
||||
#-keepclasseswithmembernames class * { @butterknife.* <fields>; }
|
||||
### Butterknife
|
||||
-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
|
||||
-keep class butterknife.*
|
||||
-keepclasseswithmembernames class * { @butterknife.* <methods>; }
|
||||
-keepclasseswithmembernames class * { @butterknife.* <fields>; }
|
||||
|
||||
-dontwarn butterknife.internal.**
|
||||
-keep class **$$ViewInjector { *; }
|
||||
-keepnames class * { @butterknife.InjectView *;}
|
||||
-dontwarn butterknife.Views$InjectViewProcessor
|
||||
-dontwarn com.gc.materialdesign.views.**
|
||||
|
||||
# eventbus
|
||||
-keepattributes *Annotation*
|
||||
-keepclassmembers class ** {
|
||||
### eventbus
|
||||
-keepclassmembers class * {
|
||||
@org.greenrobot.eventbus.Subscribe <methods>;
|
||||
}
|
||||
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
|
||||
|
||||
# Only required if you use AsyncExecutor
|
||||
### Only required if you use AsyncExecutor
|
||||
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
|
||||
<init>(java.lang.Throwable);
|
||||
}
|
||||
|
||||
# weiboSdk
|
||||
-keep class com.sina.weibo.sdk.** { *; }
|
||||
### weiboSdk
|
||||
-keep class com.sina.weibo.sdk.* { *; }
|
||||
-dontwarn android.webkit.WebView
|
||||
-dontwarn android.webkit.WebViewClient
|
||||
|
||||
# app models
|
||||
-keep class com.gh.common.view.** {*;}
|
||||
-keep class com.gh.gamecenter.db.info.** {*;}
|
||||
-keep class com.gh.gamecenter.entity.** {*;}
|
||||
-keep class com.gh.gamecenter.qa.entity.** {*;}
|
||||
-keep class com.gh.gamecenter.retrofit.** {*;}
|
||||
-keep class com.gh.gamecenter.eventbus.** {*;}
|
||||
-keep class * extends rx.Subscriber
|
||||
### app models
|
||||
-keep class com.gh.common.view.* {*;}
|
||||
-keep class com.gh.gamecenter.db.info.* {*;}
|
||||
-keep class com.gh.gamecenter.entity.* {*;}
|
||||
-keep class com.gh.gamecenter.qa.entity.* {*;}
|
||||
-keep class com.gh.gamecenter.retrofit.* {*;}
|
||||
-keep class com.gh.gamecenter.eventbus.* {*;}
|
||||
-keep class com.gh.gamecenter.video.detail.* {*;}
|
||||
|
||||
#---------------------------------webview------------------------------------
|
||||
###
|
||||
-keepclassmembers class * extends android.webkit.WebViewClient {
|
||||
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
|
||||
public boolean *(android.webkit.WebView, java.lang.String);
|
||||
@ -153,109 +72,67 @@
|
||||
-keepclassmembers class * extends android.webkit.WebViewClient {
|
||||
public void *(android.webkit.WebView, java.lang.String);
|
||||
}
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
|
||||
##---------------Begin: proguard configuration for Gson ----------
|
||||
# Gson uses generic type information stored in a class file when working with fields. Proguard
|
||||
# removes such information by default, so configure it to keep all of it.
|
||||
-keepattributes Signature
|
||||
|
||||
# For using GSON @Expose annotation
|
||||
-keepattributes *Annotation*
|
||||
|
||||
# Gson specific classes
|
||||
-keep class sun.misc.Unsafe { *; }
|
||||
#-keep class com.google.gson.stream.** { *; }
|
||||
|
||||
# Prevent proguard from stripping interface information from TypeAdapterFactory,
|
||||
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
|
||||
-keep class * implements com.google.gson.TypeAdapterFactory
|
||||
-keep class * implements com.google.gson.JsonSerializer
|
||||
-keep class * implements com.google.gson.JsonDeserializer
|
||||
|
||||
-keepclassmembers enum * { *; }
|
||||
|
||||
##---------------End: proguard configuration for Gson ----------
|
||||
|
||||
# ------ bugly ---------
|
||||
-dontwarn com.tencent.bugly.**
|
||||
-keep public class com.tencent.bugly.**{*;}
|
||||
|
||||
# easypermission
|
||||
### easypermission
|
||||
-keepclassmembers class * {
|
||||
@pub.devrel.easypermissions.AfterPermissionGranted <methods>;
|
||||
}
|
||||
|
||||
# 重命名文件为SourceFile,再配合mapping符号表,可以拿到真实的类名
|
||||
-renamesourcefileattribute SourceFile
|
||||
# 保留源文件行号
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# TODO What's this ?
|
||||
-ignorewarnings
|
||||
|
||||
### Keep Annotation
|
||||
-keep @androidx.annotation.Keep class *
|
||||
-keepclassmembers class ** {
|
||||
-keepclassmembers class * {
|
||||
@androidx.annotation.Keep *;
|
||||
}
|
||||
|
||||
-keep class com.gh.loghub.** { *; }
|
||||
### LoghubHelper
|
||||
-keep class com.gh.loghub.* { *; }
|
||||
|
||||
### greenDAO 3
|
||||
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
|
||||
public static java.lang.String TABLENAME;
|
||||
}
|
||||
-keep class **$Properties
|
||||
-keep class org.greenrobot.greendao.** { *; }
|
||||
-keep class **$Properties { *; }
|
||||
-keep class org.greenrobot.greendao.* { *; }
|
||||
# If you do not use SQLCipher:
|
||||
-dontwarn org.greenrobot.greendao.database.**
|
||||
# If you do not use RxJava:
|
||||
-dontwarn rx.**
|
||||
-dontwarn org.greenrobot.greendao.rx.**
|
||||
-dontwarn org.greenrobot.greendao.**
|
||||
|
||||
### fastJson
|
||||
-dontwarn com.alibaba.fastjson.**
|
||||
-keep class com.alibaba.fastjson.** { *; }
|
||||
-keepattributes Signature
|
||||
-keepattributes Annotation
|
||||
-keep class com.alibaba.fastjson.* { *; }
|
||||
|
||||
### 广点通
|
||||
-dontwarn com.qq.gdt.action.**
|
||||
-keep class com.qq.gdt.action.** {*;}
|
||||
-keep class com.qq.gdt.action.* {*;}
|
||||
|
||||
### AndroidX
|
||||
-keep class androidx.core.app.CoreComponentFactory { *; }
|
||||
|
||||
#阿里云上传
|
||||
-keep class com.alibaba.sdk.android.oss.** { *; }
|
||||
### 阿里云上传
|
||||
-keep class com.alibaba.sdk.android.oss.* { *; }
|
||||
-dontwarn okio.**
|
||||
-dontwarn org.apache.commons.codec.binary.**
|
||||
|
||||
#视频相关
|
||||
-keep class com.shuyu.gsyvideoplayer.video.** { *; }
|
||||
### 视频相关
|
||||
-keep class com.shuyu.gsyvideoplayer.video.* { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.video.**
|
||||
-keep class com.shuyu.gsyvideoplayer.video.base.** { *; }
|
||||
-keep class com.shuyu.gsyvideoplayer.video.base.* { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.video.base.**
|
||||
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
|
||||
-keep class com.shuyu.gsyvideoplayer.utils.* { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.utils.**
|
||||
-keep class tv.danmaku.ijk.** { *; }
|
||||
-keep class tv.danmaku.ijk.* { *; }
|
||||
-dontwarn tv.danmaku.ijk.**
|
||||
-keep public class * extends android.view.View{
|
||||
*** get*();
|
||||
void set*(***);
|
||||
public <init>(android.content.Context);
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
#穿山甲
|
||||
-keep class com.bytedance.sdk.openadsdk.** { *; }
|
||||
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
|
||||
-keep class com.pgl.sys.ces.* {*;}
|
||||
-keep class com.alibaba.sdk.android.*{*;}
|
||||
-keep class com.ut.*{*;}
|
||||
-keep class com.ta.*{*;}
|
||||
|
||||
-keep class com.gyf.immersionbar.* {*;}
|
||||
-dontwarn com.gyf.immersionbar.**
|
||||
|
||||
-keep class com.taobao.securityjni.**{*;}
|
||||
-keep class com.taobao.wireless.security.**{*;}
|
||||
-keep class com.ut.secbody.**{*;}
|
||||
-keep class com.taobao.dp.**{*;}
|
||||
-keep class com.alibaba.wireless.security.**{*;}
|
||||
|
||||
-keep class com.alibaba.sdk.android.**{*;}
|
||||
-keep class com.ut.**{*;}
|
||||
-keep class com.ta.**{*;}
|
||||
### GDT & TEA
|
||||
-keep class com.gh.gamecenter.GdtHelper { *; }
|
||||
-keep class com.gh.gamecenter.TeaHelper { *; }
|
||||
77
app/src/gdt/java/com/gh/gamecenter/GdtHelper.kt
Normal file
77
app/src/gdt/java/com/gh/gamecenter/GdtHelper.kt
Normal file
@ -0,0 +1,77 @@
|
||||
package com.gh.gamecenter
|
||||
|
||||
import android.app.Application
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import com.gh.common.util.ToastUtils
|
||||
import com.lightgame.utils.Utils
|
||||
import com.qq.gdt.action.GDTAction
|
||||
import org.json.JSONObject
|
||||
|
||||
/**
|
||||
* 广点通辅助类 [https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/403]
|
||||
*
|
||||
* 更换帐号 [https://gitlab.ghzs.com/pm/yunying/issues/893]
|
||||
*/
|
||||
object GdtHelper {
|
||||
|
||||
const val NETWORK_TYPE = "NETWORK_TYPE"
|
||||
const val PAGE_TYPE = "PAGE_TYPE"
|
||||
const val CONTENT_TYPE = "CONTENT_TYPE"
|
||||
const val CONTENT_ID = "CONTENT_ID"
|
||||
const val KEYWORD = "KEYWORD"
|
||||
const val GAME_ID = "GAME_ID"
|
||||
const val SCORE = "SCORE"
|
||||
const val PLATFORM = "PLATFORM"
|
||||
|
||||
@JvmStatic
|
||||
fun init(application: Application, channel: String) {
|
||||
if (shouldUseGdtHelper()) {
|
||||
if (channel == "GH_728") {
|
||||
GDTAction.init(application, "1111012969", "9d3d9da5b0948a317c03d08f14d445dc")
|
||||
} else if (channel == "GH_729") {
|
||||
GDTAction.init(application, "1111013063", "f53dabf458a356b101d99fc4069eb7f1")
|
||||
} else if (channel == "GH_765") {
|
||||
GDTAction.init(application, "1111327925", "588d503f0990f98f9b2394fbb795c570")
|
||||
} else {
|
||||
GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a")
|
||||
}
|
||||
}
|
||||
Utils.log("init GdtHelper")
|
||||
}
|
||||
|
||||
// fun logAction(type: String) {
|
||||
// if (shouldUseGdtHelper()) {
|
||||
// GDTAction.logAction(type)
|
||||
// Utils.log("GDT", type)
|
||||
// }
|
||||
// }
|
||||
@JvmStatic
|
||||
fun logAction(type: String, vararg kv: String?) {
|
||||
try {
|
||||
val actionParam = JSONObject()
|
||||
for (i in kv.indices) {
|
||||
if (i % 2 != 0) {
|
||||
val key = kv[i - 1]
|
||||
val value = kv[i]
|
||||
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
||||
actionParam.put(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]")
|
||||
GDTAction.logAction(type, actionParam)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 确认开启的渠道条件
|
||||
private fun shouldUseGdtHelper(): Boolean {
|
||||
return true
|
||||
//
|
||||
// val channel = HaloApp.getInstance().channel
|
||||
// return !(TextUtils.isEmpty(channel) || channel.contains("GDT".toLowerCase(Locale.CHINA)))
|
||||
}
|
||||
|
||||
}
|
||||
BIN
app/src/gdt/libs/GDTActionSDK.min.1.6.10.aar
Normal file
BIN
app/src/gdt/libs/GDTActionSDK.min.1.6.10.aar
Normal file
Binary file not shown.
@ -9,8 +9,6 @@
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<!-- 允许应用程序读取扩展存储器 -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<!-- 允许挂载和反挂载文件系统可移动存储 -->
|
||||
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
|
||||
<!-- 允许应用程序访问Wi-Fi网络状态信息 -->
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<!-- 允许应用程序获取网络信息状态 -->
|
||||
@ -25,17 +23,19 @@
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<!-- 允许应用程序打开系统窗口,显示其他应用程序 -->
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<!-- 修改系统设置的权限 -->
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
<!-- 创建快捷方式的权限 -->
|
||||
<!-- 允许应用程序快捷方式 -->
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
<!-- 允许应用程序读取日历-->
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR"/>
|
||||
<!-- 允许应用程序写入日历-->
|
||||
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.PACKAGE_USAGE_STATS"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
|
||||
<!-- bugly with tinker -->
|
||||
<uses-permission android:name="android.permission.READ_LOGS" />
|
||||
<!-- <uses-permission android:name="android.permission.READ_LOGS" />-->
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<!--可选,穿山甲提供“获取地理位置权限”和“不给予地理位置权限,开发者传入地理位置参数”两种方式上报用户位置,两种方式均可不选,添加位置权限或参数将帮助投放定位广告-->
|
||||
@ -79,6 +79,10 @@
|
||||
tools:replace="android:allowBackup"
|
||||
tools:targetApi="n">
|
||||
|
||||
<meta-data
|
||||
android:name="io.sentry.auto-init"
|
||||
android:value="false" />
|
||||
|
||||
<!--android:launchMode = "singleTask"-->
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SplashScreenActivity"
|
||||
@ -462,7 +466,7 @@
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.video.upload.view.UploadVideoActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateHidden"/>
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.video.game.GameVideoActivity"
|
||||
@ -577,7 +581,7 @@
|
||||
<activity
|
||||
android:name=".personalhome.background.BackgroundClipActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar"/>
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar" />
|
||||
|
||||
<activity
|
||||
android:name=".personalhome.excellentcomments.ExcellentCommentsActivity"
|
||||
@ -591,12 +595,44 @@
|
||||
android:name=".simulatorgame.SimulatorManagementActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.PushProxyActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@android:style/Theme.Translucent" />
|
||||
android:name=".catalog.CatalogActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".catalog.NewCatalogListActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.search.ForumOrUserSearchActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".energy.EnergyCenterActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".energy.EnergyHouseActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".personal.NewPersonalActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.questions.draft.QuestionDraftActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".home.skip.PackageSkipActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- <!– 使用小米/华为推送弹窗功能提高推送成功率–>-->
|
||||
<!-- <activity-->
|
||||
<!-- android:name="com.gh.gamecenter.PushProxyActivity"-->
|
||||
<!-- android:exported="true"-->
|
||||
<!-- android:launchMode="singleTask"-->
|
||||
<!-- android:theme="@android:style/Theme.Translucent" />-->
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SkipActivity"
|
||||
@ -608,6 +644,14 @@
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<data android:scheme="market" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
@ -618,11 +662,11 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity>
|
||||
|
||||
<!-- <activity-->
|
||||
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
|
||||
<!-- android:launchMode="singleTask"-->
|
||||
<!-- android:taskAffinity="${applicationId}"-->
|
||||
<!-- android:exported="true" />-->
|
||||
<!-- <activity-->
|
||||
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
|
||||
<!-- android:launchMode="singleTask"-->
|
||||
<!-- android:taskAffinity="${applicationId}"-->
|
||||
<!-- android:exported="true" />-->
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
@ -657,45 +701,45 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMessageReceiver">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="com.gh.gamecenter.UMENG" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMessageReceiver">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="com.gh.gamecenter.UMENG" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
|
||||
<!-- <!–魅族push应用定义消息receiver声明 –>-->
|
||||
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMeizuPushReceiver">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <!– 接收push消息 –>-->
|
||||
<!-- <action android:name="com.meizu.flyme.push.intent.MESSAGE" />-->
|
||||
<!-- <!– 接收register消息 –>-->
|
||||
<!-- <action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />-->
|
||||
<!-- <!– 接收unregister消息–>-->
|
||||
<!-- <action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />-->
|
||||
<!-- <!– 兼容低版本Flyme3推送服务配置 –>-->
|
||||
<!-- <action android:name="com.meizu.c2dm.intent.REGISTRATION" />-->
|
||||
<!-- <action android:name="com.meizu.c2dm.intent.RECEIVE" />-->
|
||||
<!-- <!–魅族push应用定义消息receiver声明 –>-->
|
||||
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMeizuPushReceiver">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <!– 接收push消息 –>-->
|
||||
<!-- <action android:name="com.meizu.flyme.push.intent.MESSAGE" />-->
|
||||
<!-- <!– 接收register消息 –>-->
|
||||
<!-- <action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />-->
|
||||
<!-- <!– 接收unregister消息–>-->
|
||||
<!-- <action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />-->
|
||||
<!-- <!– 兼容低版本Flyme3推送服务配置 –>-->
|
||||
<!-- <action android:name="com.meizu.c2dm.intent.REGISTRATION" />-->
|
||||
<!-- <action android:name="com.meizu.c2dm.intent.RECEIVE" />-->
|
||||
|
||||
<!-- <category android:name="${applicationId}" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
<!-- <category android:name="${applicationId}" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
|
||||
<!-- <receiver-->
|
||||
<!-- android:name="com.gh.common.im.ImReceiver"-->
|
||||
<!-- android:enabled="true">-->
|
||||
<!-- <intent-filter android:priority="2147483647">-->
|
||||
<!-- <action android:name="com.gh.im" />-->
|
||||
<!-- <action android:name="action_finish" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
<!-- <receiver-->
|
||||
<!-- android:name="com.gh.common.im.ImReceiver"-->
|
||||
<!-- android:enabled="true">-->
|
||||
<!-- <intent-filter android:priority="2147483647">-->
|
||||
<!-- <action android:name="com.gh.im" />-->
|
||||
<!-- <action android:name="action_finish" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
|
||||
<!-- <meta-data-->
|
||||
<!-- android:name="com.huawei.hms.client.appid"-->
|
||||
<!-- android:value="@string/huawei_push_appid" />-->
|
||||
<!-- <meta-data-->
|
||||
<!-- android:name="com.huawei.hms.client.appid"-->
|
||||
<!-- android:value="@string/huawei_push_appid" />-->
|
||||
|
||||
<!-- <service-->
|
||||
<!-- android:name="com.gh.base.GHUmengNotificationService"-->
|
||||
<!-- android:permission="android.permission.BIND_JOB_SERVICE" />-->
|
||||
<!-- <service-->
|
||||
<!-- android:name="com.gh.base.GHUmengNotificationService"-->
|
||||
<!-- android:permission="android.permission.BIND_JOB_SERVICE" />-->
|
||||
|
||||
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->
|
||||
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
emoji_kf_1.png,:smile:
|
||||
emoji_kf_2.png,:smiley:
|
||||
emoji_kf_3.png,:laughing:
|
||||
emoji_kf_4.png,:blush:
|
||||
emoji_kf_5.png,:heart_eyes:
|
||||
emoji_kf_6.png,:smirk:
|
||||
emoji_kf_7.png,:flushed:
|
||||
emoji_kf_8.png,:kissing_heart:
|
||||
emoji_kf_9.png,:grin:
|
||||
emoji_kf_10.png,:wink:
|
||||
emoji_kf_11.png,:stuck_out_tongue_winking_eye:
|
||||
emoji_kf_12.png,:stuck_out_tongue_closed eyes:
|
||||
emoji_kf_13.png,:worried:
|
||||
emoji_kf_14.png,:sleeping:
|
||||
emoji_kf_15.png,:expressionless:
|
||||
emoji_kf_16.png,:sweat_smile:
|
||||
emoji_kf_17.png,:joy:
|
||||
emoji_kf_18.png,:cold_sweat:
|
||||
emoji_kf_19.png,:sob:
|
||||
emoji_kf_20.png,:angry:
|
||||
emoji_kf_21.png,:mask:
|
||||
emoji_kf_22.png,:scream:
|
||||
emoji_kf_23.png,:sunglasses:
|
||||
emoji_kf_24.png,:heart:
|
||||
emoji_kf_25.png,:broken_heart:
|
||||
emoji_kf_26.png,:star:
|
||||
emoji_kf_27.png,:anger:
|
||||
emoji_kf_28.png,:exclamation:
|
||||
emoji_kf_29.png,:question:
|
||||
emoji_kf_30.png,:zzz:
|
||||
emoji_kf_31.png,:thumbsup:
|
||||
emoji_kf_32.png,:thumbsdown:
|
||||
emoji_kf_33.png,:ok_hand:
|
||||
emoji_kf_34.png,:punch:
|
||||
emoji_kf_35.png,:yeah:
|
||||
emoji_kf_36.png,:clap:
|
||||
emoji_kf_37.png,:muscle:
|
||||
emoji_kf_38.png,:pray:
|
||||
emoji_kf_39.png,:skull:
|
||||
emoji_kf_40.png,:trollface:
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@ -1,5 +0,0 @@
|
||||
# This is a simple Microlog configuration file
|
||||
microlog.level=DEBUG
|
||||
microlog.appender=LogCatAppender;FileAppender
|
||||
microlog.formatter=PatternFormatter
|
||||
microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
|
||||
@ -25,6 +25,9 @@ import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import io.sentry.Sentry;
|
||||
|
||||
public class AppUncaughtHandler implements UncaughtExceptionHandler {
|
||||
|
||||
@ -36,17 +39,21 @@ public class AppUncaughtHandler implements UncaughtExceptionHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable ex) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
if (("FinalizerWatchdogDaemon").equals(t.getName())
|
||||
&& e instanceof TimeoutException) {
|
||||
// ignore timeoutException
|
||||
// detail can be found in this didi tech blog post https://mp.weixin.qq.com/s?__biz=MzU1ODEzNjI2NA==&mid=2247487185&idx=2&sn=cf2d9e10053f625bde0f61d246f14870&source=41#wechat_redirect
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
Looper.prepare();
|
||||
Utils.toast(mContext.getApplicationContext(), "\"光环助手\"发生错误");
|
||||
Looper.loop();
|
||||
}
|
||||
});
|
||||
saveLocalLog(mContext, ex);
|
||||
restart(mContext);
|
||||
});
|
||||
saveLocalLog(mContext, e);
|
||||
restart(mContext);
|
||||
Sentry.captureException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void restart(final Context context) {
|
||||
|
||||
@ -8,6 +8,8 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Parcel;
|
||||
import android.os.TransactionTooLargeException;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
@ -32,13 +34,18 @@ import com.gh.common.util.ExtensionsKt;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.RunningUtils;
|
||||
import com.gh.common.util.SPUtils;
|
||||
import com.gh.common.util.ShareUtils;
|
||||
import com.gh.common.util.StringUtils;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.LoginActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.gh.gamecenter.eventbus.EBShowDialog;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.BaseAppCompatActivity;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.tencent.tauth.Tencent;
|
||||
@ -68,6 +75,8 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
public final static String DOWNLOAD_HIJACK = "hijack";
|
||||
public final static String LOGIN_EXCEPTION = "loginException";
|
||||
public final static String PLUGGABLE = "plugin";
|
||||
public final static int ID_ROOT_INDICATOR = 999;
|
||||
public final int MAX_BUNDLE_SIZE = 300;
|
||||
|
||||
@NonNull
|
||||
protected String mEntrance;
|
||||
@ -112,6 +121,7 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (useEventBus()) EventBus.getDefault().register(this);
|
||||
if (useButterKnife()) ButterKnife.bind(this);
|
||||
mEntrance = getIntent().getStringExtra(KEY_ENTRANCE);
|
||||
@ -122,6 +132,23 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("ACTIVITY_ENTRANCE -> " + mEntrance);
|
||||
}
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
String xapkUnzipActivity = SPUtils.getString(Constants.SP_XAPK_UNZIP_ACTIVITY);
|
||||
String xapkUrl = SPUtils.getString(Constants.SP_XAPK_URL);
|
||||
Utils.log("页面重建了--" + xapkUnzipActivity + "--" + xapkUrl);
|
||||
if (this.getClass().getName().equals(SplashScreenActivity.class.getName())) {
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, "");
|
||||
return;
|
||||
}
|
||||
if (this.getClass().getName().equals(xapkUnzipActivity) && !TextUtils.isEmpty(xapkUrl)) {
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance(this).getDownloadEntityByUrl(xapkUrl);
|
||||
PackageInstaller.install(this, downloadEntity, false);
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@ -185,6 +212,7 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
|
||||
tv.measure(0, 0);
|
||||
tv.setAlpha(0.15F);
|
||||
tv.setId(ID_ROOT_INDICATOR);
|
||||
int height = tv.getMeasuredHeight();
|
||||
int width = tv.getMeasuredWidth();
|
||||
tv.setPadding(DisplayUtils.dip2px(20), 0, DisplayUtils.dip2px(20), 0);
|
||||
@ -338,4 +366,30 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ActivityThread每次调用onSaveInstanceState时outState大小都会累加,最终会导致{@link TransactionTooLargeException}异常
|
||||
* 解决方案:判断每次获取到的outState大小,当达到300k时手动clear掉
|
||||
*/
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
long bundleSize = getBundleSize(outState);
|
||||
if (bundleSize > MAX_BUNDLE_SIZE * 1024) {
|
||||
outState.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private long getBundleSize(Bundle bundle) {
|
||||
long dataSize;
|
||||
Parcel obtain = Parcel.obtain();
|
||||
try {
|
||||
obtain.writeBundle(bundle);
|
||||
dataSize = obtain.dataSize();
|
||||
} finally {
|
||||
obtain.recycle();
|
||||
}
|
||||
return dataSize;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,15 +9,18 @@ import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import butterknife.OnClick
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.view.RichEditor
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.MyVideoEntity
|
||||
import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity
|
||||
import com.gh.gamecenter.qa.article.edit.ArticleEditActivity
|
||||
import com.gh.gamecenter.qa.editor.GameActivity
|
||||
import com.gh.gamecenter.qa.editor.InsertAnswerWrapperActivity
|
||||
import com.gh.gamecenter.qa.editor.InsertArticleWrapperActivity
|
||||
@ -26,6 +29,7 @@ import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.qa.entity.ArticleEntity
|
||||
import com.gh.gamecenter.qa.entity.EditorInsertEntity
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Util_System_Keyboard
|
||||
import com.lightgame.utils.Utils
|
||||
import com.lightgame.view.CheckableImageView
|
||||
import kotterknife.bindView
|
||||
@ -33,15 +37,15 @@ import kotterknife.bindView
|
||||
abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
|
||||
val mRichEditor by bindView<RichEditor>(R.id.rich_editor)
|
||||
val mDraftBtn by bindView<TextView>(R.id.draft_btn)
|
||||
|
||||
private val mEditorTextNumTv by bindView<TextView>(R.id.editorTextNumTv)
|
||||
private val mEditorFont by bindView<CheckableImageView>(R.id.editor_font)
|
||||
private val mEditorLink by bindView<CheckableImageView>(R.id.editor_link)
|
||||
private val mEditorParagraph by bindView<CheckableImageView>(R.id.editor_paragraph)
|
||||
|
||||
private val mEditorFontBold by bindView<CheckableImageView>(R.id.editor_font_bold)
|
||||
private val mEditorFontItalic by bindView<CheckableImageView>(R.id.editor_font_italic)
|
||||
private val mEditorFontStrikeThrough by bindView<CheckableImageView>(R.id.editor_font_strikethrough)
|
||||
private val mEditorFontUnderline by bindView<CheckableImageView>(R.id.editor_font_underline)
|
||||
private val mEditorParagraphH1 by bindView<CheckableImageView>(R.id.editor_paragraph_h1)
|
||||
private val mEditorParagraphH2 by bindView<CheckableImageView>(R.id.editor_paragraph_h2)
|
||||
private val mEditorParagraphH3 by bindView<CheckableImageView>(R.id.editor_paragraph_h3)
|
||||
@ -50,9 +54,15 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
private val mEditorFontContainer by bindView<View>(R.id.editor_font_container)
|
||||
private val mEditorParagraphContainer by bindView<View>(R.id.editor_paragraph_container)
|
||||
private val mEditorLinkContainer by bindView<View>(R.id.editor_link_container)
|
||||
private val mEditorInsertDetail by bindView<View>(R.id.editor_insert_detail)
|
||||
private val mEditorInsertDetailContainer by bindView<View>(R.id.editor_insert_detail_container)
|
||||
val mAddLabelContainer by bindView<View>(R.id.add_label_container)
|
||||
val mAddLabelTv by bindView<TextView>(R.id.add_label_tv)
|
||||
val mLabelNumTv by bindView<TextView>(R.id.label_num_tv)
|
||||
val mLabelArrowIv by bindView<ImageView>(R.id.label_arrow)
|
||||
val mTagsContainer by bindView<FrameLayout>(R.id.tagsContainer)
|
||||
|
||||
private var mCurrentParagraphStyle = ""
|
||||
private var mIsExtendedKeyboardShow = false
|
||||
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
@ -63,29 +73,50 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
when (requestCode) {
|
||||
INSERT_ANSWER_CODE -> {
|
||||
val answer = data?.getParcelableExtra<AnswerEntity>(AnswerEntity::class.java.simpleName)
|
||||
if (answer != null) insertData = EditorInsertEntity.transform(answer)
|
||||
if (answer != null) {
|
||||
mRichEditor.focusEditor()
|
||||
insertData = EditorInsertEntity.transform(answer)
|
||||
mRichEditor.insertCustomStyleLink(insertData)
|
||||
}
|
||||
}
|
||||
INSERT_ARTICLE_CODE -> {
|
||||
val article = data?.getParcelableExtra<ArticleEntity>(ArticleEntity::class.java.simpleName)
|
||||
if (article != null) insertData = EditorInsertEntity.transform(article)
|
||||
if (article != null) {
|
||||
mRichEditor.focusEditor()
|
||||
insertData = EditorInsertEntity.transform(article)
|
||||
mRichEditor.insertCustomStyleLink(insertData)
|
||||
}
|
||||
}
|
||||
INSERT_GAME_CODE -> {
|
||||
val game = data?.getParcelableExtra<GameEntity>(GameEntity::class.java.simpleName)
|
||||
if (game != null) insertData = EditorInsertEntity.transform(game)
|
||||
if (game != null) {
|
||||
mRichEditor.focusEditor()
|
||||
insertData = EditorInsertEntity.transform(game)
|
||||
mRichEditor.insertCustomStyleLink(insertData)
|
||||
}
|
||||
}
|
||||
VideoActivity.INSERT_VIDEO_CODE -> {
|
||||
val video = data?.getParcelableExtra<MyVideoEntity>(MyVideoEntity::class.java.simpleName)
|
||||
if (video != null) mRichEditor.insertCustomVideo(video)
|
||||
return
|
||||
if (video != null) {
|
||||
mRichEditor.focusEditor()
|
||||
mRichEditor.insertCustomVideo(video)
|
||||
}
|
||||
}
|
||||
}
|
||||
closeExtendedKeyboard()
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable {
|
||||
Util_System_Keyboard.showSoftKeyboard(this)
|
||||
}, 100)
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable {
|
||||
mRichEditor.scrollTo(0, 1000000)
|
||||
}, 500)
|
||||
|
||||
mRichEditor.insertCustomStyleLink(insertData)
|
||||
}
|
||||
|
||||
@SuppressLint("AddJavascriptInterface")
|
||||
@SuppressLint("AddJavascriptInterface", "ClickableViewAccessibility")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mAddLabelContainer.visibility = if (this is ArticleEditActivity) View.VISIBLE else View.GONE
|
||||
mRichEditor.setPadding(20, 15, 20, 15)
|
||||
// 防止个别手机在Js里无法获取粘贴内容
|
||||
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
|
||||
@ -93,12 +124,59 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
mRichEditor.addJavascriptInterface(OnEditorTextChangeListener(), "OnEditorTextChangeListener")
|
||||
mRichEditor.setInputEnabled(true)
|
||||
|
||||
mDraftBtn.text = if (this is AnswerEditActivity) {
|
||||
"回答草稿"
|
||||
} else "帖子草稿"
|
||||
mRichEditor.setOnTouchListener { _, _ ->
|
||||
if (mIsExtendedKeyboardShow) {
|
||||
closeExtendedKeyboard()
|
||||
Util_System_Keyboard.showSoftKeyboard(this)
|
||||
//是否消费事件根据mRichEditor是否含有焦点决定,mRichEditor没有焦点则不消费事件
|
||||
mRichEditor.hasFocus()
|
||||
} else false
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.editor_paragraph,
|
||||
|
||||
fun closeExtendedKeyboard() {
|
||||
mEditorInsertDetailContainer.visibility = View.GONE
|
||||
mEditorFont.isChecked = false
|
||||
mEditorLink.isChecked = false
|
||||
mAddLabelContainer.isSelected = false
|
||||
mIsExtendedKeyboardShow = false
|
||||
}
|
||||
|
||||
protected fun controlEditorInsertContainerEnabled(isEnabled: Boolean) {
|
||||
mEditorFont.isEnabled = isEnabled
|
||||
}
|
||||
|
||||
fun changeAddLabel(isLabelContainerShow: Boolean) {
|
||||
if (isLabelContainerShow) {
|
||||
mLabelNumTv.visibility = View.GONE
|
||||
mLabelArrowIv.visibility = View.VISIBLE
|
||||
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.theme_font))
|
||||
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
|
||||
mAddLabelContainer.background = ContextCompat.getDrawable(this, R.drawable.bg_editor_insert_add_label)
|
||||
} else {
|
||||
val selectedLabel = getSelectedLabel()
|
||||
if (selectedLabel == 0) {
|
||||
mAddLabelTv.text = "添加标签"
|
||||
mLabelNumTv.visibility = View.GONE
|
||||
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.text_666666))
|
||||
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(this, R.drawable.ic_add_label), null, null, null)
|
||||
} else {
|
||||
mAddLabelTv.text = "标签"
|
||||
mLabelNumTv.visibility = View.VISIBLE
|
||||
mLabelNumTv.text = selectedLabel.toString()
|
||||
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.theme_font))
|
||||
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
|
||||
}
|
||||
mLabelArrowIv.visibility = View.GONE
|
||||
mAddLabelContainer.background = ContextCompat.getDrawable(this, R.drawable.border_round_stroke_eee_999)
|
||||
}
|
||||
}
|
||||
|
||||
open fun getSelectedLabel(): Int = 0
|
||||
|
||||
|
||||
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.add_label_container, R.id.editor_font_underline,
|
||||
R.id.editor_font_bold, R.id.editor_font_italic, R.id.editor_font_strikethrough,
|
||||
R.id.editor_paragraph_h1, R.id.editor_paragraph_h2, R.id.editor_paragraph_h3,
|
||||
R.id.editor_paragraph_h4, R.id.editor_font_container, R.id.editor_paragraph_container,
|
||||
@ -107,31 +185,13 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
fun onRichClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.editor_font -> {
|
||||
mEditorFont.isChecked = !mEditorFont.isChecked
|
||||
mEditorParagraph.isChecked = false
|
||||
mEditorLink.isChecked = false
|
||||
mEditorFontContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorParagraphContainer.visibility = if (!mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = if (!mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorInsertDetail.visibility = mEditorFontContainer.visibility
|
||||
}
|
||||
R.id.editor_paragraph -> {
|
||||
mEditorParagraph.isChecked = !mEditorParagraph.isChecked
|
||||
mEditorFont.isChecked = false
|
||||
mEditorLink.isChecked = false
|
||||
mEditorParagraphContainer.visibility = if (mEditorParagraph.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorFontContainer.visibility = if (!mEditorParagraph.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = if (!mEditorParagraph.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorInsertDetail.visibility = mEditorParagraphContainer.visibility
|
||||
controlEditorFontContainer()
|
||||
}
|
||||
R.id.editor_link -> {
|
||||
mEditorLink.isChecked = !mEditorLink.isChecked
|
||||
mEditorFont.isChecked = false
|
||||
mEditorParagraph.isChecked = false
|
||||
mEditorLinkContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorParagraphContainer.visibility = if (!mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorFontContainer.visibility = if (!mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorInsertDetail.visibility = mEditorLinkContainer.visibility
|
||||
controlEditorLinkContainer()
|
||||
}
|
||||
R.id.add_label_container -> {
|
||||
controlAddLabelContainer()
|
||||
}
|
||||
R.id.editor_font_bold -> {
|
||||
mEditorFontBold.isChecked = !mEditorFontBold.isChecked
|
||||
@ -155,6 +215,14 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-删除线")
|
||||
}
|
||||
}
|
||||
R.id.editor_font_underline -> {
|
||||
mEditorFontUnderline.isChecked = !mEditorFontUnderline.isChecked
|
||||
mRichEditor.setUnderline()
|
||||
|
||||
if (mEditorFontUnderline.isChecked) {
|
||||
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-下滑线")
|
||||
}
|
||||
}
|
||||
R.id.editor_paragraph_h1 -> {
|
||||
if (mEditorParagraphH1.isChecked) {
|
||||
mRichEditor.formatBlock()
|
||||
@ -213,12 +281,93 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
startActivityForResult(GameActivity.getIntent(this, GameActivity.INSERT_GAME_TITLE), INSERT_GAME_CODE)
|
||||
}
|
||||
R.id.editor_link_video -> {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-视频")
|
||||
startActivityForResult(VideoActivity.getIntent(this), VideoActivity.INSERT_VIDEO_CODE)
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(this,
|
||||
object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-视频")
|
||||
startActivityForResult(VideoActivity.getIntent(this@BaseRichEditorActivity), VideoActivity.INSERT_VIDEO_CODE)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun controlEditorFontContainer() {
|
||||
mEditorFont.isChecked = !mEditorFont.isChecked
|
||||
mEditorLink.isChecked = false
|
||||
mAddLabelContainer.isSelected = false
|
||||
val isShouldDelay = if (mEditorFont.isChecked) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(this)
|
||||
true
|
||||
} else {
|
||||
Util_System_Keyboard.showSoftKeyboard(this)
|
||||
false
|
||||
}
|
||||
mEditorInsertDetailContainer.postDelayed({
|
||||
mEditorInsertDetailContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorFontContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorParagraphContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = View.GONE
|
||||
mTagsContainer.visibility = View.GONE
|
||||
mIsExtendedKeyboardShow = mEditorFont.isChecked
|
||||
changeAddLabel(false)
|
||||
}, if (isShouldDelay) 200 else 0L)
|
||||
}
|
||||
|
||||
private fun controlEditorLinkContainer() {
|
||||
mEditorLink.isChecked = !mEditorLink.isChecked
|
||||
mEditorFont.isChecked = false
|
||||
mAddLabelContainer.isSelected = false
|
||||
val isShouldDelay = if (mEditorLink.isChecked) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(this)
|
||||
true
|
||||
} else {
|
||||
Util_System_Keyboard.showSoftKeyboard(this)
|
||||
false
|
||||
}
|
||||
mEditorInsertDetailContainer.postDelayed({
|
||||
mEditorInsertDetailContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorFontContainer.visibility = View.GONE
|
||||
mEditorParagraphContainer.visibility = View.GONE
|
||||
mTagsContainer.visibility = View.GONE
|
||||
mIsExtendedKeyboardShow = mEditorLink.isChecked
|
||||
changeAddLabel(false)
|
||||
}, if (isShouldDelay) 200 else 0L)
|
||||
}
|
||||
|
||||
fun controlAddLabelContainer() {
|
||||
mEditorLink.isChecked = false
|
||||
mEditorFont.isChecked = false
|
||||
mAddLabelContainer.isSelected = !mAddLabelContainer.isSelected
|
||||
val isShouldDelay = if (mAddLabelContainer.isSelected) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(this)
|
||||
changeAddLabel(true)
|
||||
true
|
||||
} else {
|
||||
Util_System_Keyboard.showSoftKeyboard(this)
|
||||
changeAddLabel(false)
|
||||
false
|
||||
}
|
||||
mEditorInsertDetailContainer.postDelayed({
|
||||
mEditorInsertDetailContainer.visibility = if (mAddLabelContainer.isSelected) View.VISIBLE else View.GONE
|
||||
mTagsContainer.visibility = if (mAddLabelContainer.isSelected) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = View.GONE
|
||||
mEditorFontContainer.visibility = View.GONE
|
||||
mEditorParagraphContainer.visibility = View.GONE
|
||||
mIsExtendedKeyboardShow = mAddLabelContainer.isSelected
|
||||
}, if (isShouldDelay) 200 else 0L)
|
||||
}
|
||||
|
||||
override fun handleBackPressed(): Boolean {
|
||||
if (mIsExtendedKeyboardShow) {
|
||||
closeExtendedKeyboard()
|
||||
return true
|
||||
}
|
||||
return super.handleBackPressed()
|
||||
}
|
||||
|
||||
|
||||
private inner class OnCursorChangeListener {
|
||||
@JavascriptInterface
|
||||
fun onElements(elements: String) {
|
||||
@ -237,6 +386,7 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
mEditorFontBold.isChecked = elements.contains(ELEMENT_NAME_BOLD)
|
||||
mEditorFontItalic.isChecked = elements.contains(ELEMENT_NAME_ITALIC)
|
||||
mEditorFontStrikeThrough.isChecked = elements.contains(ELEMENT_NAME_STRIKE)
|
||||
mEditorFontUnderline.isChecked = elements.contains(ELEMENT_NAME_UNDERLINE)
|
||||
mEditorParagraphH1.isChecked = elements.contains(ELEMENT_PARAGRAPH_H1)
|
||||
mEditorParagraphH2.isChecked = elements.contains(ELEMENT_PARAGRAPH_H2)
|
||||
mEditorParagraphH3.isChecked = elements.contains(ELEMENT_PARAGRAPH_H3)
|
||||
@ -264,7 +414,9 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
@JavascriptInterface
|
||||
fun onTextChange(count: Int) {
|
||||
val num = if (count > MAX_INPUT_TEXT_NUM) MAX_INPUT_TEXT_NUM - count else count
|
||||
mEditorTextNumTv.text = num.toString()
|
||||
mEditorTextNumTv.post {
|
||||
mEditorTextNumTv.text = num.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,6 +426,7 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
const val ELEMENT_NAME_BOLD = " b "
|
||||
const val ELEMENT_NAME_ITALIC = " i "
|
||||
const val ELEMENT_NAME_STRIKE = " strike "
|
||||
const val ELEMENT_NAME_UNDERLINE = " u "
|
||||
const val ELEMENT_PARAGRAPH_H1 = " h1 "
|
||||
const val ELEMENT_PARAGRAPH_H2 = " h2 "
|
||||
const val ELEMENT_PARAGRAPH_H3 = " h3 "
|
||||
|
||||
@ -7,6 +7,7 @@ import android.os.Bundle;
|
||||
import com.gh.common.notifier.Notifier;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.AppManager;
|
||||
|
||||
@ -41,7 +42,9 @@ public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallba
|
||||
//FIXME 这里应该只是部分Activity需要
|
||||
try {
|
||||
// 初始化gameMap
|
||||
DownloadManager.getInstance(activity).initGameMap();
|
||||
if (!(activity instanceof SplashScreenActivity)) {
|
||||
DownloadManager.getInstance(activity).initGameMap();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
17
app/src/main/java/com/gh/base/GHThreadFactory.kt
Normal file
17
app/src/main/java/com/gh/base/GHThreadFactory.kt
Normal file
@ -0,0 +1,17 @@
|
||||
package com.gh.base
|
||||
|
||||
import java.util.concurrent.ThreadFactory
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class GHThreadFactory(threadNamePrefix: String) : ThreadFactory {
|
||||
|
||||
private val THREAD_NAME_STEM = "${threadNamePrefix}_%d"
|
||||
private val mThreadId = AtomicInteger(0)
|
||||
|
||||
override fun newThread(r: Runnable?): Thread {
|
||||
val t = Thread(r)
|
||||
t.name = String.format(THREAD_NAME_STEM, mThreadId.getAndIncrement())
|
||||
return t
|
||||
}
|
||||
|
||||
}
|
||||
@ -9,6 +9,8 @@ import com.gh.gamecenter.R;
|
||||
import com.lightgame.utils.RuntimeUtils;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
@ -29,7 +31,7 @@ public class BaseDialogFragment extends DialogFragment {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Dialog dialog = new Dialog(getActivity(), R.style.DialogWindowTransparent);
|
||||
final Dialog dialog = new Dialog(getActivity(), getThemeRes());
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
dialog.setOnKeyListener((dialog1, keyCode, event) -> {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && !ClickUtils.isFastDoubleClick()) {
|
||||
@ -41,6 +43,10 @@ public class BaseDialogFragment extends DialogFragment {
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public int getThemeRes() {
|
||||
return R.style.DialogWindowTransparent;
|
||||
}
|
||||
|
||||
public void toast(@StringRes int res) {
|
||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED))
|
||||
toast(getString(res));
|
||||
@ -71,7 +77,22 @@ public class BaseDialogFragment extends DialogFragment {
|
||||
transaction.show(fragment);
|
||||
transaction.commit();
|
||||
} else {
|
||||
super.show(manager, tag);
|
||||
try {
|
||||
Class<?> clazz = DialogFragment.class;
|
||||
Field dismissed = clazz.getDeclaredField("mDismissed");
|
||||
dismissed.setAccessible(true);
|
||||
dismissed.set(this, false);
|
||||
|
||||
Field shownByMe = clazz.getDeclaredField("mShownByMe");
|
||||
shownByMe.setAccessible(true);
|
||||
shownByMe.set(this, true);
|
||||
FragmentTransaction transaction = manager.beginTransaction();
|
||||
transaction.add(this, tag);
|
||||
transaction.commitAllowingStateLoss();
|
||||
} catch (Exception e) {
|
||||
super.show(manager, tag);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.gh.common.util.ExtensionsKt;
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
/**
|
||||
@ -81,8 +82,17 @@ public class WaitingDialogFragment extends BaseDialogFragment {
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
dismissAllowingStateLoss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismissAllowingStateLoss() {
|
||||
mBackListener = null;
|
||||
super.dismiss();
|
||||
try {
|
||||
super.dismissAllowingStateLoss();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static class WaitingDialogData {
|
||||
|
||||
@ -2,12 +2,13 @@ package com.gh.common
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import com.gh.base.GHThreadFactory
|
||||
import com.gh.common.AppExecutor.ioExecutor
|
||||
import com.gh.common.AppExecutor.lightWeightIoExecutor
|
||||
import com.gh.common.AppExecutor.logExecutor
|
||||
import com.gh.common.AppExecutor.uiExecutor
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.*
|
||||
|
||||
/**
|
||||
* APP 线程池管理类
|
||||
@ -15,16 +16,30 @@ import java.util.concurrent.Executors
|
||||
* [ioExecutor] 是一个最大线程数固定的线程池,较为繁重的 IO 任务可以交给它
|
||||
* [uiExecutor] 是主线程的包裹,需要切换至主线程执行可以用它
|
||||
* [lightWeightIoExecutor] 是一个单线程的线程池,轻量级且需要保证同一线程的 IO 任务可以交给它
|
||||
*
|
||||
* [logExecutor] 只为上传 log 而使用的线程池
|
||||
*/
|
||||
object AppExecutor {
|
||||
|
||||
private val mCoreSize = Runtime.getRuntime().availableProcessors()
|
||||
private val mMinimumPoolSize = 6.coerceAtLeast(mCoreSize * 2)
|
||||
private val mMaximumPoolSize = 32.coerceAtLeast(mCoreSize * 8)
|
||||
|
||||
@JvmStatic
|
||||
val uiExecutor by lazy { MainThreadExecutor() }
|
||||
|
||||
@JvmStatic
|
||||
val lightWeightIoExecutor by lazy { Executors.newSingleThreadExecutor() }
|
||||
val lightWeightIoExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_LIGHT_WEIGHT_IO_THREAD")) }
|
||||
|
||||
@JvmStatic
|
||||
val ioExecutor = Executors.newCachedThreadPool() // 用 by lazy 可能影响初始化速度
|
||||
val logExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_LOG_THREAD")) }
|
||||
|
||||
@JvmStatic
|
||||
val ioExecutor = ThreadPoolExecutor(
|
||||
mMinimumPoolSize,
|
||||
mMaximumPoolSize,
|
||||
20L, TimeUnit.SECONDS,
|
||||
LinkedBlockingQueue<Runnable>(1000),
|
||||
GHThreadFactory("GH_IO_THREAD"))
|
||||
|
||||
val cachedScheduler by lazy { Schedulers.from(ioExecutor) }
|
||||
|
||||
|
||||
@ -17,6 +17,8 @@ import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.entity.Badge
|
||||
import com.gh.gamecenter.entity.MtaEvent
|
||||
import com.gh.gamecenter.entity.NotificationUgc
|
||||
import com.gh.gamecenter.energy.EnergyCenterActivity
|
||||
import com.gh.gamecenter.energy.EnergyHouseActivity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
@ -115,6 +117,7 @@ class DefaultJsApi(var context: Context) {
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
EnergyTaskHelper.postEnergyTask("bind_wechat")
|
||||
handler.complete(true)
|
||||
}
|
||||
|
||||
@ -198,6 +201,7 @@ class DefaultJsApi(var context: Context) {
|
||||
@JavascriptInterface
|
||||
fun updateRegulationTestStatus(msg: Any) {
|
||||
if (msg.toString().toLowerCase(Locale.getDefault()) == "pass") {
|
||||
EnergyTaskHelper.postEnergyTask("finish_etiquette_exam")
|
||||
SPUtils.setString(Constants.SP_REGULATION_TEST_PASS_STATUS, "pass")
|
||||
}
|
||||
}
|
||||
@ -228,6 +232,20 @@ class DefaultJsApi(var context: Context) {
|
||||
MessageShareUtils.getInstance(context).shareFromWeb(context, imageShareEvent.type)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun inviteFriends(event: Any) {
|
||||
val inviteEvent = event.toString().toObject() ?: InviteFriendsEvent()
|
||||
val context = CurrentActivityHolder.getCurrentActivity()
|
||||
if ("poster" == inviteEvent.type) {
|
||||
Base64ImageHolder.image = inviteEvent.poster.run {
|
||||
if (this.startsWith("data:image/png;base64")) this.split(",")[1] else this
|
||||
}
|
||||
MessageShareUtils.getInstance(context).shareFromWeb(context, inviteEvent.way)
|
||||
} else {
|
||||
ShareUtils.getInstance(context).shareInviteFriends(context, inviteEvent.url, inviteEvent.way)
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun bindPhone(msg: Any) {
|
||||
val intent = BindPhoneActivity.getNormalIntent(context, false)
|
||||
@ -252,10 +270,36 @@ class DefaultJsApi(var context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun openInNewWebview(url: Any) {
|
||||
runOnUiThread { DirectUtils.directToWebView(context, url.toString(), "内部网页") }
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun postWearBadgeTask(msg: Any) {
|
||||
EnergyTaskHelper.postEnergyTask("wear_badge")
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun startEnergyCenter(msg: Any) {
|
||||
context.startActivity(EnergyCenterActivity.getIntent(context))
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun startEnergyHouse(msg: Any) {
|
||||
context.startActivity(EnergyHouseActivity.getIntent(context))
|
||||
}
|
||||
|
||||
@Keep
|
||||
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)
|
||||
|
||||
@Keep
|
||||
internal data class ImageShareEvent(var image: String = "", var type: String = "")
|
||||
|
||||
@Keep
|
||||
internal data class InviteFriendsEvent(var type: String = "",
|
||||
var way: String = "",
|
||||
var url: String = "",
|
||||
var poster: String = "")
|
||||
|
||||
}
|
||||
|
||||
@ -344,6 +344,11 @@ object DefaultUrlHandler {
|
||||
return true
|
||||
}
|
||||
|
||||
// 处理内部页面逻辑
|
||||
if (transformNormalScheme(context, url, entrance)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if ("http" != uri.scheme && "https" != uri.scheme) return true
|
||||
return false
|
||||
}
|
||||
@ -360,7 +365,7 @@ object DefaultUrlHandler {
|
||||
uri.path?.apply {
|
||||
when {
|
||||
contains("game") -> {
|
||||
val gameId = uri.getQueryParameter("gameId") ?: ""
|
||||
val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last() ?: ""
|
||||
DirectUtils.directToGameDetail(context, gameId, entrance, autoDownload = false, traceEvent = null)
|
||||
}
|
||||
contains("question") -> {
|
||||
|
||||
@ -11,6 +11,7 @@ import com.gh.gamecenter.entity.TimeEntity
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
|
||||
object FixedRateJobHelper {
|
||||
@ -35,7 +36,7 @@ object FixedRateJobHelper {
|
||||
// 时间校对,10分钟一次
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % TIME_PERIOD == 0L) {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api.time
|
||||
.subscribeOn(AppExecutor.cachedScheduler)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : Response<TimeEntity>() {
|
||||
override fun onResponse(response: TimeEntity?) {
|
||||
val serverTime = response?.time
|
||||
|
||||
@ -5,6 +5,7 @@ import android.app.Application
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.gh.base.GHThreadFactory
|
||||
import com.halo.assistant.HaloApp
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
@ -29,31 +30,31 @@ class TimeElapsedHelper(val fragment: Fragment?, val activity: Activity?) {
|
||||
|
||||
init {
|
||||
activity?.application?.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
|
||||
override fun onActivityStarted(a: Activity?) {
|
||||
override fun onActivityStarted(a: Activity) {
|
||||
}
|
||||
|
||||
override fun onActivitySaveInstanceState(a: Activity?, outState: Bundle?) {
|
||||
override fun onActivitySaveInstanceState(a: Activity, outState: Bundle) {
|
||||
}
|
||||
|
||||
override fun onActivityStopped(a: Activity?) {
|
||||
override fun onActivityStopped(a: Activity) {
|
||||
}
|
||||
|
||||
override fun onActivityCreated(a: Activity?, savedInstanceState: Bundle?) {
|
||||
override fun onActivityCreated(a: Activity, savedInstanceState: Bundle?) {
|
||||
}
|
||||
|
||||
override fun onActivityPaused(a: Activity?) {
|
||||
override fun onActivityPaused(a: Activity) {
|
||||
if (activity == a) {
|
||||
pauseCounting()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResumed(a: Activity?) {
|
||||
override fun onActivityResumed(a: Activity) {
|
||||
if (activity == a) {
|
||||
resumeCounting()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityDestroyed(a: Activity?) {
|
||||
override fun onActivityDestroyed(a: Activity) {
|
||||
if (activity == a) {
|
||||
HaloApp.getInstance().application.unregisterActivityLifecycleCallbacks(this)
|
||||
}
|
||||
@ -114,7 +115,7 @@ class TimeElapsedHelper(val fragment: Fragment?, val activity: Activity?) {
|
||||
}
|
||||
|
||||
object TimeElapsedThreadHolder {
|
||||
val threadService: ExecutorService by lazy { Executors.newSingleThreadExecutor() }
|
||||
val threadService: ExecutorService by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("TIME_ELAPSED_THREAD")) }
|
||||
}
|
||||
|
||||
interface TimeoutCallback {
|
||||
|
||||
@ -56,7 +56,7 @@ public class Config {
|
||||
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // ghzs/ghzs666 统一
|
||||
public static final String PATCHES = "patches";
|
||||
|
||||
public static final String DEFAULT_CHANNEL = "GH_TEST";
|
||||
public static final String DEFAULT_CHANNEL = "TEST";
|
||||
|
||||
private static String SETTINGS_KEY = "settingsKey";
|
||||
|
||||
|
||||
@ -27,12 +27,14 @@ public class Constants {
|
||||
|
||||
public static final String GAME_DETAIL_COME_IN = "game_detail_come_in"; // 从游戏详情进入
|
||||
|
||||
public static final String SPLASH_AD = "splash_ad"; // 启动广告
|
||||
|
||||
public static final String XPOSED_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer";
|
||||
|
||||
public static final String EB_QUIT_LOGIN = "quit_login";
|
||||
|
||||
public static final String EB_SHOW_AD = "show_ad";
|
||||
|
||||
// 用于避免历史下载掺和到普通下载状态的 ID 修饰符
|
||||
public static final String GAME_ID_DIVIDER = ":";
|
||||
// 用于避免历史下载影响到部分依赖名字作为数据更新条件的修饰符
|
||||
public static final String GAME_NAME_DECORATOR = " ";
|
||||
|
||||
@ -49,10 +51,17 @@ public class Constants {
|
||||
public static final String RAW_GAME_ICON = "raw_game_icon";
|
||||
public static final String GAME_ICON_SUBSCRIPT = "game_icon_subscript";
|
||||
|
||||
// 下载 id,一般来说跟下载文件名一样
|
||||
public static final String DOWNLOAD_ID = "download_id";
|
||||
|
||||
public static final String GHZS_GAME_ID = "5ae4462c2924bc7936438d07";
|
||||
|
||||
public static final String EXTRA_DOWNLOAD_TYPE = "extra_download_type";
|
||||
public static final String SILENT_UPDATE = "静默更新";
|
||||
public static final String SIMULATOR_DOWNLOAD = "下载模拟器";
|
||||
public static final String SIMULATOR_GAME = "simulator_game";
|
||||
public static final String SIMULATOR = "simulator";
|
||||
public static final String GAME_NAME = "game_name";
|
||||
public static final String SIMULATOR_DOWNLOAD_START_TIME = "simulator_download_start_time";
|
||||
public static final String LAST_GHZS_UPDATE_FILE_SIZE = "last_ghzs_update_file_size";
|
||||
|
||||
@ -61,6 +70,8 @@ public class Constants {
|
||||
|
||||
public static final String SP_IMEI = "imei";
|
||||
public static final String SP_ANDROID_ID = "android_id";
|
||||
|
||||
public static final String LAST_INSTALL_GAME = "last_install_game";
|
||||
|
||||
//引导设置 “通知管理” 引导弹窗
|
||||
public static final String SP_SHOWED_NOTIFICATION_LOGIN = "show_notification_login_hint";
|
||||
@ -106,8 +117,6 @@ public class Constants {
|
||||
public static final String SP_FILTER_TAGS = "filter_tags";
|
||||
//实名认证弹窗分类数据
|
||||
public static final String SP_AUTH_DIALOG = "auth_dialog";
|
||||
//顶部视频进度保存,重启恢复
|
||||
public static final String SP_TOP_VIDEO_SCHEDULE = "top_video_schedule";
|
||||
//我的光环小红点提示
|
||||
public static final String SP_GH_RED_POINT_REMIND = "gh_red_point_remind";
|
||||
//论坛首页引导
|
||||
@ -129,6 +138,25 @@ public class Constants {
|
||||
|
||||
public static final String SP_IS_USER_ACCEPTED_PRIVACY_STATEMENT = "has_user_accepted_privacy_statement";
|
||||
public static final String SP_BRAND_NEW_USER = "brand_new_user";
|
||||
//包名检测是否点击不再提示
|
||||
public static final String SP_PACKAGE_CHECK = "package_check";
|
||||
//游戏详情预约引导提示
|
||||
public static final String SP_GAME_DETAIL_RESERVE_GUIDE = "game_detail_reserve_guide";
|
||||
|
||||
public static final String SP_XAPK_UNZIP_ACTIVITY = "xapk_unzip_activity";
|
||||
public static final String SP_XAPK_URL = "xapk_url";
|
||||
|
||||
//首页视频播放进度
|
||||
public static final String SP_HOME_VIDEO_PLAY_RECORD = "home_video_play_record";
|
||||
|
||||
// 用户是否曾经永久拒绝过存储权限
|
||||
public static final String SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION = "user_has_permanently_denied_storage_permission";
|
||||
|
||||
// 是否已经填写邀请码
|
||||
public static final String SP_HAS_COMPLETE_INVITE_CODE = "has_complete_invite_code";
|
||||
|
||||
// 签到提醒开关
|
||||
public static final String SP_SIGN_REMIND = "sign_remind";
|
||||
|
||||
//手机号码匹配规则
|
||||
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
|
||||
@ -164,6 +192,9 @@ public class Constants {
|
||||
//版规声明
|
||||
public static final String FORUM_REGULATIONS_NEWS_ID = "5f4db9cc34d44d01b92fd670";
|
||||
|
||||
// 权限使用场景地址
|
||||
public static final String PERMISSION_SCENARIO_ADDRESS = "https://resource.ghzs.com/page/permissions/android.html";
|
||||
|
||||
//帮助内容详情
|
||||
public static final String HELP_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_help_dev/help.html?content=";
|
||||
public static final String HELP_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=";
|
||||
@ -172,6 +203,30 @@ public class Constants {
|
||||
public static final String LOGOUT_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_help_dev/help.html?content=5f6b1f02786564003944a693";
|
||||
public static final String LOGOUT_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=5f534111b1f72909fc225672";
|
||||
|
||||
// 商品详情
|
||||
public static final String COMMODITY_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/product?from=ghzs";
|
||||
public static final String COMMODITY_DETAIL_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/product?from=ghzs";
|
||||
|
||||
// 光能记录
|
||||
public static final String ENERGY_RECORD_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/record?from=ghzs";
|
||||
public static final String ENERGY_RECORD_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/record?from=ghzs";
|
||||
|
||||
// 订单中心
|
||||
public static final String ORDER_CENTER_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/orders?from=ghzs";
|
||||
public static final String ORDER_CENTER_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/orders?from=ghzs";
|
||||
|
||||
// 订单详情
|
||||
public static final String ORDER_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/order-detail?from=ghzs";
|
||||
public static final String ORDER_DETAIL_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/order-detail?from=ghzs";
|
||||
|
||||
// 邀请好友
|
||||
public static final String INVITE_FRIENDS_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_activity_dev/inviteFriends.html#/invite";
|
||||
public static final String INVITE_FRIENDS_ADDRESS = "https://static-web.ghzs.com/ghzs_activity/inviteFriends.html#/invite";
|
||||
|
||||
// 等级页面
|
||||
public static final String LEVEL_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs-userhome-dev/index.html#/level";
|
||||
public static final String LEVEL_ADDRESS = "https://static-web.ghzs.com/ghzs-userhome/index.html#/level";
|
||||
|
||||
//最少需要多少数据才能上传
|
||||
public static final int DATA_AMOUNT = 20;
|
||||
|
||||
|
||||
@ -14,10 +14,17 @@ import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.BindingAdapter;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.gh.base.OnViewClickListener;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.dialog.CertificationDialog;
|
||||
import com.gh.common.dialog.PackageCheckDialogFragment;
|
||||
import com.gh.common.dialog.ReserveDialogFragment;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
@ -38,7 +45,6 @@ import com.gh.common.util.NewsUtils;
|
||||
import com.gh.common.util.NumberUtils;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.PermissionHelper;
|
||||
import com.gh.common.util.PlatformUtils;
|
||||
import com.gh.common.util.ReservationHelper;
|
||||
import com.gh.common.view.DownloadProgressBar;
|
||||
@ -74,12 +80,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.BindingAdapter;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
/**
|
||||
* Created by khy on 12/02/18.
|
||||
*/
|
||||
@ -256,6 +256,14 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lazy 的 paddingTop
|
||||
*/
|
||||
@BindingAdapter("lazyPaddingLeft")
|
||||
public static void lazyPaddingLeft(View view, int paddingLeftInDp) {
|
||||
view.setPadding(DisplayUtils.dip2px(paddingLeftInDp), view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
|
||||
}
|
||||
|
||||
/**
|
||||
* lazy 的 paddingTop
|
||||
*/
|
||||
@ -448,12 +456,14 @@ public class BindingAdapters {
|
||||
return;
|
||||
}
|
||||
}
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
|
||||
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
|
||||
PackageCheckDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity.getPackageDialog(), () -> {
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
|
||||
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -509,13 +519,11 @@ public class BindingAdapters {
|
||||
break;
|
||||
case RESERVABLE:
|
||||
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
|
||||
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(progressBar.getContext(), () -> {
|
||||
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
updateReservation(progressBar, gameEntity);
|
||||
});
|
||||
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
|
||||
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
updateReservation(progressBar, gameEntity);
|
||||
});
|
||||
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
|
||||
});
|
||||
break;
|
||||
case RESERVED:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,8 @@ import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.lightgame.dialog.BaseDialogFragment
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
@ -63,4 +65,29 @@ abstract class BaseTrackableDialogFragment : BaseDialogFragment() {
|
||||
|
||||
open fun trackWithBasicDeviceInfo() = false
|
||||
|
||||
|
||||
override fun show(manager: FragmentManager, tag: String?) {
|
||||
val fragment = manager.findFragmentByTag(tag)
|
||||
if (fragment != null) {
|
||||
val transaction = manager.beginTransaction()
|
||||
transaction.show(fragment)
|
||||
transaction.commit()
|
||||
} else {
|
||||
try {
|
||||
val clazz: Class<*> = DialogFragment::class.java
|
||||
val dismissed = clazz.getDeclaredField("mDismissed")
|
||||
dismissed.isAccessible = true
|
||||
dismissed[this] = false
|
||||
val shownByMe = clazz.getDeclaredField("mShownByMe")
|
||||
shownByMe.isAccessible = true
|
||||
shownByMe[this] = true
|
||||
val transaction = manager.beginTransaction()
|
||||
transaction.add(this, tag)
|
||||
transaction.commitAllowingStateLoss()
|
||||
} catch (e: Exception) {
|
||||
super.show(manager, tag)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,7 +118,9 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi
|
||||
|
||||
//跳转登录页面
|
||||
private fun gotoLoginPage() {
|
||||
CheckLoginUtils.checkLogin(AppManager.getInstance().currentActivity() as AppCompatActivity,
|
||||
val currentActivity = AppManager.getInstance().currentActivity() ?: return
|
||||
|
||||
CheckLoginUtils.checkLogin(currentActivity as AppCompatActivity,
|
||||
null, true, "实名认证弹窗") {
|
||||
if (UserManager.getInstance().isAuth) {
|
||||
listener.onConfirm()
|
||||
@ -129,7 +131,9 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi
|
||||
|
||||
//跳转实名认证页面
|
||||
private fun gotoAuthPage() {
|
||||
AvoidOnResultManager.getInstance(AppManager.getInstance().currentActivity() as AppCompatActivity)
|
||||
val currentActivity = AppManager.getInstance().currentActivity() ?: return
|
||||
|
||||
AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity)
|
||||
.startForResult(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD), object : Callback {
|
||||
override fun onActivityResult(resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
|
||||
@ -215,7 +215,7 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
|
||||
class LooperHandle(val mAdapter: BannerAdapter) : Handler() {
|
||||
private val mWeakReference: WeakReference<BannerAdapter> = WeakReference(mAdapter)
|
||||
override fun handleMessage(msg: Message?) {
|
||||
override fun handleMessage(msg: Message) {
|
||||
val adapter = mWeakReference.get()
|
||||
adapter?.scrollToNextPage()
|
||||
adapter?.startScroll()
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
@ -13,7 +14,6 @@ import androidx.core.text.HtmlCompat
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import kotlinx.android.synthetic.main.dialog_game_off_service.*
|
||||
@ -21,7 +21,7 @@ import kotlinx.android.synthetic.main.dialog_game_off_service.*
|
||||
// 游戏关闭下载弹窗
|
||||
class GameOffServiceDialogFragment
|
||||
// : BaseTrackableDialogFragment()
|
||||
:BaseDialogFragment() {
|
||||
: BaseDialogFragment() {
|
||||
|
||||
private var mDialog: GameEntity.Dialog? = null
|
||||
|
||||
@ -48,7 +48,7 @@ class GameOffServiceDialogFragment
|
||||
siteTv.setOnClickListener {
|
||||
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
|
||||
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
|
||||
dismiss()
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
container.addView(siteTv)
|
||||
@ -56,6 +56,10 @@ class GameOffServiceDialogFragment
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply { setCanceledOnTouchOutside(true) }
|
||||
}
|
||||
|
||||
// override fun getEvent(): String {
|
||||
// return "游戏下载状态按钮"
|
||||
// }
|
||||
|
||||
@ -13,16 +13,19 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.PermissionHelper
|
||||
import com.gh.common.util.PermissionHelper.INSTALL_PERMISS_CODE
|
||||
import com.gh.common.util.goneIf
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.PermissionHelper.INSTALL_PERMISSION_CODE
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.gamecenter.R
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import kotlin.random.Random
|
||||
|
||||
class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
|
||||
|
||||
lateinit var mView: View
|
||||
var isXapk = false
|
||||
var url: String = ""
|
||||
var mCallBack: (() -> Unit)? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
@ -35,16 +38,26 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
|
||||
val closeTv = mView.findViewById<TextView>(R.id.closeTv)
|
||||
val closeIv = mView.findViewById<ImageView>(R.id.closeIv)
|
||||
val activateTv = mView.findViewById<TextView>(R.id.activateTv)
|
||||
val contentTv = mView.findViewById<TextView>(R.id.contentTv)
|
||||
val switchLottie = mView.findViewById<LottieAnimationView>(R.id.switchLottie)
|
||||
contentTv.text = if (isXapk) "未授权下解压XAPK可能导致解压失败" else "以保证游戏的安装和更新"
|
||||
|
||||
switchLottie.setAnimation("lottie/install_permission_switch.json")
|
||||
switchLottie.playAnimation()
|
||||
|
||||
val randomNumber = Random.nextInt(2)
|
||||
val randomNumber = if (isXapk) 1 else Random.nextInt(2)
|
||||
closeTv.goneIf(randomNumber == 0)
|
||||
closeIv.goneIf(randomNumber != 0)
|
||||
if (isXapk) {
|
||||
closeTv.text = "暂不,尝试解压"
|
||||
closeIv.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
closeTv.setOnClickListener {
|
||||
MtaHelper.onEvent(getEvent(), getKey(), "文案样式_点击以后再说")
|
||||
if (isXapk) {
|
||||
mCallBack?.invoke()
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
closeIv.setOnClickListener {
|
||||
@ -54,12 +67,18 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
|
||||
activateTv.setOnClickListener {
|
||||
MtaHelper.onEvent(getEvent(), getKey(), if (randomNumber == 0) "文案样式_点击立即开启" else "图标样式_点击立即开启")
|
||||
PermissionHelper.toInstallPermissionSetting(requireActivity())
|
||||
if (isXapk) {
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, requireActivity().javaClass.name)
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISS_CODE) {
|
||||
if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISSION_CODE) {
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "")
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, "")
|
||||
mCallBack?.invoke()
|
||||
dismiss()
|
||||
}
|
||||
@ -71,30 +90,43 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun show(activity: AppCompatActivity, callBack: (() -> Unit)?) {
|
||||
fun show(activity: AppCompatActivity, downloadEntity: DownloadEntity, callBack: (() -> Unit)?) {
|
||||
val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == downloadEntity.path.getExtension()
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
callBack?.invoke()
|
||||
return
|
||||
}
|
||||
if (!Config.isPermissionPopupSwitchOpen()) {
|
||||
callBack?.invoke()
|
||||
return
|
||||
}
|
||||
val haveInstallPermission = activity.packageManager.canRequestPackageInstalls();
|
||||
val haveInstallPermission = activity.packageManager.canRequestPackageInstalls()
|
||||
if (haveInstallPermission) {
|
||||
callBack?.invoke()
|
||||
return
|
||||
|
||||
}
|
||||
if (isXapk) {
|
||||
val xapkUnzipVersions = Config.getSettings()?.permissionPopupAppliedVersions?.xapkUnzip
|
||||
if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
|
||||
callBack?.invoke()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
val installVersions = Config.getSettings()?.permissionPopupAppliedVersions?.install
|
||||
if (installVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
|
||||
callBack?.invoke()
|
||||
return
|
||||
}
|
||||
}
|
||||
var installPermissionDialogFragment = activity.supportFragmentManager.findFragmentByTag(InstallPermissionDialogFragment::class.java.simpleName) as? InstallPermissionDialogFragment
|
||||
if (installPermissionDialogFragment != null) {
|
||||
installPermissionDialogFragment.mCallBack = callBack
|
||||
installPermissionDialogFragment.isXapk = isXapk
|
||||
installPermissionDialogFragment.url = downloadEntity.url
|
||||
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
|
||||
transaction.show(installPermissionDialogFragment)
|
||||
transaction.commit()
|
||||
} else {
|
||||
installPermissionDialogFragment = InstallPermissionDialogFragment().apply {
|
||||
mCallBack = callBack
|
||||
this.mCallBack = callBack
|
||||
this.isXapk = isXapk
|
||||
this.url = downloadEntity.url
|
||||
}
|
||||
installPermissionDialogFragment.show(activity.supportFragmentManager, InstallPermissionDialogFragment::class.java.simpleName)
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ class NotificationHintDialogFragment : BaseTrackableDialogFragment() {
|
||||
activateTv.setOnClickListener {
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击立即开启")
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "${styleEntity.scenes}_${styleEntity.styleNo}_点击立即开启")
|
||||
dismiss()
|
||||
dismissAllowingStateLoss()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
//这种方案适用于 API 26, 即8.0(含8.0)以上可以用
|
||||
val intent = Intent()
|
||||
@ -80,7 +80,7 @@ class NotificationHintDialogFragment : BaseTrackableDialogFragment() {
|
||||
}
|
||||
|
||||
closeIv.setOnClickListener {
|
||||
dismiss()
|
||||
dismissAllowingStateLoss()
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击关闭")
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "${styleEntity.scenes}_${styleEntity.styleNo}_点击关闭")
|
||||
}
|
||||
|
||||
@ -0,0 +1,309 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.base.BaseRecyclerViewHolder
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.view.CustomLinkMovementMethod
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.FragmentPackageCheckBinding
|
||||
import com.gh.gamecenter.databinding.PackageCheckItemBinding
|
||||
import com.gh.gamecenter.entity.DetectionObjectEntity
|
||||
import com.gh.gamecenter.entity.PackageDialogEntity
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
import com.lightgame.dialog.BaseDialogFragment
|
||||
import io.reactivex.disposables.Disposable
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
/**
|
||||
* 包名检测弹窗
|
||||
*/
|
||||
class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
|
||||
private lateinit var binding: FragmentPackageCheckBinding
|
||||
private var mTotalWidth = 0f
|
||||
private val mDuration = 3000
|
||||
private var mDisposable: Disposable? = null
|
||||
private var mAdapter: PackageCheckAdapter? = null
|
||||
var packageDialogEntity: PackageDialogEntity? = null
|
||||
var callBack: DialogUtils.ConfirmListener? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
binding = FragmentPackageCheckBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
packageDialogEntity?.let {
|
||||
changeParams(it.detectionObjects.size)
|
||||
|
||||
binding.packageRv.layoutManager = LinearLayoutManager(requireContext())
|
||||
mAdapter = PackageCheckAdapter(requireContext(), it.detectionObjects)
|
||||
binding.packageRv.adapter = mAdapter
|
||||
|
||||
binding.titleTv.text = it.title
|
||||
binding.contentTv.text = it.content
|
||||
|
||||
val spanBuilder = SpanBuilder(it.linkHintText).build()
|
||||
it.links.forEachIndexed { index, link ->
|
||||
val linkSpan = SpanBuilder(link.title ?: "").click(0, (link.title
|
||||
?: "").length, R.color.theme_font, true) {
|
||||
DirectUtils.directToLinkPage(requireContext(), link, "包名检测弹窗", "")
|
||||
}.build()
|
||||
spanBuilder.append(linkSpan)
|
||||
if (index != it.links.size - 1) {
|
||||
spanBuilder.append("、")
|
||||
}
|
||||
}
|
||||
binding.linkHintTv.text = spanBuilder
|
||||
binding.linkHintTv.movementMethod = CustomLinkMovementMethod.getInstance()
|
||||
|
||||
when (it.level) {
|
||||
"HINT_SKIP" -> {
|
||||
binding.cancelTv.text = "取消"
|
||||
binding.noRemindAgainCb.visibility = View.GONE
|
||||
}
|
||||
"ALWAYS_HINT" -> {
|
||||
binding.cancelTv.text = "我知道了"
|
||||
binding.noRemindAgainCb.visibility = View.GONE
|
||||
}
|
||||
else -> {
|
||||
binding.cancelTv.text = "我知道了"
|
||||
binding.noRemindAgainCb.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
initListener(it)
|
||||
}
|
||||
checkPackage()
|
||||
}
|
||||
|
||||
private fun changeParams(size: Int) {
|
||||
val params = binding.packageRv.layoutParams as LinearLayout.LayoutParams
|
||||
params.height = if (size > 3) (28f.dip2px() * 3.5).toInt() else 28f.dip2px() * size
|
||||
binding.packageRv.layoutParams = params
|
||||
}
|
||||
|
||||
private fun initListener(entity: PackageDialogEntity) {
|
||||
binding.downloadBtn.setOnClickListener {
|
||||
if (binding.noRemindAgainCb.isChecked) {
|
||||
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity?.id}", true)
|
||||
}
|
||||
val isAllPackageInstalled = isAllPackageInstalled(entity)
|
||||
if (isAllPackageInstalled) {
|
||||
callBack?.onConfirm()
|
||||
dismissAllowingStateLoss()
|
||||
} else {
|
||||
val packageLink = entity.links.find { it.buttonLink }
|
||||
if (packageLink != null) {
|
||||
DirectUtils.directToLinkPage(requireContext(), packageLink, "包名检测弹窗", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.cancelTv.setOnClickListener {
|
||||
if (entity.level != "HINT_SKIP") {
|
||||
callBack?.onConfirm()
|
||||
}
|
||||
if (binding.noRemindAgainCb.isChecked) {
|
||||
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity?.id}", true)
|
||||
}
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPackage() {
|
||||
var index = 0
|
||||
mTotalWidth = (DisplayUtils.getScreenWidth() - 108f.dip2px()).toFloat()
|
||||
mDisposable = rxTimer(1) {
|
||||
val width = (mTotalWidth / mDuration) * it
|
||||
val params = binding.progressView.layoutParams as RelativeLayout.LayoutParams
|
||||
params.width = width.toInt()
|
||||
binding.progressView.layoutParams = params
|
||||
|
||||
packageDialogEntity?.detectionObjects?.let { objects ->
|
||||
if (objects.isNotEmpty()) {
|
||||
val averageTime = if (objects.size == 1) {
|
||||
mDuration
|
||||
} else {
|
||||
mDuration / objects.size
|
||||
}
|
||||
if (it != 0L && it % averageTime == 0L && index < objects.size) {
|
||||
mAdapter?.notifyPackages()
|
||||
binding.packageRv.smoothScrollToPosition(index)
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (it >= mDuration) {
|
||||
mDisposable?.dispose()
|
||||
binding.downloadBtn.isEnabled = true
|
||||
binding.progressText.text = "检测完成"
|
||||
binding.progressView.background = ContextCompat.getDrawable(requireContext(), R.drawable.package_check_complete_bg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
|
||||
val height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
dialog?.window?.setLayout(width, height)
|
||||
dialog?.setCanceledOnTouchOutside(true)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
packageDialogEntity?.let {
|
||||
if (isAllPackageInstalled(it)) {
|
||||
callBack?.onConfirm()
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
EventBus.getDefault().unregister(this)
|
||||
if (mDisposable?.isDisposed == false) {
|
||||
mDisposable?.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
//安装、卸载事件
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(busFour: EBPackage) {
|
||||
if ("安装" == busFour.type || "卸载" == busFour.type) {
|
||||
mAdapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
private var index = -1
|
||||
|
||||
fun notifyPackages() {
|
||||
index++
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return PackageCheckViewHolder(PackageCheckItemBinding.bind(LayoutInflater.from(context).inflate(R.layout.package_check_item, parent, false)))
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = entities.size
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is PackageCheckViewHolder) {
|
||||
val entity = entities[position]
|
||||
holder.binding.entity = entity
|
||||
if (position <= index) {
|
||||
var isAllInstalled = false
|
||||
entity.packages.forEach { packageName ->
|
||||
val isInstalled = PackageUtils.getInstalledPackages(context, 0).find { it.packageName == packageName } != null
|
||||
if (isInstalled) {
|
||||
isAllInstalled = true
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
if (isAllInstalled) {
|
||||
holder.binding.statusTv.text = "已安装"
|
||||
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
|
||||
} else {
|
||||
holder.binding.statusTv.text = "未安装"
|
||||
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.text_FF4147))
|
||||
}
|
||||
holder.binding.statusTv.visibility = View.VISIBLE
|
||||
} else {
|
||||
holder.binding.statusTv.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PackageCheckViewHolder(val binding: PackageCheckItemBinding) : BaseRecyclerViewHolder<DetectionObjectEntity>(binding.root)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun show(activity: AppCompatActivity, packageDialogEntity: PackageDialogEntity?, callBack: DialogUtils.ConfirmListener) {
|
||||
if (packageDialogEntity == null) {
|
||||
callBack.onConfirm()
|
||||
return
|
||||
}
|
||||
if (isAllPackageInstalled(packageDialogEntity)) {
|
||||
callBack.onConfirm()
|
||||
return
|
||||
}
|
||||
val isChoose = SPUtils.getBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity.id}", false)
|
||||
if (packageDialogEntity.level == "OPTIONAL_HINT" && isChoose) {
|
||||
callBack.onConfirm()
|
||||
return
|
||||
}
|
||||
|
||||
if (!activity.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) return
|
||||
|
||||
var dialogFragment = activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.simpleName) as? PackageCheckDialogFragment
|
||||
if (dialogFragment == null) {
|
||||
dialogFragment = PackageCheckDialogFragment()
|
||||
dialogFragment.packageDialogEntity = packageDialogEntity
|
||||
dialogFragment.callBack = callBack
|
||||
|
||||
dialogFragment.show(activity.supportFragmentManager, PackageCheckDialogFragment::class.java.simpleName)
|
||||
} else {
|
||||
dialogFragment.packageDialogEntity = packageDialogEntity
|
||||
dialogFragment.callBack = callBack
|
||||
|
||||
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
|
||||
transaction.show(dialogFragment)
|
||||
transaction.commit()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun isAllPackageInstalled(packageDialogEntity: PackageDialogEntity): Boolean {
|
||||
var isAllInstalled = true
|
||||
val allInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
|
||||
|
||||
val isPackagesInstall: (ArrayList<String>) -> Boolean = { packages ->
|
||||
var isPackagesInstalled = false
|
||||
packages.forEach { packageName ->
|
||||
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
|
||||
if (isInstalled) {
|
||||
isPackagesInstalled = true
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
isPackagesInstalled
|
||||
}
|
||||
|
||||
packageDialogEntity.detectionObjects.forEach loop@{ obj ->
|
||||
if (!isPackagesInstall(obj.packages)) {
|
||||
isAllInstalled = false
|
||||
return isAllInstalled
|
||||
}
|
||||
}
|
||||
return isAllInstalled
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,23 +2,27 @@ package com.gh.common.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.TextPaint
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.*
|
||||
import android.webkit.WebSettings
|
||||
import android.webkit.WebView
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.util.DirectUtils.directToExternalBrowser
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.view.CustomLinkMovementMethod
|
||||
import com.gh.gamecenter.R
|
||||
|
||||
class PrivacyDialogFragment : BaseDialogFragment() {
|
||||
|
||||
private val mLocalPrivacyHtml = "file:///android_asset/privacy_policies.html"
|
||||
private val mLocalRegulationHtml = "file:///android_asset/user_regulation.html"
|
||||
// private val mLocalPrivacyHtml = "file:///android_asset/privacy_policies.html"
|
||||
// private val mLocalRegulationHtml = "file:///android_asset/user_regulation.html"
|
||||
|
||||
var containerView: View? = null
|
||||
var mCallBack: ((isSuccess: Boolean) -> Unit)? = null
|
||||
@ -30,83 +34,80 @@ class PrivacyDialogFragment : BaseDialogFragment() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
|
||||
val mWebViewRegulation = containerView?.findViewById<WebView>(R.id.webView2)
|
||||
// val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
|
||||
// val mWebViewRegulation = containerView?.findViewById<WebView>(R.id.webView2)
|
||||
//
|
||||
// mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
|
||||
// mWebViewRegulation?.isHorizontalScrollBarEnabled = false
|
||||
|
||||
mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
|
||||
mWebViewRegulation?.isHorizontalScrollBarEnabled = false
|
||||
val contentTv = containerView?.findViewById<TextView>(R.id.contentTv)
|
||||
val descTv = containerView?.findViewById<TextView>(R.id.descTv)
|
||||
contentTv?.movementMethod = ScrollingMovementMethod()
|
||||
|
||||
val mTitlePrivacyTv = containerView?.findViewById<TextView>(R.id.privacyTitleTv)
|
||||
val mTitleRegulationTv = containerView?.findViewById<TextView>(R.id.userRegulationTitleTv)
|
||||
|
||||
val settingsArrayList = arrayListOf(mWebViewPrivacy?.settings, mWebViewRegulation?.settings)
|
||||
|
||||
for (settings in settingsArrayList) {
|
||||
settings?.javaScriptEnabled = true
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
|
||||
}
|
||||
// 避免提示网页有害信息不能访问
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
settings?.safeBrowsingEnabled = false
|
||||
val skipText = SpannableStringBuilder("查看完整版的隐私政策和用户协议")
|
||||
skipText.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
// 适配大于屏幕宽度的页面
|
||||
settings?.useWideViewPort = true
|
||||
settings?.loadWithOverviewMode = true
|
||||
settings?.domStorageEnabled = true
|
||||
|
||||
// 自适应屏幕
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
settings?.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING
|
||||
override fun onClick(widget: View) {
|
||||
directToExternalBrowser(context!!, context!!.getString(R.string.privacy_policy_url))
|
||||
}
|
||||
}
|
||||
}, skipText.length - 9, skipText.length - 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
|
||||
// if (NetworkUtils.isNetworkConnected(requireContext())) {
|
||||
// mWebViewPrivacy?.loadUrl(requireContext().getString(R.string.privacy_policy_url))
|
||||
// mWebViewRegulation?.loadUrl(requireContext().getString(R.string.user_regulation_url))
|
||||
// } else {
|
||||
mWebViewPrivacy?.loadUrl(mLocalPrivacyHtml)
|
||||
mWebViewRegulation?.loadUrl(mLocalRegulationHtml)
|
||||
// }
|
||||
skipText.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
// val client = object : WebViewClient() {
|
||||
// override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
|
||||
// super.onReceivedError(view, request, error)
|
||||
// if (view == mWebViewPrivacy) {
|
||||
// view?.loadUrl(mLocalPrivacyHtml)
|
||||
// } else {
|
||||
// view?.loadUrl(mLocalRegulationHtml)
|
||||
// }
|
||||
override fun onClick(widget: View) {
|
||||
directToExternalBrowser(requireContext(), requireContext().getString(R.string.disclaimer_url))
|
||||
}
|
||||
}, skipText.length - 4, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
descTv?.movementMethod = CustomLinkMovementMethod()
|
||||
descTv?.text = skipText
|
||||
|
||||
// val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
|
||||
//
|
||||
// mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
|
||||
//
|
||||
// val settingsArrayList = arrayListOf(mWebViewPrivacy?.settings, mWebViewRegulation?.settings)
|
||||
//
|
||||
// for (settings in settingsArrayList) {
|
||||
// settings?.javaScriptEnabled = true
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
|
||||
// }
|
||||
// // 避免提示网页有害信息不能访问
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// settings?.safeBrowsingEnabled = false
|
||||
// }
|
||||
//
|
||||
// // 适配大于屏幕宽度的页面
|
||||
// settings?.useWideViewPort = true
|
||||
// settings?.loadWithOverviewMode = true
|
||||
// settings?.domStorageEnabled = true
|
||||
//
|
||||
// // 自适应屏幕
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
// settings?.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING
|
||||
// }
|
||||
// }
|
||||
|
||||
// mWebViewPrivacy?.webViewClient = client
|
||||
// mWebViewRegulation?.webViewClient = client
|
||||
|
||||
mTitlePrivacyTv?.setOnClickListener {
|
||||
mTitlePrivacyTv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
|
||||
mTitleRegulationTv?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_F5F5F5))
|
||||
|
||||
mWebViewPrivacy?.visibility = View.VISIBLE
|
||||
mWebViewRegulation?.visibility = View.GONE
|
||||
}
|
||||
|
||||
mTitleRegulationTv?.setOnClickListener {
|
||||
mTitlePrivacyTv?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_F5F5F5))
|
||||
mTitleRegulationTv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
|
||||
|
||||
mWebViewPrivacy?.visibility = View.GONE
|
||||
mWebViewRegulation?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
containerView?.findViewById<View>(R.id.refuseTv)?.setOnClickListener {
|
||||
mCallBack?.invoke(false)
|
||||
dismiss()
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
containerView?.findViewById<View>(R.id.agreeTv)?.setOnClickListener {
|
||||
mCallBack?.invoke(true)
|
||||
dismiss()
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,9 +13,13 @@ data class ExposureEntity(
|
||||
val gameName: String? = "",
|
||||
val gameVersion: String? = "",
|
||||
val sequence: Int? = 0,
|
||||
val outerSequence: Int? = 0,
|
||||
val platform: String? = "",
|
||||
var isMirrorData: Boolean = false,
|
||||
val downloadType: String? = "",
|
||||
val downloadCompleteType: String? = "",
|
||||
@SerializedName("display_type")
|
||||
val displayType: String? = "",
|
||||
|
||||
// 下载地址的 host 和 path
|
||||
var host: String? = "",
|
||||
|
||||
@ -10,6 +10,7 @@ import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.exposure.time.TimeUtil
|
||||
import com.gh.common.util.getFirstElementDividedByDivider
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import java.util.*
|
||||
|
||||
@ -35,13 +36,16 @@ data class ExposureEvent(
|
||||
}
|
||||
return ExposureEvent(
|
||||
payload = ExposureEntity(
|
||||
gameId = gameEntity?.id?.getFirstElementDividedByDivider(Constants.GAME_ID_DIVIDER),
|
||||
gameName = gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
|
||||
gameVersion = gameEntity?.gameVersion,
|
||||
sequence = gameEntity?.sequence,
|
||||
platform = gameEntity?.platform,
|
||||
gameId = gameEntity?.id?.getFirstElementDividedByDivider(DownloadEntity.GAME_ID_DIVIDER),
|
||||
gameName = eTrace?.firstOrNull()?.payload?.gameName ?: gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
|
||||
gameVersion = eTrace?.firstOrNull()?.payload?.gameVersion ?:gameEntity?.gameVersion,
|
||||
isMirrorData = eTrace?.firstOrNull()?.payload?.isMirrorData ?: gameEntity?.shouldUseMirrorInfo() ?: false,
|
||||
sequence = eTrace?.firstOrNull()?.payload?.sequence ?: gameEntity?.sequence,
|
||||
outerSequence = eTrace?.firstOrNull()?.payload?.outerSequence ?: gameEntity?.outerSequence,
|
||||
platform = eTrace?.firstOrNull()?.payload?.platform ?:gameEntity?.platform,
|
||||
downloadType = gameEntity?.downloadType,
|
||||
downloadCompleteType = gameEntity?.downloadCompleteType,
|
||||
displayType = eTrace?.firstOrNull()?.payload?.displayType ?:gameEntity?.displayContent,
|
||||
// ugly
|
||||
welcomeDialogId = gameEntity?.welcomeDialogId ?: eTrace?.firstOrNull()?.payload?.welcomeDialogId,
|
||||
welcomeDialogLinkTitle = gameEntity?.welcomeDialogTitle ?: eTrace?.firstOrNull()?.payload?.welcomeDialogLinkTitle),
|
||||
|
||||
@ -11,20 +11,16 @@ import io.reactivex.functions.Consumer
|
||||
*/
|
||||
class ExposureListener(var fragment: Fragment, var exposable: IExposable) : RecyclerView.OnScrollListener() {
|
||||
|
||||
var throttleBus: ExposureThrottleBus? = null
|
||||
val throttleBus: ExposureThrottleBus by lazy { ExposureThrottleBus(Consumer { commitExposure(it) }, Consumer(Throwable::printStackTrace)) }
|
||||
var layoutManager: LinearLayoutManager? = null
|
||||
var visibleState: ExposureThrottleBus.VisibleState? = null
|
||||
|
||||
init {
|
||||
fragment.fragmentManager?.registerFragmentLifecycleCallbacks(
|
||||
object : FragmentManager.FragmentLifecycleCallbacks() {
|
||||
override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
|
||||
throttleBus = ExposureThrottleBus(Consumer { commitExposure(it) }, Consumer(Throwable::printStackTrace))
|
||||
}
|
||||
|
||||
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
|
||||
visibleState?.let { commitExposure(it) }
|
||||
throttleBus?.clear()
|
||||
throttleBus.clear()
|
||||
}
|
||||
|
||||
override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {
|
||||
@ -44,7 +40,7 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
|
||||
|
||||
layoutManager?.run {
|
||||
visibleState = ExposureThrottleBus.VisibleState(findFirstVisibleItemPosition(), findLastVisibleItemPosition())
|
||||
throttleBus?.postVisibleState(visibleState!!)
|
||||
throttleBus.postVisibleState(visibleState!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import com.gh.loghub.LgLOG
|
||||
import com.gh.loghub.LoghubHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
||||
/**
|
||||
* A handful tool for committing logs to aliyun loghub.
|
||||
@ -31,17 +31,19 @@ object ExposureManager {
|
||||
|
||||
// exposureCache 用来过滤掉具有相同 id 的曝光事件,避免重复发送事件
|
||||
private val exposureSet by lazy { hashSetOf<ExposureEvent>() }
|
||||
private val exposureExecutor by lazy { Executors.newSingleThreadExecutor() }
|
||||
private var exposureExecutor: ExecutorService? = null
|
||||
private val exposureCache by lazy { FixedSizeLinkedHashSet<String>(300) }
|
||||
private val exposureDao by lazy { ExposureDatabase.buildDatabase(HaloApp.getInstance().application).logHubEventDao() }
|
||||
|
||||
@JvmStatic
|
||||
fun init() {
|
||||
fun init(excutor: ExecutorService) {
|
||||
loghubHelper.init(HaloApp.getInstance().application, ENDPOINT, PROJECT, LOG_STORE) { TimeUtil.currentTimeMillis() }
|
||||
|
||||
exposureExecutor.execute {
|
||||
val eventList = exposureDao.getAll()
|
||||
exposureSet.addAll(eventList)
|
||||
exposureExecutor = excutor
|
||||
exposureExecutor?.execute {
|
||||
tryWithDefaultCatch {
|
||||
val eventList = exposureDao.getAll()
|
||||
exposureSet.addAll(eventList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +51,7 @@ object ExposureManager {
|
||||
* Log a single exposure event.
|
||||
*/
|
||||
fun log(event: ExposureEvent) {
|
||||
exposureExecutor.execute {
|
||||
exposureExecutor?.execute {
|
||||
try {
|
||||
if (!exposureCache.contains(event.id)) {
|
||||
// Catch `android.database.sqlite.SQLiteFullException: database or disk is full` exception.
|
||||
@ -71,7 +73,7 @@ object ExposureManager {
|
||||
* Log a collection of exposure event.
|
||||
*/
|
||||
fun log(eventList: List<ExposureEvent>) {
|
||||
exposureExecutor.execute {
|
||||
exposureExecutor?.execute {
|
||||
for (event in eventList) {
|
||||
try {
|
||||
if (!exposureCache.contains(event.id)) {
|
||||
@ -94,7 +96,7 @@ object ExposureManager {
|
||||
* @param forced Ignore all restrictions.
|
||||
*/
|
||||
fun commitSavedExposureEvents(forced: Boolean = false) {
|
||||
exposureExecutor.execute {
|
||||
exposureExecutor?.execute {
|
||||
tryWithDefaultCatch {
|
||||
// TODO 初始化 loghubHelper 去掉这个 tryCatch 块
|
||||
if (exposureSet.size < STORE_SIZE && !forced || exposureSet.size == 0) return@execute
|
||||
@ -138,7 +140,7 @@ object ExposureManager {
|
||||
return log
|
||||
}
|
||||
|
||||
internal class FixedSizeLinkedHashSet<T>(var maxSize: Int) : LinkedHashSet<T>() {
|
||||
class FixedSizeLinkedHashSet<T>(var maxSize: Int) : LinkedHashSet<T>() {
|
||||
override fun add(element: T): Boolean {
|
||||
if (size == maxSize) {
|
||||
pop()
|
||||
|
||||
@ -2,35 +2,39 @@ package com.gh.common.exposure
|
||||
|
||||
import android.text.TextUtils
|
||||
import com.g00fy2.versioncompare.Version
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.common.util.toObject
|
||||
import com.gh.gamecenter.entity.ApkEntity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.halo.assistant.HaloApp
|
||||
import java.util.*
|
||||
import com.lightgame.download.DownloadEntity
|
||||
|
||||
object ExposureUtils {
|
||||
|
||||
private val mDownloadCompleteTraceEventIdSet = ExposureManager.FixedSizeLinkedHashSet<String>(3)
|
||||
|
||||
@JvmStatic
|
||||
fun logADownloadExposureEvent(entity: GameEntity,
|
||||
platform: String?,
|
||||
traceEvent: ExposureEvent?,
|
||||
downloadType: DownloadType): ExposureEvent {
|
||||
val gameEntity = entity.clone()
|
||||
gameEntity.id = if (entity.id.contains(Constants.GAME_ID_DIVIDER)) {
|
||||
entity.id.split(Constants.GAME_ID_DIVIDER).toTypedArray()[0]
|
||||
gameEntity.id = if (entity.id.contains(DownloadEntity.GAME_ID_DIVIDER)) {
|
||||
entity.id.split(DownloadEntity.GAME_ID_DIVIDER).toTypedArray()[0]
|
||||
} else {
|
||||
entity.id
|
||||
}
|
||||
gameEntity.gameVersion = entity.getApk().elementAtOrNull(0)?.version ?: gameEntity.gameVersion
|
||||
gameEntity.gameVersion = entity.getApk().elementAtOrNull(0)?.version
|
||||
?: gameEntity.gameVersion
|
||||
gameEntity.platform = platform
|
||||
gameEntity.downloadType = downloadType.toString()
|
||||
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
|
||||
source = traceEvent?.source ?: ArrayList(),
|
||||
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
|
||||
event = ExposureType.DOWNLOAD)
|
||||
ExposureManager.log(exposureEvent)
|
||||
if (!TextUtils.isEmpty(entity.id)) {
|
||||
ExposureManager.log(exposureEvent)
|
||||
}
|
||||
return exposureEvent
|
||||
}
|
||||
|
||||
@ -45,6 +49,16 @@ object ExposureUtils {
|
||||
gameEntity.platform = platform
|
||||
gameEntity.downloadCompleteType = downloadType.toString()
|
||||
val traceEvent = trace?.toObject<ExposureEvent>()
|
||||
|
||||
if (TextUtils.isEmpty(entity.id)) return
|
||||
|
||||
// 避免生成 trace 相同的下载完成事件,根据日志看下载完成的同一秒有可能生成两条
|
||||
if (mDownloadCompleteTraceEventIdSet.contains(traceEvent?.id)) {
|
||||
return
|
||||
}
|
||||
|
||||
traceEvent?.payload?.gameId?.let { mDownloadCompleteTraceEventIdSet.add(it) }
|
||||
|
||||
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
|
||||
source = traceEvent?.source ?: ArrayList(),
|
||||
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
|
||||
@ -80,6 +94,15 @@ object ExposureUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun updateExposureSequence(gameList: List<GameEntity>?) {
|
||||
gameList?.let {
|
||||
for ((index, game) in it.withIndex()) {
|
||||
game.sequence = index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class DownloadType {
|
||||
DOWNLOAD,
|
||||
|
||||
|
||||
@ -8,10 +8,10 @@ import kotlinx.android.parcel.Parcelize
|
||||
@Parcelize
|
||||
data class Meta(
|
||||
val mac: String? = "",
|
||||
val imei: String? = "",
|
||||
val jnfj: String? = "",
|
||||
val model: String? = "",
|
||||
val manufacturer: String? = "",
|
||||
val android_id: String? = "",
|
||||
val dia: String? = "",
|
||||
val android_sdk: Int? = -1,
|
||||
val android_version: String? = "",
|
||||
val network: String? = "",
|
||||
|
||||
@ -11,6 +11,7 @@ import android.telephony.TelephonyManager
|
||||
import android.text.TextUtils
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.SPUtils
|
||||
import com.gh.common.util.tryWithDefaultCatch
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.halo.assistant.HaloApp
|
||||
@ -24,14 +25,27 @@ object MetaUtil {
|
||||
|
||||
private var m: Meta? = null
|
||||
private var imei: String? = null
|
||||
private var base64EncodedImei: String? = null
|
||||
private var androidId: String? = null
|
||||
private var base64EncodedAndroidId: String? = null
|
||||
|
||||
private var romName: String? = null
|
||||
private var romVersion: String? = null
|
||||
|
||||
fun refreshMeta() {
|
||||
|
||||
if (romName == null) {
|
||||
tryWithDefaultCatch {
|
||||
romName = RomIdentifier.getRom().name
|
||||
romVersion = RomIdentifier.getRom().versionName
|
||||
}
|
||||
}
|
||||
|
||||
m = Meta(mac = "",
|
||||
imei = getIMEI(),
|
||||
jnfj = getBase64EncodedIMEI(),
|
||||
model = getModel(),
|
||||
manufacturer = getManufacturer(),
|
||||
android_id = getAndroidId(),
|
||||
dia = getBase64EncodedAndroidId(),
|
||||
android_sdk = getAndroidSDK(),
|
||||
android_version = getAndroidVersion(),
|
||||
network = getNetwork(),
|
||||
@ -42,7 +56,7 @@ object MetaUtil {
|
||||
appVersion = BuildConfig.VERSION_NAME,
|
||||
userId = UserManager.getInstance().userId,
|
||||
exposureVersion = BuildConfig.EXPOSURE_VERSION,
|
||||
rom = RomIdentifier.getRom().name + "" + RomIdentifier.getRom().versionName)
|
||||
rom = romName + "" + romVersion)
|
||||
}
|
||||
|
||||
fun getMeta(): Meta {
|
||||
@ -104,6 +118,42 @@ object MetaUtil {
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getBase64EncodedIMEI(): String {
|
||||
if (imei == null) {
|
||||
getIMEI()
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(base64EncodedImei) && imei != null) {
|
||||
try {
|
||||
base64EncodedImei = android.util.Base64.encodeToString(getIMEI().trim().toByteArray(), android.util.Base64.NO_WRAP)
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
return base64EncodedImei ?: ""
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getBase64EncodedAndroidId(): String {
|
||||
if (androidId == null) {
|
||||
getAndroidId()
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(base64EncodedAndroidId) && androidId != null) {
|
||||
try {
|
||||
base64EncodedAndroidId = android.util.Base64.encodeToString(getAndroidId().trim().toByteArray(), android.util.Base64.NO_WRAP)
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
return base64EncodedAndroidId ?: ""
|
||||
}
|
||||
|
||||
fun getModel(): String? {
|
||||
return Build.MODEL
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package com.gh.common.filter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.SPUtils
|
||||
import com.gh.common.util.debounceActionWithInterval
|
||||
@ -14,6 +13,7 @@ import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.functions.Function
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
object RegionSettingHelper {
|
||||
|
||||
@ -67,7 +67,7 @@ object RegionSettingHelper {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.sensitiveApi
|
||||
.getRegionSetting(HaloApp.getInstance().channel)
|
||||
.subscribeOn(AppExecutor.cachedScheduler)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<RegionSetting>() {
|
||||
override fun onSuccess(data: RegionSetting) {
|
||||
@ -76,7 +76,7 @@ object RegionSettingHelper {
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
SPUtils.getString(SP_SETTING).toObject<RegionSetting>()?.let {
|
||||
SPUtils.getString(SP_SETTING)?.toObject<RegionSetting>()?.let {
|
||||
updateSettingsInMemory(it)
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ import com.gh.gamecenter.room.converter.*
|
||||
import com.gh.gamecenter.room.dao.*
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 7, exportSchema = false)
|
||||
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 8, exportSchema = false)
|
||||
@TypeConverters(CountConverter::class,
|
||||
CommunityConverter::class,
|
||||
TimeConverter::class,
|
||||
@ -23,8 +23,10 @@ import com.halo.assistant.HaloApp
|
||||
ThumbnailConverter::class,
|
||||
TagStyleListConverter::class,
|
||||
StringArrayListConverter::class,
|
||||
ListStringConverter::class,
|
||||
CommunityVideoConverter::class,
|
||||
UserConverter::class)
|
||||
UserConverter::class,
|
||||
ImageInfoConverter::class)
|
||||
|
||||
abstract class HistoryDatabase : RoomDatabase() {
|
||||
|
||||
@ -69,6 +71,14 @@ abstract class HistoryDatabase : RoomDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_7_8: Migration = object : Migration(7, 8) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("Alter TABLE ArticleEntity add images TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add imagesInfo TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add imagesInfo TEXT NOT NULL DEFAULT ''")
|
||||
}
|
||||
}
|
||||
|
||||
val instance by lazy {
|
||||
Room.databaseBuilder(HaloApp.getInstance().application, HistoryDatabase::class.java, "USER_TRACK_HISTORY_DATABASE")
|
||||
.addMigrations(MIGRATION_2_3)
|
||||
@ -76,6 +86,7 @@ abstract class HistoryDatabase : RoomDatabase() {
|
||||
.addMigrations(MIGRATION_4_5)
|
||||
.addMigrations(MIGRATION_5_6)
|
||||
.addMigrations(MIGRATION_6_7)
|
||||
.addMigrations(MIGRATION_7_8)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import com.gh.common.runOnIoThread
|
||||
import com.gh.common.util.clearHtmlFormatCompletely
|
||||
import com.gh.common.util.removeInsertedContent
|
||||
import com.gh.common.util.removeVideoContent
|
||||
import com.gh.common.util.tryCatchInRelease
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.qa.entity.AnswerDetailEntity
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
@ -14,27 +15,28 @@ object HistoryHelper {
|
||||
|
||||
fun insertAnswerEntity(answerDetailEntity: AnswerDetailEntity) {
|
||||
val answerEntity = convertAnswerDetailToAnswer(answerDetailEntity)
|
||||
runOnIoThread { HistoryDatabase.instance.answerDao().addAnswer(answerEntity) }
|
||||
// 偶尔有设备会出现磁盘满了写不进数据库的问题 database or disk is full 异常,毕竟只是插入个本地历史,这里直接捕抓
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.answerDao().addAnswer(answerEntity) } }
|
||||
}
|
||||
|
||||
fun insertArticleEntity(articleDetailEntity: ArticleDetailEntity) {
|
||||
val articleEntity = convertArticleDetailToArticle(articleDetailEntity)
|
||||
runOnIoThread { HistoryDatabase.instance.articleDao().addArticle(articleEntity) }
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.articleDao().addArticle(articleEntity) } }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun insertGameEntity(gameEntity: GameEntity) {
|
||||
val historyGameEntity = convertGameEntityToHistoryGameEntity(gameEntity)
|
||||
runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) }
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun insertGameEntity(updateEntity: GameUpdateEntity) {
|
||||
val historyGameEntity = convertGameUpdateEntityToHistoryGameEntity(updateEntity)
|
||||
runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) }
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } }
|
||||
}
|
||||
|
||||
private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity{
|
||||
private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity {
|
||||
val historyGame = HistoryGameEntity()
|
||||
|
||||
historyGame.orderTag = System.currentTimeMillis()
|
||||
@ -67,48 +69,44 @@ object HistoryHelper {
|
||||
@JvmStatic
|
||||
fun insertNewsEntity(newsEntity: NewsEntity) {
|
||||
newsEntity.orderTag = System.currentTimeMillis()
|
||||
runOnIoThread { HistoryDatabase.instance.newsDao().addNews(newsEntity) }
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.newsDao().addNews(newsEntity) } }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteNewsEntity(newsId: String) {
|
||||
runOnIoThread { HistoryDatabase.instance.newsDao().deleteNews(NewsEntity().apply { id = newsId }) }
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.newsDao().deleteNews(NewsEntity().apply { id = newsId }) } }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteGameEntity(gameId: String) {
|
||||
runOnIoThread { HistoryDatabase.instance.gameDao().deleteGame(HistoryGameEntity(id = gameId)) }
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().deleteGame(HistoryGameEntity(id = gameId)) } }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteArticleEntity(articleId: String) {
|
||||
runOnIoThread { HistoryDatabase.instance.articleDao().deleteArticle(ArticleEntity(id = articleId)) }
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.articleDao().deleteArticle(ArticleEntity(id = articleId)) } }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteAnswerEntity(answerId: String) {
|
||||
runOnIoThread { HistoryDatabase.instance.answerDao().deleteAnswer(AnswerEntity().apply { primaryKey = answerId }) }
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.answerDao().deleteAnswer(AnswerEntity().apply { primaryKey = answerId }) } }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteVideoEntity(videoId: String) {
|
||||
runOnIoThread { HistoryDatabase.instance.videoHistoryDao().deleteVideo(MyVideoEntity().apply { id = videoId }) }
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().deleteVideo(MyVideoEntity().apply { id = videoId }) } }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun emptyDatabase() {
|
||||
runOnIoThread { HistoryDatabase.instance.clearAllTables() }
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.clearAllTables() } }
|
||||
}
|
||||
|
||||
private fun convertArticleDetailToArticle(articleDetailEntity: ArticleDetailEntity): ArticleEntity {
|
||||
val articleEntity = ArticleEntity()
|
||||
|
||||
articleEntity.id = articleDetailEntity.id
|
||||
articleEntity.brief = articleDetailEntity.content.
|
||||
removeVideoContent().
|
||||
removeInsertedContent().
|
||||
clearHtmlFormatCompletely().
|
||||
replace(" +".toRegex()," ")
|
||||
articleEntity.brief = articleDetailEntity.content.removeVideoContent().removeInsertedContent().clearHtmlFormatCompletely().replace(" +".toRegex(), " ")
|
||||
articleEntity.count = articleDetailEntity.count
|
||||
articleDetailEntity.community.id = articleDetailEntity.communityId
|
||||
articleEntity.community = articleDetailEntity.community
|
||||
@ -116,6 +114,9 @@ object HistoryHelper {
|
||||
articleEntity.title = articleDetailEntity.title
|
||||
articleEntity.user = articleDetailEntity.user
|
||||
articleEntity.orderTag = System.currentTimeMillis()
|
||||
articleEntity.images = articleDetailEntity.images
|
||||
articleEntity.imagesInfo = articleDetailEntity.imagesInfo
|
||||
articleEntity.videos = articleDetailEntity.videos
|
||||
|
||||
return articleEntity
|
||||
}
|
||||
@ -130,12 +131,11 @@ object HistoryHelper {
|
||||
answerEntity.vote = answerDetailEntity.vote
|
||||
answerEntity.user = answerDetailEntity.user
|
||||
answerEntity.orderTag = System.currentTimeMillis()
|
||||
answerEntity.brief = answerDetailEntity.content.
|
||||
removeVideoContent().
|
||||
removeInsertedContent().
|
||||
clearHtmlFormatCompletely().
|
||||
replace(" +".toRegex(), " ")
|
||||
answerEntity.brief = answerDetailEntity.content.removeVideoContent().removeInsertedContent().clearHtmlFormatCompletely().replace(" +".toRegex(), " ")
|
||||
answerEntity.time = answerDetailEntity.time
|
||||
answerEntity.images = answerDetailEntity.images
|
||||
answerEntity.imagesInfo = answerDetailEntity.imagesInfo
|
||||
answerEntity.videos = answerDetailEntity.videos
|
||||
|
||||
return answerEntity
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import com.gh.common.exposure.meta.Meta
|
||||
import com.gh.common.util.tryWithDefaultCatch
|
||||
import com.gh.loghub.LoghubHelper
|
||||
import org.json.JSONObject
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
||||
object LoghubUtils {
|
||||
|
||||
@ -17,22 +17,25 @@ object LoghubUtils {
|
||||
private lateinit var mApplication: Application
|
||||
|
||||
private val loghubEventSet by lazy { hashSetOf<LoghubEvent>() }
|
||||
private val loghubEventExecutor by lazy { Executors.newSingleThreadExecutor() }
|
||||
private var loghubEventExecutor: ExecutorService? = null
|
||||
private val loghubEventDao by lazy { LoghubDatabase.buildDatabase(mApplication).logHubEventDao() }
|
||||
|
||||
@JvmStatic
|
||||
fun init(application: Application) {
|
||||
fun init(application: Application, executor: ExecutorService) {
|
||||
mApplication = application
|
||||
|
||||
loghubEventExecutor.execute {
|
||||
val eventList = loghubEventDao.getAll()
|
||||
loghubEventSet.addAll(eventList)
|
||||
loghubEventExecutor = executor
|
||||
loghubEventExecutor?.execute {
|
||||
tryWithDefaultCatch {
|
||||
val eventList = loghubEventDao.getAll()
|
||||
loghubEventSet.addAll(eventList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun log(logJson: JSONObject, logStore: String, forcedUpload: Boolean) {
|
||||
loghubEventExecutor.execute {
|
||||
loghubEventExecutor?.execute {
|
||||
try {
|
||||
val event = LoghubEvent(time = (System.currentTimeMillis() / 1000L).toString(), content = logJson.toString(), logStore = logStore)
|
||||
loghubEventSet.add(event)
|
||||
@ -49,7 +52,7 @@ object LoghubUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun log(jsonString: String, logStore: String, forcedUpload: Boolean) {
|
||||
loghubEventExecutor.execute {
|
||||
loghubEventExecutor?.execute {
|
||||
try {
|
||||
val event = LoghubEvent(time = (System.currentTimeMillis() / 1000L).toString(), content = jsonString, logStore = logStore)
|
||||
loghubEventSet.add(event)
|
||||
@ -69,7 +72,7 @@ object LoghubUtils {
|
||||
}
|
||||
|
||||
fun commitSavedLoghubEvents() {
|
||||
loghubEventExecutor.execute {
|
||||
loghubEventExecutor?.execute {
|
||||
// TODO 初始化 loghubHelper 去掉这个 tryCatch 块
|
||||
tryWithDefaultCatch {
|
||||
if (loghubEventSet.isEmpty()) return@execute
|
||||
|
||||
@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.database.ContentObserver
|
||||
import android.media.AudioManager
|
||||
import android.os.Handler
|
||||
import com.gh.common.util.tryCatchInRelease
|
||||
|
||||
class VolumeObserver(var context: Context, handler: Handler, var callback: MuteCallback? = null)
|
||||
: ContentObserver(handler) {
|
||||
@ -11,14 +12,20 @@ class VolumeObserver(var context: Context, handler: Handler, var callback: MuteC
|
||||
|
||||
init {
|
||||
val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||
// 部分设备的 audioManager getStreamVolume 内部会触发空指针 :(
|
||||
tryCatchInRelease { previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC) }
|
||||
}
|
||||
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
super.onChange(selfChange)
|
||||
|
||||
val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
val currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||
var currentVolume = 0
|
||||
|
||||
tryCatchInRelease {
|
||||
// 部分设备(Meizu 7.1.2 M6 Note)的 audioManager getStreamVolume 内部会触发空指针 :(
|
||||
currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||
}
|
||||
|
||||
val delta = previousVolume - currentVolume
|
||||
|
||||
|
||||
@ -2,10 +2,12 @@ package com.gh.common.simulator
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.g00fy2.versioncompare.Version
|
||||
@ -13,7 +15,6 @@ import com.gh.common.AppExecutor.uiExecutor
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.dialog.TrackableDialog
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.PackageInstaller.getDownloadPath
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.ApkEntity
|
||||
@ -22,6 +23,7 @@ import com.gh.gamecenter.entity.TrackableEntity
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.*
|
||||
import com.lightgame.utils.Utils
|
||||
import java.lang.ref.WeakReference
|
||||
import java.text.DecimalFormat
|
||||
|
||||
class SimulatorDownloadManager private constructor() {
|
||||
@ -33,6 +35,7 @@ class SimulatorDownloadManager private constructor() {
|
||||
private var appProgressFilling: View? = null
|
||||
private var appProgressAnchor: View? = null
|
||||
private var downloadDialog: Dialog? = null
|
||||
private var mContextRef: WeakReference<Context>? = null
|
||||
|
||||
private var simulatorLocation: SimulatorLocation? = null
|
||||
private var simulator: SimulatorEntity? = null
|
||||
@ -70,7 +73,10 @@ class SimulatorDownloadManager private constructor() {
|
||||
val startTime = downloadEntity.getMetaExtra(Constants.SIMULATOR_DOWNLOAD_START_TIME)
|
||||
LogUtils.uploadSimulatorDownload("simulator_download_complete", fileName, simulator?.id, downloadEntity.name, gameId, locationStr, downloadType, startTime)
|
||||
DownloadManager.getInstance(HaloApp.getInstance().application).cancel(downloadEntity.url, false, true)
|
||||
downloadDialog?.dismiss()
|
||||
val activity = mContextRef?.get() as? AppCompatActivity
|
||||
if (activity?.isFinishing == false) {
|
||||
downloadDialog?.dismiss()
|
||||
}
|
||||
}
|
||||
DownloadStatus.neterror == downloadEntity.status -> {
|
||||
ToastUtils.showToast("网络不稳定,下载任务已暂停")
|
||||
@ -93,7 +99,9 @@ class SimulatorDownloadManager private constructor() {
|
||||
showDownloadDialog(context, simulator, location, "", "", null)
|
||||
}
|
||||
|
||||
fun showDownloadDialog(context: Context, simulator: SimulatorEntity?, location: SimulatorLocation, gameId: String = "", gameName: String = "", cancelCallback: (() -> Unit)? = null) {
|
||||
fun showDownloadDialog(context: Context?, simulator: SimulatorEntity?, location: SimulatorLocation, gameId: String = "", gameName: String = "", cancelCallback: (() -> Unit)? = null) {
|
||||
if (context == null) return
|
||||
mContextRef = WeakReference(context)
|
||||
this.simulatorLocation = location
|
||||
this.simulator = simulator
|
||||
this.gameId = gameId
|
||||
@ -116,8 +124,8 @@ class SimulatorDownloadManager private constructor() {
|
||||
key = if (shouldShowUpdate && isInstalled) "更新弹窗" else "下载弹窗",
|
||||
logShowEvent = true
|
||||
)
|
||||
DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, {
|
||||
if (shouldShowUpdate && isInstalled){
|
||||
DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, Gravity.LEFT, false, {
|
||||
if (shouldShowUpdate && isInstalled) {
|
||||
cancelCallback?.invoke()
|
||||
MtaHelper.onEvent(trackableEntity.event, trackableEntity.key, "点击下次再说")
|
||||
}
|
||||
@ -152,7 +160,10 @@ class SimulatorDownloadManager private constructor() {
|
||||
view.findViewById<View>(R.id.app_tv_cancel).setOnClickListener {
|
||||
DownloadManager.getInstance(context).pause(simulator?.apk?.url)
|
||||
MtaHelper.onEvent("模拟器下载", "下载中弹窗", "点击关闭")
|
||||
downloadDialog?.dismiss()
|
||||
val activity = mContextRef?.get() as? AppCompatActivity
|
||||
if (activity?.isFinishing == false) {
|
||||
downloadDialog?.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
downloadDialog?.setOnDismissListener {
|
||||
@ -183,6 +194,7 @@ class SimulatorDownloadManager private constructor() {
|
||||
DownloadManager.getInstance(context).pauseAll()
|
||||
|
||||
val entity = DownloadManager.getInstance(context).getDownloadEntityByUrl(apkEntity.url)
|
||||
HaloApp.put(simulator.name, simulator)
|
||||
if (entity != null) {
|
||||
when (entity.status) {
|
||||
DownloadStatus.pause, DownloadStatus.subscribe,
|
||||
@ -202,16 +214,18 @@ class SimulatorDownloadManager private constructor() {
|
||||
|
||||
private fun createDownload(context: Context, apkEntity: ApkEntity, simulator: SimulatorEntity) {
|
||||
DownloadManager.getInstance(context).addObserver(dataWatcher)
|
||||
val downloadId = PackageInstaller.createDownloadId(simulator.name)
|
||||
val downloadEntity = DownloadEntity()
|
||||
downloadEntity.url = apkEntity.url
|
||||
downloadEntity.name = simulator.name
|
||||
downloadEntity.path = getDownloadPath(simulator.name, apkEntity.format)
|
||||
downloadEntity.path = PackageInstaller.getDownloadPathWithId(downloadId, apkEntity.format)
|
||||
downloadEntity.platform = apkEntity.getPlatform()
|
||||
downloadEntity.packageName = apkEntity.packageName
|
||||
downloadEntity.versionName = apkEntity.version
|
||||
|
||||
downloadEntity.addMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE, Constants.SIMULATOR_DOWNLOAD)
|
||||
downloadEntity.addMetaExtra(Constants.SIMULATOR_DOWNLOAD_START_TIME, (System.currentTimeMillis() / 1000).toString())
|
||||
downloadEntity.addMetaExtra(Constants.DOWNLOAD_ID, downloadId)
|
||||
uiExecutor.executeWithDelay(Runnable { DownloadManager.getInstance(context).add(downloadEntity) }, 200)
|
||||
|
||||
val locationStr = if (simulatorLocation == SimulatorLocation.LAUNCH) "${simulatorLocation?.value}《${gameName}》" else simulatorLocation?.value
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.common.simulator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import com.g00fy2.versioncompare.Version
|
||||
@ -18,9 +19,11 @@ import com.lightgame.download.DownloadDao
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.FileUtils
|
||||
import com.lightgame.utils.AppManager
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
|
||||
|
||||
@ -33,7 +36,7 @@ object SimulatorGameManager {
|
||||
|
||||
@JvmStatic
|
||||
fun deleteLocalGames(names: List<String>) {
|
||||
val downloadEntityList = DownloadDao.getInstance(HaloApp.getInstance().application).all
|
||||
val downloadEntityList = DownloadManager.getInstance(HaloApp.getInstance().application).allDownloadEntity
|
||||
names.forEach { name ->
|
||||
val downloadEntity = downloadEntityList.find { it.name == name }
|
||||
if (downloadEntity != null) {
|
||||
@ -48,7 +51,7 @@ object SimulatorGameManager {
|
||||
|
||||
@JvmStatic
|
||||
fun deleteLocalGame(name: String) {
|
||||
val downloadEntityList = DownloadDao.getInstance(HaloApp.getInstance().application).all
|
||||
val downloadEntityList = DownloadManager.getInstance(HaloApp.getInstance().application).allDownloadEntity
|
||||
val downloadEntity = downloadEntityList.find { it.name == name }
|
||||
if (downloadEntity != null) {
|
||||
val file = File(downloadEntity.path)
|
||||
@ -90,31 +93,62 @@ object SimulatorGameManager {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun jumpToSimulator(downloadEntity: DownloadEntity, gameEntity: GameEntity) {
|
||||
val intent = Intent()
|
||||
intent.data = Uri.fromFile(File(downloadEntity.path))
|
||||
if (gameEntity.simulatorType == "FBA") {
|
||||
val apkEntity = gameEntity.getApk()[0]
|
||||
intent.putExtra("rom_name", apkEntity.packageName)
|
||||
}
|
||||
intent.putExtra("default_path", downloadEntity.path.substring(0, downloadEntity.path.lastIndexOf('/')))
|
||||
intent.putExtra("game_type", gameEntity.simulatorType)
|
||||
intent.putExtra("title", downloadEntity.name)
|
||||
intent.putExtra("icon", gameEntity.icon ?: "")
|
||||
intent.putExtra("meta", LogUtils.getMetaObject().toString())
|
||||
intent.putExtra("simulatorId", gameEntity.simulator?.id)
|
||||
intent.putExtra("simulatorName", gameEntity.simulator?.name)
|
||||
intent.putExtra("gameId", gameEntity.id)
|
||||
Single.just(gameEntity.icon ?: "")
|
||||
.flatMap {
|
||||
getBitmapFormCache(it)
|
||||
}.map {
|
||||
BitmapUtils.compressBitmap(it, 100)
|
||||
}.map {
|
||||
val baos = ByteArrayOutputStream()
|
||||
it.compress(Bitmap.CompressFormat.WEBP, 100, baos)
|
||||
baos.toByteArray()
|
||||
}
|
||||
.compose(singleToMain())
|
||||
.subscribe({
|
||||
val intent = Intent()
|
||||
intent.data = Uri.fromFile(File(downloadEntity.path))
|
||||
if (gameEntity.simulatorType == "FBA") {
|
||||
val apkEntity = gameEntity.getApk()[0]
|
||||
intent.putExtra("rom_name", apkEntity.packageName)
|
||||
}
|
||||
intent.putExtra("default_path", downloadEntity.path.substring(0, downloadEntity.path.lastIndexOf('/')))
|
||||
intent.putExtra("game_type", gameEntity.simulatorType)
|
||||
intent.putExtra("title", downloadEntity.name)
|
||||
intent.putExtra("icon", gameEntity.icon ?: "")
|
||||
intent.putExtra("iconStream", it)
|
||||
intent.putExtra("meta", LogUtils.getMetaObject().toString())
|
||||
intent.putExtra("simulatorId", gameEntity.simulator?.id)
|
||||
intent.putExtra("simulatorName", gameEntity.simulator?.name)
|
||||
intent.putExtra("gameId", gameEntity.id)
|
||||
|
||||
val destActivity = "com.gh.emu.RequestPermissionActivity"
|
||||
intent.setClassName(gameEntity.simulator?.apk?.packageName ?: "", destActivity)
|
||||
try {
|
||||
AppManager.getInstance().recentActiveActivity.startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
ToastUtils.showToast("模拟器安装错误")
|
||||
}
|
||||
val destActivity = "com.gh.emu.RequestPermissionActivity"
|
||||
intent.setClassName(gameEntity.simulator?.apk?.packageName ?: "", destActivity)
|
||||
try {
|
||||
AppManager.getInstance().recentActiveActivity?.startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
ToastUtils.showToast("模拟器安装错误")
|
||||
}
|
||||
|
||||
recordPlaySimulatorGames(gameEntity.id)
|
||||
recordPlaySimulatorGames(gameEntity.id)
|
||||
}, {
|
||||
ToastUtils.showToast("跳转失败")
|
||||
})
|
||||
}
|
||||
|
||||
private fun getBitmapFormCache(url: String): Single<Bitmap> {
|
||||
return Single.create {
|
||||
ImageUtils.getBitmap(url, object : BiCallback<Bitmap, Boolean> {
|
||||
override fun onFirst(first: Bitmap) {
|
||||
it.onSuccess(first)
|
||||
}
|
||||
|
||||
override fun onSecond(second: Boolean) {
|
||||
it.onError(Throwable("获取bitmap失败"))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.gamecenter.entity.SettingsEntity
|
||||
import com.gh.gamecenter.entity.StartupAdEntity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
object AdHelper {
|
||||
|
||||
@ -12,6 +19,28 @@ object AdHelper {
|
||||
const val LOCATION_DISCOVER = "discover"
|
||||
const val LOCATION_SIMULATOR_GAME = "simulator_game"
|
||||
|
||||
@JvmField
|
||||
var startupAd = MutableLiveData<StartupAdEntity>()
|
||||
|
||||
@JvmStatic
|
||||
@SuppressLint("CheckResult")
|
||||
fun getStartUpAd() {
|
||||
if (!NetworkUtils.isNetworkConnected(HaloApp.getInstance())) {
|
||||
startupAd.postValue(null)
|
||||
return
|
||||
}
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance())
|
||||
.api
|
||||
.getSplashAd(HaloApp.getInstance().channel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : BiResponse<StartupAdEntity>() {
|
||||
override fun onSuccess(data: StartupAdEntity) {
|
||||
startupAd.postValue(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun getAd(location: String): SettingsEntity.AD? {
|
||||
val adList = Config.getSettings()?.adList ?: return null
|
||||
|
||||
|
||||
@ -333,14 +333,19 @@ public class BitmapUtils {
|
||||
}
|
||||
|
||||
|
||||
public static Bitmap compressBitmap(Bitmap bitmap) {
|
||||
/**
|
||||
* 压缩图片
|
||||
*
|
||||
* @param bitmap
|
||||
* @param compressSize 压缩大小(单位k)
|
||||
*/
|
||||
public static Bitmap compressBitmap(Bitmap bitmap, int compressSize) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
Matrix matrix = new Matrix();
|
||||
Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
result.compress(Bitmap.CompressFormat.WEBP, 100, bos);
|
||||
|
||||
while (bos.toByteArray().length > 400 * 1024) {
|
||||
System.out.println(bos.toByteArray().length);
|
||||
while (bos.toByteArray().length > compressSize * 1024) {
|
||||
matrix.setScale(0.9f, 0.9f);
|
||||
result = Bitmap.createBitmap(result, 0, 0, result.getWidth(), result.getHeight(), matrix, true);
|
||||
bos.reset();
|
||||
|
||||
148
app/src/main/java/com/gh/common/util/CalendarHelper.kt
Normal file
148
app/src/main/java/com/gh/common/util/CalendarHelper.kt
Normal file
@ -0,0 +1,148 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.ContentUris
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.CalendarContract.*
|
||||
import android.text.TextUtils
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* 签到日历提醒辅助类
|
||||
*/
|
||||
object CalendarHelper {
|
||||
|
||||
private val CALENDAR_URL = Calendars.CONTENT_URI
|
||||
private val CALENDAR_EVENT_URL = Events.CONTENT_URI
|
||||
private val CALENDAR_REMINDER_URL = Reminders.CONTENT_URI
|
||||
private const val CALENDARS_NAME = "guanghuan"
|
||||
private const val CALENDARS_ACCOUNT_TYPE = BuildConfig.APPLICATION_ID
|
||||
private const val CALENDARS_DISPLAY_NAME = "光环助手"
|
||||
|
||||
|
||||
private fun checkAndAddCalendarAccount(context: Context): Int {
|
||||
val oldId: Int = checkCalendarAccount(context)
|
||||
return if (oldId >= 0) {
|
||||
oldId
|
||||
} else {
|
||||
val addId: Long = addCalendarAccount(context)
|
||||
if (addId >= 0) {
|
||||
checkCalendarAccount(context)
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCalendarAccount(context: Context): Int {
|
||||
val userCursor: Cursor? = context.contentResolver.query(CALENDAR_URL,
|
||||
null, null, null, null)
|
||||
return userCursor?.use {
|
||||
val count: Int = it.count
|
||||
if (count > 0) { // 存在现有账户,取第一个账户的id返回
|
||||
it.moveToFirst()
|
||||
it.getInt(userCursor.getColumnIndex(Calendars._ID))
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
} ?: -1
|
||||
}
|
||||
|
||||
private fun addCalendarAccount(context: Context): Long {
|
||||
val value = ContentValues().apply {
|
||||
put(Calendars.NAME, CALENDARS_NAME)
|
||||
put(Calendars.ACCOUNT_NAME, CALENDARS_DISPLAY_NAME)
|
||||
put(Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE)
|
||||
put(Calendars.CALENDAR_DISPLAY_NAME, CALENDARS_DISPLAY_NAME)
|
||||
put(Calendars.VISIBLE, 1)
|
||||
put(Calendars.CALENDAR_COLOR, R.color.theme.toColor())
|
||||
put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER)
|
||||
put(Calendars.SYNC_EVENTS, 1)
|
||||
put(Calendars.CALENDAR_TIME_ZONE, TimeZone.getDefault().id)
|
||||
put(Calendars.OWNER_ACCOUNT, CALENDARS_NAME)
|
||||
put(Calendars.CAN_ORGANIZER_RESPOND, 0)
|
||||
}
|
||||
|
||||
var calendarUri: Uri = CALENDAR_URL
|
||||
calendarUri = calendarUri.buildUpon()
|
||||
.appendQueryParameter(CALLER_IS_SYNCADAPTER, "true")
|
||||
.appendQueryParameter(Calendars.ACCOUNT_NAME, CALENDARS_NAME)
|
||||
.appendQueryParameter(Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE)
|
||||
.build()
|
||||
val result: Uri? = context.contentResolver.insert(calendarUri, value)
|
||||
return if (result == null) -1 else ContentUris.parseId(result)
|
||||
}
|
||||
|
||||
fun insertCalendarEvent(context: Context,
|
||||
title: String,
|
||||
description: String,
|
||||
beginTimeMillis: Long,
|
||||
endTimeMillis: Long,
|
||||
rRule: String?): Boolean {
|
||||
val calendarId = checkAndAddCalendarAccount(context) // 获取日历账户的id
|
||||
if (calendarId < 0) { // 获取账户id失败直接返回,添加日历事件失败
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
/** 插入日程 */
|
||||
val eventValues = ContentValues().apply {
|
||||
if (rRule != null) put(Events.RRULE, rRule)
|
||||
put(Events.DTSTART, beginTimeMillis)
|
||||
put(Events.DTEND, endTimeMillis)
|
||||
put(Events.TITLE, title)
|
||||
put(Events.DESCRIPTION, description)
|
||||
put(Events.CALENDAR_ID, calendarId)
|
||||
put(Events.EVENT_TIMEZONE, TimeZone.getDefault().id)
|
||||
}
|
||||
val eUri: Uri? = context.contentResolver.insert(CALENDAR_EVENT_URL, eventValues)
|
||||
val eventId = eUri?.let { ContentUris.parseId(it) }
|
||||
if (eventId == 0L) { // 插入失败
|
||||
return false
|
||||
}
|
||||
/** 插入提醒 - 依赖插入日程成功 */
|
||||
val reminderValues = ContentValues()
|
||||
// uri.getLastPathSegment();
|
||||
reminderValues.put(Reminders.EVENT_ID, eventId)
|
||||
reminderValues.put(Reminders.MINUTES, 0) // 准时提醒
|
||||
reminderValues.put(Reminders.METHOD, Reminders.METHOD_ALERT)
|
||||
val rUri: Uri? = context.contentResolver.insert(CALENDAR_REMINDER_URL, reminderValues)
|
||||
if (rUri == null || ContentUris.parseId(rUri) == 0L) {
|
||||
return false
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun deleteCalendarEvent(context: Context,
|
||||
title: String): Boolean {
|
||||
val eventCursor = context.contentResolver.query(CALENDAR_EVENT_URL,
|
||||
null, null, null, null)
|
||||
eventCursor?.use {
|
||||
if (it.count > 0) {
|
||||
// 遍历所有事件,找到title跟需要查询的title一样的项
|
||||
it.moveToFirst()
|
||||
while (!it.isAfterLast) {
|
||||
val eventTitle = eventCursor.getString(eventCursor.getColumnIndex("title"))
|
||||
if (!TextUtils.isEmpty(title) && title == eventTitle) {
|
||||
val id = eventCursor.getInt(eventCursor
|
||||
.getColumnIndex(Calendars._ID)) // 取得id
|
||||
val deleteUri = ContentUris.withAppendedId(CALENDAR_EVENT_URL, id.toLong())
|
||||
val rows = context.contentResolver.delete(deleteUri, null, null)
|
||||
return rows != -1
|
||||
}
|
||||
it.moveToNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -33,6 +33,7 @@ object CommentHelper {
|
||||
showConversation: Boolean,
|
||||
articleId: String,
|
||||
communityId: String,
|
||||
isShowTop: Boolean = false,
|
||||
ignoreModerator: Boolean = false,
|
||||
listener: OnCommentOptionClickListener?) {
|
||||
showCommentOptions(view = view,
|
||||
@ -40,6 +41,7 @@ object CommentHelper {
|
||||
showConversation = showConversation,
|
||||
articleId = articleId,
|
||||
communityId = communityId,
|
||||
isShowTop = isShowTop,
|
||||
ignoreModerator = ignoreModerator,
|
||||
listener = listener)
|
||||
}
|
||||
@ -79,11 +81,16 @@ object CommentHelper {
|
||||
communityId: String? = null,
|
||||
answerId: String? = null,
|
||||
videoId: String? = null,
|
||||
isShowTop: Boolean = false,
|
||||
ignoreModerator: Boolean = false,
|
||||
isVideoAuthor: Boolean = false,
|
||||
listener: OnCommentOptionClickListener? = null) {
|
||||
val context = view.context
|
||||
val dialogOptions = ArrayList<String>()
|
||||
if (isShowTop && articleId != null && commentEntity.me?.isArticleOrAnswerAuthor == true) {
|
||||
dialogOptions.add(if (commentEntity.isTop) "取消置顶" else "置顶")
|
||||
}
|
||||
|
||||
dialogOptions.add("复制")
|
||||
if (commentEntity.user.id != UserManager.getInstance().userId) {
|
||||
dialogOptions.add("投诉")
|
||||
|
||||
@ -2,7 +2,6 @@ package com.gh.common.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.text.TextUtils;
|
||||
@ -12,6 +11,9 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.gh.gamecenter.CommentDetailActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
|
||||
@ -39,8 +41,6 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.ResponseBody;
|
||||
@ -334,15 +334,16 @@ public class CommentUtils {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static void voteVideoComment(final Context context,
|
||||
String answerId,
|
||||
String articleId,
|
||||
String articleCommunityId,
|
||||
String videoId,
|
||||
final CommentEntity commentEntity,
|
||||
final TextView commentLikeCountTv,
|
||||
final ImageView commentLikeIv,
|
||||
final OnVoteListener listener) {
|
||||
String answerId,
|
||||
String articleId,
|
||||
String articleCommunityId,
|
||||
String videoId,
|
||||
final CommentEntity commentEntity,
|
||||
final TextView commentLikeCountTv,
|
||||
final ImageView commentLikeIv,
|
||||
final OnVoteListener listener) {
|
||||
|
||||
String entrance = "视频流-评论-点赞";
|
||||
CheckLoginUtils.checkLogin(context, entrance, () -> {
|
||||
@ -389,10 +390,10 @@ public class CommentUtils {
|
||||
}
|
||||
|
||||
public static void unVoteVideoComment(final Context context,
|
||||
String videoId,
|
||||
final CommentEntity commentEntity,
|
||||
final TextView commentLikeCountTv,
|
||||
final ImageView commentLikeIv) {
|
||||
String videoId,
|
||||
final CommentEntity commentEntity,
|
||||
final TextView commentLikeCountTv,
|
||||
final ImageView commentLikeIv) {
|
||||
String entrance = "视频流-评论-取消点赞";
|
||||
CheckLoginUtils.checkLogin(context, entrance, () -> {
|
||||
RetrofitManager.getInstance(context).getApi()
|
||||
@ -434,10 +435,10 @@ public class CommentUtils {
|
||||
holder.commentLikeIv.setImageResource(R.drawable.comment_vote_unselect);
|
||||
|
||||
if (userDataEntity == null || !userDataEntity.isCommentOwner()) {
|
||||
holder.replyLine.setVisibility(View.VISIBLE);
|
||||
if (holder.replyLine != null) holder.replyLine.setVisibility(View.VISIBLE);
|
||||
holder.commentReply.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.replyLine.setVisibility(View.GONE);
|
||||
if (holder.replyLine != null) holder.replyLine.setVisibility(View.GONE);
|
||||
holder.commentReply.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@ -529,10 +530,7 @@ public class CommentUtils {
|
||||
|
||||
//复制文字
|
||||
public static void copyText(String copyContent, Context context) {
|
||||
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cmb.setText(copyContent);
|
||||
|
||||
ToastUtils.INSTANCE.showToast("复制成功");
|
||||
ExtensionsKt.copyTextAndToast(copyContent, "复制成功");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ public class DataCollectionUtils {
|
||||
public static void uploadDownload(Context context, DownloadEntity downloadEntity, String status) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("game", StringsKt.removeSuffix(downloadEntity.getName(), Constants.GAME_NAME_DECORATOR));
|
||||
map.put("game_id", downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER));
|
||||
map.put("game_id", downloadEntity.getGameId());
|
||||
if (downloadEntity.isPluggable()) {
|
||||
map.put("method", "插件化");
|
||||
map.put("btn_status", "插件化");
|
||||
|
||||
@ -52,8 +52,8 @@ public class DataLogUtils {
|
||||
String user = Installation.getUUID(context);
|
||||
String channel = HaloApp.getInstance().getChannel();
|
||||
map.put("version", version);
|
||||
map.put("user", user);
|
||||
map.put("device_id", MetaUtil.getIMEI());
|
||||
map.put("resu", user);
|
||||
map.put("jnfj", MetaUtil.getBase64EncodedIMEI());
|
||||
map.put("channel", channel);
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
|
||||
@ -3,11 +3,14 @@ package com.gh.common.util;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.exposure.meta.MetaUtil;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gid.GidCallback;
|
||||
import com.gh.gid.GidHelper;
|
||||
import com.halo.assistant.HaloApp;
|
||||
@ -16,7 +19,9 @@ import com.lightgame.utils.Utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import io.sentry.Sentry;
|
||||
import io.sentry.android.core.SentryAndroid;
|
||||
|
||||
/**
|
||||
* Created by LGT on 2016/6/15.
|
||||
@ -35,6 +40,10 @@ public class DataUtils {
|
||||
if (CommonDebug.IS_DEBUG) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化 Sentry 约占用 90ms,这里切换到子线程初始化
|
||||
AppExecutor.getIoExecutor().execute(() -> initSentry(context, channel));
|
||||
|
||||
//TalkingData
|
||||
// try {
|
||||
// TCAgent.LOG_ON = false;
|
||||
@ -103,6 +112,41 @@ public class DataUtils {
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
private static void initSentry(Context context, String channel) {
|
||||
SentryAndroid.init(context, options -> {
|
||||
// Sentry 疯狂报 ANR (很大一部分还是莫名奇妙的 ANR)严重影响到其它闪退日志的收集
|
||||
// 这里将它局限到只有官网渠道的包才统计 ANR
|
||||
if ("GH_206".equals(channel)) {
|
||||
options.setAnrEnabled(true);
|
||||
options.setAnrTimeoutIntervalMillis(6000);
|
||||
} else {
|
||||
options.setAnrEnabled(false);
|
||||
}
|
||||
|
||||
options.setDebug(BuildConfig.DEBUG);
|
||||
options.setEnableSessionTracking(true);
|
||||
options.setEnvironment(BuildConfig.FLAVOR);
|
||||
options.setDsn("https://6b1caf0d17c1408e8680f3f73ff80bd0@sentry.ghzs.com/22");
|
||||
|
||||
options.setBeforeSend((event, hint) -> {
|
||||
if (BuildConfig.DEBUG) {
|
||||
return null;
|
||||
} else {
|
||||
return event;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Sentry.configureScope(scope -> {
|
||||
if (BuildConfig.BUILD_TIME != 0L) {
|
||||
scope.setTag("alias", "内测版" + BuildConfig.VERSION_NAME);
|
||||
} else {
|
||||
scope.setTag("alias", "正式版" + BuildConfig.VERSION_NAME);
|
||||
scope.setTag("channel", channel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// MTA ->【次数统计】Key-Value参数的事件
|
||||
public static void onMtaEvent(Context context, String eventId, String... kv) {
|
||||
@ -139,8 +183,8 @@ public class DataUtils {
|
||||
}
|
||||
|
||||
public static void onEvent(Context var0, String var1, String var2) {
|
||||
Properties prop = new Properties();
|
||||
prop.setProperty(var1, var2);
|
||||
// Properties prop = new Properties();
|
||||
// prop.setProperty(var1, var2);
|
||||
// StatService.trackCustomKVEvent(var0, var1, prop);
|
||||
}
|
||||
|
||||
@ -161,64 +205,64 @@ public class DataUtils {
|
||||
}
|
||||
|
||||
public static void onEvent(Context var0, String var1, String var2, Map<String, Object> var3) {
|
||||
Properties prop = new Properties();
|
||||
prop.setProperty("label", var2);
|
||||
for (String key : var3.keySet()) {
|
||||
prop.setProperty(key, var3.get(key) + "");
|
||||
}
|
||||
// Properties prop = new Properties();
|
||||
// prop.setProperty("label", var2);
|
||||
// for (String key : var3.keySet()) {
|
||||
// prop.setProperty(key, var3.get(key) + "");
|
||||
// }
|
||||
// StatService.trackCustomKVEvent(var0, var1, prop);
|
||||
}
|
||||
|
||||
public static void trackTimeEvent(Context context, String eventId, int costTime, String... kv) {
|
||||
|
||||
Properties prop = new Properties();
|
||||
for (int i = 0; i < kv.length; i++) {
|
||||
if (i % 2 != 0 || i != 0) {
|
||||
String key = kv[i - 1];
|
||||
String value = kv[i];
|
||||
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
||||
prop.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prop.size() == 0) return;
|
||||
|
||||
//
|
||||
// Properties prop = new Properties();
|
||||
// for (int i = 0; i < kv.length; i++) {
|
||||
// if (i % 2 != 0 || i != 0) {
|
||||
// String key = kv[i - 1];
|
||||
// String value = kv[i];
|
||||
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
||||
// prop.setProperty(key, value);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (prop.size() == 0) return;
|
||||
//
|
||||
// StatService.trackCustomKVTimeIntervalEvent(context, costTime, eventId, prop);
|
||||
}
|
||||
|
||||
// 游戏下载
|
||||
public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status, String method) {
|
||||
// Map<String, Object> kv = new HashMap<>();
|
||||
//
|
||||
// platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
|
||||
//
|
||||
// kv.put("版本", platform);
|
||||
// kv.put("用户机型", Build.MODEL);
|
||||
// kv.put("设备IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().getApplication()));
|
||||
// kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
// kv.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
// kv.put("位置", entrance);
|
||||
// kv.put("类型", method);
|
||||
// kv.put("厂商", Build.MANUFACTURER);
|
||||
// kv.put("Android版本", Build.VERSION.RELEASE);
|
||||
// onEvent(context, "游戏下载", gameName, kv);
|
||||
//
|
||||
// Map<String, Object> kv2 = new HashMap<>();
|
||||
// kv2.put("状态", status);
|
||||
// kv2.put("位置", entrance);
|
||||
//
|
||||
// if (status.equals("开始")) {
|
||||
// kv2.put("版本", entrance + "-开始");
|
||||
// kv2.put("游戏分平台", gameName + "-" + platform + "-开始");
|
||||
// kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
|
||||
// } else {
|
||||
// kv2.put("版本", platform);
|
||||
// kv2.put("游戏分平台", gameName + "-" + platform);
|
||||
// kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
// }
|
||||
//
|
||||
// onEvent(context, "游戏下载位置", gameName, kv2);
|
||||
Map<String, Object> kv = new HashMap<>();
|
||||
|
||||
platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
|
||||
|
||||
kv.put("版本", platform);
|
||||
kv.put("用户机型", Build.MODEL);
|
||||
kv.put("设备JNFJ", MetaUtil.getBase64EncodedIMEI());
|
||||
kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
kv.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
kv.put("位置", entrance);
|
||||
kv.put("类型", method);
|
||||
kv.put("厂商", Build.MANUFACTURER);
|
||||
kv.put("Android版本", Build.VERSION.RELEASE);
|
||||
onEvent(context, "游戏下载", gameName, kv);
|
||||
|
||||
Map<String, Object> kv2 = new HashMap<>();
|
||||
kv2.put("状态", status);
|
||||
kv2.put("位置", entrance);
|
||||
|
||||
if (status.equals("开始")) {
|
||||
kv2.put("版本", entrance + "-开始");
|
||||
kv2.put("游戏分平台", gameName + "-" + platform + "-开始");
|
||||
kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
|
||||
} else {
|
||||
kv2.put("版本", platform);
|
||||
kv2.put("游戏分平台", gameName + "-" + platform);
|
||||
kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
}
|
||||
|
||||
onEvent(context, "游戏下载位置", gameName, kv2);
|
||||
}
|
||||
|
||||
// 游戏更新
|
||||
|
||||
@ -41,11 +41,11 @@ public class DeviceUtils {
|
||||
context = context.getApplicationContext();
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("os", "Android");
|
||||
object.put("imei", MetaUtil.getIMEI());
|
||||
object.put("jnfj", MetaUtil.getBase64EncodedIMEI());
|
||||
object.put("mac", getMac(context));
|
||||
object.put("model", MODEL);
|
||||
object.put("manufacturer", MANUFACTURER);
|
||||
object.put("android_id", MetaUtil.getAndroidId());
|
||||
object.put("dia", MetaUtil.getBase64EncodedAndroidId());
|
||||
object.put("android_sdk", Build.VERSION.SDK_INT);
|
||||
object.put("android_version", android.os.Build.VERSION.RELEASE);
|
||||
object.put("ip", "");
|
||||
@ -57,8 +57,8 @@ public class DeviceUtils {
|
||||
public static JSONObject getUserDevice(Context context) { // 判断新老用户device数据
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("IMEI", MetaUtil.getIMEI());
|
||||
object.put("ANDROID_ID", MetaUtil.getAndroidId());
|
||||
object.put("JNFJ", MetaUtil.getBase64EncodedIMEI());
|
||||
object.put("DIA", MetaUtil.getBase64EncodedAndroidId());
|
||||
object.put("MAC", getMac(context));
|
||||
// object.put("MTA_ID", StatConfig.getMid(context));
|
||||
object.put("MANUFACTURER", MANUFACTURER);
|
||||
@ -258,7 +258,7 @@ public class DeviceUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static long getTotalRamSizeOfDevice(Context context) {
|
||||
public static long getTotalRamSizeOfDevice(Context context) {
|
||||
ActivityManager actManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
|
||||
if (actManager != null) {
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.common.util
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.TextView
|
||||
import com.gh.common.dialog.TrackableDialog
|
||||
@ -73,6 +74,65 @@ object DialogHelper {
|
||||
return dialog
|
||||
}
|
||||
|
||||
fun showRoundedCornerDialog(
|
||||
context: Context,
|
||||
title: String,
|
||||
content: CharSequence,
|
||||
hint: String? = "",
|
||||
confirmText: String,
|
||||
cancelText: String,
|
||||
confirmClickCallback: (() -> Unit)? = null,
|
||||
cancelClickCallback: (() -> Unit)? = null,
|
||||
hintClickCallback: (() -> Unit)? = null,
|
||||
trackMtaEvent: Boolean = false,
|
||||
mtaEvent: String = "",
|
||||
mtaKey: String = ""): Dialog {
|
||||
val solidContext = checkDialogContext(context)
|
||||
|
||||
val dialog = if (trackMtaEvent) {
|
||||
TrackableDialog(solidContext, R.style.GhAlertDialog, mtaEvent, mtaKey)
|
||||
} else {
|
||||
Dialog(solidContext, R.style.GhAlertDialog)
|
||||
}
|
||||
|
||||
val contentView = LayoutInflater.from(solidContext).inflate(R.layout.dialog_alert_default, null)
|
||||
val contentTv = contentView.findViewById<TextView>(R.id.contentTv)
|
||||
val titleTv = contentView.findViewById<TextView>(R.id.titleTv)
|
||||
val hintTv = contentView.findViewById<TextView>(R.id.hintTv)
|
||||
val cancelTv = contentView.findViewById<TextView>(R.id.cancelTv)
|
||||
val confirmTv = contentView.findViewById<TextView>(R.id.confirmTv)
|
||||
contentTv.text = content
|
||||
titleTv.text = title
|
||||
if (!hint.isNullOrEmpty()) {
|
||||
hintTv.visibility = View.VISIBLE
|
||||
hintTv.text = hint
|
||||
hintTv.setOnClickListener {
|
||||
hintClickCallback?.invoke()
|
||||
}
|
||||
}
|
||||
cancelTv.text = cancelText
|
||||
confirmTv.text = confirmText
|
||||
|
||||
cancelTv.setOnClickListener {
|
||||
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击$cancelText")
|
||||
|
||||
cancelClickCallback?.invoke()
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
confirmTv.setOnClickListener {
|
||||
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击$confirmText")
|
||||
|
||||
confirmClickCallback?.invoke()
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
dialog.setContentView(contentView)
|
||||
dialog.show()
|
||||
return dialog
|
||||
}
|
||||
|
||||
/**
|
||||
* For legacy java invocation
|
||||
*/
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
@ -14,12 +15,15 @@ import android.os.CountDownTimer;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
import android.text.Html;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.text.style.URLSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
@ -33,6 +37,7 @@ import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@ -41,12 +46,15 @@ import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.dialog.TrackableDialog;
|
||||
import com.gh.common.view.CustomLinkMovementMethod;
|
||||
import com.gh.common.view.DrawableView;
|
||||
import com.gh.common.view.FixLinearLayoutManager;
|
||||
import com.gh.common.view.LimitHeightLinearLayout;
|
||||
@ -56,6 +64,8 @@ import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.SuggestionActivity;
|
||||
import com.gh.gamecenter.adapter.viewholder.PrivacyPolicyItemViewHolder;
|
||||
import com.gh.gamecenter.databinding.DialogOverseaConfirmationBinding;
|
||||
import com.gh.gamecenter.databinding.DialogPackageParseErrorBinding;
|
||||
import com.gh.gamecenter.databinding.DialogReportReasonBinding;
|
||||
import com.gh.gamecenter.databinding.ImprintContentItemBinding;
|
||||
import com.gh.gamecenter.databinding.PrivacyItemBinding;
|
||||
import com.gh.gamecenter.entity.ApkEntity;
|
||||
@ -64,6 +74,7 @@ import com.gh.gamecenter.entity.BadgeEntity;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.PrivacyPolicyEntity;
|
||||
import com.gh.gamecenter.entity.SettingsEntity;
|
||||
import com.gh.gamecenter.entity.SimpleGameEntity;
|
||||
import com.gh.gamecenter.entity.TrackableEntity;
|
||||
import com.gh.gamecenter.suggest.SuggestType;
|
||||
import com.halo.assistant.HaloApp;
|
||||
@ -350,7 +361,7 @@ public class DialogUtils {
|
||||
* @param cmListener 确认按钮监听
|
||||
*/
|
||||
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
|
||||
, String negative, String positive, TrackableEntity trackableEntity, final CancelListener clListener, final ConfirmListener cmListener) {
|
||||
, String negative, String positive, TrackableEntity trackableEntity, int gravity, boolean shouldShowCloseBtn, final CancelListener clListener, final ConfirmListener cmListener) {
|
||||
context = checkDialogContext(context);
|
||||
final Dialog dialog;
|
||||
if (trackableEntity != null) {
|
||||
@ -373,6 +384,9 @@ public class DialogUtils {
|
||||
TextView cancelBtn = contentView.findViewById(R.id.cancel);
|
||||
TextView confirmBtn = contentView.findViewById(R.id.confirm);
|
||||
View middleLine = contentView.findViewById(R.id.middle_line);
|
||||
View closeIv = contentView.findViewById(R.id.closeIv);
|
||||
titleTv.setGravity(gravity);
|
||||
contentTv.setGravity(gravity);
|
||||
|
||||
titleTv.setText(title);
|
||||
contentTv.setText(message);
|
||||
@ -387,6 +401,8 @@ public class DialogUtils {
|
||||
confirmBtn.setVisibility(View.GONE);
|
||||
middleLine.setVisibility(View.GONE);
|
||||
}
|
||||
closeIv.setVisibility(shouldShowCloseBtn ? View.VISIBLE : View.GONE);
|
||||
closeIv.setOnClickListener(v -> dialog.dismiss());
|
||||
|
||||
cancelBtn.setOnClickListener(v -> {
|
||||
if (clListener != null) clListener.onCancel();
|
||||
@ -411,7 +427,12 @@ public class DialogUtils {
|
||||
|
||||
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
|
||||
, String negative, String positive, final CancelListener clListener, final ConfirmListener cmListener) {
|
||||
return showNewAlertDialog(context, title, message, negative, positive, null, clListener, cmListener);
|
||||
return showNewAlertDialog(context, title, message, negative, positive, null, Gravity.LEFT, false, clListener, cmListener);
|
||||
}
|
||||
|
||||
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
|
||||
, String negative, String positive, int gravity, boolean shouldShowCloseBtn, final CancelListener clListener, final ConfirmListener cmListener) {
|
||||
return showNewAlertDialog(context, title, message, negative, positive, null, gravity, shouldShowCloseBtn, clListener, cmListener);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -968,7 +989,7 @@ public class DialogUtils {
|
||||
|
||||
public static void showPrivacyPolicyDialog(Context context,
|
||||
@NonNull PrivacyPolicyEntity entity,
|
||||
EmptyCallback callback) {
|
||||
SimpleCallback<Boolean> callback) {
|
||||
|
||||
final Context activityContext = checkDialogContext(context);
|
||||
|
||||
@ -986,13 +1007,13 @@ public class DialogUtils {
|
||||
WindowManager.LayoutParams params = window.getAttributes();
|
||||
params.horizontalMargin = 0;
|
||||
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(40);
|
||||
int height = context.getResources().getDisplayMetrics().heightPixels - DisplayUtils.dip2px(120);
|
||||
int maxHeight = DisplayUtils.dip2px(446);
|
||||
if (height > maxHeight) {
|
||||
params.height = maxHeight;
|
||||
} else {
|
||||
params.height = height;
|
||||
}
|
||||
// int height = context.getResources().getDisplayMetrics().heightPixels - DisplayUtils.dip2px(120);
|
||||
// int maxHeight = DisplayUtils.dip2px(446);
|
||||
// if (height > maxHeight) {
|
||||
// params.height = maxHeight;
|
||||
// } else {
|
||||
// params.height = height;
|
||||
// }
|
||||
window.setAttributes(params);
|
||||
}
|
||||
|
||||
@ -1025,8 +1046,6 @@ public class DialogUtils {
|
||||
hierarchy.setPlaceholderImage(R.drawable.permission_storage);
|
||||
} else if (position == 1) {
|
||||
hierarchy.setPlaceholderImage(R.drawable.permission_phone_state);
|
||||
} else {
|
||||
hierarchy.setPlaceholderImage(R.drawable.permission_sdk);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1086,19 +1105,31 @@ public class DialogUtils {
|
||||
|
||||
title.setText(entity.getTitle());
|
||||
linkContent.setText(skipText);
|
||||
linkContent.setMovementMethod(new LinkMovementMethod());
|
||||
linkContent.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
topContent.setText(entity.getTopContent());
|
||||
bottomContent.setText(entity.getBottomContent());
|
||||
bottomContent.setText(ExtensionsKt.fromHtml(entity.getBottomContent()));
|
||||
bottomContent.setMovementMethod(CustomLinkMovementMethod.getInstance());
|
||||
|
||||
// Remove underline
|
||||
Spannable sa = (Spannable) bottomContent.getText();
|
||||
for (URLSpan u : sa.getSpans(0, sa.length(), URLSpan.class)) {
|
||||
sa.setSpan(new UnderlineSpan() {
|
||||
public void updateDrawState(TextPaint tp) {
|
||||
tp.setUnderlineText(false);
|
||||
}
|
||||
}, sa.getSpanStart(u), sa.getSpanEnd(u), 0);
|
||||
}
|
||||
|
||||
allowButton.setOnClickListener(view -> {
|
||||
dialog.dismiss();
|
||||
callback.onCallback();
|
||||
callback.onCallback(true);
|
||||
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击同意");
|
||||
});
|
||||
|
||||
disallowButton.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
showPrivacyPolicyDisallowDialog(activityContext, entity, callback);
|
||||
callback.onCallback(false);
|
||||
// showPrivacyPolicyDisallowDialog(activityContext, entity, callback);
|
||||
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "不同意并退出App");
|
||||
});
|
||||
|
||||
@ -1902,6 +1933,234 @@ public class DialogUtils {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static Dialog showCancelOrDeleteReservationDialog(Context context, String title, String message
|
||||
, String positive, String negative, final ConfirmListener cmListener, final CancelListener clListener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_cancel_reservation, null);
|
||||
TextView contentTv = contentView.findViewById(R.id.dialog_content);
|
||||
TextView titleTv = contentView.findViewById(R.id.dialog_title);
|
||||
TextView negativeTv = contentView.findViewById(R.id.dialog_negative);
|
||||
TextView positiveTv = contentView.findViewById(R.id.dialog_positive);
|
||||
contentTv.setText(message);
|
||||
titleTv.setText(title);
|
||||
negativeTv.setText(negative);
|
||||
positiveTv.setText(positive);
|
||||
|
||||
negativeTv.setOnClickListener(view -> {
|
||||
if (clListener != null) {
|
||||
clListener.onCancel();
|
||||
}
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
positiveTv.setOnClickListener(view -> {
|
||||
if (cmListener != null) {
|
||||
cmListener.onConfirm();
|
||||
}
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
Window window = dialog.getWindow();
|
||||
if (window != null) {
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
WindowManager.LayoutParams params = window.getAttributes();
|
||||
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(60f);
|
||||
window.setAttributes(params);
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static void showEnergyDialog(Context context, String userName, int energy) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_energy, null);
|
||||
((TextView) contentView.findViewById(R.id.userName)).setText("\"" + userName + "\"");
|
||||
((TextView) contentView.findViewById(R.id.energy)).setText(energy + "");
|
||||
|
||||
contentView.findViewById(R.id.dialog_positive).setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showEnergyTaskNoticeDialog(Context context, String title, String content) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_notice, null);
|
||||
TextView titleTv = contentView.findViewById(R.id.dialog_title);
|
||||
TextView contentTv = contentView.findViewById(R.id.dialog_content);
|
||||
TextView okTv = contentView.findViewById(R.id.dialog_ok);
|
||||
|
||||
if (title == null) {
|
||||
titleTv.setVisibility(View.GONE);
|
||||
} else {
|
||||
titleTv.setVisibility(View.VISIBLE);
|
||||
titleTv.setText(title);
|
||||
}
|
||||
contentTv.setText(content);
|
||||
|
||||
okTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font));
|
||||
okTv.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showSimulatorParseErrorDialog(Context context, String gameId, String gameName, ConfirmListener confirmListener) {
|
||||
context = checkDialogContext(context);
|
||||
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
|
||||
|
||||
DialogPackageParseErrorBinding binding = DialogPackageParseErrorBinding.inflate(LayoutInflater.from(context), null, false);
|
||||
Context finalContext = context;
|
||||
SpannableStringBuilder builder = new SpanBuilder("您也可以点击提交反馈跟我们联系").click(6, 10, R.color.theme_font, true, new Function0<Unit>() {
|
||||
@Override
|
||||
public Unit invoke() {
|
||||
SimpleGameEntity entity = new SimpleGameEntity(gameId, gameName, "");
|
||||
SuggestionActivity.startSuggestionActivity(finalContext, SuggestType.gameQuestion, "notfound", "模拟器安装包解析错误", entity, "-");
|
||||
dialog.dismiss();
|
||||
return null;
|
||||
}
|
||||
}).build();
|
||||
binding.feedbackTv.setText(builder);
|
||||
binding.feedbackTv.setMovementMethod(new LinkMovementMethod());
|
||||
|
||||
binding.cancel.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
});
|
||||
binding.confirm.setOnClickListener(v -> {
|
||||
confirmListener.onConfirm();
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(binding.getRoot());
|
||||
dialog.show();
|
||||
Window window = dialog.getWindow();
|
||||
if (window != null) {
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
WindowManager.LayoutParams params = window.getAttributes();
|
||||
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(60f);
|
||||
window.setAttributes(params);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
public static void showReportReasonDialog(Context context, ReportReasonCallBack callBack) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
DialogReportReasonBinding binding = DialogReportReasonBinding.inflate(LayoutInflater.from(context));
|
||||
|
||||
binding.reasonOne.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
callBack.onResponse(binding.reasonOne.getText().toString(), "");
|
||||
});
|
||||
|
||||
binding.reasonTwo.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
callBack.onResponse(binding.reasonTwo.getText().toString(), "");
|
||||
});
|
||||
|
||||
binding.reasonThree.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
callBack.onResponse(binding.reasonThree.getText().toString(), "");
|
||||
});
|
||||
|
||||
binding.reasonFour.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
callBack.onResponse(binding.reasonFour.getText().toString(), "");
|
||||
});
|
||||
|
||||
binding.reasonOther.setOnClickListener(v -> {
|
||||
binding.reasonTitle.setText(R.string.report_reason_other_title);
|
||||
binding.normalReasonContainer.setVisibility(View.GONE);
|
||||
binding.otherReasonContainer.setVisibility(View.VISIBLE);
|
||||
});
|
||||
|
||||
binding.negativeBtn.setOnClickListener(v -> {
|
||||
binding.reasonTitle.setText(R.string.report_reason_title);
|
||||
binding.normalReasonContainer.setVisibility(View.VISIBLE);
|
||||
binding.otherReasonContainer.setVisibility(View.GONE);
|
||||
});
|
||||
|
||||
binding.positiveBtn.setOnClickListener(v -> {
|
||||
if (TextUtils.isEmpty(binding.otherReasonEt.getText().toString().trim())) {
|
||||
ToastUtils.INSTANCE.showToast("请填写举报原因");
|
||||
} else {
|
||||
dialog.dismiss();
|
||||
callBack.onResponse("其它", binding.otherReasonEt.getText().toString());
|
||||
}
|
||||
});
|
||||
|
||||
Context finalContext = context;
|
||||
ExtensionsKt.setTextChangedListener(binding.otherReasonEt, (s, start, before, count) -> {
|
||||
int tvCount = s.length();
|
||||
if (tvCount >= 500) {
|
||||
binding.tvCount.setTextColor(ContextCompat.getColor(finalContext, R.color.text_FF4147));
|
||||
}
|
||||
binding.tvCount.setText(tvCount + "/500");
|
||||
return null;
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(binding.getRoot());
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showSignSuccessDialog(Context context, ConfirmListener listener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_sign_success, null);
|
||||
|
||||
ImageView signBg = contentView.findViewById(R.id.signBg);
|
||||
RelativeLayout signContainer = contentView.findViewById(R.id.signContainer);
|
||||
|
||||
Animation animation1 = AnimationUtils.loadAnimation(context, R.anim.anim_badge_light_bg);
|
||||
signBg.startAnimation(animation1);
|
||||
|
||||
Animation animation2 = AnimationUtils.loadAnimation(context, R.anim.anim_sign_dialog_dismiss);
|
||||
signContainer.postDelayed(() -> signContainer.startAnimation(animation2), 2000);
|
||||
|
||||
signContainer.postDelayed(dialog::dismiss, 3000);
|
||||
|
||||
dialog.setOnDismissListener(dialogInterface -> listener.onConfirm());
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showSignRuleDialog(Context context) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_sign_rule, null);
|
||||
contentView.findViewById(R.id.dialog_ok).setOnClickListener(v -> dialog.dismiss());
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context may be is application context
|
||||
* @return activity context
|
||||
@ -1935,4 +2194,7 @@ public class DialogUtils {
|
||||
void onResponse(boolean isSubscribe);
|
||||
}
|
||||
|
||||
public interface ReportReasonCallBack {
|
||||
void onResponse(String reason, String desc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
@ -22,6 +23,7 @@ import com.gh.common.exposure.ExposureType
|
||||
import com.gh.common.util.EntranceUtils.*
|
||||
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.download.DownloadFragment.Companion.INDEX_UPDATE
|
||||
import com.gh.gamecenter.entity.*
|
||||
@ -38,6 +40,8 @@ import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.mygame.PlayedGameActivity
|
||||
import com.gh.gamecenter.personalhome.UserHomeActivity
|
||||
import com.gh.gamecenter.personalhome.background.PersonalityBackgroundActivity
|
||||
import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
|
||||
import com.gh.gamecenter.qa.CommunityFragment
|
||||
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
|
||||
import com.gh.gamecenter.qa.article.SimpleArticleListActivity
|
||||
@ -47,17 +51,18 @@ import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity
|
||||
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.security.BindPhoneActivity
|
||||
import com.gh.gamecenter.servers.GameServersActivity
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
import com.gh.gamecenter.suggest.SuggestType
|
||||
import com.gh.gamecenter.tag.TagsActivity
|
||||
import com.gh.gamecenter.user.UserViewModel
|
||||
import com.gh.gamecenter.video.data.VideoDataActivity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailActivity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
import com.gh.gamecenter.video.game.GameVideoActivity
|
||||
import com.gh.gamecenter.video.videomanager.VideoManagerActivity
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Util_System_ClipboardManager
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
@ -133,7 +138,9 @@ object DirectUtils {
|
||||
"server",
|
||||
"top_game_comment",
|
||||
"wechat_bind",
|
||||
"video")
|
||||
"video",
|
||||
"catalog"
|
||||
)
|
||||
|
||||
fun directToLinkPage(context: Context,
|
||||
linkEntity: LinkEntity,
|
||||
@ -200,6 +207,8 @@ object DirectUtils {
|
||||
|
||||
"category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!)
|
||||
|
||||
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
|
||||
|
||||
"block", "版块" -> {
|
||||
if (linkEntity.link.isNullOrEmpty()) return
|
||||
directToBlock(context,
|
||||
@ -245,6 +254,68 @@ object DirectUtils {
|
||||
|
||||
"bbs_detail" -> directForumDetail(context, linkEntity.link ?: "", entrance)
|
||||
|
||||
"mobile_bind" -> {
|
||||
CheckLoginUtils.checkLogin(context, entrance) {
|
||||
context.startActivity(BindPhoneActivity.getNormalIntent(context, false))
|
||||
}
|
||||
}
|
||||
|
||||
"authentication" -> {
|
||||
CheckLoginUtils.checkLogin(context, entrance) {
|
||||
context.startActivity(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD))
|
||||
}
|
||||
}
|
||||
|
||||
"user_background" -> {
|
||||
CheckLoginUtils.checkLogin(context, entrance) {
|
||||
context.startActivity(PersonalityBackgroundActivity.getIntent(context))
|
||||
}
|
||||
}
|
||||
|
||||
"avatar_frame" -> {
|
||||
CheckLoginUtils.checkLogin(context, entrance) {
|
||||
context.startActivity(AvatarBorderActivity.getIntent(context))
|
||||
}
|
||||
}
|
||||
|
||||
"badge" -> {
|
||||
CheckLoginUtils.checkLogin(context, entrance) {
|
||||
UserManager.getInstance().userInfoEntity?.run {
|
||||
directToBadgeWall(context, userId, name, icon)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"etiquette_exam" -> directToRegulationTestPage(context)
|
||||
|
||||
"setting" -> context.startActivity(SettingActivity.getIntent(context, false, entrance))
|
||||
|
||||
"index_page" -> directToHomeTab(context)
|
||||
|
||||
"video_upload" -> context.startActivity(VideoManagerActivity.getIntent(context, "", entrance))
|
||||
|
||||
"bbs" -> directToForum(context)
|
||||
|
||||
"user_page" -> directToHomeActivity(context, UserManager.getInstance().userId, "", entrance)
|
||||
|
||||
"video_tab" -> directToVideoTab(context)
|
||||
|
||||
"toolkit" -> context.startActivity(ToolBoxActivity.getIntent(context, entrance))
|
||||
|
||||
"toolkit_detail" -> {
|
||||
linkEntity.toolkit?.run {
|
||||
if (url != null && url!!.contains(Config.URL_ARTICLE)) {
|
||||
val newsId = url!!.substring(url!!.lastIndexOf("/") + 1, url!!.length - 5) // 5: ".html"
|
||||
val intent = NewsDetailActivity.getIntentById(context, newsId, entrance)
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
context.startActivity(WebActivity.getWebByCollectionTools(context, this, false))
|
||||
}
|
||||
} ?: ""
|
||||
}
|
||||
|
||||
"halo_tab" -> directToPersonalTab(context)
|
||||
|
||||
//"h5_game_center" -> directLetoGameCenter(context)
|
||||
|
||||
"" -> {
|
||||
@ -574,12 +645,17 @@ object DirectUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun directToExternalBrowser(context: Context, url: String) {
|
||||
if (url.isEmpty()) return
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
if (context !is AppCompatActivity) {
|
||||
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
try {
|
||||
if (url.isEmpty()) return
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(Uri.decode(url)))
|
||||
if (context !is AppCompatActivity) {
|
||||
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(browserIntent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
e.printStackTrace()
|
||||
Utils.toast(context, "跳转地址无效")
|
||||
}
|
||||
context.startActivity(browserIntent)
|
||||
}
|
||||
|
||||
// 跳转 QQ,qqNumber 为空选择默认客服 QQ
|
||||
@ -606,8 +682,7 @@ object DirectUtils {
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
// 没有安装QQ 复制账号
|
||||
Util_System_ClipboardManager.setText(context, qq)
|
||||
Utils.toast(context, "已复制 QQ $qq")
|
||||
qq?.copyTextAndToast("已复制 QQ $qq")
|
||||
}
|
||||
}
|
||||
|
||||
@ -889,6 +964,20 @@ object DirectUtils {
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到问题标签详情
|
||||
*/
|
||||
@ -1013,7 +1102,28 @@ object DirectUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 到首页论坛 tab
|
||||
* 到首页-首页 tab
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToHomeTab(context: Context) {
|
||||
if (RunningUtils.isRunning(context)
|
||||
&& MainActivity::class.java.name == RunningUtils.getBaseActivity(context)) {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
context.startActivity(intent)
|
||||
|
||||
// 这里换个线程操作是为了做一点延时
|
||||
AppExecutor.ioExecutor.execute {
|
||||
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_HOME))
|
||||
}
|
||||
} else {
|
||||
jumpActivity(context, Bundle().apply { putInt(KEY_POSITION, MainWrapperFragment.INDEX_HOME) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 到首页-论坛 tab
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToForum(context: Context) {
|
||||
@ -1032,6 +1142,46 @@ object DirectUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 到首页-视频 tab
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToVideoTab(context: Context) {
|
||||
if (RunningUtils.isRunning(context)
|
||||
&& MainActivity::class.java.name == RunningUtils.getBaseActivity(context)) {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
context.startActivity(intent)
|
||||
|
||||
// 这里换个线程操作是为了做一点延时
|
||||
AppExecutor.ioExecutor.execute {
|
||||
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_VIDEO))
|
||||
}
|
||||
} else {
|
||||
jumpActivity(context, Bundle().apply { putInt(KEY_POSITION, MainWrapperFragment.INDEX_VIDEO) })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 到首页-我的光环 tab
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToPersonalTab(context: Context) {
|
||||
if (RunningUtils.isRunning(context)
|
||||
&& MainActivity::class.java.name == RunningUtils.getBaseActivity(context)) {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
context.startActivity(intent)
|
||||
|
||||
// 这里换个线程操作是为了做一点延时
|
||||
AppExecutor.ioExecutor.execute {
|
||||
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_PERSONAL))
|
||||
}
|
||||
} else {
|
||||
jumpActivity(context, Bundle().apply { putInt(KEY_POSITION, MainWrapperFragment.INDEX_PERSONAL) })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至使用帮助与反馈
|
||||
* @param position 使用帮助:[HelpAndFeedbackActivity.HELP_ITEM],意见反馈:[HelpAndFeedbackActivity.SUGGESTION_ITEM]
|
||||
@ -1043,4 +1193,95 @@ object DirectUtils {
|
||||
bundle.putInt(BaseActivity_TabLayout.PAGE_INDEX, position)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至商品详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToCommodityDetail(context: Context, commodityId: String) {
|
||||
var url: String = if ("internal" == BuildConfig.FLAVOR) {
|
||||
Constants.COMMODITY_DETAIL_ADDRESS_DEV
|
||||
} else {
|
||||
Constants.COMMODITY_DETAIL_ADDRESS
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s&shopid=%s×tamp=%d", url, commodityId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至光能记录(默认跳到光能记录第一个Tab)
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToEnergyRecord(context: Context) {
|
||||
directToEnergyRecord(context, 0)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToEnergyRecord(context: Context, position: Int) {
|
||||
var url: String = if ("internal" == BuildConfig.FLAVOR) {
|
||||
Constants.ENERGY_RECORD_ADDRESS_DEV
|
||||
} else {
|
||||
Constants.ENERGY_RECORD_ADDRESS
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s&position=%s×tamp=%d", url, position, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至订单中心
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToOrderCenter(context: Context) {
|
||||
var url: String = if ("internal" == BuildConfig.FLAVOR) {
|
||||
Constants.ORDER_CENTER_ADDRESS_DEV
|
||||
} else {
|
||||
Constants.ORDER_CENTER_ADDRESS
|
||||
}
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至订单详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToOrderDetail(context: Context, orderId: String) {
|
||||
var url: String = if ("internal" == BuildConfig.FLAVOR) {
|
||||
Constants.ORDER_DETAIL_ADDRESS_DEV
|
||||
} else {
|
||||
Constants.ORDER_DETAIL_ADDRESS
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s&order_id=%s×tamp=%d", url, orderId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至邀请好友
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToInviteFriends(context: Context) {
|
||||
var url: String = if ("internal" == BuildConfig.FLAVOR) {
|
||||
Constants.INVITE_FRIENDS_ADDRESS_DEV
|
||||
} else {
|
||||
Constants.INVITE_FRIENDS_ADDRESS
|
||||
}
|
||||
directToFullScreenWebPage(context, url, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至等级页面
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToLevelPage(context: Context) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.LEVEL_ADDRESS
|
||||
} else {
|
||||
Constants.LEVEL_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s?timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
}
|
||||
@ -8,9 +8,16 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.dialog.CertificationDialog;
|
||||
import com.gh.common.dialog.DeviceRemindDialog;
|
||||
import com.gh.common.dialog.PackageCheckDialogFragment;
|
||||
import com.gh.common.dialog.ReserveDialogFragment;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
@ -39,12 +46,6 @@ import com.lightgame.utils.Utils;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* todo 下载判断不能以按钮文案为判断条件,否则按钮文案修改时又要修改判断逻辑
|
||||
*/
|
||||
@ -124,16 +125,17 @@ public class DownloadItemUtils {
|
||||
public static void updateItemWithReserveStatus(GameViewHolder holder, GameEntity gameEntity) {
|
||||
if ("download".equals(gameEntity.getReserveStatus())) {
|
||||
// 已上线
|
||||
holder.gameDownloadBtn.setVisibility(View.VISIBLE);
|
||||
holder.gameDownloadBtn.setText("已上线");
|
||||
holder.gameDownloadBtn.setTextColor(Color.WHITE);
|
||||
holder.gameDownloadBtn.setBackground(ContextCompat.getDrawable(holder.gameDes.getContext(), R.drawable.game_item_btn_pause_dn));
|
||||
// holder.gameDownloadBtn.setVisibility(View.VISIBLE);
|
||||
// holder.gameDownloadBtn.setText("已上线");
|
||||
// holder.gameDownloadBtn.setTextColor(Color.WHITE);
|
||||
// holder.gameDownloadBtn.setBackground(ContextCompat.getDrawable(holder.gameDes.getContext(), R.drawable.game_item_btn_pause_dn));
|
||||
updateItem(holder.gameDes.getContext(), gameEntity, holder, false);
|
||||
} else if ("appointment".equals(gameEntity.getReserveStatus())) {
|
||||
// 已预约
|
||||
holder.gameDownloadBtn.setVisibility(View.VISIBLE);
|
||||
holder.gameDownloadBtn.setText("已预约");
|
||||
holder.gameDownloadBtn.setTextColor(Color.WHITE);
|
||||
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_pause_dn);
|
||||
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(holder.gameDes.getContext(), R.color.aaaaaa));
|
||||
holder.gameDownloadBtn.setBackgroundResource(R.drawable.button_round_f5f5f5);
|
||||
}
|
||||
}
|
||||
|
||||
@ -419,7 +421,7 @@ public class DownloadItemUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clickCallback 供那些需要知道点击回调的地方使用
|
||||
* @param clickCallback 供那些需要知道点击回调的地方使用,触发具体响应才会回调
|
||||
*/
|
||||
public static void setOnClickListener(final Context context,
|
||||
final TextView downloadBtn,
|
||||
@ -431,103 +433,13 @@ public class DownloadItemUtils {
|
||||
final ExposureEvent traceEvent,
|
||||
@Nullable final EmptyCallback clickCallback) {
|
||||
|
||||
if (gameEntity.isReservable()) {
|
||||
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
CheckLoginUtils.checkLogin(context, entrance, () -> {
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
}
|
||||
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> {
|
||||
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
|
||||
gameEntity,
|
||||
() -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
adapter.notifyItemChanged(position);
|
||||
}
|
||||
);
|
||||
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
}
|
||||
if ("download".equals(gameEntity.getReserveStatus())) {
|
||||
ReservationHelper.showDeleteReservationDialog(context, () -> {
|
||||
ReservationHelper.deleteReservation(gameEntity, () -> {
|
||||
adapter.notifyItemChanged(position);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
ReservationHelper.showCancelReservationDialog(context, () -> {
|
||||
ReservationHelper.cancelReservation(gameEntity, () -> {
|
||||
adapter.notifyItemChanged(position);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
|
||||
|
||||
LinkEntity linkEntity = gameEntity.getH5Link();
|
||||
|
||||
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
|
||||
if (isPlay) {
|
||||
HistoryHelper.insertGameEntity(gameEntity);
|
||||
}
|
||||
|
||||
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton());
|
||||
context.startActivity(i);
|
||||
});
|
||||
} else if (gameEntity.getApk().size() == 1) {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
EmptyCallback clickRunnable = () -> {
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
}
|
||||
onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent);
|
||||
};
|
||||
|
||||
// 启动不需要请求存储权限
|
||||
if (downloadBtn.getText().toString().equals(context.getString(R.string.launch))) {
|
||||
clickRunnable.onCallback();
|
||||
} else {
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(context, clickRunnable);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
}
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(context, () -> {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
setOnClickListener(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent, clickCallback, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clickCallback 供那些需要知道点击回调的地方使用,只要触发了点击事件就响应回调(未登录状态下点击预约也要响应回调)
|
||||
* @param allStateClickCallback 供那些需要知道点击回调的地方使用,只要触发点击动作就会回调
|
||||
*/
|
||||
public static void setOnClickListenerWithInvokeCallbackForAllState(final Context context,
|
||||
public static void setOnClickListener(final Context context,
|
||||
final TextView downloadBtn,
|
||||
final GameEntity gameEntity,
|
||||
final int position,
|
||||
@ -535,29 +447,36 @@ public class DownloadItemUtils {
|
||||
final String entrance,
|
||||
final String location,
|
||||
final ExposureEvent traceEvent,
|
||||
@Nullable final EmptyCallback clickCallback) {
|
||||
@Nullable final EmptyCallback clickCallback,
|
||||
@Nullable final EmptyCallback allStateClickCallback) {
|
||||
|
||||
if (gameEntity.isReservable()) {
|
||||
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
if (allStateClickCallback != null) {
|
||||
allStateClickCallback.onCallback();
|
||||
}
|
||||
|
||||
CheckLoginUtils.checkLogin(context, entrance, () -> {
|
||||
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> {
|
||||
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
|
||||
gameEntity,
|
||||
() -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
adapter.notifyItemChanged(position);
|
||||
}
|
||||
);
|
||||
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
|
||||
});
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
}
|
||||
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
|
||||
gameEntity,
|
||||
() -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
adapter.notifyItemChanged(position);
|
||||
}
|
||||
);
|
||||
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
|
||||
});
|
||||
});
|
||||
} else {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
if (allStateClickCallback != null) {
|
||||
allStateClickCallback.onCallback();
|
||||
}
|
||||
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
}
|
||||
@ -581,9 +500,10 @@ public class DownloadItemUtils {
|
||||
|
||||
if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
if (allStateClickCallback != null) {
|
||||
allStateClickCallback.onCallback();
|
||||
}
|
||||
|
||||
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
|
||||
|
||||
LinkEntity linkEntity = gameEntity.getH5Link();
|
||||
@ -599,6 +519,10 @@ public class DownloadItemUtils {
|
||||
} else if (gameEntity.getApk().size() == 1) {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
EmptyCallback clickRunnable = () -> {
|
||||
if (allStateClickCallback != null) {
|
||||
allStateClickCallback.onCallback();
|
||||
}
|
||||
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
}
|
||||
@ -614,6 +538,10 @@ public class DownloadItemUtils {
|
||||
});
|
||||
} else {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
if (allStateClickCallback != null) {
|
||||
allStateClickCallback.onCallback();
|
||||
}
|
||||
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
}
|
||||
@ -652,28 +580,33 @@ public class DownloadItemUtils {
|
||||
final String location,
|
||||
@Nullable final ExposureEvent traceEvent) {
|
||||
String str = downloadBtn.getText().toString();
|
||||
ApkEntity apk = gameEntity.getApk().get(0);
|
||||
if (gameEntity.getApk().isEmpty()) return;
|
||||
ApkEntity apk = ExtensionsKt.safelyGetInRelease(gameEntity.getApk(), 0);
|
||||
if (apk == null) return;
|
||||
|
||||
if (str.equals(context.getString(R.string.download))) {
|
||||
// 先弹下载弹窗(如果需要的话)
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
|
||||
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
|
||||
DialogUtils.checkDownload(context, apk.getSize(),
|
||||
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
|
||||
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity.getPackageDialog(), () -> {
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
|
||||
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
|
||||
DialogUtils.checkDownload(context, apk.getSize(),
|
||||
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
DataLogUtils.uploadGameLog(context, gameEntity.getId(), gameEntity.getName(), entrance);
|
||||
} else if (str.equals(context.getString(R.string.attempt))) {
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
|
||||
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
|
||||
DialogUtils.checkDownload(context, apk.getSize(),
|
||||
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
|
||||
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity.getPackageDialog(), () -> {
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
|
||||
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
|
||||
DialogUtils.checkDownload(context, apk.getSize(),
|
||||
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -700,7 +633,7 @@ public class DownloadItemUtils {
|
||||
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(context, gameEntity.getSimulator().getApk().getPackageName());
|
||||
if (downloadEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity) && !isInstalled) {
|
||||
SimulatorDownloadManager.getInstance().showDownloadDialog(context, gameEntity.getSimulator(),
|
||||
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(),null);
|
||||
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(), null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -724,6 +657,8 @@ public class DownloadItemUtils {
|
||||
}
|
||||
DataUtils.onGameLaunchEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
|
||||
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk().get(0).getPackageName());
|
||||
|
||||
EnergyTaskHelper.postEnergyTask("play_game", gameEntity.getId(), gameEntity.getApk().get(0).getPackageName());
|
||||
} else if (str.equals(context.getString(R.string.update))) {
|
||||
if (entrance.contains("我的游戏")) {
|
||||
MtaHelper.onEvent("我的游戏_启动", "更新", gameEntity.getName());
|
||||
@ -757,6 +692,8 @@ public class DownloadItemUtils {
|
||||
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
|
||||
downloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
|
||||
DeviceRemindDialog.Companion.showDeviceRemindDialog(context, gameEntity);
|
||||
|
||||
EnergyTaskHelper.postEnergyTask("download_game", gameEntity.getId(), gameEntity.getApk().get(0).getPackageName());
|
||||
} else {
|
||||
Utils.toast(context, msg);
|
||||
}
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.preference.PreferenceManager
|
||||
import com.gh.base.BaseActivity
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.ExposureUtils
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.simulator.SimulatorDownloadManager
|
||||
import com.gh.common.simulator.SimulatorGameManager
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.download.DownloadDataHelper
|
||||
import com.gh.download.DownloadManager
|
||||
@ -17,6 +16,7 @@ import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.SuggestionActivity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.SimpleGameEntity
|
||||
import com.gh.gamecenter.entity.SimulatorEntity
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus
|
||||
import com.gh.gamecenter.eventbus.EBShowDialog
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
@ -51,7 +51,7 @@ object DownloadObserver {
|
||||
val xapkStatus = downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
|
||||
if (!xapkStatus.isNullOrEmpty()) return
|
||||
|
||||
val gameId = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)
|
||||
val gameId = downloadEntity.gameId
|
||||
val downloadManager = DownloadManager.getInstance(HaloApp.getInstance().application)
|
||||
|
||||
tryCatchInRelease {
|
||||
@ -77,9 +77,10 @@ object DownloadObserver {
|
||||
// MtaHelper.onEventWithBasicDeviceInfo("下载失败弹窗",
|
||||
// "游戏", downloadEntity.name,
|
||||
// "平台", downloadEntity.platform)
|
||||
val currentActivity = AppManager.getInstance().currentActivity() ?: return
|
||||
|
||||
DialogUtils.showAlertDialog(AppManager.getInstance().currentActivity(), "下载失败", "下载链接已失效,建议提交反馈", "立即反馈", "取消", {
|
||||
SuggestionActivity.startSuggestionActivity(AppManager.getInstance().currentActivity(),
|
||||
DialogUtils.showAlertDialog(currentActivity, "下载失败", "下载链接已失效,建议提交反馈", "立即反馈", "取消", {
|
||||
SuggestionActivity.startSuggestionActivity(currentActivity,
|
||||
SuggestType.gameQuestion, "notfound",
|
||||
StringUtils.buildString(downloadEntity.name, ",问题反馈:下载链接失效"),
|
||||
SimpleGameEntity(gameId, downloadEntity.name, ""))
|
||||
@ -111,11 +112,14 @@ object DownloadObserver {
|
||||
}
|
||||
if (DownloadStatus.done == downloadEntity.status) {
|
||||
if (downloadEntity.name.contains(mApplication.getString(R.string.app_name))) {
|
||||
statDoneEvent(downloadEntity)
|
||||
MtaHelper.onEvent("软件更新", "下载完成")
|
||||
// 会有 ActivityNotFoundException 异常,catch 掉不管了
|
||||
tryWithDefaultCatch {
|
||||
if (Constants.SILENT_UPDATE != downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)) {
|
||||
PackageInstaller.install(mApplication, downloadEntity)
|
||||
// TODO 在 Android 11 上没有授权安装未知应用的权限前第一次调用这个方法系统会杀掉我们的进程...
|
||||
// 没能找到类似的解释,最接近的是这个 https://issuetracker.google.com/issues/154157387,但也只是点授权杀进程而已
|
||||
PackageInstaller.install(mApplication, downloadEntity);
|
||||
DataLogUtils.uploadUpgradeLog(mApplication, "install") //上传更新安装数据
|
||||
}
|
||||
}
|
||||
@ -136,17 +140,20 @@ object DownloadObserver {
|
||||
}
|
||||
if (!downloadEntity.isPluggable) {
|
||||
if (downloadEntity.isSimulatorGame()) {
|
||||
val gameEntity = HaloApp.get(GameEntity::class.java.simpleName, true) as? GameEntity
|
||||
if (gameEntity?.simulator != null) {
|
||||
val isInstalled = PackageUtils.isInstalledFromAllPackage(HaloApp.getInstance().application, gameEntity.simulator!!.apk!!.packageName)
|
||||
if (!isInstalled) {
|
||||
SimulatorDownloadManager.getInstance().showDownloadDialog(AppManager.getInstance().currentActivity(), gameEntity.simulator,
|
||||
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.id, gameEntity.name
|
||||
?: "", null)
|
||||
}
|
||||
SimulatorGameManager.recordDownloadSimulatorGames(gameEntity.id)
|
||||
SimulatorGameManager.postPlayedGame(gameEntity.id, downloadEntity.packageName)
|
||||
val simulatorJson = downloadEntity.getMetaExtra(Constants.SIMULATOR)
|
||||
val gameName = downloadEntity.getMetaExtra(Constants.GAME_NAME)
|
||||
if (simulatorJson.isEmpty()) return
|
||||
val simulator = GsonUtils.fromJson(simulatorJson, SimulatorEntity::class.java)
|
||||
val isInstalled = PackageUtils.isInstalledFromAllPackage(HaloApp.getInstance().application, simulator.apk?.packageName)
|
||||
if (!isInstalled) {
|
||||
val currentActivity = AppManager.getInstance().currentActivity()
|
||||
?: return
|
||||
|
||||
SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator,
|
||||
SimulatorDownloadManager.SimulatorLocation.LAUNCH, downloadEntity.gameId, gameName, null)
|
||||
}
|
||||
SimulatorGameManager.recordDownloadSimulatorGames(downloadEntity.gameId)
|
||||
SimulatorGameManager.postPlayedGame(downloadEntity.gameId, downloadEntity.packageName)
|
||||
} else {
|
||||
val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
|
||||
// 是否是自动安装
|
||||
@ -175,14 +182,32 @@ object DownloadObserver {
|
||||
}
|
||||
|
||||
// 下载过程分析统计
|
||||
|
||||
// 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
|
||||
// 这里为了让它能用就不判断是否解析包错误了
|
||||
if (PackageUtils.isDeviceUnableToHandleBigApkFile(downloadEntity.path)) {
|
||||
return
|
||||
}
|
||||
|
||||
val pm = mApplication.packageManager
|
||||
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, PackageManager.GET_ACTIVITIES)
|
||||
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0)
|
||||
if (packageInfo == null) {
|
||||
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析",
|
||||
// "游戏名字", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
|
||||
//
|
||||
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误_新",
|
||||
// "游戏", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
|
||||
val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
|
||||
if (downloadType == Constants.SIMULATOR_DOWNLOAD) {
|
||||
val currentActivity = AppManager.getInstance().currentActivity()
|
||||
?: return
|
||||
DialogUtils.showSimulatorParseErrorDialog(currentActivity, downloadEntity.gameId, downloadEntity.name) {
|
||||
val simulator = HaloApp.get(downloadEntity.name, true) as? SimulatorEntity
|
||||
?: return@showSimulatorParseErrorDialog
|
||||
DownloadManager.getInstance(currentActivity).cancel(downloadEntity.url, true, true)
|
||||
SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator, SimulatorDownloadManager.SimulatorLocation.SIMULATOR_GAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,7 +240,7 @@ object DownloadObserver {
|
||||
kv1["版本"] = platform
|
||||
kv1["状态"] = "下载完成"
|
||||
kv1["用户机型"] = Build.MODEL
|
||||
kv1["设备IMEI"] = MetaUtil.getIMEI()
|
||||
kv1["设备JNFJ"] = MetaUtil.getBase64EncodedIMEI()
|
||||
kv1["网络状态"] = DeviceUtils.getNetwork(HaloApp.getInstance().application)
|
||||
kv1["光环助手版本"] = BuildConfig.VERSION_NAME
|
||||
if (downloadEntity.isUpdate) {
|
||||
@ -253,7 +278,7 @@ object DownloadObserver {
|
||||
}
|
||||
|
||||
ExposureUtils.logADownloadCompleteExposureEvent(
|
||||
GameEntity(id = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER),
|
||||
GameEntity(id = downloadEntity.gameId,
|
||||
mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR),
|
||||
gameVersion = downloadEntity.versionName ?: ""),
|
||||
downloadEntity.platform,
|
||||
@ -283,7 +308,7 @@ object DownloadObserver {
|
||||
params["game"] = id
|
||||
params["platform"] = platform ?: ""
|
||||
val body = RequestBody.create(MediaType.parse("application/json"),
|
||||
JSONObject(params).toString())
|
||||
JSONObject(params as Map<*, *>).toString())
|
||||
RetrofitManager.getInstance(mApplication).api.postDownload(body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
||||
160
app/src/main/java/com/gh/common/util/EnergyTaskHelper.kt
Normal file
160
app/src/main/java/com/gh/common/util/EnergyTaskHelper.kt
Normal file
@ -0,0 +1,160 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.energy.EnergyCenterActivity
|
||||
import com.gh.gamecenter.entity.EnergyTaskCompleteEntity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.AppManager
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import org.json.JSONObject
|
||||
|
||||
/**
|
||||
* 上报光能任务辅助类
|
||||
*/
|
||||
object EnergyTaskHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun postEnergyTask(action: String) {
|
||||
postEnergyTask(action, null, null, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun postEnergyTask(action: String, id: String) {
|
||||
postEnergyTask(action, id, null, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun postEnergyTask(action: String, id: String, packageName: String) {
|
||||
postEnergyTask(action, id, packageName, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun postEnergyTaskForWeb(action: String, url: String) {
|
||||
postEnergyTask(action, null, null, url)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun postEnergyTaskForShare(type: String, id: String, url: String) {
|
||||
when (type) {
|
||||
"游戏详情" -> postEnergyTask("share_game_detail", id)
|
||||
|
||||
"视频" -> postEnergyTask("share_video", id)
|
||||
|
||||
"资讯文章" -> postEnergyTask("share_article", id)
|
||||
|
||||
"问题详情" -> postEnergyTask("share_question", id)
|
||||
|
||||
"回答详情" -> postEnergyTask("share_answer", id)
|
||||
|
||||
"文章详情" -> postEnergyTask("share_community_article", id)
|
||||
|
||||
"工具箱" -> postEnergyTask("share_toolkit", id)
|
||||
|
||||
"web链接" -> postEnergyTaskForWeb("share_web", url)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun postEnergyTask(action: String, id: String? = null, packageName: String? = null, url: String? = null) {
|
||||
if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0L) {
|
||||
val taskParams = JSONObject()
|
||||
taskParams.put("action", action)
|
||||
|
||||
val actionParams = JSONObject()
|
||||
if (id != null) actionParams.put("_id", id)
|
||||
if (packageName != null) actionParams.put("package", packageName)
|
||||
if (url != null) actionParams.put("url", url)
|
||||
taskParams.put("action_param", actionParams)
|
||||
|
||||
debugOnly { Utils.log("EnergyTaskHelper -> $taskParams") }
|
||||
|
||||
val body = RequestBody.create(MediaType.parse("application/json"), taskParams.toString())
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.api.postEnergyTask(UserManager.getInstance().userId, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<List<EnergyTaskCompleteEntity>>() {
|
||||
override fun onSuccess(data: List<EnergyTaskCompleteEntity>) {
|
||||
data.forEach { showCompletePopup(it) }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun postInviteCodeTask(code: String, from: String, successCallback: () -> Unit, failCallback: () -> Unit) {
|
||||
if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0L) {
|
||||
val taskParams = JSONObject()
|
||||
taskParams.put("action", "enter_invite_code")
|
||||
|
||||
val actionParams = JSONObject()
|
||||
actionParams.put("code", code)
|
||||
actionParams.put("type", "new")
|
||||
actionParams.put("from", from)
|
||||
taskParams.put("action_param", actionParams)
|
||||
|
||||
debugOnly { Utils.log("EnergyTaskHelper -> $taskParams") }
|
||||
|
||||
val body = RequestBody.create(MediaType.parse("application/json"), taskParams.toString())
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.api.postEnergyTask(UserManager.getInstance().userId, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<List<EnergyTaskCompleteEntity>>() {
|
||||
override fun onSuccess(data: List<EnergyTaskCompleteEntity>) {
|
||||
SPUtils.setBoolean(Constants.SP_HAS_COMPLETE_INVITE_CODE, true)
|
||||
successCallback.invoke()
|
||||
data.forEach { showCompletePopup(it) }
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
failCallback.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 完成弹窗
|
||||
@JvmStatic
|
||||
fun showCompletePopup(entity: EnergyTaskCompleteEntity) {
|
||||
val currentActivity = AppManager.getInstance().recentActiveActivity
|
||||
currentActivity?.run {
|
||||
val contentView = View.inflate(this, R.layout.popup_energy_task, null)
|
||||
contentView.run {
|
||||
findViewById<TextView>(R.id.taskDesc).text = "恭喜你!完成任务:${entity.name}"
|
||||
findViewById<TextView>(R.id.taskEnergy).text = "+${entity.energy}光能"
|
||||
isFocusable = true
|
||||
isFocusableInTouchMode = true
|
||||
setOnClickListener {
|
||||
currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity))
|
||||
}
|
||||
}
|
||||
val popWindow = PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, 88F.dip2px())
|
||||
popWindow.showAtLocation(currentActivity.window.decorView, Gravity.TOP, 0, 0)
|
||||
|
||||
countDownTimer(3) { finish, _ ->
|
||||
if (finish && popWindow != null && popWindow.isShowing) {
|
||||
popWindow.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -215,6 +215,15 @@ public class EntranceUtils {
|
||||
public static final String KEY_BBS_ID = "bbs_id";
|
||||
public static final String KEY_DIAGNOSIS = "diagnosis";
|
||||
public static final String KEY_SIMULATOR = "simulator";
|
||||
public static final String KEY_MARKET_DETAILS = "market_details";
|
||||
public static final String KEY_CATALOG_ID = "catalogId";
|
||||
public static final String KEY_PRIMARY_CATALOG_ID = "primaryCatalogId";
|
||||
public static final String KEY_PRIMARY_CATALOG_NAME = "primaryCatalogName";
|
||||
public static final String KEY_CATALOG_TITLE = "catalog_title";
|
||||
public static final String KEY_CATALOG_INIT_TITLE = "catalog_init_title";
|
||||
public static final String KEY_CATEGORY_LIST = "categoty_list";
|
||||
public static final String KEY_IS_FREE = "is_free";
|
||||
public static final String KEY_IS_SIGN = "is_sign";
|
||||
|
||||
public static void jumpActivity(Context context, Bundle bundle) {
|
||||
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
|
||||
|
||||
@ -6,6 +6,7 @@ import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.entity.ErrorEntity
|
||||
import com.lightgame.utils.Utils
|
||||
import retrofit2.HttpException
|
||||
|
||||
/**
|
||||
* 这个类用来管理一些错误,像弹窗、TOAST 什么的
|
||||
@ -17,6 +18,7 @@ object ErrorHelper {
|
||||
* [showHighPriorityHint] 用来标识有同样错误码可以触发两种处理时,为 true 时选择重要的
|
||||
* [customizedHandler] 返回 true 为已处理该错误码,false 则交由 [handleError] 处理
|
||||
*/
|
||||
@JvmStatic
|
||||
fun handleErrorWithCustomizedHandler(context: Context,
|
||||
errorString: String?,
|
||||
showHighPriorityHint: Boolean = false,
|
||||
@ -169,4 +171,23 @@ object ErrorHelper {
|
||||
}, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun handleLoginError(context: Context, httpException: HttpException?) {
|
||||
try {
|
||||
val errorEntity: ErrorEntity? = httpException?.response()?.errorBody()?.string()?.toObject()
|
||||
when {
|
||||
errorEntity?.code == 403099 -> {
|
||||
Utils.toast(context, "当前账号正在注销,禁止登录")
|
||||
}
|
||||
errorEntity?.toast?.isNotEmpty() == true -> {
|
||||
Utils.toast(context, errorEntity.toast)
|
||||
}
|
||||
else -> Utils.toast(context, R.string.login_failure)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Utils.toast(context, R.string.login_failure)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.animation.Animator
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
@ -43,8 +44,11 @@ import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.ObservableTransformer
|
||||
import io.reactivex.SingleTransformer
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import java.net.URI
|
||||
@ -124,6 +128,20 @@ fun ViewPager.addOnScrollStateChanged(onStateChanged: ((state: Int) -> Unit)? =
|
||||
addOnPageChangeListener(listener)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fragment related
|
||||
*/
|
||||
inline fun <reified T : Fragment> Fragment.fragmentFromActivity() =
|
||||
parentFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
|
||||
?: parentFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T
|
||||
|
||||
|
||||
inline fun <reified T : Fragment> Fragment.fragmentFromParentFragment() =
|
||||
childFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
|
||||
?: childFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T
|
||||
|
||||
|
||||
/**
|
||||
* RecyclerView Extensions
|
||||
*/
|
||||
@ -329,6 +347,15 @@ fun throwExceptionInDebug(message: String = "", predicate: Boolean = true) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在自动打包的包里弹 toast
|
||||
*/
|
||||
fun toastInInternalRelease(content: String) {
|
||||
if (BuildConfig.BUILD_TIME != 0L) {
|
||||
Utils.toast(HaloApp.getInstance(), content)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 主动抛出异常
|
||||
*/
|
||||
@ -388,11 +415,25 @@ fun String.getFirstElementDividedByDivider(divider: String): String {
|
||||
return this
|
||||
}
|
||||
|
||||
fun String.copyText() {
|
||||
this.copyTextAndToast("")
|
||||
}
|
||||
|
||||
fun String.copyTextAndToast(toastText: String = "复制成功") {
|
||||
val application = HaloApp.getInstance().application
|
||||
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
cmb.text = this
|
||||
ToastUtils.showToast(toastText)
|
||||
try {
|
||||
val application = HaloApp.getInstance().application
|
||||
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(null, this)
|
||||
cmb.setPrimaryClip(clip)
|
||||
|
||||
if (!TextUtils.isEmpty(toastText)) {
|
||||
ToastUtils.showToast(toastText)
|
||||
}
|
||||
} catch (e: SecurityException) {
|
||||
// 在一些情况下会报以下这样的错误,可能是以浮动窗口显示然后没有焦点?(https://developer.android.com/about/versions/10/privacy/changes#clipboard-data)
|
||||
// java.lang.Throwable: java.lang.SecurityException: com.xunmeng.pinduoduo from uid 10317 not allowed to perform READ_CLIPBOARD
|
||||
ToastUtils.showToast("复制失败,请重试")
|
||||
}
|
||||
}
|
||||
|
||||
fun Map<String, String>.createRequestBody(): RequestBody {
|
||||
@ -436,6 +477,7 @@ fun Float.sp2px(): Int {
|
||||
return (this * scale + 0.5f).toInt()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PopupWindow 自动适配方向
|
||||
* 弹出与锚点右对齐
|
||||
@ -492,6 +534,14 @@ fun Fragment.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
|
||||
})
|
||||
}
|
||||
|
||||
fun Fragment.checkCalendarPermissionBeforeAction(action: (() -> Unit)) {
|
||||
PermissionHelper.checkCalendarPermissionBeforeAction(requireContext(), object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
action.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun FragmentActivity.checkReadPhoneStateAndStoragePermissionBeforeAction(action: (() -> Unit)) {
|
||||
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(this, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
@ -516,6 +566,14 @@ fun FragmentActivity.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
|
||||
})
|
||||
}
|
||||
|
||||
fun FragmentActivity.checkCalendarPermissionBeforeAction(action: (() -> Unit)) {
|
||||
PermissionHelper.checkCalendarPermissionBeforeAction(this, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
action.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* List related.
|
||||
*/
|
||||
@ -559,6 +617,19 @@ fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* List related
|
||||
*/
|
||||
fun <T> List<T>.safelyGetInRelease(index: Int): T? {
|
||||
return if (index >= size) {
|
||||
throwExceptionInDebug("这里触发了数组越界,请检查 (index $index >= size $size)")
|
||||
toastInInternalRelease("这个操作可能触发闪退,请确定复现方式并联系开发处理")
|
||||
null
|
||||
} else {
|
||||
this[index]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截 TextView 中的 Url Span,用应用内页面的形式打开链接
|
||||
* @param shrankText 未展开时的文字
|
||||
@ -651,11 +722,16 @@ fun SimpleDraweeView.display(url: String) {
|
||||
* DownloadEntity extension
|
||||
*/
|
||||
fun DownloadEntity.addMetaExtra(key: String, value: String?) {
|
||||
value?.let { meta[key] = value }
|
||||
value?.let {
|
||||
if (meta == null) {
|
||||
meta = hashMapOf()
|
||||
}
|
||||
meta[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
fun DownloadEntity.getMetaExtra(key: String): String {
|
||||
return meta[key] ?: ""
|
||||
return meta?.get(key) ?: ""
|
||||
}
|
||||
|
||||
fun DownloadEntity.isSilentUpdate(): Boolean {
|
||||
@ -677,6 +753,9 @@ fun Context.doOnMainProcessOnly(callback: EmptyCallback) {
|
||||
doOnMainProcessOnly { callback.onCallback() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 虽然现在我们没有了友盟以后只是单进程APP,但在 debug 模式下还有 whatTheStack 这个进程如果不限定主进程会出现奇奇怪怪的问题 (BroadcastReceiver相关)
|
||||
*/
|
||||
inline fun Context.doOnMainProcessOnly(f: () -> Unit) {
|
||||
val processName = PackageUtils.obtainProcessName(this)
|
||||
if (processName == null || BuildConfig.APPLICATION_ID == processName) {
|
||||
@ -849,4 +928,18 @@ fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)?
|
||||
onStopTrackingTouch?.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun <T> observableToMain(): ObservableTransformer<T, T> {
|
||||
return ObservableTransformer { upstream ->
|
||||
upstream.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> singleToMain(): SingleTransformer<T, T> {
|
||||
return SingleTransformer { upstream ->
|
||||
upstream.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
}
|
||||
@ -78,6 +78,9 @@ public class GameUtils {
|
||||
int pluginCount = 0; // 可插件化数量
|
||||
int updateCount = 0; // 可更新数量
|
||||
int installCount = 0; // 已安装数量
|
||||
|
||||
boolean isRelatedEmulatorInstalled = false; // 若该游戏是模拟器游戏时其对应的模拟器是否已经安装
|
||||
|
||||
DownloadEntity downloadEntity;
|
||||
Object gh_id;
|
||||
apkFor:
|
||||
@ -113,7 +116,10 @@ public class GameUtils {
|
||||
&& !PackageUtils.isSignedByGh(context, apkEntity.getPackageName())
|
||||
&& apkEntity.isShowPlugin(pluginLocation)) {
|
||||
pluginCount++;
|
||||
} else if (gh_id == null || gh_id.equals(gameEntity.getId())) {
|
||||
} else if (gh_id == null
|
||||
|| gh_id.equals(gameEntity.getId())
|
||||
// 当使用镜像时,可能会存在镜像 gh_id 与当前游戏 id 不一样的情况,这时也让它通过,避免装完还是显示`下载`
|
||||
|| gameEntity.shouldUseMirrorInfo()) {
|
||||
installCount++;
|
||||
}
|
||||
}
|
||||
@ -123,20 +129,26 @@ public class GameUtils {
|
||||
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(context, gameEntity.getSimulator().getApk().getPackageName());
|
||||
if (isInstalled) {
|
||||
installCount++;
|
||||
isRelatedEmulatorInstalled = true;
|
||||
} else {
|
||||
doneCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (installCount != 0) {
|
||||
|
||||
if (isRelatedEmulatorInstalled && doneCount != 0) {
|
||||
return context.getString(R.string.launch);
|
||||
}
|
||||
|
||||
if (doneCount != 0) {
|
||||
return context.getString(R.string.install);
|
||||
} else if (pluginCount != 0 && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
|
||||
return context.getString(R.string.pluggable);
|
||||
} else if (updateCount != 0 && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
|
||||
return context.getString(R.string.update);
|
||||
} else if (doneCount != 0) {
|
||||
return context.getString(R.string.install);
|
||||
} else if (installCount != 0) {
|
||||
return context.getString(R.string.launch);
|
||||
} else if (gameEntity.getVersionNumber().contains("无版号") && Config.isGameDomeSwitchOpen() && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
|
||||
return context.getString(R.string.attempt);
|
||||
} else {
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.app.Application
|
||||
|
||||
/**
|
||||
* 广点通辅助类 [https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/403]
|
||||
*
|
||||
* 更换帐号 [https://gitlab.ghzs.com/pm/yunying/issues/893]
|
||||
*/
|
||||
object GdtHelper {
|
||||
|
||||
const val NETWORK_TYPE = "NETWORK_TYPE"
|
||||
const val PAGE_TYPE = "PAGE_TYPE"
|
||||
const val CONTENT_TYPE = "CONTENT_TYPE"
|
||||
const val CONTENT_ID = "CONTENT_ID"
|
||||
const val KEYWORD = "KEYWORD"
|
||||
const val GAME_ID = "GAME_ID"
|
||||
const val SCORE = "SCORE"
|
||||
const val PLATFORM = "PLATFORM"
|
||||
|
||||
fun init(application: Application, channel: String) {
|
||||
// if (channel == "GH_728") {
|
||||
// GDTAction.init(application, "1111012969", "9d3d9da5b0948a317c03d08f14d445dc")
|
||||
// } else if (channel == "GH_729") {
|
||||
// GDTAction.init(application, "1111013063", "f53dabf458a356b101d99fc4069eb7f1")
|
||||
// } else {
|
||||
// GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a")
|
||||
// }
|
||||
}
|
||||
|
||||
fun logAction(type: String) {
|
||||
// GDTAction.logAction(type)
|
||||
// Utils.log("GDT", type)
|
||||
}
|
||||
|
||||
fun logAction(type: String, vararg kv: String?) {
|
||||
// try {
|
||||
// val actionParam = JSONObject()
|
||||
// for (i in kv.indices) {
|
||||
// if (i % 2 != 0) {
|
||||
// val key = kv[i - 1]
|
||||
// val value = kv[i]
|
||||
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
||||
// actionParam.put(key, value)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]")
|
||||
// GDTAction.logAction(type, actionParam)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
@ -15,7 +15,7 @@ object HomePluggableHelper {
|
||||
if (apkList.isNotEmpty()) {
|
||||
val apk = apkList.first()
|
||||
val tag = if (isNever) "never" else apk.version ?: ""
|
||||
mHomePluggableFilterDao.addData(HomePluggableFilterEntity(pkgName = apk.packageName, tag = tag, active = isNever))
|
||||
tryCatchInRelease { mHomePluggableFilterDao.addData(HomePluggableFilterEntity(pkgName = apk.packageName, tag = tag, active = isNever)) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,13 +38,18 @@ object HomePluggableHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun activationFilterData() {
|
||||
val filterList = mHomePluggableFilterDao.getDataByActive(false)
|
||||
try {
|
||||
val filterList = mHomePluggableFilterDao.getDataByActive(false)
|
||||
|
||||
if (filterList != null) {
|
||||
for (entity in filterList) {
|
||||
entity.active = true
|
||||
if (filterList != null) {
|
||||
for (entity in filterList) {
|
||||
entity.active = true
|
||||
}
|
||||
mHomePluggableFilterDao.addData(filterList)
|
||||
}
|
||||
mHomePluggableFilterDao.addData(filterList)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
toastInInternalRelease("数据库/磁盘已满,插件筛选失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,4 +67,15 @@ public class HtmlUtils {
|
||||
|
||||
return htmlStr.trim(); //返回文本字符串
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤掉标签,保留标签内容
|
||||
*/
|
||||
public static String filterHtmlLabel(String htmlStr) {
|
||||
String regEx_html = "<[^>]+>([\\s\\S]*?)<\\/[^>]+>"; //定义HTML标签的正则表达式
|
||||
Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
|
||||
Matcher m_html = p_html.matcher(htmlStr);
|
||||
htmlStr = m_html.replaceAll("$1"); //过滤html标签
|
||||
return htmlStr.trim(); //返回文本字符串
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ import com.facebook.imagepipeline.image.CloseableImage
|
||||
import com.facebook.imagepipeline.image.ImageInfo
|
||||
import com.facebook.imagepipeline.request.ImageRequest
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder
|
||||
import com.facebook.imagepipeline.request.Postprocessor
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.structure.FixedSizeLinkedHashSet
|
||||
import com.gh.gamecenter.R
|
||||
@ -85,8 +86,13 @@ object ImageUtils {
|
||||
@JvmStatic
|
||||
fun addLimitWidth(imageUrl: String?, width: Int?): String? {
|
||||
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
|
||||
val webpConfig = Config.getSettings()?.image?.oss?.webp ?: Config.getSettings()?.image?.oss?.gif
|
||||
if (jpegConfig != null) {
|
||||
return "$imageUrl$jpegConfig,w_$width"
|
||||
return if (width == 0 || width == null) {
|
||||
"$imageUrl$webpConfig"
|
||||
} else {
|
||||
"$imageUrl$jpegConfig,w_$width"
|
||||
}
|
||||
}
|
||||
return imageUrl
|
||||
}
|
||||
@ -279,92 +285,108 @@ object ImageUtils {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 规则 width>0 Wifi/4G:x2 traffic:x1
|
||||
* 第一种方案:通过LayoutParams获取 可以快速(无延迟)获取宽高,但是无法获取wrap_content和match_parent的View
|
||||
* 第二种方案(备用方案):有延迟,View的宽高需要在Measure过程后才能确定,能够在这里获取到正确的宽高
|
||||
*/
|
||||
@JvmStatic
|
||||
fun display(view: SimpleDraweeView?, url: String?) {
|
||||
url?.let {
|
||||
val width = view?.layoutParams?.width
|
||||
val height = view?.layoutParams?.height
|
||||
display(view, url, true)
|
||||
}
|
||||
|
||||
var lowResUrl = ""
|
||||
var highResUrl = ""
|
||||
/**
|
||||
* 规则 width>0 Wifi/4G:x2 traffic:x1
|
||||
* 统一加载 webp 忽略掉第二种方案
|
||||
* 第一种方案:通过LayoutParams获取 可以快速(无延迟)获取宽高,但是无法获取wrap_content和match_parent的View
|
||||
* ~~第二种方案(备用方案):有延迟,View的宽高需要在Measure过程后才能确定,能够在这里获取到正确的宽高~~
|
||||
* @param isAutoPlayGif 是否禁止播放动图
|
||||
*/
|
||||
@JvmStatic
|
||||
fun display(view: SimpleDraweeView?, url: String?, isAutoPlayGif: Boolean = true, processor: Postprocessor? = null) {
|
||||
if (url == null) return
|
||||
|
||||
// 找同一图片地址已加载过的图片作为低质量预览图
|
||||
// TODO 根据实际请求大小(w_width)来避免小图用大图作为低质量图片
|
||||
for (cachedImageUrl in mImageUrlCacheSet) {
|
||||
if (cachedImageUrl.contains(url)) {
|
||||
lowResUrl = cachedImageUrl
|
||||
break
|
||||
}
|
||||
val width = view?.layoutParams?.width
|
||||
val height = view?.layoutParams?.height
|
||||
|
||||
var lowResUrl = ""
|
||||
var highResUrl = ""
|
||||
|
||||
// 找同一图片地址已加载过的图片作为低质量预览图
|
||||
// TODO 根据实际请求大小(w_width)来避免小图用大图作为低质量图片
|
||||
for (cachedImageUrl in mImageUrlCacheSet) {
|
||||
if (url.isNotEmpty() && cachedImageUrl.contains(url)) {
|
||||
lowResUrl = cachedImageUrl
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
val loadImageClosure: (autoPlay: Boolean, highResUrl: String, lowResUrl: String) -> Unit = { autoPlay, hUrl, lUrl ->
|
||||
view?.controller = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(ImageRequest.fromUri(hUrl))
|
||||
.apply {
|
||||
if (lUrl.isNotEmpty()
|
||||
&& lUrl != hUrl
|
||||
&& hUrl != view?.getTag(R.string.highResImageTag)) {
|
||||
lowResImageRequest = ImageRequest.fromUri(lUrl)
|
||||
}
|
||||
autoPlayAnimations = autoPlay
|
||||
val loadImageClosure: (autoPlay: Boolean, highResUrl: String, lowResUrl: String) -> Unit = { autoPlay, hUrl, lUrl ->
|
||||
val imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(hUrl))
|
||||
.setPostprocessor(processor)
|
||||
.build()
|
||||
val controller = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(imageRequest)
|
||||
.apply {
|
||||
if (lUrl.isNotEmpty()
|
||||
&& lUrl != hUrl
|
||||
&& hUrl != view?.getTag(R.string.highResImageTag)) {
|
||||
lowResImageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(lUrl))
|
||||
.setPostprocessor(processor)
|
||||
.build()
|
||||
}
|
||||
.build()
|
||||
autoPlayAnimations = autoPlay
|
||||
}
|
||||
.build()
|
||||
view?.controller = controller
|
||||
|
||||
view?.setTag(R.string.highResImageTag, highResUrl)
|
||||
}
|
||||
view?.setTag(R.string.highResImageTag, highResUrl)
|
||||
}
|
||||
|
||||
val shouldLoadAsGif = it.endsWith(".gif") && view?.getTag(R.id.tag_show_gif) != false
|
||||
// 低于 2G 运行内存的不加载 gif
|
||||
val shouldLoadAsGif = url.endsWith(".gif")
|
||||
&& isAutoPlayGif
|
||||
&& (HaloApp.getInstance().deviceRamSize == 0L || HaloApp.getInstance().deviceRamSize > 2500)
|
||||
&& view?.getTag(R.id.tag_show_gif) != false
|
||||
|
||||
if (shouldLoadAsGif && view?.tag == url) return
|
||||
if (shouldLoadAsGif && view?.tag == url) return
|
||||
|
||||
if (!shouldLoadAsGif) {
|
||||
highResUrl = getTransformLimitUrl(url, width ?: 0, view?.context) ?: ""
|
||||
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
|
||||
} else {
|
||||
if (width != null && width > 0) {
|
||||
highResUrl = if (shouldLoadAsGif) {
|
||||
resizeGif(url, width, height ?: 0)
|
||||
} else {
|
||||
getTransformLimitUrl(url, width, view.context) ?: ""
|
||||
}
|
||||
highResUrl = resizeGif(url, view.width, height ?: 0)
|
||||
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
|
||||
} else {
|
||||
view?.post {
|
||||
highResUrl = if (shouldLoadAsGif) {
|
||||
resizeGif(url, view.width, height ?: 0)
|
||||
} else {
|
||||
getTransformLimitUrl(url, view.width, view.context) ?: ""
|
||||
}
|
||||
highResUrl = resizeGif(url, view.width, height ?: 0)
|
||||
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
|
||||
}
|
||||
}
|
||||
view?.tag = url
|
||||
}
|
||||
view?.tag = url
|
||||
}
|
||||
|
||||
// Wifi/4G:x2 traffic:x1
|
||||
@JvmStatic
|
||||
fun getTransformLimitUrl(url: String?, width: Int?, context: Context?): String? {
|
||||
var transformUrl: String? = url
|
||||
val transformUrl: String?
|
||||
if (width != null && width > 0) {
|
||||
// 加载大小是实际 ImageView 大小两倍的图片真的有意义吗?
|
||||
val transformUrlX2 = addLimitWidth(url, width * 2)
|
||||
val transformUrlX1 = addLimitWidth(url, width)
|
||||
// 当网络为 WIFI 或 4G, 且系统版本大于 5.0 && 手机内存大于 1G 才用高清图片
|
||||
if (NetworkUtils.isWifiOr4GConnected(context)
|
||||
// 当网络为 WIFI 或 4G, 且系统版本大于 5.0 && 手机内存大于 2G 才用高清图片
|
||||
transformUrl = if (NetworkUtils.isWifiOr4GConnected(context)
|
||||
&& Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP
|
||||
&& HaloApp.getInstance().deviceRamSize > 1024) {
|
||||
transformUrl = transformUrlX2
|
||||
&& HaloApp.getInstance().deviceRamSize > 2500) {
|
||||
transformUrlX2
|
||||
} else {
|
||||
// 检查X2大图是否被缓存
|
||||
if (Fresco.getImagePipeline().isInBitmapMemoryCache(Uri.parse(transformUrlX2)) ||
|
||||
Fresco.getImagePipeline().isInDiskCacheSync(Uri.parse(transformUrlX2))) {
|
||||
transformUrl = transformUrlX2
|
||||
transformUrlX2
|
||||
} else {
|
||||
transformUrl = transformUrlX1
|
||||
transformUrlX1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
transformUrl = addLimitWidth(url, null)
|
||||
}
|
||||
addCachedUrl(transformUrl ?: "")
|
||||
return transformUrl
|
||||
@ -377,9 +399,7 @@ object ImageUtils {
|
||||
if (width != null && width > 0) {
|
||||
view.setImageURI(addLimitWidth(url, width * 2))
|
||||
} else {
|
||||
view?.post {
|
||||
view.setImageURI(addLimitWidth(url, view.width * 2))
|
||||
}
|
||||
view?.setImageURI(addLimitWidth(url, view.width * 2))
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,6 +409,18 @@ object ImageUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已缓存的图片地址,不区分质量,暂时只供查看大图页面使用
|
||||
*/
|
||||
fun getCachedUrl(url: String): String {
|
||||
for (decoratedUrl in mImageUrlCacheSet) {
|
||||
if (decoratedUrl.contains(url)) {
|
||||
return decoratedUrl
|
||||
}
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun bmpToByteArray(bmp: Bitmap, needRecycle: Boolean): ByteArray {
|
||||
val output = ByteArrayOutputStream()
|
||||
@ -438,7 +470,7 @@ object ImageUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnImageloadListener {
|
||||
interface OnImageloadListener {
|
||||
fun onLoadFinal(imageInfo: ImageInfo?)
|
||||
}
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ public class InstallUtils {
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == INSTALL_WHAT && packageManager != null) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);
|
||||
List<PackageInfo> packageInfos = PackageUtils.getInstalledPackages(context, 0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
list.add(packageInfo.packageName);
|
||||
|
||||
@ -18,11 +18,11 @@ public class Installation {
|
||||
private static String sID = null;
|
||||
|
||||
public synchronized static String getUUID(Context context) {
|
||||
String imei = MetaUtil.getIMEI();
|
||||
String imei = MetaUtil.getBase64EncodedIMEI();
|
||||
if (!TextUtils.isEmpty(imei)) {
|
||||
return imei;
|
||||
}
|
||||
String android_id = MetaUtil.getAndroidId();
|
||||
String android_id = MetaUtil.getBase64EncodedAndroidId();
|
||||
if (!TextUtils.isEmpty(android_id)) {
|
||||
return android_id;
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.graphics.Color;
|
||||
@ -11,6 +10,8 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.adapter.LibaoDetailAdapter;
|
||||
@ -36,7 +37,6 @@ import org.json.JSONObject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
@ -237,85 +237,160 @@ public class LibaoUtils {
|
||||
|
||||
// 领取限制
|
||||
CheckLoginUtils.checkLogin(context, "礼包详情-[" + btnStatus + "]", () -> {
|
||||
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> {
|
||||
if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) {
|
||||
if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) {
|
||||
String platform;
|
||||
if (TextUtils.isEmpty(libaoEntity.getPlatform())) {
|
||||
platform = "";
|
||||
} else {
|
||||
platform = PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform());
|
||||
}
|
||||
if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) {
|
||||
if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) {
|
||||
String platform;
|
||||
if (TextUtils.isEmpty(libaoEntity.getPlatform())) {
|
||||
platform = "";
|
||||
} else {
|
||||
platform = PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform());
|
||||
}
|
||||
|
||||
boolean isExistPlatform = false;
|
||||
ArrayList<ApkEntity> apk = adapter.getGameEntity().getApk();
|
||||
for (ApkEntity apkEntity : apk) {
|
||||
if (TextUtils.isEmpty(libaoEntity.getPlatform())) break;
|
||||
if (libaoEntity.getPlatform().equals(apkEntity.getPlatform())) {
|
||||
isExistPlatform = true;
|
||||
break;
|
||||
}
|
||||
boolean isExistPlatform = false;
|
||||
ArrayList<ApkEntity> apk = adapter.getGameEntity().getApk();
|
||||
for (ApkEntity apkEntity : apk) {
|
||||
if (TextUtils.isEmpty(libaoEntity.getPlatform())) break;
|
||||
if (libaoEntity.getPlatform().equals(apkEntity.getPlatform())) {
|
||||
isExistPlatform = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform);
|
||||
boolean finalIsExistPlatform = isExistPlatform;
|
||||
DialogUtils.showWarningDialog(context, "条件不符",
|
||||
Html.fromHtml(dialogContent), isExistPlatform ? "关闭" : null,
|
||||
isExistPlatform ? "立即安装" : "关闭",
|
||||
() -> {
|
||||
if (finalIsExistPlatform) {
|
||||
adapter.openDownload(libaoEntity.getPlatform());
|
||||
}
|
||||
}, null);
|
||||
String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform);
|
||||
boolean finalIsExistPlatform = isExistPlatform;
|
||||
DialogUtils.showWarningDialog(context, "条件不符",
|
||||
Html.fromHtml(dialogContent), isExistPlatform ? "关闭" : null,
|
||||
isExistPlatform ? "立即安装" : "关闭",
|
||||
() -> {
|
||||
if (finalIsExistPlatform) {
|
||||
adapter.openDownload(libaoEntity.getPlatform());
|
||||
}
|
||||
}, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (btnStatus) {
|
||||
case "未开始":
|
||||
Utils.toast(context, "还没到开始领取时间");
|
||||
break;
|
||||
case "查看":
|
||||
if (!TextUtils.isEmpty(libaoEntity.getDes())) {
|
||||
DialogUtils.showAlertDialog(v.getContext(), "使用说明",
|
||||
Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null);
|
||||
}
|
||||
break;
|
||||
case "再领一个":
|
||||
case "领取":
|
||||
if ("repeatLing".equals(status)) {
|
||||
DialogUtils.showWarningDialog(context, "礼包刷新提醒"
|
||||
, "礼包每天0点刷新,换新区或者换新角色需要继续领取礼包的童鞋,请于明天0点之后回来即可[再领一个]"
|
||||
, null, "知道了", null, null);
|
||||
} else {
|
||||
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
|
||||
}
|
||||
break;
|
||||
case "再淘一个":
|
||||
case "淘号":
|
||||
if ("repeatTao".equals(status)) {
|
||||
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
|
||||
return;
|
||||
}
|
||||
}
|
||||
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
|
||||
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
|
||||
@Override
|
||||
public void postSucceed(Object response) {
|
||||
|
||||
switch (btnStatus) {
|
||||
case "未开始":
|
||||
Utils.toast(context, "还没到开始领取时间");
|
||||
break;
|
||||
case "查看":
|
||||
if (!TextUtils.isEmpty(libaoEntity.getDes())) {
|
||||
DialogUtils.showAlertDialog(v.getContext(), "使用说明",
|
||||
Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null);
|
||||
}
|
||||
break;
|
||||
case "再领一个":
|
||||
case "领取":
|
||||
if ("repeatLing".equals(status)) {
|
||||
DialogUtils.showWarningDialog(context, "礼包刷新提醒"
|
||||
, "礼包每天0点刷新,换新区或者换新角色需要继续领取礼包的童鞋,请于明天0点之后回来即可[再领一个]"
|
||||
, null, "知道了", null, null);
|
||||
} else {
|
||||
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
|
||||
}
|
||||
break;
|
||||
case "再淘一个":
|
||||
case "淘号":
|
||||
if ("repeatTao".equals(status)) {
|
||||
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
|
||||
return;
|
||||
}
|
||||
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
|
||||
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
|
||||
@Override
|
||||
public void postSucceed(Object response) {
|
||||
if (loadingDialog != null) loadingDialog.dismiss();
|
||||
|
||||
if (loadingDialog != null) loadingDialog.dismiss();
|
||||
JSONObject responseBody = (JSONObject) response;
|
||||
String libaoCode = null;
|
||||
try {
|
||||
libaoCode = responseBody.getString("code");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
JSONObject responseBody = (JSONObject) response;
|
||||
String libaoCode = null;
|
||||
if (TextUtils.isEmpty(libaoCode)) {
|
||||
try {
|
||||
libaoCode = responseBody.getString("code");
|
||||
String detail = responseBody.getString("detail");
|
||||
switch (detail) {
|
||||
case "maintaining":
|
||||
Utils.toast(context, "网络状态异常,请稍后再试");
|
||||
break;
|
||||
case "fail to compete":
|
||||
Utils.toast(context, "淘号失败,稍后重试");
|
||||
break;
|
||||
default:
|
||||
Utils.toast(context, "淘号异常");
|
||||
break;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(libaoCode)) {
|
||||
Utils.toast(context, "淘号成功");
|
||||
|
||||
libaoEntity.setStatus("taoed");
|
||||
|
||||
EventBus.getDefault().post(new EBReuse("libaoChanged"));
|
||||
|
||||
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
|
||||
|
||||
final String finalLibaoCode = libaoCode;
|
||||
|
||||
DialogUtils.showWarningDialog(context, "淘号成功"
|
||||
, Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode))
|
||||
, "关闭", " 复制礼包码"
|
||||
, () -> {
|
||||
copyLink(finalLibaoCode, context);
|
||||
if (isInstallRequired) {
|
||||
libaoBtn.postDelayed(() -> {
|
||||
Spanned msg = Html.fromHtml(
|
||||
context.getString(R.string.taoed_copy_dialog
|
||||
, finalLibaoCode));
|
||||
lunningAppDialog(context
|
||||
, msg, libaoEntity);
|
||||
}, 300);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postFailed(Throwable error) {
|
||||
Utils.log("---" + error.toString());
|
||||
|
||||
if (loadingDialog != null) loadingDialog.dismiss();
|
||||
|
||||
if (error instanceof HttpException) {
|
||||
HttpException exception = (HttpException) error;
|
||||
if (exception.code() == 403) {
|
||||
try {
|
||||
String detail = responseBody.getString("detail");
|
||||
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
|
||||
String detail = errorJson.getString("detail");
|
||||
// Utils.toast(context, "返回::" + detail);
|
||||
switch (detail) {
|
||||
case "coming":
|
||||
Utils.toast(context, "礼包领取时间未开始");
|
||||
break;
|
||||
case "finish":
|
||||
Utils.toast(context, "礼包领取时间已结束");
|
||||
break;
|
||||
case "fetched":
|
||||
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
|
||||
|
||||
libaoBtn.setText("已淘号");
|
||||
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
|
||||
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
|
||||
libaoEntity.setStatus("taoed");
|
||||
break;
|
||||
case "try tao":
|
||||
case "used up":
|
||||
DialogUtils.showHintDialog(context, "礼包已领光"
|
||||
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
|
||||
break;
|
||||
case "maintaining":
|
||||
Utils.toast(context, "网络状态异常,请稍后再试");
|
||||
break;
|
||||
@ -323,101 +398,24 @@ public class LibaoUtils {
|
||||
Utils.toast(context, "淘号失败,稍后重试");
|
||||
break;
|
||||
default:
|
||||
Utils.toast(context, "淘号异常");
|
||||
Utils.toast(context, "操作失败");
|
||||
break;
|
||||
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
Utils.toast(context, "礼包处理异常" + ex.toString());
|
||||
}
|
||||
return;
|
||||
} else if (exception.code() == 401) {
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.toast(context, "淘号成功");
|
||||
|
||||
libaoEntity.setStatus("taoed");
|
||||
|
||||
EventBus.getDefault().post(new EBReuse("libaoChanged"));
|
||||
|
||||
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
|
||||
|
||||
final String finalLibaoCode = libaoCode;
|
||||
|
||||
DialogUtils.showWarningDialog(context, "淘号成功"
|
||||
, Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode))
|
||||
, "关闭", " 复制礼包码"
|
||||
, () -> {
|
||||
copyLink(finalLibaoCode, context);
|
||||
if (isInstallRequired) {
|
||||
libaoBtn.postDelayed(() -> {
|
||||
Spanned msg = Html.fromHtml(
|
||||
context.getString(R.string.taoed_copy_dialog
|
||||
, finalLibaoCode));
|
||||
lunningAppDialog(context
|
||||
, msg, libaoEntity);
|
||||
}, 300);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postFailed(Throwable error) {
|
||||
Utils.log("---" + error.toString());
|
||||
|
||||
if (loadingDialog != null) loadingDialog.dismiss();
|
||||
|
||||
if (error instanceof HttpException) {
|
||||
HttpException exception = (HttpException) error;
|
||||
if (exception.code() == 403) {
|
||||
try {
|
||||
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
|
||||
String detail = errorJson.getString("detail");
|
||||
// Utils.toast(context, "返回::" + detail);
|
||||
switch (detail) {
|
||||
case "coming":
|
||||
Utils.toast(context, "礼包领取时间未开始");
|
||||
break;
|
||||
case "finish":
|
||||
Utils.toast(context, "礼包领取时间已结束");
|
||||
break;
|
||||
case "fetched":
|
||||
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
|
||||
|
||||
libaoBtn.setText("已淘号");
|
||||
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
|
||||
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
|
||||
libaoEntity.setStatus("taoed");
|
||||
break;
|
||||
case "try tao":
|
||||
case "used up":
|
||||
DialogUtils.showHintDialog(context, "礼包已领光"
|
||||
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
|
||||
break;
|
||||
case "maintaining":
|
||||
Utils.toast(context, "网络状态异常,请稍后再试");
|
||||
break;
|
||||
case "fail to compete":
|
||||
Utils.toast(context, "淘号失败,稍后重试");
|
||||
break;
|
||||
default:
|
||||
Utils.toast(context, "操作失败");
|
||||
break;
|
||||
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
Utils.toast(context, "礼包处理异常" + ex.toString());
|
||||
}
|
||||
return;
|
||||
} else if (exception.code() == 401) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Utils.toast(context, "发生异常");
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
Utils.toast(context, "发生异常");
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -458,7 +456,7 @@ public class LibaoUtils {
|
||||
adapter.notifyDataSetChanged();
|
||||
final String finalLibaoCode = libaoCode;
|
||||
NotificationHelper.showNotificationHintDialog(NotificationUgc.GIFT, isShow -> {
|
||||
if (!isShow){
|
||||
if (!isShow) {
|
||||
DialogUtils.showWarningDialog(context, "领取成功", Html.fromHtml(context.getString(R.string.linged_dialog, finalLibaoCode))
|
||||
, "关闭", " 复制礼包码"
|
||||
, () -> {
|
||||
@ -547,8 +545,7 @@ public class LibaoUtils {
|
||||
}
|
||||
|
||||
public static boolean isAppInstalled(Context context, String packageName) {
|
||||
final android.content.pm.PackageManager packageManager = context.getPackageManager();
|
||||
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
|
||||
List<PackageInfo> pinfo = PackageUtils.getInstalledPackages(context, 0);
|
||||
if (pinfo != null) {
|
||||
for (int i = 0; i < pinfo.size(); i++) {
|
||||
String pn = pinfo.get(i).packageName;
|
||||
@ -576,10 +573,7 @@ public class LibaoUtils {
|
||||
|
||||
//复制文字
|
||||
public static void copyLink(String copyContent, Context context) {
|
||||
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cmb.setText(copyContent);
|
||||
|
||||
Utils.toast(context, copyContent + " 复制成功");
|
||||
ExtensionsKt.copyTextAndToast(copyContent, copyContent + " 复制成功");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ import com.gh.gamecenter.entity.CommunityEntity;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.ShareResultEntity;
|
||||
import com.gh.gamecenter.entity.SpecialColumn;
|
||||
import com.gh.gamecenter.entity.StartupAdEntity;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.gh.gamecenter.qa.entity.Questions;
|
||||
import com.gh.gamecenter.retrofit.EmptyResponse;
|
||||
@ -33,6 +34,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
@ -234,6 +236,7 @@ public class LogUtils {
|
||||
object.put("game_name", gameEntity.getName());
|
||||
object.put("game_id", gameEntity.getId());
|
||||
object.put("game_platform", gameEntity.getPlatform());
|
||||
object.put("download_open", gameEntity.getDownloadOffStatus() == null ? "true" : "false");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -254,13 +257,13 @@ public class LogUtils {
|
||||
try {
|
||||
object.put("version", PackageUtils.getVersionName());
|
||||
object.put("channel", HaloApp.getInstance().getChannel());
|
||||
object.put("android_id", MetaUtil.getAndroidId());
|
||||
object.put("dia", MetaUtil.getBase64EncodedAndroidId());
|
||||
object.put("time", Utils.getTime(context));
|
||||
object.put("network", DeviceUtils.getNetwork(context));
|
||||
object.put("user_id", UserManager.getInstance().getUserId());
|
||||
object.put("device_system", android.os.Build.VERSION.RELEASE);
|
||||
object.put("device_model", android.os.Build.MODEL);
|
||||
object.put("imei", MetaUtil.getIMEI());
|
||||
object.put("jnfj", MetaUtil.getBase64EncodedIMEI());
|
||||
object.put("G_ID", UserManager.getInstance().getDeviceId());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
@ -278,13 +281,13 @@ public class LogUtils {
|
||||
try {
|
||||
object.put("version", PackageUtils.getVersionName());
|
||||
object.put("channel", HaloApp.getInstance().getChannel());
|
||||
object.put("android_id", MetaUtil.getAndroidId());
|
||||
object.put("dia", MetaUtil.getBase64EncodedAndroidId());
|
||||
object.put("time", Utils.getTime(context));
|
||||
object.put("network", DeviceUtils.getNetwork(context));
|
||||
object.put("user_id", UserManager.getInstance().getUserId());
|
||||
object.put("device_system", android.os.Build.VERSION.RELEASE);
|
||||
object.put("device_model", android.os.Build.MODEL);
|
||||
object.put("imei", MetaUtil.getIMEI());
|
||||
object.put("jnfj", MetaUtil.getBase64EncodedIMEI());
|
||||
object.put("G_ID", UserManager.getInstance().getDeviceId());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
@ -297,13 +300,13 @@ public class LogUtils {
|
||||
Meta meta = MetaUtil.INSTANCE.getMeta();
|
||||
JSONObject metaObject = new JSONObject();
|
||||
try {
|
||||
metaObject.put("android_id", meta.getAndroid_id());
|
||||
metaObject.put("dia", MetaUtil.getBase64EncodedAndroidId());
|
||||
metaObject.put("android_sdk", meta.getAndroid_sdk());
|
||||
metaObject.put("android_version", meta.getAndroid_version());
|
||||
metaObject.put("appVersion", meta.getAppVersion());
|
||||
metaObject.put("channel", meta.getChannel());
|
||||
metaObject.put("gid", meta.getGid());
|
||||
metaObject.put("imei", meta.getImei());
|
||||
metaObject.put("jnfj", MetaUtil.getBase64EncodedIMEI());
|
||||
metaObject.put("mac", meta.getMac());
|
||||
metaObject.put("manufacturer", meta.getManufacturer());
|
||||
metaObject.put("model", meta.getModel());
|
||||
@ -375,6 +378,63 @@ public class LogUtils {
|
||||
uploadVideoStreaming(object);
|
||||
}
|
||||
|
||||
public static void uploadTopVideoStreamingPlaying(String action, String videoId, String videoTitle, String gameId, String gameName, String videoModel, String videoPlayStatus, double videoSize, int videoTotalTime, int videoPlayTs, int progress) {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONObject payloadObject = new JSONObject();
|
||||
try {
|
||||
object.put("event", "TOP_VIDEO_PLAYING");
|
||||
object.put("action", action);
|
||||
|
||||
payloadObject.put("video_mode", videoModel);//视频播放方式 ["自动播放"/"点击播放"/"全屏播放"]
|
||||
payloadObject.put("video_id", videoId);
|
||||
payloadObject.put("video_title", videoTitle);
|
||||
payloadObject.put("game_id", gameId);
|
||||
payloadObject.put("game_name", gameName);
|
||||
payloadObject.put("video_size", videoSize);
|
||||
payloadObject.put("video_total_time", videoTotalTime);
|
||||
payloadObject.put("progress", progress);
|
||||
payloadObject.put("video_play_ts", videoPlayTs);
|
||||
payloadObject.put("video_play_status", videoPlayStatus);
|
||||
|
||||
object.put("payload", payloadObject);
|
||||
object.put("meta", getMetaObject());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "video_streaming", false);
|
||||
}
|
||||
|
||||
public static void uploadHomeVideoStreamingPlaying(String action, boolean videoShade, String videoId, String videoTitle, String gameId, String gameName, double videoSize, int videoTotalTime, int videoPlayTs, int progress) {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONObject payloadObject = new JSONObject();
|
||||
try {
|
||||
object.put("event", "HOME_VIDEO_PLAYING");
|
||||
object.put("action", action);
|
||||
|
||||
payloadObject.put("video_id", videoId);
|
||||
payloadObject.put("video_title", videoTitle);
|
||||
payloadObject.put("game_id", gameId);
|
||||
payloadObject.put("game_name", gameName);
|
||||
payloadObject.put("video_size", videoSize);
|
||||
payloadObject.put("video_total_time", videoTotalTime);
|
||||
payloadObject.put("progress", progress);
|
||||
payloadObject.put("video_play_ts", videoPlayTs);
|
||||
payloadObject.put("video_shade", String.valueOf(videoShade));//["true"/"false"]是否存在引导遮罩
|
||||
|
||||
object.put("payload", payloadObject);
|
||||
object.put("meta", getMetaObject());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "video_streaming", false);
|
||||
}
|
||||
|
||||
public static void uploadWelcomeDialog(String action, String dialogId, String linkTitle) {
|
||||
ExposureEntity payload = new ExposureEntity();
|
||||
payload.setWelcomeDialogId(dialogId);
|
||||
@ -428,13 +488,13 @@ public class LogUtils {
|
||||
Meta meta = MetaUtil.INSTANCE.getMeta();
|
||||
JSONObject metaObject = new JSONObject();
|
||||
try {
|
||||
metaObject.put("android_id", meta.getAndroid_id());
|
||||
metaObject.put("dia", MetaUtil.getBase64EncodedAndroidId());
|
||||
metaObject.put("android_sdk", meta.getAndroid_sdk());
|
||||
metaObject.put("android_version", meta.getAndroid_version());
|
||||
metaObject.put("appVersion", meta.getAppVersion());
|
||||
metaObject.put("channel", meta.getChannel());
|
||||
metaObject.put("gid", meta.getGid());
|
||||
metaObject.put("imei", meta.getImei());
|
||||
metaObject.put("jnfj", MetaUtil.getBase64EncodedIMEI());
|
||||
metaObject.put("mac", meta.getMac());
|
||||
metaObject.put("manufacturer", meta.getManufacturer());
|
||||
metaObject.put("model", meta.getModel());
|
||||
@ -522,13 +582,13 @@ public class LogUtils {
|
||||
Meta meta = MetaUtil.INSTANCE.getMeta();
|
||||
JSONObject metaObject = new JSONObject();
|
||||
try {
|
||||
metaObject.put("android_id", meta.getAndroid_id());
|
||||
metaObject.put("dia", MetaUtil.getBase64EncodedAndroidId());
|
||||
metaObject.put("android_sdk", meta.getAndroid_sdk());
|
||||
metaObject.put("android_version", meta.getAndroid_version());
|
||||
metaObject.put("appVersion", meta.getAppVersion());
|
||||
metaObject.put("channel", meta.getChannel());
|
||||
metaObject.put("gid", meta.getGid());
|
||||
metaObject.put("imei", meta.getImei());
|
||||
metaObject.put("jnfj", MetaUtil.getBase64EncodedIMEI());
|
||||
metaObject.put("mac", meta.getMac());
|
||||
metaObject.put("manufacturer", meta.getManufacturer());
|
||||
metaObject.put("model", meta.getModel());
|
||||
@ -611,10 +671,16 @@ public class LogUtils {
|
||||
}
|
||||
|
||||
public static void uploadSearchGame(String event, String location, String key, String searchType) {
|
||||
uploadSearchClick(event, location, key, searchType, "", "");
|
||||
uploadSearchClick(event, location, key, searchType, "", "", false);
|
||||
}
|
||||
|
||||
public static void uploadSearchClick(String event, String location, String key, String searchType, String gameId, String gameName) {
|
||||
public static void uploadSearchClick(String event,
|
||||
String location,
|
||||
String key,
|
||||
String searchType,
|
||||
String gameId,
|
||||
String gameName,
|
||||
Boolean isMirrorData) {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONObject payload = new JSONObject();
|
||||
try {
|
||||
@ -627,6 +693,7 @@ public class LogUtils {
|
||||
payload.put("search_type", searchType); //搜索类型, 有四种取值 默认搜索/历史搜索/自动搜索/主动搜索
|
||||
payload.put("game_id", gameId); //event为search_click才取值
|
||||
payload.put("game_name", gameName); //event为search_click才取值
|
||||
payload.put("is_mirror_data", isMirrorData);
|
||||
object.put("payload", payload);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
@ -637,4 +704,112 @@ public class LogUtils {
|
||||
}
|
||||
LoghubUtils.log(object, "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);
|
||||
}
|
||||
|
||||
public static void logSpecialCatalogSpecificContentClickEvent(String entrance, String key, int seq1, int seqContent, int seqContentList) {
|
||||
logCatalogEvent("click_content_list", entrance, key, seq1, -1, seqContent, seqContentList);
|
||||
}
|
||||
|
||||
public static void logSpecialCatalogBannerClickEvent(String key, int seq) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("event", "category_lunbo_click");
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
|
||||
object.put("key", key);
|
||||
object.put("sequence", seq);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
private static void logCatalogEvent(String event, String entrance, String key, int seq1, int seq2, int seqContent, int seqContentList) {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONObject payload = new JSONObject();
|
||||
try {
|
||||
object.put("event", event);
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
|
||||
payload.put("entrance", entrance); //入口分类, 分为 首页或版块,
|
||||
payload.put("key", key); //搜索类型, 有四种取值 默认搜索/历史搜索/自动搜索/主动搜索
|
||||
payload.put("seq_1st", seq1); //从0开始,默认-1表示没有
|
||||
payload.put("seq_2nd", seq2); //从0开始,默认-1表示没有
|
||||
payload.put("seq_content", seqContent); //精选页上 图片、专题-全部按钮、专题合集-全部按钮 的排序;从0开始,默认-1表示没有
|
||||
payload.put("seq_content_list", seqContentList);
|
||||
object.put("payload", payload);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void uploadPackageSkip(String event, String action, String gameId, String gameName) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("event", event);//external_jump/external_show
|
||||
object.put("action", action);
|
||||
if (!TextUtils.isEmpty(gameId) && !TextUtils.isEmpty(gameName)) {
|
||||
object.put("game_id", gameId);
|
||||
object.put("game_name", gameName);
|
||||
}
|
||||
object.put("meta", getMetaObject());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void logStartAd(String event, StartupAdEntity adEntity) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("event", event);
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
object.put("meta", getMetaObject());
|
||||
if (adEntity != null) {
|
||||
object.put("abs_id", adEntity.getId());
|
||||
object.put("abs_text", adEntity.getDesc());
|
||||
if (adEntity.getButton()) {
|
||||
object.put("abs_type", adEntity.getJump().getType());
|
||||
object.put("abs_link", adEntity.getJump().getLink());
|
||||
object.put("abs_link_title", adEntity.getJump().getText());
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -29,7 +29,10 @@ import android.widget.TextView;
|
||||
import com.gh.common.Base64ImageHolder;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.WeiBoShareActivity;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.sina.weibo.sdk.WbSdk;
|
||||
import com.sina.weibo.sdk.auth.AuthInfo;
|
||||
import com.tencent.connect.auth.QQToken;
|
||||
import com.tencent.connect.share.QQShare;
|
||||
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX;
|
||||
@ -48,7 +51,8 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static com.gh.common.util.LoginHelper.WEIBO_SCOPE;
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/11/8.
|
||||
@ -86,13 +90,17 @@ public class MessageShareUtils {
|
||||
@Override
|
||||
public void onError(UiError uiError) {
|
||||
// 单分享图片不支持显示未安装弹窗,手动调出
|
||||
Activity activity = mActivity.get();
|
||||
if (activity != null && !ShareUtils.isQQClientAvailable(activity.getApplication())) {
|
||||
new TDialog(activity,
|
||||
"",
|
||||
"http://openmobile.qq.com/oauth2.0/m_jump_by_version",
|
||||
null,
|
||||
new QQToken("")).show();
|
||||
if (mActivity != null) {
|
||||
Activity activity = mActivity.get();
|
||||
if (activity != null && !ShareUtils.isQQClientAvailable(activity.getApplication())) {
|
||||
new TDialog(activity,
|
||||
"",
|
||||
"http://openmobile.qq.com/oauth2.0/m_jump_by_version",
|
||||
null,
|
||||
new QQToken("")).show();
|
||||
} else {
|
||||
Utils.toast(mContext, "分享失败");
|
||||
}
|
||||
} else {
|
||||
Utils.toast(mContext, "分享失败");
|
||||
}
|
||||
@ -207,49 +215,54 @@ public class MessageShareUtils {
|
||||
}
|
||||
|
||||
public void shareFromWeb(Activity activity, String type) {
|
||||
// base64转bitmap
|
||||
byte[] decode = Base64.decode(Base64ImageHolder.INSTANCE.getImage(), Base64.DEFAULT);
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(decode, 0, decode.length);
|
||||
// 转完后重新置位
|
||||
Base64ImageHolder.INSTANCE.setImage("");
|
||||
|
||||
this.picName = "shareImgPic.jpg";
|
||||
this.mActivity = new WeakReference<>(activity);
|
||||
this.shareBm = bitmap;
|
||||
|
||||
// 保存图片
|
||||
File file = new File(activity.getExternalCacheDir().getPath() + "/ShareImg");
|
||||
if (!file.isDirectory()) {
|
||||
file.delete();
|
||||
file.mkdirs();
|
||||
}
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
writeBitmap(file.getPath(), picName, bitmap, false);
|
||||
if ("weibo".equals(type)) {
|
||||
weiboShare();
|
||||
} else {
|
||||
// base64转bitmap
|
||||
byte[] decode = Base64.decode(Base64ImageHolder.INSTANCE.getImage(), Base64.DEFAULT);
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(decode, 0, decode.length);
|
||||
// 转完后重新置位
|
||||
Base64ImageHolder.INSTANCE.setImage("");
|
||||
this.picName = "shareImgPic.jpg";
|
||||
this.shareBm = bitmap;
|
||||
|
||||
// 分享
|
||||
switch (type) {
|
||||
case "qq" :
|
||||
qqSahre();
|
||||
break;
|
||||
case "qq_zone" :
|
||||
qZoneSahre();
|
||||
break;
|
||||
case "wechat" :
|
||||
wechatSahre();
|
||||
break;
|
||||
case "wechat_moments" :
|
||||
wechatMomentsSahre();
|
||||
case "save" :
|
||||
String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/ghzhushou/";
|
||||
writeBitmap(savePath, "gh-" + new Date().getTime() + ".jpg", shareBm, true);
|
||||
break;
|
||||
// 保存图片
|
||||
File file = new File(activity.getExternalCacheDir().getPath() + "/ShareImg");
|
||||
if (!file.isDirectory()) {
|
||||
file.delete();
|
||||
file.mkdirs();
|
||||
}
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
writeBitmap(file.getPath(), picName, bitmap, false);
|
||||
|
||||
// 分享
|
||||
switch (type) {
|
||||
case "qq" :
|
||||
qqShare();
|
||||
break;
|
||||
case "qq_zone" :
|
||||
qZoneShare();
|
||||
break;
|
||||
case "wechat" :
|
||||
wechatShare();
|
||||
break;
|
||||
case "wechat_moments" :
|
||||
wechatMomentsShare();
|
||||
break;
|
||||
case "save" :
|
||||
String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/ghzhushou/";
|
||||
writeBitmap(savePath, "gh-" + new Date().getTime() + ".jpg", shareBm, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//QQ分享
|
||||
private void qqSahre() {
|
||||
private void qqShare() {
|
||||
Utils.toast(mContext, "分享跳转中...");
|
||||
Bundle params = new Bundle();
|
||||
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE,
|
||||
@ -269,7 +282,7 @@ public class MessageShareUtils {
|
||||
}
|
||||
|
||||
//QQ空间分享
|
||||
private void qZoneSahre() {
|
||||
private void qZoneShare() {
|
||||
Utils.toast(mContext, "分享跳转中...");
|
||||
Bundle params = new Bundle();
|
||||
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE,
|
||||
@ -289,7 +302,7 @@ public class MessageShareUtils {
|
||||
}
|
||||
|
||||
//微信好友分享
|
||||
private void wechatSahre() {
|
||||
private void wechatShare() {
|
||||
Utils.toast(mContext, "分享跳转中...");
|
||||
|
||||
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
|
||||
@ -325,7 +338,7 @@ public class MessageShareUtils {
|
||||
}
|
||||
|
||||
//微信朋友圈分享
|
||||
private void wechatMomentsSahre() {
|
||||
private void wechatMomentsShare() {
|
||||
Utils.toast(mContext, "分享跳转中...");
|
||||
|
||||
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
|
||||
@ -352,6 +365,20 @@ public class MessageShareUtils {
|
||||
mPopupWindow.dismiss();
|
||||
}
|
||||
|
||||
//新浪微博分享
|
||||
public void weiboShare() {
|
||||
WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
|
||||
|
||||
Activity activity = mActivity.get();
|
||||
if (activity != null) {
|
||||
Intent intent = WeiBoShareActivity.getWeiboImageShareIntent(activity);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
if (mPopupWindow == null) return;
|
||||
mPopupWindow.dismiss();
|
||||
}
|
||||
|
||||
private String buildTransaction(final String type) {
|
||||
return (type == null) ? String.valueOf(System.currentTimeMillis()) : type + System.currentTimeMillis();
|
||||
}
|
||||
@ -474,22 +501,22 @@ public class MessageShareUtils {
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
switch (holder.getPosition()) {
|
||||
case 0:
|
||||
wechatSahre();
|
||||
wechatShare();
|
||||
if (shareType != 2) {
|
||||
// activity.finish();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
wechatMomentsSahre();
|
||||
wechatMomentsShare();
|
||||
if (shareType != 2) {
|
||||
// activity.finish();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
qqSahre();
|
||||
qqShare();
|
||||
break;
|
||||
case 3:
|
||||
qZoneSahre();
|
||||
qZoneShare();
|
||||
break;
|
||||
case 4:
|
||||
String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/ghzhushou/";
|
||||
|
||||
@ -9,7 +9,7 @@ object MtaHelper {
|
||||
// if (kv.size == 1) {
|
||||
// prop.setProperty(kv[0], kv[0])
|
||||
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
|
||||
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
|
||||
// Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
@ -23,7 +23,7 @@ object MtaHelper {
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
|
||||
// Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]")
|
||||
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ object MtaHelper {
|
||||
// }
|
||||
//
|
||||
// if (prop.size == 0) return
|
||||
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}] + last $time seconds")
|
||||
// Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}] + last $time seconds")
|
||||
// StatService.trackCustomKVTimeIntervalEvent(HaloApp.getInstance().application, time, eventId, prop)
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ object MtaHelper {
|
||||
// prop.setProperty("GID", HaloApp.getInstance().gid)
|
||||
// }
|
||||
//
|
||||
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
|
||||
// Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]")
|
||||
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
|
||||
}
|
||||
|
||||
|
||||
@ -37,4 +37,15 @@ object NumberUtils {
|
||||
val minute = Math.round((totalMinute - hour * 60).toFloat())
|
||||
return hour.toString() + "小时" + if (minute == 0) "" else minute.toString() + "分钟"
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun findMax(lastPositions: IntArray): Int {
|
||||
var max = lastPositions[0]
|
||||
for (value in lastPositions) {
|
||||
if (value > max) {
|
||||
max = value
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
}
|
||||
@ -63,7 +63,7 @@ object PackageHelper {
|
||||
private fun getAllPackageName(context: Context): HashSet<String> {
|
||||
val set = HashSet<String>()
|
||||
return try {
|
||||
val packageInfos = context.applicationContext.packageManager.getInstalledPackages(0)
|
||||
val packageInfos = PackageUtils.getInstalledPackages(context, 0)
|
||||
for (packageInfo in packageInfos) {
|
||||
if (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0) {
|
||||
if (context.packageName != packageInfo.packageName) {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@ -25,8 +26,8 @@ object PackageInstaller {
|
||||
* 为了兼容java代码
|
||||
*/
|
||||
@JvmStatic
|
||||
fun install(context: Context, downloadEntity: DownloadEntity) {
|
||||
install(context, downloadEntity, true)
|
||||
fun install(context: Context, downloadEntity: DownloadEntity?) {
|
||||
downloadEntity?.let { install(context, downloadEntity, true) }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -38,16 +39,24 @@ object PackageInstaller {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun install(context: Context, downloadEntity: DownloadEntity, showUnzipToast: Boolean) {
|
||||
InstallPermissionDialogFragment.show(AppManager.getInstance().currentActivity() as AppCompatActivity) {
|
||||
// 取消状态栏下载完成的通知,若存在
|
||||
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
|
||||
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
|
||||
val pkgPath = downloadEntity.path
|
||||
val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()
|
||||
|
||||
val pkgPath = downloadEntity.path
|
||||
if (XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()) {
|
||||
XapkInstaller.install(context, downloadEntity, showUnzipToast)
|
||||
} else {
|
||||
install(context, downloadEntity.path)
|
||||
val currentActivity = AppManager.getInstance().currentActivity() ?: return
|
||||
|
||||
// TODO 此处可能遇到 activity 是 WXEntryActivity
|
||||
// TODO 当 activity 全部出栈,但是应用还在下载游戏,下载完会唤不起安装!
|
||||
if (currentActivity is AppCompatActivity) {
|
||||
InstallPermissionDialogFragment.show(currentActivity, downloadEntity) {
|
||||
// 取消状态栏下载完成的通知,若存在
|
||||
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
|
||||
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
|
||||
|
||||
if (isXapk) {
|
||||
XapkInstaller.install(context, downloadEntity, showUnzipToast)
|
||||
} else {
|
||||
install(context, downloadEntity.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,6 +71,8 @@ object PackageInstaller {
|
||||
fun install(context: Context, pkgPath: String) {
|
||||
try {
|
||||
if (PackageUtils.isCanLaunchSetup(context, pkgPath)) {
|
||||
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
|
||||
|
||||
val installIntent = getInstallIntent(context, pkgPath)
|
||||
context.startActivity(installIntent)
|
||||
} else {
|
||||
@ -110,25 +121,43 @@ object PackageInstaller {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun uninstall(context: Context, path: String) {
|
||||
val packageName = PackageUtils.getPackageNameByPath(context, path)
|
||||
uninstallForPackageName(context, packageName)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据包名卸载应用
|
||||
*/
|
||||
@JvmStatic
|
||||
fun uninstallForPackageName(context: Context, pkn: String) {
|
||||
if (pkn.isBlank()) return
|
||||
|
||||
val uninstallIntent = Intent()
|
||||
uninstallIntent.action = Intent.ACTION_DELETE
|
||||
uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
val packageName = PackageUtils.getPackageNameByPath(context, path)
|
||||
uninstallIntent.data = Uri.parse("package:$packageName")
|
||||
InstallUtils.getInstance(context).addUninstall(packageName)
|
||||
if (context !is Activity) {
|
||||
uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
uninstallIntent.data = Uri.parse("package:$pkn")
|
||||
InstallUtils.getInstance(context).addUninstall(pkn)
|
||||
context.startActivity(uninstallIntent)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDownloadPath(gameName: String?, format: String?): String {
|
||||
return FileUtils.getDownloadPath(HaloApp.getInstance().application, getDownloadFileName(gameName, format))
|
||||
fun getDownloadPathWithId(id: String, format: String?): String {
|
||||
return FileUtils.getDownloadPath(HaloApp.getInstance().application, id + "." + getFileSuffixByFormat(format))
|
||||
}
|
||||
|
||||
private fun getDownloadFileName(gameName: String?, format: String?): String {
|
||||
var fileExtension = "apk"
|
||||
if (format == XapkInstaller.XAPK_EXTENSION_NAME) {
|
||||
fileExtension = XapkInstaller.XAPK_EXTENSION_NAME
|
||||
private fun getFileSuffixByFormat(format: String?): String {
|
||||
return if (format == XapkInstaller.XAPK_EXTENSION_NAME) {
|
||||
XapkInstaller.XAPK_EXTENSION_NAME
|
||||
} else {
|
||||
"apk"
|
||||
}
|
||||
return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis()) + "." + fileExtension
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createDownloadId(gameName: String?): String {
|
||||
return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis())
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,7 @@ import android.text.TextUtils;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.g00fy2.versioncompare.Version;
|
||||
import com.gh.common.xapk.XapkInstaller;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.entity.ApkEntity;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
@ -26,12 +27,19 @@ import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import net.dongliu.apk.parser.ApkFile;
|
||||
import net.dongliu.apk.parser.bean.ApkMeta;
|
||||
|
||||
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;
|
||||
@ -180,11 +188,13 @@ public class PackageUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO 找一个更好的办法来比较签名并且不触发 ANR
|
||||
public static boolean compareSignatureBetweenInstalledAppWithApk(Context context, String packageName, String apkFilePath) {
|
||||
try {
|
||||
// 据 Sentry 统计,刚上架一个周末的包里对这个方法有 700+ 次调用,然后其中一部分会造成 ANR
|
||||
Signature sig = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures[0];
|
||||
|
||||
// Fuck HUAWEI, 华为系统调用 getPackageArchiveInfo 获取魔羯 apk 的签名时会耗时超过5秒造成 ANR,没有找到解决方法
|
||||
// 调用 getPackageArchiveInfo 获取较大的 apk 的签名时会耗时超过5秒造成 ANR,没有找到解决方法
|
||||
// 如果可以的话尽量避免调用 getPackageArchiveInfo 方法
|
||||
Signature releaseSig = context.getPackageManager().getPackageArchiveInfo(apkFilePath, PackageManager.GET_SIGNATURES).signatures[0];
|
||||
return sig.hashCode() == releaseSig.hashCode();
|
||||
@ -285,14 +295,69 @@ public class PackageUtils {
|
||||
* 根据路径,获取apk的包名
|
||||
*/
|
||||
public static String getPackageNameByPath(Context context, String path) {
|
||||
|
||||
// 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
|
||||
// 大于 1G 的 APK 就走另类方法
|
||||
if (isDeviceUnableToHandleBigApkFile(path)) {
|
||||
// XAPK 不存在 AndroidManifest
|
||||
if (path.contains(XapkInstaller.XAPK_EXTENSION_NAME)) {
|
||||
return null;
|
||||
}
|
||||
return getPackageNameByPathAlternative(path);
|
||||
}
|
||||
|
||||
PackageManager packageManager = context.getApplicationContext().getPackageManager();
|
||||
PackageInfo info = packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
|
||||
PackageInfo info = packageManager.getPackageArchiveInfo(path, 0);
|
||||
if (info != null) {
|
||||
ApplicationInfo appInfo = info.applicationInfo;
|
||||
return appInfo.packageName;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 此设备是否不能调用 packageManager.getPackageArchiveInfo 来获取 APK 信息
|
||||
*
|
||||
* 部分设备 (已知 vivo 5.1.1 及 5.0.1 的设备) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
|
||||
*/
|
||||
public static boolean isDeviceUnableToHandleBigApkFile(String path) {
|
||||
if ("vivo".equals(Build.MANUFACTURER)
|
||||
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
File file = new File(path);
|
||||
|
||||
if (file != null && file.length() > 1024 * 1024 * 1024) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 APK 文件里读包名的另类方法
|
||||
* 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
|
||||
*
|
||||
* 令人迷惑的点:
|
||||
* 1. 同样的代码,同样的 APK 在 demo 包里调用 packageManager.getPackageArchiveInfo 并不会 ANR
|
||||
* 2. 把 packageManager.getPackageArchiveInfo 放在子线程调用一样会出现 ANR
|
||||
* 3. demo 里 manifest 中 application 配置和 targetSdk 也改成与光环一样也不会出现 ANR
|
||||
*
|
||||
* 大概是光环的某个配置触发了系统的 bug ?
|
||||
*
|
||||
*/
|
||||
private static String getPackageNameByPathAlternative(String path) {
|
||||
ApkFile apkParser = null;
|
||||
try {
|
||||
apkParser = new ApkFile(new File(path));
|
||||
ApkMeta apkMeta = apkParser.getApkMeta();
|
||||
apkParser.close();
|
||||
return apkMeta.getPackageName();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 根据包名,判断是否已安装该游戏
|
||||
@ -370,7 +435,7 @@ public class PackageUtils {
|
||||
*/
|
||||
public static ArrayList<String> getAllPackageName(Context context) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
List<PackageInfo> packageInfos = context.getApplicationContext().getPackageManager().getInstalledPackages(0);
|
||||
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
if (!context.getPackageName().equals(packageInfo.packageName)) {
|
||||
@ -385,7 +450,7 @@ public class PackageUtils {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
try {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
List<PackageInfo> packageInfos = pm.getInstalledPackages(0);
|
||||
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
@ -477,9 +542,14 @@ public class PackageUtils {
|
||||
|
||||
if (gh_version != null && apkEntity.getGhVersion() != null && gh_id != null) {
|
||||
gh_version = gh_version.substring(2);
|
||||
return Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion())
|
||||
&& apkEntity.getForce()
|
||||
&& gh_id.equals(gameId);
|
||||
try {
|
||||
return Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion()) && apkEntity
|
||||
.getForce() && gh_id.equals(gameId);
|
||||
} catch (NumberFormatException exception) {
|
||||
// gh_id 可能出錯
|
||||
exception.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -511,15 +581,21 @@ public class PackageUtils {
|
||||
* @return 进程名
|
||||
*/
|
||||
public static String obtainProcessName(Context context) {
|
||||
final int pid = android.os.Process.myPid();
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
List<ActivityManager.RunningAppProcessInfo> listTaskInfo = am.getRunningAppProcesses();
|
||||
if (listTaskInfo != null && !listTaskInfo.isEmpty()) {
|
||||
for (ActivityManager.RunningAppProcessInfo info : listTaskInfo) {
|
||||
if (info != null && info.pid == pid) {
|
||||
return info.processName;
|
||||
try {
|
||||
final int pid = android.os.Process.myPid();
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
List<ActivityManager.RunningAppProcessInfo> listTaskInfo = am.getRunningAppProcesses();
|
||||
if (listTaskInfo != null && !listTaskInfo.isEmpty()) {
|
||||
for (ActivityManager.RunningAppProcessInfo info : listTaskInfo) {
|
||||
if (info != null && info.pid == pid) {
|
||||
return info.processName;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 遇到异常了让这次调用正常执行
|
||||
e.printStackTrace();
|
||||
return BuildConfig.APPLICATION_ID;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -545,6 +621,13 @@ public class PackageUtils {
|
||||
if (!pm.isScreenOn()) return false;
|
||||
}
|
||||
|
||||
// 上面的判断逻辑可能还是不够用,还是有少部分
|
||||
// Not allowed to start service Intent: app is in background 错误
|
||||
// 这里补充个自有的规则
|
||||
if (!HaloApp.getInstance().isRunningForeground) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String packageName = context.getApplicationContext().getPackageName();
|
||||
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
|
||||
// The name of the process that this object is associated with.
|
||||
@ -557,4 +640,42 @@ public class PackageUtils {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在5.1系统手机使用PackageManager获取已安装应用容易发生Package manager has died异常
|
||||
* https://stackoverflow.com/questions/13235793/transactiontoolargeeception-when-trying-to-get-a-list-of-applications-installed/30062632#30062632
|
||||
*/
|
||||
public static List<PackageInfo> getInstalledPackages(Context context, int flags) {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
try {
|
||||
return pm.getInstalledPackages(flags);
|
||||
} catch (Exception ignored) {
|
||||
//we don't care why it didn't succeed. We'll do it using an alternative way instead
|
||||
}
|
||||
// use fallback:
|
||||
Process process;
|
||||
List<PackageInfo> result = new ArrayList<>();
|
||||
BufferedReader bufferedReader = null;
|
||||
try {
|
||||
process = Runtime.getRuntime().exec("pm list packages");
|
||||
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
final String packageName = line.substring(line.indexOf(':') + 1);
|
||||
final PackageInfo packageInfo = pm.getPackageInfo(packageName, flags);
|
||||
result.add(packageInfo);
|
||||
}
|
||||
process.waitFor();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (bufferedReader != null)
|
||||
try {
|
||||
bufferedReader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,15 +5,17 @@ import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.gh.common.constant.Constants
|
||||
import com.tbruyelle.rxpermissions2.RxPermissions
|
||||
|
||||
object PermissionHelper {
|
||||
|
||||
const val INSTALL_PERMISS_CODE = 100
|
||||
const val INSTALL_PERMISSION_CODE = 100
|
||||
|
||||
@JvmStatic
|
||||
fun requestReadPhoneStateAndStoragePermissionFromStartUp(context: Context) {
|
||||
@ -59,41 +61,41 @@ object PermissionHelper {
|
||||
@JvmStatic
|
||||
fun checkStoragePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
|
||||
if (context is FragmentActivity) {
|
||||
val rxPermission = RxPermissions(context)
|
||||
if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
|
||||
&& context.checkCallingOrSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
|
||||
emptyCallback.onCallback()
|
||||
SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, false)
|
||||
} else {
|
||||
showDialogBeforeRequestingStorageDialog(context, emptyCallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tryWithDefaultCatch {
|
||||
rxPermission
|
||||
.requestEachCombined(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
.subscribe { permission ->
|
||||
when {
|
||||
permission.granted -> {
|
||||
emptyCallback.onCallback()
|
||||
}
|
||||
permission.shouldShowRequestPermissionRationale -> {
|
||||
DialogUtils.showPermissionDialog(context,
|
||||
"权限申请",
|
||||
"光环助手需要存储权限,以保证能正常使用相关功能",
|
||||
"重试",
|
||||
"放弃",
|
||||
{ checkStoragePermissionBeforeAction(context, emptyCallback) },
|
||||
null)
|
||||
}
|
||||
else -> {
|
||||
DialogUtils.showPermissionDialog(context,
|
||||
"权限申请",
|
||||
"在设置-应用-光环助手-权限中开启存储权限,以保证能正常使用相关功能",
|
||||
"去设置",
|
||||
"放弃",
|
||||
{
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||
intent.data = Uri.parse("package:" + context.getPackageName())
|
||||
context.startActivity(intent)
|
||||
},
|
||||
null)
|
||||
private fun checkStoragePermissionBeforeAction(context: FragmentActivity, emptyCallback: EmptyCallback) {
|
||||
tryWithDefaultCatch {
|
||||
val rxPermission = RxPermissions(context)
|
||||
rxPermission
|
||||
.requestEachCombined(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
.subscribe { permission ->
|
||||
when {
|
||||
permission.granted -> {
|
||||
emptyCallback.onCallback()
|
||||
SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, false)
|
||||
}
|
||||
permission.shouldShowRequestPermissionRationale -> {
|
||||
// do nothing
|
||||
}
|
||||
else -> {
|
||||
if (SPUtils.getBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION)) {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||
intent.data = Uri.parse("package:" + context.packageName)
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,39 +103,37 @@ object PermissionHelper {
|
||||
@JvmStatic
|
||||
fun checkReadPhoneStateAndStoragePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
|
||||
if (context is FragmentActivity) {
|
||||
val rxPermission = RxPermissions(context)
|
||||
if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
|
||||
&& context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
|
||||
&& context.checkCallingOrSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
|
||||
emptyCallback.onCallback()
|
||||
} else {
|
||||
val rxPermission = RxPermissions(context)
|
||||
|
||||
tryWithDefaultCatch {
|
||||
rxPermission
|
||||
.requestEachCombined(
|
||||
Manifest.permission.READ_PHONE_STATE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
.subscribe { permission ->
|
||||
when {
|
||||
permission.granted -> {
|
||||
emptyCallback.onCallback()
|
||||
tryWithDefaultCatch {
|
||||
rxPermission
|
||||
.requestEachCombined(
|
||||
Manifest.permission.READ_PHONE_STATE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
.subscribe { permission ->
|
||||
when {
|
||||
permission.granted -> {
|
||||
emptyCallback.onCallback()
|
||||
|
||||
ActivationHelper.sendActivationInfo()
|
||||
}
|
||||
permission.shouldShowRequestPermissionRationale -> {
|
||||
DialogUtils.showPermissionDialog(context, "权限申请",
|
||||
"光环助手需要获取存储权限和手机信息权限,以保证能正常使用相关功能", "重试", "放弃",
|
||||
{ checkStoragePermissionBeforeAction(context, emptyCallback) }, null)
|
||||
}
|
||||
else -> {
|
||||
DialogUtils.showPermissionDialog(context, "权限申请",
|
||||
"在设置-应用-光环助手-权限中开启获取存储权限和手机信息,以保证能正常使用相关功能",
|
||||
"去设置",
|
||||
"放弃",
|
||||
{
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||
intent.data = Uri.parse("package:" + context.getPackageName())
|
||||
context.startActivity(intent)
|
||||
}, null)
|
||||
ActivationHelper.sendActivationInfo()
|
||||
}
|
||||
permission.shouldShowRequestPermissionRationale -> {
|
||||
// do nothing
|
||||
}
|
||||
else -> {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||
intent.data = Uri.parse("package:" + context.getPackageName())
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -141,34 +141,73 @@ object PermissionHelper {
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun checkReadPhoneStatePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
|
||||
if (context is FragmentActivity) {
|
||||
|
||||
if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
|
||||
emptyCallback.onCallback()
|
||||
} else {
|
||||
val rxPermission = RxPermissions(context)
|
||||
|
||||
tryWithDefaultCatch {
|
||||
rxPermission
|
||||
.requestEachCombined(Manifest.permission.READ_PHONE_STATE)
|
||||
.subscribe { permission ->
|
||||
when {
|
||||
permission.granted -> {
|
||||
emptyCallback.onCallback()
|
||||
|
||||
ActivationHelper.sendActivationInfo()
|
||||
}
|
||||
permission.shouldShowRequestPermissionRationale -> {
|
||||
// do nothing
|
||||
}
|
||||
else -> {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||
intent.data = Uri.parse("package:" + context.getPackageName())
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun checkCalendarPermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
|
||||
if (context is FragmentActivity) {
|
||||
val rxPermission = RxPermissions(context)
|
||||
|
||||
tryWithDefaultCatch {
|
||||
rxPermission
|
||||
.requestEachCombined(Manifest.permission.READ_PHONE_STATE)
|
||||
.requestEachCombined(Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CALENDAR)
|
||||
.subscribe { permission ->
|
||||
when {
|
||||
permission.granted -> {
|
||||
emptyCallback.onCallback()
|
||||
|
||||
ActivationHelper.sendActivationInfo()
|
||||
}
|
||||
permission.shouldShowRequestPermissionRationale -> {
|
||||
DialogUtils.showPermissionDialog(context, "权限申请",
|
||||
"光环助手需要获取手机信息权限,以保证能正常使用相关功能", "重试", "放弃",
|
||||
{ checkStoragePermissionBeforeAction(context, emptyCallback) }, null)
|
||||
DialogUtils.showPermissionDialog(context,
|
||||
"权限申请",
|
||||
"光环助手需要日历权限,以保证能正常使用相关功能",
|
||||
"重试",
|
||||
"放弃",
|
||||
{ checkCalendarPermissionBeforeAction(context, emptyCallback) },
|
||||
null)
|
||||
}
|
||||
else -> {
|
||||
DialogUtils.showPermissionDialog(context, "权限申请",
|
||||
"在设置-应用-光环助手-权限中开启获取手机信息,以保证能正常使用相关功能",
|
||||
DialogUtils.showPermissionDialog(context,
|
||||
"权限申请",
|
||||
"在设置-应用-光环助手-权限中开启日历权限,以保证能正常使用相关功能",
|
||||
"去设置",
|
||||
"放弃",
|
||||
{
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||
intent.data = Uri.parse("package:" + context.getPackageName())
|
||||
context.startActivity(intent)
|
||||
}, null)
|
||||
},
|
||||
null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -220,7 +259,24 @@ object PermissionHelper {
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDialogBeforeRequestingStorageDialog(context: FragmentActivity, emptyCallback: EmptyCallback) {
|
||||
DialogHelper.showRoundedCornerDialog(
|
||||
context,
|
||||
title = "权限申请",
|
||||
content = "光环助手将向您申请开启设备的存储权限,以保证能正常使用相关功能。拒绝授权将无法正常使用部分功能。",
|
||||
hint = "查看权限应用场景",
|
||||
cancelText = "放弃",
|
||||
confirmText = "去授权",
|
||||
hintClickCallback = {
|
||||
DirectUtils.directToWebView(context, Constants.PERMISSION_SCENARIO_ADDRESS, "(权限弹窗)")
|
||||
},
|
||||
cancelClickCallback = null,
|
||||
confirmClickCallback = {
|
||||
checkStoragePermissionBeforeAction(context, emptyCallback)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,9 +288,8 @@ object PermissionHelper {
|
||||
} else {
|
||||
val packageURI = Uri.fromParts("package", activity.packageName, null)
|
||||
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI)
|
||||
activity.startActivityForResult(intent, INSTALL_PERMISS_CODE)
|
||||
activity.startActivityForResult(intent, INSTALL_PERMISSION_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -64,34 +64,24 @@ object ReservationHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun showDeleteReservationDialog(context: Context, emptyCallback: EmptyCallback) {
|
||||
DialogHelper.showDialog(
|
||||
context,
|
||||
DialogUtils.showCancelOrDeleteReservationDialog(context,
|
||||
"删除预约",
|
||||
"游戏已上线,你可以删除此预约记录,确定删除吗?",
|
||||
"确定删除",
|
||||
"暂不删除",
|
||||
{ emptyCallback.onCallback() },
|
||||
null,
|
||||
trackMtaEvent = true
|
||||
// , mtaEvent = "预约游戏",
|
||||
// mtaKey = "删除预约弹窗"
|
||||
)
|
||||
"暂不删除", {
|
||||
emptyCallback.onCallback()
|
||||
}, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showCancelReservationDialog(context: Context, emptyCallback: EmptyCallback) {
|
||||
DialogHelper.showDialog(
|
||||
context,
|
||||
DialogUtils.showCancelOrDeleteReservationDialog(context,
|
||||
"取消预约",
|
||||
"取消之后你将无法收到游戏上线的通知,确定取消预约吗?",
|
||||
"确定取消",
|
||||
"暂不取消",
|
||||
{ emptyCallback.onCallback() },
|
||||
null,
|
||||
trackMtaEvent = true
|
||||
// , mtaEvent = "预约游戏",
|
||||
// mtaKey = "取消预约弹窗"
|
||||
)
|
||||
"暂不取消", {
|
||||
emptyCallback.onCallback()
|
||||
}, null)
|
||||
}
|
||||
|
||||
|
||||
|
||||
47
app/src/main/java/com/gh/common/util/SentryHelper.kt
Normal file
47
app/src/main/java/com/gh/common/util/SentryHelper.kt
Normal file
@ -0,0 +1,47 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.text.TextUtils
|
||||
import com.lightgame.utils.Utils
|
||||
import io.sentry.Sentry
|
||||
import io.sentry.SentryEvent
|
||||
import io.sentry.SentryLevel
|
||||
import io.sentry.protocol.Message
|
||||
|
||||
object SentryHelper {
|
||||
|
||||
/**
|
||||
* 注意 tag-key 不支持中文
|
||||
*/
|
||||
fun onEvent(eventId: String, vararg kv: String?) {
|
||||
val sentryEvent = SentryEvent()
|
||||
val message = Message()
|
||||
message.message = eventId
|
||||
sentryEvent.message = message
|
||||
sentryEvent.level = SentryLevel.INFO
|
||||
|
||||
for (i in kv.indices) {
|
||||
if (i % 2 != 0) {
|
||||
val key = kv[i - 1]
|
||||
val value = kv[i]
|
||||
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
||||
sentryEvent.setTag(key, value)
|
||||
debugOnly {
|
||||
throwExceptionInDebug("tag-key 不支持中文", isContainChinese(key))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Utils.log("Sentry", "$eventId + [${kv.joinToString(" , ")}]")
|
||||
Sentry.captureEvent(sentryEvent)
|
||||
}
|
||||
|
||||
// 判断一个字符串是否含有中文
|
||||
private fun isContainChinese(str: String?): Boolean {
|
||||
if (str == null) return false
|
||||
for (c in str.toCharArray()) {
|
||||
if (c.toInt() in 0x4E00..0x9FA5) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,9 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
@ -24,6 +22,9 @@ import android.widget.PopupWindow;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.WeiBoShareActivity;
|
||||
@ -50,9 +51,6 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import static com.gh.common.util.LoginHelper.WEIBO_SCOPE;
|
||||
|
||||
/**
|
||||
@ -92,7 +90,8 @@ public class ShareUtils {
|
||||
video("视频"),
|
||||
web("web链接"),
|
||||
userHome("个人主页"),
|
||||
qaDetail("QA内容详情");
|
||||
qaDetail("QA内容详情"),
|
||||
inviteFriends("邀请好友");
|
||||
|
||||
private String name;
|
||||
|
||||
@ -126,6 +125,7 @@ public class ShareUtils {
|
||||
EventBus.getDefault().post(new EBShare(ShareUtils.shareEntrance));
|
||||
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "success",
|
||||
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
|
||||
EnergyTaskHelper.postEnergyTaskForShare(ShareUtils.shareEntrance.getName(), ShareUtils.resourceId, ShareUtils.shareEntity.getShareUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -159,8 +159,7 @@ public class ShareUtils {
|
||||
|
||||
//检查是否安装手机QQ
|
||||
public static boolean isQQClientAvailable(Context context) {
|
||||
final PackageManager packageManager = context.getPackageManager();
|
||||
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
|
||||
List<PackageInfo> pinfo = PackageUtils.getInstalledPackages(context, 0);
|
||||
if (pinfo != null) {
|
||||
for (int i = 0; i < pinfo.size(); i++) {
|
||||
String pn = pinfo.get(i).packageName;
|
||||
@ -172,6 +171,40 @@ public class ShareUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 邀请好友(专属链接)
|
||||
public void shareInviteFriends(Activity activity, String url, String way) {
|
||||
if (activity.isFinishing()) return;
|
||||
this.mActivity = new WeakReference<>(activity);
|
||||
this.shareIcon = activity.getString(R.string.gh_icon_url);
|
||||
this.shareUrl = url;
|
||||
this.mSummary = "卡牌神器,海量游戏下载,积分大礼,等你尝鲜";
|
||||
this.mTitle = "推荐一款好玩的游戏下载APP【光环助手】";
|
||||
this.mShareEntrance = ShareEntrance.inviteFriends;
|
||||
ShareUtils.shareEntrance = mShareEntrance;
|
||||
ShareUtils.resourceId = "";
|
||||
ShareUtils.shareEntity = new ShareEntity(shareUrl, mTitle, mSummary);
|
||||
LogUtils.uploadShareEnter(mShareEntrance.getName(), shareUrl, mTitle, mSummary, "");
|
||||
|
||||
// 分享
|
||||
switch (way) {
|
||||
case "qq" :
|
||||
qqShare();
|
||||
break;
|
||||
case "qq_zone" :
|
||||
qZoneShare();
|
||||
break;
|
||||
case "wechat" :
|
||||
wechatShare();
|
||||
break;
|
||||
case "wechat_moments" :
|
||||
wechatMomentsShare();
|
||||
break;
|
||||
case "weibo" :
|
||||
sinaWeiboShare();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void showShareUserHomeWindows(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareEntrance shareEntrance, String id, ShareCallBack callBack) {
|
||||
if (activity.isFinishing()) return;
|
||||
this.mActivity = new WeakReference<>(activity);
|
||||
@ -321,13 +354,27 @@ public class ShareUtils {
|
||||
});
|
||||
}
|
||||
|
||||
public void shareParamsDetail(Activity activity, String url, String icon, String shareTitle, String shareSummary, ShareEntrance shareEntrance, String id, ShareCallBack callBack) {
|
||||
if (activity.isFinishing()) return;
|
||||
this.mActivity = new WeakReference<>(activity);
|
||||
this.shareIcon = icon;
|
||||
this.shareUrl = url;
|
||||
this.mSummary = shareSummary;
|
||||
this.mTitle = shareTitle;
|
||||
this.mShareEntrance = shareEntrance;
|
||||
ShareUtils.shareEntrance = mShareEntrance;
|
||||
ShareUtils.resourceId = id;
|
||||
ShareUtils.shareEntity = new ShareEntity(shareUrl, mTitle, mSummary);
|
||||
LogUtils.uploadShareEnter(mShareEntrance.getName(), shareUrl, mTitle, mSummary, id);
|
||||
}
|
||||
|
||||
|
||||
public void showShareWindows(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareEntrance shareEntrance, String id) {
|
||||
showShareWindowsCallback(activity, view, url, icon, shareTitle, shareSummary, shareEntrance, id, null);
|
||||
}
|
||||
|
||||
//QQ分享
|
||||
private void qqShare() {
|
||||
public void qqShare() {
|
||||
Utils.toast(mContext, R.string.share_skip);
|
||||
Bundle params = new Bundle();
|
||||
|
||||
@ -362,7 +409,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
//微信好友分享
|
||||
private void wechatShare() {
|
||||
public void wechatShare() {
|
||||
Utils.toast(mContext, R.string.share_skip);
|
||||
|
||||
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
|
||||
@ -479,7 +526,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
//QQ空间分享
|
||||
private void qZoneShare() {
|
||||
public void qZoneShare() {
|
||||
Utils.toast(mContext, R.string.share_skip);
|
||||
Bundle params = new Bundle();
|
||||
|
||||
@ -518,7 +565,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
//微信朋友圈分享
|
||||
private void wechatMomentsShare() {
|
||||
public void wechatMomentsShare() {
|
||||
Utils.toast(mContext, R.string.share_skip);
|
||||
|
||||
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
|
||||
@ -561,7 +608,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
//新浪微博分享
|
||||
private void sinaWeiboShare() {
|
||||
public void sinaWeiboShare() {
|
||||
WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
|
||||
|
||||
if (mShareEntrance == ShareEntrance.qaDetail) {
|
||||
@ -570,7 +617,7 @@ public class ShareUtils {
|
||||
}
|
||||
Activity activity = mActivity.get();
|
||||
if (activity != null) {
|
||||
Intent intent = WeiBoShareActivity.getWeiboshareIntent(
|
||||
Intent intent = WeiBoShareActivity.getWeiboShareIntent(
|
||||
activity,
|
||||
shareUrl,
|
||||
shareIcon,
|
||||
@ -587,7 +634,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
//短信分享
|
||||
private void shortMessageShare() {
|
||||
public void shortMessageShare() {
|
||||
String smsBody;
|
||||
switch (mShareEntrance) {
|
||||
case news:
|
||||
@ -631,19 +678,21 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
//复制文字链接
|
||||
private void copyLink(String copyContent) {
|
||||
public void copyLink(String copyContent) {
|
||||
shareType = "copy_link";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
ClipboardManager cmb = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cmb.setText(copyContent);
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
Utils.toast(mContext, "复制成功");
|
||||
ExtensionsKt.copyTextAndToast(copyContent, "复制成功");
|
||||
safelyDismiss();
|
||||
} else {
|
||||
Utils.toast(mContext, "复制成功,请到微信/QQ粘贴分享");
|
||||
ExtensionsKt.copyTextAndToast(copyContent, "复制成功,请到微信/QQ粘贴分享");
|
||||
}
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
private class ShareRecyclerViewAdapter extends RecyclerView.Adapter<ShareRecyclerViewAdapter.ViewHolder> {
|
||||
|
||||
private OnItemClickListener listener;
|
||||
@ -669,6 +718,7 @@ public class ShareUtils {
|
||||
if (listener != null) {
|
||||
listener.onItemClick(holder.getAdapterPosition());
|
||||
}
|
||||
|
||||
switch (holder.getPosition()) {
|
||||
case 0:
|
||||
shareType = "wechat_friend";
|
||||
@ -754,7 +804,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
private void safelyDismiss() {
|
||||
if (popupWindow.get() != null) {
|
||||
if (popupWindow != null && popupWindow.get() != null) {
|
||||
popupWindow.get().dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ object SPUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun getString(key: String): String {
|
||||
return sp.getString(key, "")
|
||||
return sp.getString(key, "")?:""
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@ -13,7 +13,7 @@ import androidx.core.content.ContextCompat
|
||||
import com.gh.common.view.CenterImageSpan
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
class SpanBuilder(content: String) {
|
||||
class SpanBuilder(content: CharSequence) {
|
||||
private var spannableString: SpannableStringBuilder = SpannableStringBuilder(content)
|
||||
|
||||
fun color(context: Context, start: Int, end: Int, colorRes: Int): SpanBuilder {
|
||||
@ -70,12 +70,12 @@ class SpanBuilder(content: String) {
|
||||
return this
|
||||
}
|
||||
|
||||
fun click(start: Int, end: Int, colorRes: Int, onClick: () -> Unit): SpanBuilder {
|
||||
fun click(start: Int, end: Int, colorRes: Int, isUnderlineText: Boolean = false, onClick: () -> Unit): SpanBuilder {
|
||||
val clickSpan = object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(HaloApp.getInstance().application, colorRes)
|
||||
ds.isUnderlineText = false
|
||||
ds.isUnderlineText = isUnderlineText
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
|
||||
@ -71,7 +71,7 @@ object SyncDataBetweenPageHelper {
|
||||
val fields = syncData::class.java.declaredFields
|
||||
var isNeedNotify = false
|
||||
for (field in fields) {
|
||||
if (field.getAnnotation(Synchronize::class.java) != null) {
|
||||
if (field.getAnnotation(Synchronize::class.java) != null && resultData != null) {
|
||||
// 同步数据
|
||||
val resultField = resultData::class.java.getDeclaredField(field.name)
|
||||
resultField.isAccessible = true
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.Context
|
||||
|
||||
/**
|
||||
* 今日头条的激活统计 SDK https://gitlab.ghzs.com/pm/halo-app-issues/issues/567
|
||||
*
|
||||
* 更新 SDK https://gitlab.ghzs.com/pm/halo-app-issues/issues/743
|
||||
*/
|
||||
object TeaHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun init(context: Context, channel: String) {
|
||||
// val config = InitConfig("163824", channel)
|
||||
// config.setUriConfig(UriConfig.DEFAULT)
|
||||
// config.appName = "guanghuan1"
|
||||
// config.setEnablePlay(true)
|
||||
// AppLog.setEnableLog(false)
|
||||
// AppLog.init(context, config)
|
||||
//
|
||||
// AppLog.setOaidObserver {
|
||||
// HaloApp.getInstance().oaid = it.id
|
||||
// Utils.log("oaid is $it.id")
|
||||
// MetaUtil.refreshMeta()
|
||||
// }
|
||||
//
|
||||
// // gameReportHelper ?!
|
||||
// GameReportHelper.onEventRegister("wechat", true)
|
||||
// GameReportHelper.onEventPurchase("gift", "flower", "008", 1, "wechat", "¥", true, 1)
|
||||
}
|
||||
|
||||
}
|
||||
@ -88,6 +88,17 @@ object TimeUtils {
|
||||
return String.format(Locale.CHINA, "%02d:%02d", minute, second)
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时长(将秒数转化为HH:mm:ss格式)
|
||||
*/
|
||||
@JvmStatic
|
||||
fun formatDuration(seconds: Long): String {
|
||||
val hour = seconds / 3600
|
||||
val minute = seconds % 3600 / 60
|
||||
val second = seconds % 60
|
||||
return String.format(Locale.CHINA, "%02d:%02d:%02d", hour, minute, second)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDayString(date: Long): String {
|
||||
val offSet = Calendar.getInstance().timeZone.rawOffset
|
||||
@ -117,6 +128,20 @@ object TimeUtils {
|
||||
return calendar.timeInMillis
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getTimeOfToday(hour: Int) = getTimeOfToday(hour, 0)
|
||||
|
||||
@JvmStatic
|
||||
fun getTimeOfToday(hour: Int, minute: Int): Long {
|
||||
val calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"))
|
||||
calendar.timeInMillis = getJavaTimestamp(System.currentTimeMillis())
|
||||
calendar.set(Calendar.HOUR_OF_DAY, hour)
|
||||
calendar.set(Calendar.MINUTE, minute)
|
||||
calendar.set(Calendar.SECOND, 0)
|
||||
calendar.set(Calendar.MILLISECOND, 0)
|
||||
return calendar.timeInMillis
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getJavaTimestamp(timestamp: Long): Long {
|
||||
return if ((log10(timestamp.toDouble()) + 1).toInt() == 10) {
|
||||
|
||||
@ -6,6 +6,7 @@ import com.gh.common.constant.Constants;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.halo.assistant.HaloApp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import androidx.collection.ArrayMap;
|
||||
@ -17,10 +18,12 @@ public class TimestampUtils {
|
||||
|
||||
private static ArrayMap<String, Integer> intervalMap; // 间隔
|
||||
private static ArrayMap<String, Integer> cdMap; // cd
|
||||
private static ArrayList<String> whiteList; // 白名单
|
||||
|
||||
public static void initMap() {
|
||||
initIntervalMap();
|
||||
initCDMap();
|
||||
initWhiteList();
|
||||
}
|
||||
|
||||
private static void initIntervalMap() {
|
||||
@ -43,11 +46,25 @@ public class TimestampUtils {
|
||||
cdMap.put(".*packages.*", Constants.PACKAGES_CD);
|
||||
}
|
||||
|
||||
private static void initWhiteList() {
|
||||
whiteList = new ArrayList<>();
|
||||
whiteList.add(".*tasks:check.*");
|
||||
whiteList.add(".*novice_tasks.*");
|
||||
whiteList.add(".*daily_tasks.*");
|
||||
whiteList.add(".*energies.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* 为url添加timestamp
|
||||
*/
|
||||
public static String addTimestamp(String url) {
|
||||
|
||||
for (String key : whiteList) {
|
||||
if (Pattern.matches(key, url)) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG || "GH_REFRESH".equals(HaloApp.getInstance().getChannel())) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
return url;
|
||||
|
||||
@ -1,65 +1,23 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.widget.Toast
|
||||
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.toast.ToastHandler
|
||||
import com.lightgame.utils.toast.ToastHelper
|
||||
|
||||
object ToastUtils {
|
||||
/** 之前显示的内容 */
|
||||
private var mOldMsg: String? = null
|
||||
|
||||
/** Toast对象 */
|
||||
private var mToast: Toast? = null
|
||||
|
||||
/** 第一次时间 */
|
||||
private var mOneTime: Long = 0
|
||||
|
||||
/** 第二次时间 */
|
||||
private var mTwoTime: Long = 0
|
||||
|
||||
/**
|
||||
* 显示Toast
|
||||
* @param message
|
||||
*/
|
||||
fun showToast(message: String) {
|
||||
showToast(message, -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示Toast
|
||||
* @param message
|
||||
* @param gravity
|
||||
*/
|
||||
fun showToast(message: String, gravity: Int = -1, yOffset: Int = 0) {
|
||||
if (mToast == null) {
|
||||
mToast = ToastHandler.INSTANCE.getToastInstance(HaloApp.getInstance().application, message, Toast.LENGTH_SHORT)
|
||||
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
|
||||
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
|
||||
mToast!!.show()
|
||||
mOneTime = System.currentTimeMillis()
|
||||
} else {
|
||||
mTwoTime = System.currentTimeMillis()
|
||||
if (message == mOldMsg) {
|
||||
if (mTwoTime - mOneTime > Toast.LENGTH_SHORT) {
|
||||
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
|
||||
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
|
||||
mToast!!.show()
|
||||
}
|
||||
} else {
|
||||
mOldMsg = message
|
||||
mToast!!.setText(message)
|
||||
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
|
||||
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
|
||||
mToast!!.show()
|
||||
}
|
||||
}
|
||||
mOneTime = mTwoTime
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun toast(message: String) {
|
||||
if (mToast != null) mToast?.cancel()
|
||||
mToast = ToastHandler.INSTANCE.getToastInstance(HaloApp.getInstance().application, message, Toast.LENGTH_SHORT)
|
||||
mToast?.show()
|
||||
showToast(message)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showToast(message: String) {
|
||||
ToastHelper.showToast(HaloApp.getInstance(), message)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showToast(message: String, gravity: Int = -1, yOffset: Int = 0) {
|
||||
ToastHelper.showToast(HaloApp.getInstance(), message, gravity, yOffset)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
21
app/src/main/java/com/gh/common/util/TopCutProcess.kt
Normal file
21
app/src/main/java/com/gh/common/util/TopCutProcess.kt
Normal file
@ -0,0 +1,21 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Matrix
|
||||
import com.facebook.common.references.CloseableReference
|
||||
import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory
|
||||
import com.facebook.imagepipeline.request.BasePostprocessor
|
||||
|
||||
class TopCutProcess(private val cutRatio: Float) : BasePostprocessor() {
|
||||
|
||||
override fun process(sourceBitmap: Bitmap, bitmapFactory: PlatformBitmapFactory): CloseableReference<Bitmap>? {
|
||||
val viewWidth = sourceBitmap.width
|
||||
val viewHeight = sourceBitmap.height.toFloat()
|
||||
var newHeight = viewWidth / cutRatio
|
||||
if (newHeight > viewHeight) {
|
||||
newHeight = viewHeight
|
||||
}
|
||||
val bitmapRef = bitmapFactory.createBitmap(sourceBitmap, 0, 0, viewWidth, (newHeight).toInt())
|
||||
return CloseableReference.cloneOrNull(bitmapRef)
|
||||
}
|
||||
}
|
||||
@ -116,6 +116,7 @@ object UploadImageUtils {
|
||||
|
||||
Observable.create(ObservableOnSubscribe<Map<String, String>> {
|
||||
val compressList = compressImageList(imgs, compressGif)
|
||||
listener.onCompressSuccess(compressList.map { file -> file.absolutePath }.toList())
|
||||
var listTotal = 0L // 总大小
|
||||
var listProgress = 0L // 已上传的大小
|
||||
for (img in compressList) {
|
||||
@ -274,7 +275,7 @@ object UploadImageUtils {
|
||||
}
|
||||
|
||||
// 防止GIF图片文件后缀不是GIF,这个FileName只是告诉服务端后缀格式,没有其他用处
|
||||
fun getFileName(file: File): String {
|
||||
fun getFileName(file: File): String {
|
||||
val options = BitmapFactory.Options()
|
||||
options.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeFile(file.absolutePath, options)
|
||||
@ -292,6 +293,7 @@ object UploadImageUtils {
|
||||
|
||||
interface OnUploadImageListListener {
|
||||
fun onSuccess(imageUrl: LinkedHashMap<String, String>, errorMap: Map<String, Exception>) // key:sourceImage value:compressImage
|
||||
fun onCompressSuccess(imageUrls: List<String>) {}
|
||||
fun onError(errorMap: Map<String, Exception>) // 全部上传失败时回调
|
||||
fun onProgress(total: Long, progress: Long)
|
||||
}
|
||||
|
||||
@ -1,127 +0,0 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
public class UriUtils {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public static String getPath(final Context context, final Uri uri) {
|
||||
|
||||
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||
|
||||
// DocumentProvider
|
||||
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
|
||||
// ExternalStorageProvider
|
||||
if (isExternalStorageDocument(uri)) {
|
||||
final String docId = DocumentsContract.getDocumentId(uri);
|
||||
final String[] split = docId.split(":");
|
||||
final String type = split[0];
|
||||
|
||||
if ("primary".equalsIgnoreCase(type)) {
|
||||
return Environment.getExternalStorageDirectory() + "/" + split[1];
|
||||
}
|
||||
}
|
||||
// DownloadsProvider
|
||||
else if (isDownloadsDocument(uri)) {
|
||||
|
||||
final String id = DocumentsContract.getDocumentId(uri);
|
||||
final Uri contentUri = ContentUris.withAppendedId(
|
||||
Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
|
||||
|
||||
return getDataColumn(context, contentUri, null, null);
|
||||
}
|
||||
// MediaProvider
|
||||
else if (isMediaDocument(uri)) {
|
||||
final String docId = DocumentsContract.getDocumentId(uri);
|
||||
final String[] split = docId.split(":");
|
||||
final String type = split[0];
|
||||
|
||||
Uri contentUri = null;
|
||||
if ("image".equals(type)) {
|
||||
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
} else if ("video".equals(type)) {
|
||||
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
||||
} else if ("audio".equals(type)) {
|
||||
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
}
|
||||
|
||||
final String selection = "_id=?";
|
||||
final String[] selectionArgs = new String[]{split[1]};
|
||||
|
||||
return getDataColumn(context, contentUri, selection, selectionArgs);
|
||||
}
|
||||
}
|
||||
// MediaStore (and general)
|
||||
else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||
return getDataColumn(context, uri, null, null);
|
||||
}
|
||||
// File
|
||||
else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||
return uri.getPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the data column for this Uri. This is useful for
|
||||
* MediaStore Uris, and other file-based ContentProviders.
|
||||
*
|
||||
* @param context The context.
|
||||
* @param uri The Uri to query.
|
||||
* @param selection (Optional) Filter used in the query.
|
||||
* @param selectionArgs (Optional) Selection arguments used in the query.
|
||||
* @return The value of the _data column, which is typically a file path.
|
||||
*/
|
||||
private static String getDataColumn(Context context, Uri uri, String selection,
|
||||
String[] selectionArgs) {
|
||||
|
||||
Cursor cursor = null;
|
||||
final String column = "_data";
|
||||
final String[] projection = {column};
|
||||
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
|
||||
null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final int column_index = cursor.getColumnIndexOrThrow(column);
|
||||
return cursor.getString(column_index);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is ExternalStorageProvider.
|
||||
*/
|
||||
private static boolean isExternalStorageDocument(Uri uri) {
|
||||
return "com.android.externalstorage.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is DownloadsProvider.
|
||||
*/
|
||||
private static boolean isDownloadsDocument(Uri uri) {
|
||||
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is MediaProvider.
|
||||
*/
|
||||
private static boolean isMediaDocument(Uri uri) {
|
||||
return "com.android.providers.media.documents".equals(uri.getAuthority());
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ import android.app.AppOpsManager.MODE_ALLOWED
|
||||
import android.app.AppOpsManager.OPSTR_GET_USAGE_STATS
|
||||
import android.app.usage.UsageEvents
|
||||
import android.app.usage.UsageStatsManager
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
@ -24,7 +25,6 @@ import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.ResponseBody
|
||||
@ -173,8 +173,6 @@ object UsageStatsHelper {
|
||||
|
||||
val body = RequestBody.create(MediaType.parse("application/json"), postBody.toString())
|
||||
mApi.postUsageStatus(body, UserManager.getInstance().userId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
debugOnly {
|
||||
@ -221,8 +219,6 @@ object UsageStatsHelper {
|
||||
}
|
||||
|
||||
mApi.getUsageStatusUpdateTime(HaloApp.getInstance().gid)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
val body = JSONObject(data.string())
|
||||
@ -257,10 +253,15 @@ object UsageStatsHelper {
|
||||
@JvmStatic
|
||||
fun skipToUsageStats(context: Context, requestCode: Int = -1) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (context is Activity && requestCode != -1) {
|
||||
context.startActivityForResult(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS), requestCode)
|
||||
} else {
|
||||
context.startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
|
||||
try {
|
||||
if (context is Activity && requestCode != -1) {
|
||||
context.startActivityForResult(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS), requestCode)
|
||||
} else {
|
||||
context.startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
|
||||
}
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Utils.toast(context, "当前设备不支持直接跳转查看应用使用情况页面,请手动进入并打开")
|
||||
e.printStackTrace()
|
||||
}
|
||||
} else {
|
||||
Utils.toast(context, "当前设备不支持查看应用使用情况")
|
||||
|
||||
@ -2,7 +2,10 @@ package com.gh.common.videolog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.database.sqlite.SQLiteFullException
|
||||
import com.gh.common.util.toRequestBody
|
||||
import com.gh.common.util.toastInInternalRelease
|
||||
import com.gh.common.util.tryWithDefaultCatch
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
@ -11,34 +14,40 @@ import com.halo.assistant.HaloApp
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
||||
object VideoRecordUtils {
|
||||
private const val STORE_SIZE = 20
|
||||
private lateinit var mApplication: Application
|
||||
|
||||
private val videoRecordSet by lazy { hashSetOf<VideoRecordEntity>() }
|
||||
private val videoRecordExecutor by lazy { Executors.newSingleThreadExecutor() }
|
||||
private var videoRecordExecutor: ExecutorService? = null
|
||||
private val videoRecordDao by lazy { AppDatabase.getInstance(mApplication).videoRecordDao() }
|
||||
|
||||
@JvmStatic
|
||||
fun init(application: Application) {
|
||||
fun init(application: Application, executor : ExecutorService) {
|
||||
mApplication = application
|
||||
|
||||
videoRecordExecutor.execute {
|
||||
val recordList = videoRecordDao.getAll()
|
||||
videoRecordSet.addAll(recordList)
|
||||
videoRecordExecutor = executor
|
||||
videoRecordExecutor?.execute {
|
||||
tryWithDefaultCatch {
|
||||
val recordList = videoRecordDao.getAll()
|
||||
videoRecordSet.addAll(recordList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun log(videoId: String) {
|
||||
videoRecordExecutor.execute {
|
||||
videoRecordExecutor?.execute {
|
||||
try {
|
||||
val entity = VideoRecordEntity(videoId = videoId, time = System.currentTimeMillis() / 1000L)
|
||||
videoRecordSet.add(entity)
|
||||
videoRecordDao.insert(entity)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
if (e is SQLiteFullException) {
|
||||
toastInInternalRelease("数据库/磁盘已满,写入视频新日志失败")
|
||||
}
|
||||
}
|
||||
if (videoRecordSet.size >= STORE_SIZE) {
|
||||
commitVideoRecord()
|
||||
@ -48,11 +57,15 @@ object VideoRecordUtils {
|
||||
|
||||
fun commitVideoRecord() {
|
||||
if (videoRecordSet.isEmpty() || !::mApplication.isInitialized) return
|
||||
videoRecordExecutor.execute {
|
||||
videoRecordExecutor?.execute {
|
||||
uploadVideoRecord()
|
||||
val exposureList = videoRecordSet.toList()
|
||||
videoRecordSet.removeAll(exposureList)
|
||||
videoRecordDao.deleteMany(exposureList)
|
||||
try {
|
||||
videoRecordDao.deleteMany(exposureList)
|
||||
} catch (e: SQLiteFullException) {
|
||||
toastInInternalRelease("数据库/磁盘已满,删除视频日志失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@ package com.gh.common.view
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.*
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -14,7 +13,6 @@ import com.gh.common.util.ImageUtils
|
||||
import com.gh.common.util.rxTimer
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.SettingsEntity
|
||||
import com.squareup.picasso.Picasso
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user