Compare commits
427 Commits
v4.7.3-293
...
v4.9.6-336
| Author | SHA1 | Date | |
|---|---|---|---|
| f826dc07c6 | |||
| 34670d08c0 | |||
| 5e5646468e | |||
| 039203408a | |||
| 60b325812e | |||
| 06a43f617b | |||
| 85d3412fd8 | |||
| 71b8cbbef3 | |||
| dfc0183a14 | |||
| 156e52f619 | |||
| 252cb3825b | |||
| 075a7e4e77 | |||
| 0c95f911d1 | |||
| 49b74c9a37 | |||
| c4240440d1 | |||
| e0205ec060 | |||
| 895024aa09 | |||
| fd946703a9 | |||
| 806935a81e | |||
| feb30ff3a4 | |||
| 4b851732c9 | |||
| 3abf29fa75 | |||
| 4bb7d2a043 | |||
| e3d830235e | |||
| 6425f3d50c | |||
| e9d2c6573f | |||
| 05e36f11cf | |||
| bc76e6eddb | |||
| 6de543261b | |||
| d9a8fa0a2d | |||
| 51c88e8586 | |||
| 9e930f1b35 | |||
| eb8fb191bb | |||
| 6653467259 | |||
| 9ec29ad367 | |||
| 406ac98616 | |||
| 5832c75909 | |||
| 9d8681c50f | |||
| 9c28bf162e | |||
| 061d5c19ed | |||
| 1241207dd2 | |||
| 702da08bc4 | |||
| 8c885e38a1 | |||
| acc6935608 | |||
| 62a87d1c71 | |||
| 2ba479d3ca | |||
| 3f5f3bf57c | |||
| 4d10ca0c6c | |||
| c816fd87f4 | |||
| 547bfd98ac | |||
| 34ba85f099 | |||
| 2d251ef453 | |||
| d7c7fe8740 | |||
| 295e783d4b | |||
| 58dfad4123 | |||
| f31d8b51fa | |||
| 01ea8b9834 | |||
| 5152060515 | |||
| 0a0d805e9d | |||
| 51511c8be8 | |||
| 4bbfa3e16e | |||
| 81c0c6ee09 | |||
| 50b449ca64 | |||
| 8764412492 | |||
| c1e011cae8 | |||
| 018f814a6b | |||
| ef9cb24b61 | |||
| 245a4273de | |||
| 94c1651510 | |||
| 07f55acb3a | |||
| 43ee3b3488 | |||
| 32625f59e0 | |||
| e1e3aa5598 | |||
| c5ff2cb5bd | |||
| acf02c99e7 | |||
| 9a00999d9e | |||
| 4c5b602a3b | |||
| cbde36f3bd | |||
| f4b6193a6b | |||
| 85a596766d | |||
| 785cfecf81 | |||
| 0c8b98084a | |||
| 87a6a3a539 | |||
| 6c50082de5 | |||
| 41195ec9d4 | |||
| 223646cf3d | |||
| ab4bb79a32 | |||
| 50b51e2f3c | |||
| 1fef7d51d6 | |||
| 6546961f81 | |||
| 75e4f32840 | |||
| a3f3c95e19 | |||
| 508231d547 | |||
| 8649b98032 | |||
| d35211262f | |||
| 96a5838155 | |||
| fc21799288 | |||
| 3e04d77d50 | |||
| 35f47e363a | |||
| 019724e9c6 | |||
| 70f059b4de | |||
| 34cd63d36d | |||
| 033cf6b566 | |||
| 513fc3be1c | |||
| fd1273a092 | |||
| 27a6f14d18 | |||
| 000c7978fd | |||
| 486c8f691c | |||
| 16450a7f8d | |||
| 438e660449 | |||
| b9bf4311cf | |||
| 75a324747c | |||
| 04b579cda7 | |||
| 5962a8cf08 | |||
| ea388a8e1b | |||
| 8a98d6323a | |||
| 1b67ff5d12 | |||
| 9ee0f65e02 | |||
| 557b6fee21 | |||
| c90d6ec0dc | |||
| 8109aa58c9 | |||
| 213e079e9d | |||
| 40e38e50b9 | |||
| b70e18af96 | |||
| 4c91f06d94 | |||
| 199067cf8a | |||
| fa01260f0b | |||
| f8dac32bd6 | |||
| d5641d437c | |||
| c27f62e726 | |||
| b98d4e6ec6 | |||
| a4e67cda91 | |||
| ab3616f237 | |||
| bd9032c659 | |||
| 4ded8cbfc8 | |||
| 5a14afa71e | |||
| 7736ef37e5 | |||
| 40adf1938e | |||
| 7e1f821d7a | |||
| 4f81996857 | |||
| 328a559ef0 | |||
| ee01512f84 | |||
| a366a87324 | |||
| 3c7a1e2ae3 | |||
| 87c71882f5 | |||
| 7fa912bc0c | |||
| 27dc3f73ae | |||
| be630e39cd | |||
| cded31298c | |||
| 54030fd1df | |||
| 98c1565dfb | |||
| d89c2d4a70 | |||
| 0f11f6344f | |||
| a25f265bd3 | |||
| 68adc0ff23 | |||
| ab5aa01ec5 | |||
| 71e5f798d9 | |||
| 2572c53305 | |||
| 64b5ca8efa | |||
| b5ef73517f | |||
| feb2f68778 | |||
| f0a6e79418 | |||
| 78699cc0e8 | |||
| 96805537f4 | |||
| 13c4be2ab0 | |||
| c2e5e8adbc | |||
| c5c9a3f4d2 | |||
| 8bd2fa9b3a | |||
| 4bd8fc4e51 | |||
| 5b26165aaa | |||
| 1bb4c1cc2c | |||
| d38b347eb8 | |||
| feaf2d0bfc | |||
| 210dcdc698 | |||
| fec291156a | |||
| 62bb23abc9 | |||
| 19be9e1842 | |||
| a5cfd147b4 | |||
| f15d572785 | |||
| 5e99e8b032 | |||
| af39b82da1 | |||
| ba3a4ede11 | |||
| db591d0249 | |||
| 1370261b87 | |||
| 3824de4719 | |||
| 6ee26fb401 | |||
| 865fe2729f | |||
| 85c556c593 | |||
| 86681b8ab1 | |||
| 5f2ce22506 | |||
| dafa85a791 | |||
| 9cc3a29b5a | |||
| d2e8a67971 | |||
| 1bd3168add | |||
| 81d81882e0 | |||
| 3f4e4f1a52 | |||
| 3845e1f3ee | |||
| 6d2ae4dca5 | |||
| e2efa26ac0 | |||
| 70e12ebd08 | |||
| 91fc511fe6 | |||
| c5530ba307 | |||
| 67cbd9b641 | |||
| 6735047e67 | |||
| 9993bca582 | |||
| 07258b08af | |||
| f8bd7787f6 | |||
| b6a3ef5faa | |||
| 730151f6ba | |||
| 532b98e002 | |||
| 202a26b09c | |||
| fe1821884a | |||
| eb1605cc0a | |||
| 08ad5c3455 | |||
| 0774525de6 | |||
| b69ebc8122 | |||
| 49f31da303 | |||
| 66568b09d5 | |||
| 57a944f954 | |||
| 1fb8a60b2b | |||
| 489a57a379 | |||
| 0aa02c186c | |||
| fd463ec1e3 | |||
| 0c16ae5f3f | |||
| 76cca46015 | |||
| 748cacce3f | |||
| b47985d4ff | |||
| 9e41bd2846 | |||
| 0e4b18fc5d | |||
| 5594a03cee | |||
| 59ece3be49 | |||
| a7f77076a5 | |||
| 6526d5b3ce | |||
| 3a2f877d0c | |||
| 0d344e66a1 | |||
| d3de323c06 | |||
| 721d5acc1d | |||
| 7069744191 | |||
| b1f56d5dcd | |||
| 5aaa5bd076 | |||
| 7e74dee0eb | |||
| 45b8f7f82f | |||
| 7c9b8732e2 | |||
| 86ae96253b | |||
| 9dcc0b5587 | |||
| 9ceba793e8 | |||
| 175cc55b75 | |||
| 5486d1803f | |||
| cb885f8b66 | |||
| ab9f5cf7d8 | |||
| 7f4fafc637 | |||
| acccd2330d | |||
| 2745147e73 | |||
| 8fb0e3feaf | |||
| 335fa8ba39 | |||
| c739074057 | |||
| a2569cf876 | |||
| a81b0a1603 | |||
| 76c20e4b82 | |||
| 4144cc2c4f | |||
| 5465ff7731 | |||
| fc6dedb320 | |||
| a76b98f20c | |||
| f05c0324fa | |||
| 606eb30d9f | |||
| aa41da022d | |||
| b62d2c1b9e | |||
| ba21543800 | |||
| 6f5b832a68 | |||
| eb4bbb9efa | |||
| 233f91d2b9 | |||
| 1c51b2fe41 | |||
| 5123d7ff11 | |||
| c20e06f2eb | |||
| df55caa1f8 | |||
| 61bdac3aa2 | |||
| d56dc53b06 | |||
| 18c02ad9c3 | |||
| 8a262532e1 | |||
| 876d920251 | |||
| 1bad70a83f | |||
| c04a1a5802 | |||
| ea8c47a6d6 | |||
| 53f3f48c4d | |||
| 706df0c22f | |||
| 74cee421f9 | |||
| 4b08fa56da | |||
| 522f664f30 | |||
| 87a92055a7 | |||
| f23aa496ae | |||
| 65d7322546 | |||
| d9178f8538 | |||
| 5de471d89a | |||
| 63cc104e9f | |||
| f06ba9bf45 | |||
| 682d5a2cd4 | |||
| 76ce4e2f04 | |||
| 54221cc976 | |||
| 79ae36c51f | |||
| 335d6787a7 | |||
| 2bf9c1e4d7 | |||
| 133635c495 | |||
| 2aaf6d8a9c | |||
| f119f6751a | |||
| 18f964c167 | |||
| 369275225e | |||
| d80daf104f | |||
| 71c697d596 | |||
| 169814d6a9 | |||
| 52cffde739 | |||
| 11f84b69ac | |||
| 2c3e03bd0f | |||
| 264e103395 | |||
| 7f4d3ffe3e | |||
| 79b7a15f7d | |||
| 638dd4ad1d | |||
| 04f58e036b | |||
| 6624868bfe | |||
| 2ff83b8cc5 | |||
| cab412ab70 | |||
| 1a83e64f3a | |||
| be76fb0526 | |||
| 5cc25482a9 | |||
| c683e6786c | |||
| 5f182eeddb | |||
| 3e0979fabb | |||
| 13685ec605 | |||
| 4eac5ff61c | |||
| 98f0cf5fc0 | |||
| cb345f49eb | |||
| ef95be60f1 | |||
| a85cfa47e2 | |||
| 66123b0ae8 | |||
| cdb660b884 | |||
| 026e4f71de | |||
| 01ecde0425 | |||
| f748fcbd48 | |||
| 65464eed3d | |||
| 6a5d8e915c | |||
| 5fde455bcd | |||
| e1e257b1d8 | |||
| 7a87f8dc14 | |||
| 3fe2b8ffcd | |||
| 565b7b2c38 | |||
| b3bf9d862f | |||
| c6f5ef64d5 | |||
| 95b21b5bb5 | |||
| 0da331d109 | |||
| 8c1f8833b1 | |||
| e53cd6dede | |||
| fa27e172e4 | |||
| 544f5102ea | |||
| 5d6134f0dd | |||
| e0b951e043 | |||
| f2476c84c4 | |||
| c186c32d47 | |||
| 194f30650e | |||
| a475b176b4 | |||
| 73cac4d39d | |||
| 93d0f30352 | |||
| 98d30d1183 | |||
| b1d178f8df | |||
| 0550df7039 | |||
| 13c7b8ff1d | |||
| d7b7633ffe | |||
| 5e536db94e | |||
| 55d8b6a866 | |||
| a2a8610083 | |||
| 8d9f0adebe | |||
| e386994e4d | |||
| fc5f1e9830 | |||
| fd17eaea00 | |||
| 8a65d6dd85 | |||
| 8d3c609ad0 | |||
| 2e71e11a09 | |||
| b9c17bcdb8 | |||
| 55bb1a1873 | |||
| 54601bc083 | |||
| df2bb9c020 | |||
| 0bf297d094 | |||
| db8a2a06aa | |||
| 44a9db7294 | |||
| 7db48b6923 | |||
| 0a8f2d51db | |||
| b06d2a479a | |||
| d56bd0078e | |||
| 7b87aadd86 | |||
| 8f2da187f2 | |||
| 8291caa5e3 | |||
| e30ec540bd | |||
| 3c4da21bf6 | |||
| 800260b6a4 | |||
| ddea202f85 | |||
| b3a786ee22 | |||
| 332e24b874 | |||
| 5413ebfba4 | |||
| 7ead1c89f3 | |||
| 03300a41f7 | |||
| 2d8698e070 | |||
| 078b1a18a0 | |||
| de1e3ba7a7 | |||
| a9275c83d2 | |||
| 1a5a4ba149 | |||
| 9bdae33655 | |||
| be1184583b | |||
| 68ee926897 | |||
| 4d0db8cbcc | |||
| 59e4b6e063 | |||
| 811b1bbfce | |||
| 00c25d0d47 | |||
| 795af0528f | |||
| d0b4ea8ec2 | |||
| 45861dff61 | |||
| 5f41463fc3 | |||
| 89cca6dbfd | |||
| e43c0efdcb | |||
| 2dbd635b8e | |||
| 728d4fd8e1 | |||
| 48b5c7efc1 | |||
| 4f6969a70a | |||
| 29140b6c0b | |||
| 11bd9bed95 | |||
| 997b5676dc | |||
| 9b8755e035 | |||
| 0ea7c81ce9 | |||
| a550305947 | |||
| 3af4dd5494 |
148
app/build.gradle
148
app/build.gradle
@ -2,24 +2,20 @@ 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"
|
||||
//apply plugin: 'io.sentry.android.gradle'
|
||||
apply plugin: 'AndResGuard'
|
||||
|
||||
import groovy.xml.XmlUtil
|
||||
|
||||
//apply from: 'tinker-support.gradle'
|
||||
|
||||
android {
|
||||
|
||||
androidExtensions {
|
||||
experimental = true
|
||||
}
|
||||
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
viewBinding {
|
||||
enabled = true
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
dataBinding = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
@ -50,7 +46,7 @@ android {
|
||||
}
|
||||
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a"
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
|
||||
renderscriptTargetApi 18
|
||||
@ -65,7 +61,7 @@ android {
|
||||
versionName rootProject.ext.versionName
|
||||
applicationId rootProject.ext.applicationId
|
||||
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-legacy.txt', 'proguard-fresco.txt'
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
|
||||
|
||||
/**
|
||||
* All third-party appid/appkey
|
||||
@ -80,6 +76,8 @@ android {
|
||||
buildConfigField "String", "TTAD_APPID", "\"${TTAD_APPID}\""
|
||||
buildConfigField "String", "DOUYIN_CLIENTKEY", "\"${DOUYIN_CLIENTKEY}\""
|
||||
buildConfigField "String", "DOUYIN_CLIENTSECRET", "\"${DOUYIN_CLIENTSECRET}\""
|
||||
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
|
||||
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
|
||||
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
|
||||
@ -187,7 +185,7 @@ android {
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
|
||||
|
||||
manifestPlaceholders.put("APPLOG_SCHEME","rangersapplog.byAx6uYt".toLowerCase())
|
||||
manifestPlaceholders.put("APPLOG_SCHEME", "rangersapplog.byAx6uYt".toLowerCase())
|
||||
}
|
||||
|
||||
gdt {
|
||||
@ -334,18 +332,18 @@ dependencies {
|
||||
// plugin 需要字符串,故不能用值
|
||||
implementation "io.sentry:sentry-android:3.2.0"
|
||||
|
||||
// implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
|
||||
implementation("com.github.nichbar.BigImageViewer:BigImageViewer:$bigImageViewer", {
|
||||
implementation("com.github.piasy: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 "org.nanohttpd:nanohttpd:$nanohttpd"
|
||||
|
||||
implementation "com.aliyun.openservices:aliyun-log-android-sdk:$aliyunLog"
|
||||
|
||||
implementation project(':libraries:LGLibrary')
|
||||
// implementation project(':libraries:MTA')
|
||||
@ -413,6 +411,72 @@ if (propFile.exists()) {
|
||||
// }.each { t -> t.dependsOn generateMetaJson }
|
||||
//}
|
||||
|
||||
andResGuard {
|
||||
mappingFile = null
|
||||
use7zip = true
|
||||
useSign = true
|
||||
// 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字
|
||||
keepRoot = false
|
||||
// 设置这个值,会把arsc name列混淆成相同的名字,减少string常量池的大小
|
||||
fixedResName = "arg"
|
||||
// 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源
|
||||
mergeDuplicatedRes = true
|
||||
whiteList = [
|
||||
"R.drawable.icon",
|
||||
"R.drawable.bg_notification_answer_style_1",
|
||||
"R.drawable.bg_notification_answer_style_2",
|
||||
"R.drawable.bg_notification_article_style_1",
|
||||
"R.drawable.bg_notification_article_style_2",
|
||||
"R.drawable.bg_notification_feedback_style_1",
|
||||
"R.drawable.bg_notification_feedback_style_2",
|
||||
"R.drawable.bg_notification_gift_style_1",
|
||||
"R.drawable.bg_notification_gift_style_2",
|
||||
"R.drawable.bg_notification_login_style_1",
|
||||
"R.drawable.bg_notification_login_style_2",
|
||||
"R.drawable.bg_notification_question_style_1",
|
||||
"R.drawable.bg_notification_question_style_2",
|
||||
"R.drawable.bg_notification_rating_style_1",
|
||||
"R.drawable.bg_notification_rating_style_2",
|
||||
"R.drawable.bg_notification_reserve_game_style_1",
|
||||
"R.drawable.bg_notification_reserve_game_style_2",
|
||||
"R.drawable.bg_notification_video_style_1",
|
||||
"R.drawable.bg_notification_video_style_2",
|
||||
"R.drawable.ic_search_no_1",
|
||||
"R.drawable.ic_search_no_2",
|
||||
"R.drawable.ic_search_no_3",
|
||||
"R.drawable.ic_search_no_4",
|
||||
"R.drawable.ic_search_no_5",
|
||||
"R.drawable.ic_search_no_6",
|
||||
"R.drawable.ic_search_no_7",
|
||||
"R.drawable.ic_search_no_8",
|
||||
"R.drawable.ic_search_no_9",
|
||||
"R.drawable.ic_search_no_10",
|
||||
"R.drawable.ic_search_no_11",
|
||||
"R.drawable.ic_search_no_12",
|
||||
"R.drawable.ic_search_no_13",
|
||||
"R.drawable.ic_search_no_14",
|
||||
"R.drawable.ic_search_no_15",
|
||||
"R.drawable.ic_search_no_16",
|
||||
"R.drawable.ic_search_no_17",
|
||||
"R.drawable.ic_search_no_18",
|
||||
"R.drawable.ic_search_no_19",
|
||||
"R.drawable.ic_search_no_20",
|
||||
"R.drawable.login_btn_bg",
|
||||
"R.drawable.ic_quick_login_check",
|
||||
"R.drawable.ic_quick_login_uncheck",
|
||||
"R.anim.anim_auth_in",
|
||||
"R.anim.anim_auth_out",
|
||||
]
|
||||
compressFilePattern = [
|
||||
"*.png",
|
||||
"*.jpg",
|
||||
"*.jpeg",
|
||||
"*.gif",
|
||||
]
|
||||
sevenzip {
|
||||
artifact = 'com.tencent.mm:SevenZip:1.2.20'
|
||||
}
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
def variants = null
|
||||
@ -444,36 +508,46 @@ project.afterEvaluate {
|
||||
if (manifestFile == null || !manifestFile.exists()) {
|
||||
return
|
||||
}
|
||||
|
||||
String[] configChanges = [
|
||||
"density",
|
||||
"fontScale",
|
||||
"keyboard",
|
||||
"keyboardHidden",
|
||||
"layoutDirection",
|
||||
"locale",
|
||||
"mcc",
|
||||
"mnc",
|
||||
"navigation",
|
||||
"orientation",
|
||||
"screenLayout",
|
||||
"screenSize",
|
||||
"smallestScreenSize",
|
||||
"touchscreen",
|
||||
"uiMode"]
|
||||
|
||||
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"
|
||||
if (value == null) value = ""
|
||||
configChanges.eachWithIndex { config, index ->
|
||||
if (index != configChanges.length - 1) {
|
||||
value += config + "|"
|
||||
} else {
|
||||
value += config
|
||||
}
|
||||
}
|
||||
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"
|
||||
println configChanges
|
||||
configChanges.eachWithIndex { config, index ->
|
||||
if (!valueSplit.contains(config)) {
|
||||
value += ("|" + config)
|
||||
}
|
||||
}
|
||||
act.attributes()['android:configChanges'] = value
|
||||
}
|
||||
|
||||
Binary file not shown.
BIN
app/libs/quick_login_android_5.8.1.aar
Normal file
BIN
app/libs/quick_login_android_5.8.1.aar
Normal file
Binary file not shown.
@ -55,6 +55,10 @@
|
||||
-dontwarn android.webkit.WebView
|
||||
-dontwarn android.webkit.WebViewClient
|
||||
|
||||
### wechatSdk
|
||||
### TODO 这里用 com.tencent.*{*;} 不起效?但其它地方可以?
|
||||
-keep class com.tencent.**{*;}
|
||||
|
||||
### app models
|
||||
-keep class com.gh.common.view.* {*;}
|
||||
-keep class com.gh.gamecenter.db.info.* {*;}
|
||||
@ -87,22 +91,6 @@
|
||||
@androidx.annotation.Keep *;
|
||||
}
|
||||
|
||||
### 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.* { *; }
|
||||
# If you do not use SQLCipher:
|
||||
-dontwarn org.greenrobot.greendao.database.**
|
||||
|
||||
### fastJson
|
||||
-dontwarn com.alibaba.fastjson.**
|
||||
-keep class com.alibaba.fastjson.* { *; }
|
||||
|
||||
### 广点通
|
||||
-dontwarn com.qq.gdt.action.**
|
||||
-keep class com.qq.gdt.action.* {*;}
|
||||
@ -135,4 +123,12 @@
|
||||
|
||||
### GDT & TEA
|
||||
-keep class com.gh.gamecenter.GdtHelper { *; }
|
||||
-keep class com.gh.gamecenter.TeaHelper { *; }
|
||||
-keep class com.gh.gamecenter.TeaHelper { *; }
|
||||
|
||||
### 阿里云日志
|
||||
-keep class com.aliyun.sls.android.producer.* { *; }
|
||||
-keep interface com.aliyun.sls.android.producer.* { *; }
|
||||
|
||||
### 中国移动一键登录
|
||||
-dontwarn com.cmic.sso.sdk.**
|
||||
-keep class com.cmic.sso.sdk.* { *; }
|
||||
@ -21,14 +21,10 @@
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<!-- 允许应用程序改变Wi-Fi连接状态 -->
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<!-- 允许应用程序打开系统窗口,显示其他应用程序 -->
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<!-- 允许应用程序改变网络连接状态 -->
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<!-- 允许应用程序快捷方式 -->
|
||||
<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"
|
||||
@ -76,6 +72,7 @@
|
||||
android:largeHeap="true"
|
||||
android:resizeableActivity="true"
|
||||
android:theme="@style/AppCompatTheme.APP"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
tools:replace="android:allowBackup"
|
||||
tools:targetApi="n">
|
||||
|
||||
@ -83,6 +80,11 @@
|
||||
android:name="io.sentry.auto-init"
|
||||
android:value="false" />
|
||||
|
||||
<!-- 不让 sentry 读取系统事件 -->
|
||||
<meta-data
|
||||
android:name="io.sentry.breadcrumbs.system-events"
|
||||
android:value="false" />
|
||||
|
||||
<!--android:launchMode = "singleTask"-->
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SplashScreenActivity"
|
||||
@ -609,7 +611,8 @@
|
||||
|
||||
<activity
|
||||
android:name=".energy.EnergyCenterActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
android:screenOrientation="portrait"
|
||||
android:launchMode="singleTask" />
|
||||
|
||||
<activity
|
||||
android:name=".energy.EnergyHouseActivity"
|
||||
@ -623,6 +626,27 @@
|
||||
android:name=".qa.questions.draft.QuestionDraftActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".servers.GameServerTestActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".category2.CategoryV2Activity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".personal.DeliveryInfoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.cmic.sso.sdk.activity.LoginAuthActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:theme="@android:style/Theme.Dialog"
|
||||
android:screenOrientation="portrait"
|
||||
android:launchMode="singleTop">
|
||||
</activity>
|
||||
|
||||
|
||||
<activity
|
||||
android:name=".home.skip.PackageSkipActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -678,6 +702,11 @@
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name="androidx.work.impl.WorkManagerInitializer"
|
||||
android:authorities="${applicationId}.workmanager-init"
|
||||
tools:node="remove" />
|
||||
|
||||
<receiver
|
||||
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
|
||||
android:exported="false">
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@ -13,6 +15,7 @@ import android.os.TransactionTooLargeException;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
@ -27,12 +30,16 @@ import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import com.gh.base.fragment.BaseFragment;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.tracker.IBusiness;
|
||||
import com.gh.common.util.DialogHelper;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.ExtensionsKt;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.NetworkUtils;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.QuickLoginHelper;
|
||||
import com.gh.common.util.RunningUtils;
|
||||
import com.gh.common.util.SPUtils;
|
||||
import com.gh.common.util.ShareUtils;
|
||||
@ -42,11 +49,12 @@ import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.LoginActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.gh.gamecenter.energy.EnergyCenterActivity;
|
||||
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.Util_System_Keyboard;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.tencent.tauth.Tencent;
|
||||
|
||||
@ -59,6 +67,7 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import kotlin.Pair;
|
||||
import pub.devrel.easypermissions.EasyPermissions;
|
||||
|
||||
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
|
||||
@ -69,12 +78,13 @@ import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
|
||||
* 需要工具栏的页面请继承{@link ToolBarActivity}
|
||||
*/
|
||||
|
||||
public abstract class BaseActivity extends BaseAppCompatActivity implements EasyPermissions.PermissionCallbacks {
|
||||
public abstract class BaseActivity extends BaseAppCompatActivity implements EasyPermissions.PermissionCallbacks, IBusiness {
|
||||
|
||||
// global dialog key
|
||||
public final static String DOWNLOAD_HIJACK = "hijack";
|
||||
public final static String LOGIN_EXCEPTION = "loginException";
|
||||
public final static String PLUGGABLE = "plugin";
|
||||
public final static String SIGNATURE_CONFLICT = "signature_conflict";
|
||||
public final static int ID_ROOT_INDICATOR = 999;
|
||||
public final int MAX_BUNDLE_SIZE = 300;
|
||||
|
||||
@ -82,6 +92,10 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
protected String mEntrance;
|
||||
|
||||
private boolean mIsExistLogoutDialog;
|
||||
private boolean mHasAddTaskFloat = false;
|
||||
private View mTaskBackView;
|
||||
private WindowManager mWM;
|
||||
private WindowManager.LayoutParams mWmParams;
|
||||
|
||||
protected final Handler mBaseHandler = new BaseHandler(this);
|
||||
|
||||
@ -144,11 +158,17 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
}
|
||||
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, "");
|
||||
if (downloadEntity != null) {
|
||||
PackageInstaller.install(this, downloadEntity, false);
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.getClass().getName().equals(EnergyCenterActivity.class.getName())) {
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@ -244,13 +264,19 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
if (DOWNLOAD_HIJACK.equals(showDialog.getType())) {
|
||||
DialogUtils.showQqSessionDialog(this);// 建议用户联系客服
|
||||
} else if (PLUGGABLE.equals(showDialog.getType())) {
|
||||
DialogUtils.showPluginDialog(this, () -> {
|
||||
DialogHelper.showPluginDialog(this, () -> {
|
||||
if (FileUtils.isEmptyFile(showDialog.getPath())) {
|
||||
toast(R.string.install_failure_hint);
|
||||
} else {
|
||||
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
|
||||
}
|
||||
return null;
|
||||
});
|
||||
} else if (SIGNATURE_CONFLICT.equals(showDialog.getType())) {
|
||||
DialogHelper.showSignatureConflictDialog(this, () -> {
|
||||
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
|
||||
return null;
|
||||
});
|
||||
} else if (LOGIN_EXCEPTION.equals(showDialog.getType())) {
|
||||
if (mIsExistLogoutDialog) return;
|
||||
mIsExistLogoutDialog = true;
|
||||
@ -262,8 +288,14 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
, StringUtils.buildString("(", model, ")")
|
||||
, "知道了", "重新登录"
|
||||
, null
|
||||
, () -> startActivity(LoginActivity.getIntent(BaseActivity.this,
|
||||
"你的账号已在另外一台设备登录多设备-重新登录"))
|
||||
, () -> {
|
||||
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(BaseActivity.this)) {
|
||||
QuickLoginHelper.startLogin(BaseActivity.this, "你的账号已在另外一台设备登录多设备-重新登录");
|
||||
} else {
|
||||
startActivity(LoginActivity.getIntent(BaseActivity.this,
|
||||
"你的账号已在另外一台设备登录多设备-重新登录"));
|
||||
}
|
||||
}
|
||||
);
|
||||
mBaseHandler.postDelayed(() -> mIsExistLogoutDialog = false, 5000);
|
||||
} catch (Exception e) {
|
||||
@ -276,6 +308,11 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (mWM != null && mTaskBackView != null && mHasAddTaskFloat) {
|
||||
mWM.removeView(mTaskBackView);
|
||||
mHasAddTaskFloat = false;
|
||||
}
|
||||
|
||||
if (isFinishing()) {
|
||||
onFinish();
|
||||
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
|
||||
@ -289,8 +326,87 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (SPUtils.getBoolean(Constants.SP_SHOW_TASK_FLOAT) && !this.getClass().getName().equals(EnergyCenterActivity.class.getName())) {
|
||||
addTaskBackView();
|
||||
mHasAddTaskFloat = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void addTaskBackView() {
|
||||
mWM = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
|
||||
mWmParams = new WindowManager.LayoutParams();
|
||||
mWmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
|
||||
mWmParams.format = PixelFormat.RGBA_8888;
|
||||
mWmParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
|
||||
mWmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
mWmParams.width = DisplayUtils.dip2px(76F);
|
||||
mWmParams.height = DisplayUtils.dip2px(36F);
|
||||
mWmParams.y = SPUtils.getInt(Constants.SP_TASK_FLOAT_LAST_Y, DisplayUtils.dip2px(114F));
|
||||
mTaskBackView = View.inflate(this, R.layout.layout_task_back, null);
|
||||
mTaskBackView.setOnClickListener(v -> {
|
||||
// 如果当前是在键盘输入时,点击"返回任务"要先收起键盘
|
||||
Util_System_Keyboard.hideSoftKeyboard(this);
|
||||
startActivity(EnergyCenterActivity.Companion.getIntent(this));
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
|
||||
mWM.removeView(mTaskBackView);
|
||||
mHasAddTaskFloat = false;
|
||||
});
|
||||
setFloatTouchListener();
|
||||
mWM.addView(mTaskBackView, mWmParams);
|
||||
}
|
||||
|
||||
private void setFloatTouchListener() {
|
||||
int screenHeight = getResources().getDisplayMetrics().heightPixels;
|
||||
|
||||
mTaskBackView.setOnTouchListener(new View.OnTouchListener() {
|
||||
|
||||
private int intervalY;
|
||||
private int startY;
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
final int y = (int) event.getRawY();
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
intervalY = y;
|
||||
startY = y;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mWmParams.y -= (y - intervalY);
|
||||
if (mWmParams.y < 0) {
|
||||
mWmParams.y = 0;
|
||||
}
|
||||
|
||||
if (mWmParams.y > screenHeight) {
|
||||
mWmParams.y = screenHeight;
|
||||
}
|
||||
|
||||
if (mWM != null && mTaskBackView != null && mHasAddTaskFloat) {
|
||||
mWM.updateViewLayout(mTaskBackView, mWmParams);
|
||||
}
|
||||
|
||||
intervalY = y;
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
// 滑动距离少于10视为点击,返回false,否则视为拖动,返回true
|
||||
if (Math.abs(y - startY) <= 10) {
|
||||
return false;
|
||||
} else {
|
||||
// 记录位置
|
||||
SPUtils.setInt(Constants.SP_TASK_FLOAT_LAST_Y, mWmParams.y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 此回调可用于确认当前 activity 已经执行了 finish() 方法并处于 isFinishing 状态
|
||||
*/
|
||||
@ -375,12 +491,31 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
if (preventRecreateFragmentByFragmentManager()) {
|
||||
outState = discardFragmentFromSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
long bundleSize = getBundleSize(outState);
|
||||
if (bundleSize > MAX_BUNDLE_SIZE * 1024) {
|
||||
outState.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否停用 Activity 重建时 FragmentManager 根据 saveState 自动重建保存的 Fragment 的功能
|
||||
*/
|
||||
protected boolean preventRecreateFragmentByFragmentManager() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private Bundle discardFragmentFromSaveInstanceState(Bundle outState) {
|
||||
if (outState != null) {
|
||||
outState.remove("android:support:fragments");
|
||||
}
|
||||
return outState;
|
||||
}
|
||||
|
||||
private long getBundleSize(Bundle bundle) {
|
||||
long dataSize;
|
||||
Parcel obtain = Parcel.obtain();
|
||||
@ -392,4 +527,9 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
}
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<String, String> getBusinessId() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,9 +107,6 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable {
|
||||
Util_System_Keyboard.showSoftKeyboard(this)
|
||||
}, 100)
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable {
|
||||
mRichEditor.scrollTo(0, 1000000)
|
||||
}, 500)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -140,9 +140,8 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
EventBus.getDefault().register(this);
|
||||
|
||||
// For data binding.
|
||||
if (getInflatedLayout() != null) {
|
||||
mCachedView = getInflatedLayout();
|
||||
} else {
|
||||
mCachedView = getInflatedLayout();
|
||||
if (mCachedView == null) {
|
||||
mCachedView = View.inflate(getContext(), getLayoutId(), null);
|
||||
}
|
||||
|
||||
@ -207,6 +206,10 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
if (container != null) {
|
||||
container.removeView(mCachedView);
|
||||
// TODO 页面重建 (framgent 的重新获取) 有大问题,这里只是修修补补
|
||||
if (mCachedView != null && mCachedView.getParent() instanceof ViewGroup) {
|
||||
((ViewGroup) mCachedView.getParent()).removeView(mCachedView);
|
||||
}
|
||||
}
|
||||
return mCachedView;
|
||||
}
|
||||
|
||||
@ -11,12 +11,14 @@ package com.gh.base.fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.gh.gamecenter.normal.NormalFragment;
|
||||
@ -53,19 +55,21 @@ public abstract class BaseFragment_ViewPager extends NormalFragment implements D
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mFragmentsList = new ArrayList<>();
|
||||
initFragmentList(mFragmentsList);
|
||||
mAdapter = BaseFragmentPagerAdapter.newInstance(getChildFragmentManager(), mFragmentsList);
|
||||
final Bundle args = getArguments();
|
||||
if (args != null) {
|
||||
mCheckedIndex = args.getInt(ARGS_INDEX);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mViewPager = (ViewPager) view.findViewById(getViewPagerId());
|
||||
mViewPager = view.findViewById(getViewPagerId());
|
||||
mFragmentsList = restoreFragments();
|
||||
if (mFragmentsList.size() == 0) {
|
||||
initFragmentList(mFragmentsList);
|
||||
}
|
||||
mAdapter = BaseFragmentPagerAdapter.newInstance(getChildFragmentManager(), mFragmentsList);
|
||||
final Bundle args = getArguments();
|
||||
if (args != null) {
|
||||
mCheckedIndex = args.getInt(ARGS_INDEX);
|
||||
}
|
||||
mViewPager.setOffscreenPageLimit(mFragmentsList.size());
|
||||
mViewPager.setAdapter(mAdapter);
|
||||
if (mCheckedIndex < mFragmentsList.size()) {
|
||||
@ -116,9 +120,24 @@ public abstract class BaseFragment_ViewPager extends NormalFragment implements D
|
||||
fragment.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ArrayList<Fragment> restoreFragments() {
|
||||
String tag = "android:switcher:" + mViewPager.getId() + ":";
|
||||
ArrayList<Fragment> fragments = new ArrayList<>();
|
||||
int childCount = getChildCount();
|
||||
for (int index = 0; index < childCount; index++) {
|
||||
Fragment fragment = getChildFragmentManager().findFragmentByTag(tag + index);
|
||||
if (fragment != null) {
|
||||
fragments.add(fragment);
|
||||
}
|
||||
}
|
||||
|
||||
return fragments;
|
||||
}
|
||||
|
||||
public abstract int getChildCount();
|
||||
|
||||
public int getCurrentItem() {
|
||||
return mViewPager != null ? mViewPager.getCurrentItem() : 0;
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ package com.gh.base.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import com.gh.gamecenter.normal.NormalFragment
|
||||
import com.lightgame.utils.Utils
|
||||
|
||||
/**
|
||||
* 懒加载(支持多层嵌套)
|
||||
@ -105,15 +104,25 @@ abstract class BaseLazyFragment : NormalFragment() {
|
||||
isSupportVisible = visible
|
||||
|
||||
if (visible) {
|
||||
if (mIsFirstVisible && view != null) {
|
||||
|
||||
// TODO 当 fragment 重建时这里的被调用很奇怪,onActivityCreated 回调触发,但此时的 view 是空的,原因是 createView 还没被调用
|
||||
// TODO 这样就造成了 onFragmentResume 里可能用到 view 的地方出现空指针异常,所以这里遇到 view 为空的时候 return 等下一次被调用才进去
|
||||
if (view == null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (mIsFirstVisible) {
|
||||
mIsFirstVisible = false
|
||||
onFragmentFirstVisible()
|
||||
}
|
||||
onFragmentResume()
|
||||
dispatchChildVisibleState(true)
|
||||
} else {
|
||||
dispatchChildVisibleState(false)
|
||||
onFragmentPause()
|
||||
// 当 fragment 重建时,这个代码块可能在第一次 view 为空的 visible 后调用导致在 onFragmentPause 里可能用到 view 的地方出现空指针异常
|
||||
if (!mIsFirstVisible) {
|
||||
dispatchChildVisibleState(false)
|
||||
onFragmentPause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
68
app/src/main/java/com/gh/base/fragment/LazyFragment.kt
Normal file
68
app/src/main/java/com/gh/base/fragment/LazyFragment.kt
Normal file
@ -0,0 +1,68 @@
|
||||
package com.gh.base.fragment
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewStub
|
||||
import com.gh.gamecenter.R
|
||||
|
||||
/**
|
||||
* 这是在 BaseLazyFragment 之上添加了一些通用功能的抽象类
|
||||
*
|
||||
* 怎么将一个已有的 fragment 转化为懒加载 (延迟渲染) 的 fragment 呢?
|
||||
* (继承 ListFragment 的类请改为继承 LazyListFragment)
|
||||
*
|
||||
* 0. 删掉旧的 getInflatedLayout() 的代码,现在由 getLayoutId() 提供 Stub 布局 (默认为 R.layout.fragment_stub,若重写请注意提供 id 为 stub 的 ViewStub)
|
||||
* 1. 重写 getRealLayoutId(),提供实际要延迟渲染的 layout Id
|
||||
* 1. 将原有在 onCreate() 的代码移动到 onFragmentFirstVisible()
|
||||
* 2. 将原有在 onViewCreated() 的代码移动到 initRealView()
|
||||
* (注意,initRealView() 在 onFragmentFirstVisible() 中被调用,如果要初始化 viewModel 等非 UI 对象请在 super.onFragmentVisible() 调用)
|
||||
* 3. 如需使用 ViewBinding ,在 onRealLayoutInflated() 的回调中初始化 ViewBinding 即可
|
||||
* 4. onResume() 的代码移动到 onFragmentResume(),onPause() 的代码移动到 onFragmentPause()
|
||||
* 5. Done!
|
||||
*/
|
||||
abstract class LazyFragment : BaseLazyFragment() {
|
||||
|
||||
// ViewStub + ViewBinding 有莫名的 bug,语法上没问题,但编译时通不过。
|
||||
private var mViewStub: ViewStub? = null
|
||||
|
||||
override fun getLayoutId() = R.layout.fragment_stub
|
||||
|
||||
override fun useButterKnife() = false
|
||||
|
||||
override fun initView(view: View?) {
|
||||
super.initView(view)
|
||||
mViewStub = mCachedView.findViewById(R.id.stub)
|
||||
}
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
super.onFragmentFirstVisible()
|
||||
inflateRealView()
|
||||
initRealView()
|
||||
}
|
||||
|
||||
/**
|
||||
* 真正 inflate View 的地方
|
||||
*/
|
||||
protected open fun inflateRealView() {
|
||||
mViewStub?.layoutResource = getRealLayoutId()
|
||||
mViewStub?.setOnInflateListener { _, inflatedView -> onRealLayoutInflated(inflatedView) }
|
||||
mCachedView = mViewStub?.inflate()
|
||||
}
|
||||
|
||||
/**
|
||||
* 请在这个方法之后获取初始化后的各种 view
|
||||
*
|
||||
* 替换旧 fragment 实现时,等同于 onViewCreated
|
||||
*/
|
||||
protected open fun initRealView() {}
|
||||
|
||||
/**
|
||||
* 提供要 stub inflate 的 layout
|
||||
*/
|
||||
protected abstract fun getRealLayoutId(): Int
|
||||
|
||||
/**
|
||||
* 真实 layout inflate 完成的回调,可用于 viewBinding
|
||||
*/
|
||||
protected open fun onRealLayoutInflated(inflatedView: View) {}
|
||||
|
||||
}
|
||||
@ -8,18 +8,22 @@ import androidx.annotation.Keep
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.base.CurrentActivityHolder
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.loghub.LoghubUtils
|
||||
import com.gh.common.tracker.Tracker
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.view.dsbridge.CompletionHandler
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.ImageViewerActivity
|
||||
import com.gh.gamecenter.LoginActivity
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.energy.EnergyCenterActivity
|
||||
import com.gh.gamecenter.energy.EnergyHouseActivity
|
||||
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.help.QaFeedbackDialogFragment
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.security.BindPhoneActivity
|
||||
@ -66,8 +70,12 @@ class DefaultJsApi(var context: Context) {
|
||||
|
||||
@JavascriptInterface
|
||||
fun login(msg: Any) {
|
||||
val intent = LoginActivity.getIntent(context, "浏览器")
|
||||
context.startActivity(intent)
|
||||
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
|
||||
QuickLoginHelper.startLogin(context, "浏览器")
|
||||
} else {
|
||||
val intent = LoginActivity.getIntent(context, "浏览器")
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -219,7 +227,7 @@ class DefaultJsApi(var context: Context) {
|
||||
|
||||
@JavascriptInterface
|
||||
fun showIncompatibleVersionDialog(msg: Any) {
|
||||
DialogUtils.showLowVersionDialog(context)
|
||||
DialogHelper.showUpgradeDialog(context)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -240,7 +248,7 @@ class DefaultJsApi(var context: Context) {
|
||||
Base64ImageHolder.image = inviteEvent.poster.run {
|
||||
if (this.startsWith("data:image/png;base64")) this.split(",")[1] else this
|
||||
}
|
||||
MessageShareUtils.getInstance(context).shareFromWeb(context, inviteEvent.way)
|
||||
MessageShareUtils.getInstance(context).shareInviteFriends(context, inviteEvent.way)
|
||||
} else {
|
||||
ShareUtils.getInstance(context).shareInviteFriends(context, inviteEvent.url, inviteEvent.way)
|
||||
}
|
||||
@ -290,6 +298,50 @@ class DefaultJsApi(var context: Context) {
|
||||
context.startActivity(EnergyHouseActivity.getIntent(context))
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun showQaFeedbackDialog(msg: Any) {
|
||||
QaFeedbackDialogFragment.show(context as AppCompatActivity, msg.toString())
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getMetaObject(msg: Any): String {
|
||||
return LogUtils.getMetaObject().toString()
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getLaunchId(msg: Any): String {
|
||||
return Tracker.launchId
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getSessionId(msg: Any): String {
|
||||
return Tracker.sessionId
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun postLogEvent(event: Any) {
|
||||
val logEvent = event.toString().toObject() ?: LogEvent()
|
||||
debugOnly {
|
||||
Utils.log("LogUtils->${logEvent.jsonString}")
|
||||
}
|
||||
LoghubUtils.log(logEvent.jsonString, logEvent.logStore, false)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun startAvatarBorderPage(msg: Any) {
|
||||
context.startActivity(AvatarBorderActivity.getIntent(context, msg.toString()))
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun isNetworkConnected(): Boolean {
|
||||
return NetworkUtils.isNetworkConnected(context)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun isWifiConnected(): Boolean {
|
||||
return NetworkUtils.isWifiConnected(context)
|
||||
}
|
||||
|
||||
@Keep
|
||||
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)
|
||||
|
||||
@ -302,4 +354,6 @@ class DefaultJsApi(var context: Context) {
|
||||
var url: String = "",
|
||||
var poster: String = "")
|
||||
|
||||
@Keep
|
||||
internal data class LogEvent(var jsonString: String = "", var logStore: String = "")
|
||||
}
|
||||
|
||||
@ -287,6 +287,7 @@ object DefaultUrlHandler {
|
||||
val platformName = PlatformUtils.getInstance(context).getPlatformName(platform)
|
||||
val gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID)
|
||||
val packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5)
|
||||
val isQaFeedback = uri.getQueryParameter(EntranceUtils.KEY_IS_QA_FEEDBACK) == "true"
|
||||
val content = if (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) String.format("%s-%s-V%s,",
|
||||
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
|
||||
if (TextUtils.isEmpty(platformName)) platform else platformName,
|
||||
@ -299,7 +300,7 @@ object DefaultUrlHandler {
|
||||
if (!TextUtils.isEmpty(qaId)) {
|
||||
directToQa(context, qaTitle, qaId)
|
||||
} else {
|
||||
directToFeedback(context, content, EntranceUtils.ENTRANCE_BROWSER)
|
||||
directToFeedback(context, content, null, isQaFeedback, EntranceUtils.ENTRANCE_BROWSER)
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,7 +308,7 @@ object DefaultUrlHandler {
|
||||
val position = uri.getQueryParameter("position") ?: ""
|
||||
DirectUtils.directToHelpAndFeedback(context, position.toInt())
|
||||
}
|
||||
else -> DialogUtils.showLowVersionDialog(context)
|
||||
else -> DialogHelper.showUpgradeDialog(context)
|
||||
}
|
||||
return true
|
||||
} else if ("zhiqu" == uri.scheme) {
|
||||
@ -365,7 +366,8 @@ object DefaultUrlHandler {
|
||||
uri.path?.apply {
|
||||
when {
|
||||
contains("game") -> {
|
||||
val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last() ?: ""
|
||||
val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last()
|
||||
?: ""
|
||||
DirectUtils.directToGameDetail(context, gameId, entrance, autoDownload = false, traceEvent = null)
|
||||
}
|
||||
contains("question") -> {
|
||||
@ -377,11 +379,12 @@ object DefaultUrlHandler {
|
||||
DirectUtils.directToAnswerDetail(context, answerId, entrance, "")
|
||||
}
|
||||
}
|
||||
contains("communities") && contains("article") -> {
|
||||
((contains("bbs")) && contains("article") ||
|
||||
(contains("communities")) && contains("article")) -> {
|
||||
var communityId = ""
|
||||
var type = ""
|
||||
var typeId = ""
|
||||
val split = replace("/communities", "").replace(".html", "").split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
val split = replace("/communities", "").replace("/bbs", "").replace(".html", "").split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
for (text in split) {
|
||||
if (TextUtils.isEmpty(communityId)) {
|
||||
communityId = text
|
||||
@ -395,7 +398,7 @@ object DefaultUrlHandler {
|
||||
typeId = text
|
||||
}
|
||||
}
|
||||
if ("articles" == type) {
|
||||
if ("articles" == type || "article" == type) {
|
||||
DirectUtils.directToCommunityArticle(
|
||||
context, typeId, communityId,
|
||||
entrance, "文章链接")
|
||||
@ -403,7 +406,11 @@ object DefaultUrlHandler {
|
||||
}
|
||||
contains("article") -> {
|
||||
val articleId = split("/")[2].replace(".html", "")
|
||||
DirectUtils.directToArticle(context, articleId, entrance)
|
||||
if (entrance == "隐私政策") {
|
||||
DirectUtils.directToArticle(context, articleId, true, entrance)
|
||||
} else {
|
||||
DirectUtils.directToArticle(context, articleId, entrance)
|
||||
}
|
||||
}
|
||||
contains("columns") -> {
|
||||
val columnsId = split("/")[3]
|
||||
|
||||
@ -2,6 +2,7 @@ package com.gh.common.constant;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
@ -11,9 +12,11 @@ import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.SPUtils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.SuggestionActivity;
|
||||
import com.gh.gamecenter.entity.NewSettingsEntity;
|
||||
import com.gh.gamecenter.entity.NewsEntity;
|
||||
import com.gh.gamecenter.entity.SettingsEntity;
|
||||
import com.gh.gamecenter.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.retrofit.BiResponse;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.halo.assistant.HaloApp;
|
||||
@ -52,15 +55,18 @@ public class Config {
|
||||
public static final String TTAD_APPID = BuildConfig.TTAD_APPID;
|
||||
public static final String DOUYIN_CLIENTKEY = BuildConfig.DOUYIN_CLIENTKEY;
|
||||
public static final String DOUYIN_CLIENTSECRET = BuildConfig.DOUYIN_CLIENTSECRET;
|
||||
public static final String QUICK_LOGIN_APPID = BuildConfig.QUICK_LOGIN_APPID;
|
||||
public static final String QUICK_LOGIN_APPKEY = BuildConfig.QUICK_LOGIN_APPKEY;
|
||||
// http://www.ghzs666.com/article/${articleId}.html
|
||||
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 = "test2";
|
||||
public static final String DEFAULT_CHANNEL = "GH_TEST2";
|
||||
|
||||
private static String SETTINGS_KEY = "settingsKey";
|
||||
|
||||
private static SettingsEntity mSettingsEntity;
|
||||
private static NewSettingsEntity mNewSettingsEntity;
|
||||
|
||||
public static final String FIX_DOWNLOAD_KEY = "isFixDownload";
|
||||
public static final String FIX_PLUGIN_KEY = "isFixPlugin";
|
||||
@ -203,6 +209,21 @@ public class Config {
|
||||
return mSettingsEntity;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static NewSettingsEntity getNewSettingsEntity() {
|
||||
if (mNewSettingsEntity == null) {
|
||||
try {
|
||||
String json = SPUtils.getString(Constants.SP_NEW_SETTINGS);
|
||||
if (!TextUtils.isEmpty(json)) {
|
||||
mNewSettingsEntity = GsonUtils.fromJson(json, NewSettingsEntity.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return mNewSettingsEntity;
|
||||
}
|
||||
|
||||
private static boolean isExistDownloadFilter() {
|
||||
if (getSettings() == null || getSettings().getDownload() == null || getSettings().getDownload().size() == 0) {
|
||||
return false;
|
||||
@ -278,5 +299,17 @@ public class Config {
|
||||
EventBus.getDefault().post(new EBReuse("Refresh"));
|
||||
}
|
||||
});
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
|
||||
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BiResponse<NewSettingsEntity>() {
|
||||
@Override
|
||||
public void onSuccess(NewSettingsEntity data) {
|
||||
mNewSettingsEntity = data;
|
||||
SPUtils.setString(Constants.SP_NEW_SETTINGS, GsonUtils.toJson(data));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,9 +32,11 @@ public class Constants {
|
||||
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";
|
||||
|
||||
public static final String EB_GAME_DETAIL = "eb_game_detail";
|
||||
|
||||
// 用于避免历史下载影响到部分依赖名字作为数据更新条件的修饰符
|
||||
public static final String GAME_NAME_DECORATOR = " ";
|
||||
|
||||
@ -51,6 +53,8 @@ public class Constants {
|
||||
public static final String RAW_GAME_ICON = "raw_game_icon";
|
||||
public static final String GAME_ICON_SUBSCRIPT = "game_icon_subscript";
|
||||
|
||||
public static final String IS_PLATFORM_RECOMMEND = "isPlatformRecommend";
|
||||
|
||||
// 下载 id,一般来说跟下载文件名一样
|
||||
public static final String DOWNLOAD_ID = "download_id";
|
||||
|
||||
@ -70,7 +74,7 @@ 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";
|
||||
|
||||
//引导设置 “通知管理” 引导弹窗
|
||||
@ -146,6 +150,23 @@ public class Constants {
|
||||
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_RECOMMEND_POPUP = "recommend_popup";
|
||||
|
||||
|
||||
// 使用浏览器安装开关
|
||||
public static final String SP_USE_BROWSER_TO_INSTALL = "use_browser_to_install";
|
||||
// 游戏详情页底部使用浏览器安装提示
|
||||
public static final String SP_SHOULD_SHOW_GAMEDETAIL_USE_BROWSER_TO_INSTALL_HINT = "should_show_gamedetail_use_browser_to_install_hint";
|
||||
// 第一次普通安装推荐使用浏览器安装提示
|
||||
public static final String SP_SHOULD_SHOW_USE_BROWSER_TO_INSTALL_HINT = "should_show_use_browser_to_install_hint";
|
||||
|
||||
//模拟器管理引导
|
||||
public static final String SP_SIMULATOR_GUIDE = "simulator_guide";
|
||||
//模拟器游戏引导
|
||||
public static final String SP_SIMULATOR_GAME_GUIDE = "simulator_game_guide";
|
||||
|
||||
|
||||
//首页视频播放进度
|
||||
public static final String SP_HOME_VIDEO_PLAY_RECORD = "home_video_play_record";
|
||||
|
||||
@ -155,8 +176,22 @@ public class Constants {
|
||||
// 是否已经填写邀请码
|
||||
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 SP_NEW_SETTINGS = "new_settings";
|
||||
|
||||
// 头像挂件ID
|
||||
public static final String SP_CHOOSE_AVATAR_ID = "choose_avatar_id";
|
||||
|
||||
// 是否显示返回任务悬浮图标
|
||||
public static final String SP_SHOW_TASK_FLOAT = "show_task_float";
|
||||
// 悬浮图标Y值
|
||||
public static final String SP_TASK_FLOAT_LAST_Y = "task_float_last_y";
|
||||
|
||||
// 是否第一次进入新分类2.0
|
||||
public static final String SP_FIRST_ENTER_CATEGORY_V2 = "first_enter_category_v2";
|
||||
|
||||
// 是否成功取过号
|
||||
public static final String SP_HAS_GET_PHONE_INFO = "has_get_phone_info";
|
||||
|
||||
//手机号码匹配规则
|
||||
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
|
||||
@ -200,8 +235,8 @@ public class Constants {
|
||||
public static final String HELP_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=";
|
||||
|
||||
// 注销页面
|
||||
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 LOGOUT_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_help_dev/help.html?content=5f6b1f02786564003944a693&from=ghzs";
|
||||
public static final String LOGOUT_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=5f534111b1f72909fc225672&from=ghzs";
|
||||
|
||||
// 商品详情
|
||||
public static final String COMMODITY_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/product?from=ghzs";
|
||||
@ -221,12 +256,48 @@ public class Constants {
|
||||
|
||||
// 邀请好友
|
||||
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 INVITE_FRIENDS_ADDRESS = "https://static-web.ghzs.com/ghzs_activity_prod/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 String EXCHANGE_RULE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/exchange-rule?from=ghzs";
|
||||
public static final String EXCHANGE_RULE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/exchange-rule?from=ghzs";
|
||||
|
||||
// 光能规则
|
||||
public static final String ENERGY_RULE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/energy-rule?from=ghzs";
|
||||
public static final String ENERGY_RULE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/energy-rule?from=ghzs";
|
||||
|
||||
// 兑换商品
|
||||
public static final String EXCHANGE_COMMODITY_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/exchange-log?from=ghzs";
|
||||
public static final String EXCHANGE_COMMODITY_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/exchange-log?from=ghzs";
|
||||
|
||||
// 抽奖乐园
|
||||
public static final String LOTTERY_PARADISE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/lottery-list?from=ghzs";
|
||||
public static final String LOTTERY_PARADISE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/lottery-list?from=ghzs";
|
||||
|
||||
// 我的奖品
|
||||
public static final String MY_PRIZE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/mywin?from=ghzs";
|
||||
public static final String MY_PRIZE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/mywin?from=ghzs";
|
||||
|
||||
// 中奖订单详情
|
||||
public static final String WIN_ORDER_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/win-order-detail?from=ghzs";
|
||||
public static final String WIN_ORDER_DETAIL_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/win-order-detail?from=ghzs";
|
||||
|
||||
// 地址信息
|
||||
public static final String ADDRESS_INFO_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/address-list?from=ghzs";
|
||||
public static final String ADDRESS_INFO_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/address-list?from=ghzs";
|
||||
|
||||
// 领奖信息
|
||||
public static final String PRIZE_INFO_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/user-info?from=ghzs";
|
||||
public static final String PRIZE_INFO_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/user-info?from=ghzs";
|
||||
|
||||
// 提现信息
|
||||
public static final String WITHDRAW_INFO_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/cash?from=ghzs";
|
||||
public static final String WITHDRAW_INFO_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/cash?from=ghzs";
|
||||
|
||||
//最少需要多少数据才能上传
|
||||
public static final int DATA_AMOUNT = 20;
|
||||
|
||||
|
||||
@ -46,12 +46,14 @@ import com.gh.common.util.NumberUtils;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.PlatformUtils;
|
||||
import com.gh.common.util.RealNameHelper;
|
||||
import com.gh.common.util.ReservationHelper;
|
||||
import com.gh.common.view.DownloadProgressBar;
|
||||
import com.gh.common.view.DrawableView;
|
||||
import com.gh.common.view.GameIconView;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.download.dialog.DownloadDialog;
|
||||
import com.gh.download.server.BrowserInstallHelper;
|
||||
import com.gh.gamecenter.DownloadManagerActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.WebActivity;
|
||||
@ -66,6 +68,7 @@ import com.gh.gamecenter.entity.ServerCalendarEntity;
|
||||
import com.gh.gamecenter.entity.TagStyleEntity;
|
||||
import com.gh.gamecenter.entity.TestEntity;
|
||||
import com.gh.gamecenter.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.gh.gamecenter.qa.entity.CommunityVideoEntity;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
@ -456,27 +459,37 @@ public class BindingAdapters {
|
||||
return;
|
||||
}
|
||||
}
|
||||
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));
|
||||
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
|
||||
BrowserInstallHelper.showBrowserInstallHintDialog(v.getContext(), () -> {
|
||||
PackageCheckDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, () -> {
|
||||
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));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location + ":" + gameEntity.getName());
|
||||
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
|
||||
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location + ":" + gameEntity.getName());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -518,12 +531,16 @@ public class BindingAdapters {
|
||||
}
|
||||
break;
|
||||
case RESERVABLE:
|
||||
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
|
||||
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
updateReservation(progressBar, gameEntity);
|
||||
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
|
||||
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
|
||||
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
updateReservation(progressBar, gameEntity);
|
||||
});
|
||||
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
|
||||
});
|
||||
});
|
||||
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
|
||||
});
|
||||
break;
|
||||
case RESERVED:
|
||||
@ -550,8 +567,10 @@ public class BindingAdapters {
|
||||
HistoryHelper.insertGameEntity(gameEntity);
|
||||
}
|
||||
|
||||
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton()));
|
||||
progressBar.getContext().startActivity(i);
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
|
||||
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton()));
|
||||
progressBar.getContext().startActivity(i);
|
||||
});
|
||||
break;
|
||||
case UPDATING:
|
||||
Utils.toast(progressBar.getContext(), "正在加急更新版本,敬请后续留意");
|
||||
@ -731,7 +750,9 @@ public class BindingAdapters {
|
||||
try {
|
||||
ArrayList<TagStyleEntity> tagStyle = new ArrayList<>();
|
||||
TestEntity test = gameEntity.getTest();
|
||||
if (test != null) {
|
||||
if (test != null
|
||||
// 这个判断用于开测表列表
|
||||
&& !"type_tag".equals(test.getGameTag())) {
|
||||
TagStyleEntity typeTag = new TagStyleEntity();
|
||||
typeTag.setName(test.getType() != null ? test.getType() : "");
|
||||
typeTag.setBackground("FFF3E0");
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.R
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
abstract class BaseDraggableDialogFragment : BaseDialogFragment(), View.OnTouchListener {
|
||||
private var mInitPositionY = 0f
|
||||
private lateinit var mGestureDetector: GestureDetector
|
||||
private lateinit var mRootView: View
|
||||
private lateinit var mDragCloseView: View
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mRootView = getRootView()
|
||||
mDragCloseView = getDragCloseView()
|
||||
mDragCloseView.setOnTouchListener(this)
|
||||
mGestureDetector = GestureDetector(requireContext(), SingleTapConfirm())
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val createDialog = super.onCreateDialog(savedInstanceState)
|
||||
createDialog.setCanceledOnTouchOutside(true)
|
||||
|
||||
val window = createDialog.window
|
||||
window?.setGravity(Gravity.BOTTOM)
|
||||
window?.setWindowAnimations(R.style.community_publication_animation)
|
||||
return createDialog
|
||||
}
|
||||
|
||||
// dialog drag animation
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
||||
if (mGestureDetector.onTouchEvent(event) && mRootView.y == 0F) {
|
||||
v.performClick()
|
||||
return true
|
||||
}
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
mInitPositionY = mRootView.y - event.rawY
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
val offsetY = event.rawY + mInitPositionY
|
||||
val dialogY = mRootView.y
|
||||
if (dialogY + offsetY > 0) {
|
||||
mRootView.animate()
|
||||
.y(offsetY)
|
||||
.setDuration(0)
|
||||
.start()
|
||||
} else {
|
||||
resetDialogPosition()
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_CANCEL,
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_OUTSIDE -> {
|
||||
if (mRootView.y >= mRootView.height / 2) {
|
||||
dismissAllowingStateLoss()
|
||||
} else {
|
||||
resetDialogPosition(300)
|
||||
}
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun resetDialogPosition(duration: Long = 0) {
|
||||
mRootView.animate()
|
||||
.y(0F)
|
||||
.setDuration(duration)
|
||||
.start()
|
||||
}
|
||||
|
||||
private class SingleTapConfirm : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onSingleTapUp(event: MotionEvent): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val width = HaloApp.getInstance().application.resources.displayMetrics.widthPixels
|
||||
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
dialog?.window?.setLayout(width, height)
|
||||
}
|
||||
|
||||
abstract fun getRootView(): View
|
||||
abstract fun getDragCloseView(): View
|
||||
override fun getThemeRes(): Int = R.style.DialogFragmentDimAmount
|
||||
}
|
||||
@ -60,26 +60,36 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
|
||||
companion object {
|
||||
fun showDeviceRemindDialog(context: Context, gameEntity: GameEntity) {
|
||||
val datas = SPUtils.getString(Constants.SP_DEVICE_REMIND)
|
||||
if (datas.isNotEmpty()) {
|
||||
val pair = shouldShowDeviceRemindDialog(gameEntity)
|
||||
if (pair.first) {
|
||||
val dialog = DeviceRemindDialog(context, pair.second!!, gameEntity)
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldShowDeviceRemindDialog(gameEntity: GameEntity): Pair<Boolean, DeviceDialogEntity?> {
|
||||
val datas = SPUtils.getString(Constants.SP_DEVICE_REMIND)
|
||||
if (datas.isNotEmpty()) {
|
||||
val type = object : TypeToken<List<DeviceDialogEntity>>() {}.type
|
||||
val entitys = GsonUtils.gson.fromJson<List<DeviceDialogEntity>>(datas, type)
|
||||
val entities = GsonUtils.gson.fromJson<List<DeviceDialogEntity>>(datas, type)
|
||||
//1.判断设备是否匹配
|
||||
val entity = entitys.find { it.manufacturer.toLowerCase().startsWith(Build.MANUFACTURER.toLowerCase()) }
|
||||
?: return
|
||||
val entity = entities.find { it.manufacturer.toLowerCase().startsWith(Build.MANUFACTURER.toLowerCase()) }
|
||||
?: return Pair(false, null)
|
||||
//2.判断游戏不含剔除标签
|
||||
gameEntity.tagStyle.forEach {
|
||||
if (entity.excludeTags.contains(it.name)) {
|
||||
return
|
||||
return Pair(false, null)
|
||||
}
|
||||
}
|
||||
//3.不再弹出提示判断
|
||||
val isNoRemindAgain = SPUtils.getBoolean(Constants.SP_NO_REMIND_AGAIN, false)
|
||||
if (isNoRemindAgain) return
|
||||
|
||||
val dialog = DeviceRemindDialog(context, entity, gameEntity)
|
||||
dialog.show()
|
||||
if (isNoRemindAgain) return Pair(false, null)
|
||||
return Pair(true, entity)
|
||||
}
|
||||
return Pair(false, null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,14 +9,14 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
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.dip2px
|
||||
import com.gh.common.util.toColor
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.DialogGameOffServiceBinding
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import kotlinx.android.synthetic.main.dialog_game_off_service.*
|
||||
|
||||
// 游戏关闭下载弹窗
|
||||
class GameOffServiceDialogFragment
|
||||
@ -24,34 +24,47 @@ class GameOffServiceDialogFragment
|
||||
: BaseDialogFragment() {
|
||||
|
||||
private var mDialog: GameEntity.Dialog? = null
|
||||
private var mBinding: DialogGameOffServiceBinding? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.dialog_game_off_service, null)
|
||||
return DialogGameOffServiceBinding
|
||||
.inflate(inflater)
|
||||
.apply { mBinding = this }
|
||||
.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
mDialog?.run {
|
||||
titleTv.text = title
|
||||
contentTv.text = HtmlCompat.fromHtml(content, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||
|
||||
for (site in sites) {
|
||||
val siteTv = TextView(context)
|
||||
siteTv.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
|
||||
topMargin = DisplayUtils.dip2px(12f)
|
||||
}
|
||||
siteTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f)
|
||||
siteTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.theme_font))
|
||||
siteTv.text = site.text
|
||||
siteTv.paintFlags = siteTv.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
siteTv.setOnClickListener {
|
||||
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
|
||||
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
|
||||
mBinding?.run {
|
||||
mDialog?.run {
|
||||
titleTv.text = title
|
||||
contentTv.text = HtmlCompat.fromHtml(content, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||
okTv.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
container.addView(siteTv)
|
||||
// 过滤内容为空的元素
|
||||
val notEmptySite = sites.filter { it.text.isNotBlank() }
|
||||
|
||||
notEmptySite.forEachIndexed { index, site ->
|
||||
val siteTv = TextView(context)
|
||||
siteTv.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
|
||||
topMargin = 24F.dip2px()
|
||||
if (index == notEmptySite.size - 1) bottomMargin = 8F.dip2px()
|
||||
}
|
||||
siteTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14F)
|
||||
siteTv.setTextColor(R.color.theme_font.toColor())
|
||||
siteTv.text = site.text
|
||||
siteTv.paintFlags = siteTv.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
siteTv.setOnClickListener {
|
||||
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
|
||||
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
container.addView(siteTv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageInfo
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
@ -17,15 +19,21 @@ 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.download.DownloadManager
|
||||
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.GameEntity
|
||||
import com.gh.gamecenter.entity.LinkEntity
|
||||
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 com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus
|
||||
import io.reactivex.disposables.Disposable
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
@ -34,6 +42,7 @@ import org.greenrobot.eventbus.ThreadMode
|
||||
/**
|
||||
* 包名检测弹窗
|
||||
*/
|
||||
// TODO 将 gameEntity 放到 argument 里再取出,避免重建时为空
|
||||
class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
|
||||
private lateinit var binding: FragmentPackageCheckBinding
|
||||
@ -41,12 +50,33 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
private val mDuration = 3000
|
||||
private var mDisposable: Disposable? = null
|
||||
private var mAdapter: PackageCheckAdapter? = null
|
||||
var packageDialogEntity: PackageDialogEntity? = null
|
||||
private var mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
|
||||
var gameEntity: GameEntity? = null
|
||||
var callBack: DialogUtils.ConfirmListener? = null
|
||||
|
||||
private val dataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
val packageName = downloadEntity.packageName
|
||||
val detectionObjects = gameEntity?.packageDialog?.detectionObjects
|
||||
if (DownloadStatus.add == downloadEntity.status || DownloadStatus.done == downloadEntity.status) {
|
||||
detectionObjects?.forEach { detectionObject ->
|
||||
if (detectionObject.packages.contains(packageName)) {
|
||||
val packageLink = gameEntity?.packageDialog?.links?.find { it.buttonLink }
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_download", if (DownloadStatus.add == downloadEntity.status) "下载开始" else "下载完成",
|
||||
gameEntity, packageLink?.text ?: "", packageLink?.title
|
||||
?: "", downloadEntity.gameId, downloadEntity.getMetaExtra(Constants.GAME_NAME))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
EventBus.getDefault().register(this)
|
||||
gameEntity?.let {
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "出现弹窗", it, "", "", "", "")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
@ -56,7 +86,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
packageDialogEntity?.let {
|
||||
gameEntity?.packageDialog?.let {
|
||||
changeParams(it.detectionObjects.size)
|
||||
|
||||
binding.packageRv.layoutManager = LinearLayoutManager(requireContext())
|
||||
@ -70,6 +100,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
it.links.forEachIndexed { index, link ->
|
||||
val linkSpan = SpanBuilder(link.title ?: "").click(0, (link.title
|
||||
?: "").length, R.color.theme_font, true) {
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "点击链接", gameEntity, link.text, link.title, "", "")
|
||||
DirectUtils.directToLinkPage(requireContext(), link, "包名检测弹窗", "")
|
||||
}.build()
|
||||
spanBuilder.append(linkSpan)
|
||||
@ -89,6 +120,10 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
binding.cancelTv.text = "我知道了"
|
||||
binding.noRemindAgainCb.visibility = View.GONE
|
||||
}
|
||||
"OPTIONAL_CURRENT_HINT" -> {
|
||||
binding.cancelTv.text = "我知道了"
|
||||
binding.noRemindAgainCb.visibility = View.VISIBLE
|
||||
}
|
||||
else -> {
|
||||
binding.cancelTv.text = "我知道了"
|
||||
binding.noRemindAgainCb.visibility = View.VISIBLE
|
||||
@ -96,7 +131,9 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
initListener(it)
|
||||
}
|
||||
checkPackage()
|
||||
binding.root.post {
|
||||
checkPackage()
|
||||
}
|
||||
}
|
||||
|
||||
private fun changeParams(size: Int) {
|
||||
@ -108,15 +145,19 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
private fun initListener(entity: PackageDialogEntity) {
|
||||
binding.downloadBtn.setOnClickListener {
|
||||
if (binding.noRemindAgainCb.isChecked) {
|
||||
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity?.id}", true)
|
||||
saveRecord(entity)
|
||||
}
|
||||
val isAllPackageInstalled = isAllPackageInstalled(entity)
|
||||
val isAllPackageInstalled = isAllPackageInstalled(mAllInstalledPackages, entity)
|
||||
if (isAllPackageInstalled) {
|
||||
callBack?.onConfirm()
|
||||
dismissAllowingStateLoss()
|
||||
} else {
|
||||
val packageLink = entity.links.find { it.buttonLink }
|
||||
var packageLink = getNotInstalledLink(entity)
|
||||
if (packageLink == null) {
|
||||
packageLink = entity.links.find { it.buttonLink }
|
||||
}
|
||||
if (packageLink != null) {
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "点击前往下载", gameEntity, packageLink.text, packageLink.title, "", "")
|
||||
DirectUtils.directToLinkPage(requireContext(), packageLink, "包名检测弹窗", "")
|
||||
}
|
||||
}
|
||||
@ -127,22 +168,26 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
callBack?.onConfirm()
|
||||
}
|
||||
if (binding.noRemindAgainCb.isChecked) {
|
||||
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity?.id}", true)
|
||||
saveRecord(entity)
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "不再提示", gameEntity, "", "", "", "")
|
||||
}
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveRecord(entity: PackageDialogEntity) {
|
||||
if (entity.level == "OPTIONAL_CURRENT_HINT") {
|
||||
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity?.id}", true)
|
||||
} else {
|
||||
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity?.packageDialog?.id}", true)
|
||||
}
|
||||
}
|
||||
|
||||
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 ->
|
||||
gameEntity?.packageDialog?.detectionObjects?.let { objects ->
|
||||
if (objects.isNotEmpty()) {
|
||||
val averageTime = if (objects.size == 1) {
|
||||
mDuration
|
||||
@ -160,24 +205,49 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
if (it >= mDuration) {
|
||||
mDisposable?.dispose()
|
||||
binding.downloadBtn.isEnabled = true
|
||||
binding.progressText.text = "检测完成"
|
||||
binding.progressView.background = ContextCompat.getDrawable(requireContext(), R.drawable.package_check_complete_bg)
|
||||
}
|
||||
}
|
||||
val animator = ValueAnimator.ofInt(0, 100)
|
||||
animator.duration = mDuration.toLong()
|
||||
animator.interpolator = LinearInterpolator()
|
||||
animator.addUpdateListener {
|
||||
binding.progressBar.progress = it.animatedValue as Int
|
||||
}
|
||||
animator.start()
|
||||
}
|
||||
|
||||
private fun getNotInstalledLink(packageDialogEntity: PackageDialogEntity): LinkEntity? {
|
||||
val links = LinkedHashSet<LinkEntity>()
|
||||
packageDialogEntity.detectionObjects.forEach { obj ->
|
||||
if (!checkDetectionsInstalled(mAllInstalledPackages, obj.packages)) {
|
||||
obj.assignDownload.forEach {
|
||||
links.add(packageDialogEntity.links[it])
|
||||
}
|
||||
}
|
||||
}
|
||||
var link: LinkEntity? = null
|
||||
if (links.size > 1) {
|
||||
link = links.find { it.buttonLink } ?: links.toList()[0]
|
||||
} else if (links.size == 1) {
|
||||
link = links.toList()[0]
|
||||
}
|
||||
return link
|
||||
}
|
||||
|
||||
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)
|
||||
requireDialog().window?.setLayout(width, height)
|
||||
requireDialog().setCanceledOnTouchOutside(true)
|
||||
DownloadManager.getInstance(context).addObserver(dataWatcher)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
packageDialogEntity?.let {
|
||||
if (isAllPackageInstalled(it)) {
|
||||
mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
|
||||
gameEntity?.packageDialog?.let {
|
||||
if (isAllPackageInstalled(mAllInstalledPackages, it)) {
|
||||
callBack?.onConfirm()
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
@ -190,22 +260,25 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
if (mDisposable?.isDisposed == false) {
|
||||
mDisposable?.dispose()
|
||||
}
|
||||
LogUtils.uploadPackageCheck("pkg_check_pop_click", "关闭弹窗", gameEntity, "", "", "", "")
|
||||
DownloadManager.getInstance(context).removeObserver(dataWatcher)
|
||||
}
|
||||
|
||||
//安装、卸载事件
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(busFour: EBPackage) {
|
||||
if ("安装" == busFour.type || "卸载" == busFour.type) {
|
||||
mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
|
||||
mAdapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
inner class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
private var index = -1
|
||||
|
||||
fun notifyPackages() {
|
||||
index++
|
||||
notifyDataSetChanged()
|
||||
notifyItemChanged(index)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
@ -219,14 +292,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
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
|
||||
}
|
||||
}
|
||||
val isAllInstalled = checkDetectionsInstalled(mAllInstalledPackages, entity.packages)
|
||||
if (isAllInstalled) {
|
||||
holder.binding.statusTv.text = "已安装"
|
||||
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
|
||||
@ -246,59 +312,65 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun show(activity: AppCompatActivity, packageDialogEntity: PackageDialogEntity?, callBack: DialogUtils.ConfirmListener) {
|
||||
fun show(activity: AppCompatActivity, gameEntity: GameEntity, callBack: DialogUtils.ConfirmListener) {
|
||||
val packageDialogEntity = gameEntity.packageDialog
|
||||
if (packageDialogEntity == null) {
|
||||
callBack.onConfirm()
|
||||
return
|
||||
}
|
||||
if (isAllPackageInstalled(packageDialogEntity)) {
|
||||
|
||||
val allInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
|
||||
if (isAllPackageInstalled(allInstalledPackages, 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
|
||||
val isCurrentGameChoose = SPUtils.getBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity.id}", false)
|
||||
if (packageDialogEntity.level == "OPTIONAL_CURRENT_HINT" && isCurrentGameChoose) {
|
||||
callBack.onConfirm()
|
||||
return
|
||||
}
|
||||
|
||||
if (!activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) return
|
||||
|
||||
var dialogFragment = activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.simpleName) as? PackageCheckDialogFragment
|
||||
if (dialogFragment == null) {
|
||||
dialogFragment = PackageCheckDialogFragment()
|
||||
dialogFragment.packageDialogEntity = packageDialogEntity
|
||||
dialogFragment.gameEntity = gameEntity
|
||||
dialogFragment.callBack = callBack
|
||||
|
||||
dialogFragment.show(activity.supportFragmentManager, PackageCheckDialogFragment::class.java.simpleName)
|
||||
} else {
|
||||
dialogFragment.packageDialogEntity = packageDialogEntity
|
||||
dialogFragment.gameEntity = gameEntity
|
||||
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
|
||||
}
|
||||
private fun checkDetectionsInstalled(allInstalledPackages: List<PackageInfo>, packages: ArrayList<String>): Boolean {
|
||||
var isPackagesInstalled = false
|
||||
packages.forEach { packageName ->
|
||||
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
|
||||
if (isInstalled) {
|
||||
isPackagesInstalled = true
|
||||
return@forEach
|
||||
}
|
||||
isPackagesInstalled
|
||||
}
|
||||
return isPackagesInstalled
|
||||
}
|
||||
|
||||
|
||||
fun isAllPackageInstalled(allInstalledPackages: List<PackageInfo>, packageDialogEntity: PackageDialogEntity): Boolean {
|
||||
var isAllInstalled = true
|
||||
packageDialogEntity.detectionObjects.forEach loop@{ obj ->
|
||||
if (!isPackagesInstall(obj.packages)) {
|
||||
if (!checkDetectionsInstalled(allInstalledPackages, obj.packages)) {
|
||||
isAllInstalled = false
|
||||
return isAllInstalled
|
||||
}
|
||||
|
||||
@ -14,10 +14,10 @@ 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
|
||||
import com.gh.gamecenter.WebActivity
|
||||
|
||||
class PrivacyDialogFragment : BaseDialogFragment() {
|
||||
|
||||
@ -53,7 +53,8 @@ class PrivacyDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
directToExternalBrowser(context!!, context!!.getString(R.string.privacy_policy_url))
|
||||
val intent = WebActivity.getIntent(requireContext(), context!!.getString(R.string.privacy_policy_url), true)
|
||||
context?.startActivity(intent)
|
||||
}
|
||||
}, skipText.length - 9, skipText.length - 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
|
||||
@ -65,7 +66,8 @@ class PrivacyDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
directToExternalBrowser(requireContext(), requireContext().getString(R.string.disclaimer_url))
|
||||
val intent = WebActivity.getIntent(requireContext(), context!!.getString(R.string.disclaimer_url), true)
|
||||
context?.startActivity(intent)
|
||||
}
|
||||
}, skipText.length - 4, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
descTv?.movementMethod = CustomLinkMovementMethod()
|
||||
|
||||
@ -16,10 +16,14 @@ data class ExposureEntity(
|
||||
val outerSequence: Int? = 0,
|
||||
val platform: String? = "",
|
||||
var isMirrorData: Boolean = false,
|
||||
@SerializedName("is_web_download")
|
||||
var isWebDownload: Boolean = false,
|
||||
val downloadType: String? = "",
|
||||
val downloadCompleteType: String? = "",
|
||||
@SerializedName("display_type")
|
||||
val displayType: String? = "",
|
||||
@SerializedName("is_platform_recommend")
|
||||
val isPlatformRecommend: Boolean? = false,
|
||||
|
||||
// 下载地址的 host 和 path
|
||||
var host: String? = "",
|
||||
|
||||
@ -9,10 +9,12 @@ import com.gh.common.exposure.meta.Meta
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.exposure.time.TimeUtil
|
||||
import com.gh.common.util.getFirstElementDividedByDivider
|
||||
import com.gh.download.server.BrowserInstallHelper
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@Keep
|
||||
@Parcelize
|
||||
@ -30,7 +32,10 @@ data class ExposureEvent(
|
||||
|
||||
// TODO 建一个 exposureEvent 池规避反复生成对象
|
||||
@JvmStatic
|
||||
fun createEvent(gameEntity: GameEntity?, source: List<ExposureSource>, eTrace: List<ExposureEvent>? = null, event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
|
||||
fun createEvent(gameEntity: GameEntity?,
|
||||
source: List<ExposureSource>,
|
||||
eTrace: List<ExposureEvent>? = null,
|
||||
event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
|
||||
if (gameEntity?.getApk()?.size == 1) {
|
||||
gameEntity.gameVersion = gameEntity.getApk().elementAtOrNull(0)?.version ?: ""
|
||||
}
|
||||
@ -40,12 +45,14 @@ data class ExposureEvent(
|
||||
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,
|
||||
isWebDownload = BrowserInstallHelper.isUseBrowserToInstallEnabled() && BrowserInstallHelper.shouldUseBrowserToInstall(), // 实时的值,不用从 eTrace 里取
|
||||
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,
|
||||
isPlatformRecommend = gameEntity?.isPlatformRecommend ?: false,
|
||||
// ugly
|
||||
welcomeDialogId = gameEntity?.welcomeDialogId ?: eTrace?.firstOrNull()?.payload?.welcomeDialogId,
|
||||
welcomeDialogLinkTitle = gameEntity?.welcomeDialogTitle ?: eTrace?.firstOrNull()?.payload?.welcomeDialogLinkTitle),
|
||||
@ -53,5 +60,19 @@ data class ExposureEvent(
|
||||
eTrace = eTrace,
|
||||
event = event).apply { gameEntity?.exposureEvent = this }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createEventWithSourceConcat(gameEntity: GameEntity?,
|
||||
basicSource: List<ExposureSource>,
|
||||
source: List<ExposureSource>,
|
||||
eTrace: List<ExposureEvent>? = null,
|
||||
event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
|
||||
val concatSourceList = ArrayList<ExposureSource>().apply {
|
||||
addAll(basicSource)
|
||||
addAll(source)
|
||||
}
|
||||
return createEvent(gameEntity, concatSourceList, eTrace, event)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,10 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import com.aliyun.sls.android.sdk.model.LogGroup
|
||||
import com.gh.common.exposure.time.TimeUtil
|
||||
import com.aliyun.sls.android.producer.Log
|
||||
import com.gh.common.loghub.LoghubHelper
|
||||
import com.gh.common.util.toJson
|
||||
import com.gh.common.util.tryWithDefaultCatch
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.loghub.LgLOG
|
||||
import com.gh.loghub.LoghubHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import java.util.concurrent.ExecutorService
|
||||
@ -22,13 +20,9 @@ import java.util.concurrent.ExecutorService
|
||||
*/
|
||||
object ExposureManager {
|
||||
|
||||
private const val ENDPOINT = "cn-qingdao.log.aliyuncs.com"
|
||||
private const val PROJECT = "ghzs"
|
||||
private const val STORE_SIZE = 100
|
||||
private const val LOG_STORE = BuildConfig.EXPOSURE_REPO
|
||||
|
||||
private val loghubHelper = LoghubHelper.getInstance()
|
||||
|
||||
// exposureCache 用来过滤掉具有相同 id 的曝光事件,避免重复发送事件
|
||||
private val exposureSet by lazy { hashSetOf<ExposureEvent>() }
|
||||
private var exposureExecutor: ExecutorService? = null
|
||||
@ -37,7 +31,6 @@ object ExposureManager {
|
||||
|
||||
@JvmStatic
|
||||
fun init(excutor: ExecutorService) {
|
||||
loghubHelper.init(HaloApp.getInstance().application, ENDPOINT, PROJECT, LOG_STORE) { TimeUtil.currentTimeMillis() }
|
||||
exposureExecutor = excutor
|
||||
exposureExecutor?.execute {
|
||||
tryWithDefaultCatch {
|
||||
@ -102,8 +95,7 @@ object ExposureManager {
|
||||
if (exposureSet.size < STORE_SIZE && !forced || exposureSet.size == 0) return@execute
|
||||
|
||||
val exposureList = exposureSet.toList()
|
||||
// uploadLogGroup 是一个异步方法,LoghubHelper 里面实现了重传功能,所以这里交给它就好了
|
||||
loghubHelper.uploadLogGroup(buildLogGroup(exposureList))
|
||||
uploadExposures(exposureList)
|
||||
|
||||
Utils.log("Exposure", "提交了${exposureList.size}条曝光记录")
|
||||
exposureSet.removeAll(exposureList)
|
||||
@ -116,28 +108,22 @@ object ExposureManager {
|
||||
return jsonWithMultipleBracket.replace("[[", "[").replace("]]", "]")
|
||||
}
|
||||
|
||||
private fun buildLogGroup(eventList: List<ExposureEvent>): LogGroup {
|
||||
val logGroup = LogGroup("sls android", "no ip")
|
||||
|
||||
eventList.forEach { logGroup.PutLog(buildLog(it)) }
|
||||
|
||||
return logGroup
|
||||
private fun uploadExposures(eventList: List<ExposureEvent>) {
|
||||
eventList.forEach {
|
||||
LoghubHelper.uploadLog(buildLog(it), LOG_STORE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildLog(event: ExposureEvent): LgLOG {
|
||||
val log = LgLOG(TimeUtil.currentTime())
|
||||
|
||||
log.PutContent("id", event.id)
|
||||
log.PutContent("payload", event.payload.toJson())
|
||||
log.PutContent("event", event.event.toString())
|
||||
log.PutContent("source", eliminateMultipleBrackets(event.source.toJson()))
|
||||
log.PutContent("meta", event.meta.toJson())
|
||||
log.PutContent("e-traces", if (event.eTrace != null) {
|
||||
private fun buildLog(event: ExposureEvent) = Log().apply {
|
||||
putContent("id", event.id)
|
||||
putContent("payload", event.payload.toJson())
|
||||
putContent("event", event.event.toString())
|
||||
putContent("source", eliminateMultipleBrackets(event.source.toJson()))
|
||||
putContent("meta", event.meta.toJson())
|
||||
putContent("e-traces", if (event.eTrace != null) {
|
||||
eliminateMultipleBrackets(event.eTrace?.toJson() ?: "")
|
||||
} else "")
|
||||
log.PutTime(event.time)
|
||||
|
||||
return log
|
||||
logTime = event.time.toLong()
|
||||
}
|
||||
|
||||
class FixedSizeLinkedHashSet<T>(var maxSize: Int) : LinkedHashSet<T>() {
|
||||
|
||||
@ -97,6 +97,11 @@ object HistoryHelper {
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().deleteVideo(MyVideoEntity().apply { id = videoId }) } }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteAttentionVideoRecord() {
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().deleteAttentionVideoRecord() } }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun emptyDatabase() {
|
||||
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.clearAllTables() } }
|
||||
|
||||
90
app/src/main/java/com/gh/common/loghub/LoghubHelper.kt
Normal file
90
app/src/main/java/com/gh/common/loghub/LoghubHelper.kt
Normal file
@ -0,0 +1,90 @@
|
||||
package com.gh.common.loghub
|
||||
|
||||
import com.aliyun.sls.android.producer.*
|
||||
import com.gh.common.util.isPublishEnv
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
|
||||
/**
|
||||
* 上传阿里云日志辅助类
|
||||
*/
|
||||
object LoghubHelper {
|
||||
|
||||
private const val ACCESS_KEY_ID = "LTAIV3i0sNc4TPK1"
|
||||
private const val ACCESS_KEY_SECRET = "8dKtTPeE5WYA6ZCeuIBcIVp7eB0ir4"
|
||||
private const val ENDPOINT = "cn-qingdao.log.aliyuncs.com"
|
||||
private const val PROJECT = "ghzs"
|
||||
|
||||
private val mClientMaps by lazy { hashMapOf<String, LogProducerClient>() }
|
||||
|
||||
fun uploadLog(log: Log, logStore: String) {
|
||||
getClient(logStore)?.addLog(log)
|
||||
}
|
||||
|
||||
fun uploadLogs(logs: List<Log>, logStore: String) {
|
||||
logs.forEach {
|
||||
uploadLog(it, logStore)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun getClient(logStore: String): LogProducerClient? {
|
||||
if (!mClientMaps.containsKey(logStore)) {
|
||||
mClientMaps[logStore] = createClient(logStore)
|
||||
}
|
||||
return mClientMaps[logStore]
|
||||
}
|
||||
|
||||
private fun createClient(logStore: String): LogProducerClient {
|
||||
val config = LogProducerConfig(ENDPOINT, PROJECT, logStore, ACCESS_KEY_ID, ACCESS_KEY_SECRET).apply {
|
||||
// 1 开启断点续传功能, 0 关闭
|
||||
// 每次发送前会把日志保存到本地的binlog文件,只有发送成功才会删除,保证日志上传At Least Once
|
||||
setPersistent(1)
|
||||
// 持久化的文件名,需要保证文件所在的文件夹已创建。配置多个客户端时,不应设置相同文件
|
||||
setPersistentFilePath(HaloApp.getInstance().application.filesDir.absolutePath + "/log.dat")
|
||||
// 是否每次AddLog强制刷新,高可靠性场景建议打开
|
||||
setPersistentForceFlush(1)
|
||||
// 持久化文件滚动个数,建议设置成10。
|
||||
setPersistentMaxFileCount(10)
|
||||
// 每个持久化文件的大小,建议设置成1-10M
|
||||
setPersistentMaxFileSize(1024 * 1024)
|
||||
// 本地最多缓存的日志数,不建议超过1M,通常设置为65536即可
|
||||
setPersistentMaxLogCount(65536)
|
||||
|
||||
//网络连接超时时间,整数,单位秒,默认为10
|
||||
setConnectTimeoutSec(15)
|
||||
//日志发送超时时间,整数,单位秒,默认为15
|
||||
setSendTimeoutSec(15)
|
||||
//flusher线程销毁最大等待时间,整数,单位秒,默认为1
|
||||
setDestroyFlusherWaitSec(2)
|
||||
//sender线程池销毁最大等待时间,整数,单位秒,默认为1
|
||||
setDestroySenderWaitSec(2)
|
||||
//日志时间与本机时间之差,超过该大小后会根据 `drop_delay_log` 选项进行处理。
|
||||
//一般此种情况只会在设置persistent的情况下出现,即设备下线后,超过几天/数月启动,发送退出前未发出的日志
|
||||
//整数,单位秒,默认为7*24*3600,即7天
|
||||
setMaxLogDelayTime(7 * 24 * 3600)
|
||||
//对于超过 `max_log_delay_time` 日志的处理策略
|
||||
//0 不丢弃,把日志时间修改为当前时间; 1 丢弃,默认为 1 (丢弃)
|
||||
setDropDelayLog(0)
|
||||
//是否丢弃鉴权失败的日志,0 不丢弃,1丢弃
|
||||
//默认为 0,即不丢弃
|
||||
setDropUnauthorizedLog(0)
|
||||
}
|
||||
|
||||
return if (isPublishEnv()) {
|
||||
LogProducerClient(config)
|
||||
} else {
|
||||
return LogProducerClient(config,
|
||||
LogProducerCallback { resultCode, reqId, errorMessage, logBytes, compressedBytes ->
|
||||
|
||||
// resultCode 返回结果代码
|
||||
// reqId 请求id
|
||||
// errorMessage 错误信息,没有为null
|
||||
// logBytes 日志大小
|
||||
// compressedBytes 压缩后日志大小
|
||||
Utils.log("LoghubHelper -> ${String.format("%s %s %s %s %s",
|
||||
LogProducerResult.fromInt(resultCode), reqId, errorMessage, logBytes, compressedBytes)}")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,12 +2,10 @@ package com.gh.common.loghub
|
||||
|
||||
import android.app.Application
|
||||
import androidx.annotation.Keep
|
||||
import com.aliyun.sls.android.sdk.model.Log
|
||||
import com.aliyun.sls.android.sdk.model.LogGroup
|
||||
import com.aliyun.sls.android.producer.Log
|
||||
import com.gh.common.exposure.ExposureEntity
|
||||
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.ExecutorService
|
||||
|
||||
@ -67,10 +65,6 @@ object LoghubUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private fun uploadLogGroup(logGroup: LogGroup, logStore: String) {
|
||||
LoghubHelper.getInstance().uploadLogGroup(logGroup, logStore)
|
||||
}
|
||||
|
||||
fun commitSavedLoghubEvents() {
|
||||
loghubEventExecutor?.execute {
|
||||
// TODO 初始化 loghubHelper 去掉这个 tryCatch 块
|
||||
@ -79,37 +73,29 @@ object LoghubUtils {
|
||||
|
||||
val exposureList = loghubEventSet.toList()
|
||||
|
||||
createLogGroupAndUpload()
|
||||
uploadEvents()
|
||||
loghubEventSet.removeAll(exposureList)
|
||||
loghubEventDao.deleteMany(exposureList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLogGroupAndUpload() {
|
||||
val logGroupHashMap = hashMapOf<String, LogGroup>()
|
||||
|
||||
private fun uploadEvents() {
|
||||
for (event in loghubEventSet) {
|
||||
if (!logGroupHashMap.containsKey(event.logStore)) {
|
||||
logGroupHashMap[event.logStore] = LogGroup("sls android", "no ip")
|
||||
}
|
||||
|
||||
val log = Log()
|
||||
// 特殊处理,以下logStore不需要用content包裹数据
|
||||
if (event.logStore == "collection" || event.logStore == "common" || event.logStore == "halo-api-device-installed") {
|
||||
val contentJson = JSONObject(event.content)
|
||||
for (key in contentJson.keys()) {
|
||||
log.PutContent(key, contentJson.get(key).toString())
|
||||
log.putContent(key, contentJson.get(key).toString())
|
||||
}
|
||||
} else {
|
||||
log.PutContent("current time ", event.time)
|
||||
log.PutContent("content", event.content)
|
||||
log.putContent("current time ", event.time)
|
||||
log.putContent("content", event.content)
|
||||
}
|
||||
logGroupHashMap[event.logStore]?.PutLog(log)
|
||||
}
|
||||
|
||||
for ((logStore, logGroup) in logGroupHashMap) {
|
||||
uploadLogGroup(logGroup, logStore)
|
||||
LoghubHelper.uploadLog(log, event.logStore)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,10 +10,12 @@ import com.g00fy2.versioncompare.Version
|
||||
import com.gh.common.util.*
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.SimulatorGameRecordEntity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.EmptyResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.room.AppDatabase
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadDao
|
||||
import com.lightgame.download.DownloadEntity
|
||||
@ -109,7 +111,7 @@ object SimulatorGameManager {
|
||||
.subscribe({
|
||||
val intent = Intent()
|
||||
intent.data = Uri.fromFile(File(downloadEntity.path))
|
||||
if (gameEntity.simulatorType == "FBA") {
|
||||
if (gameEntity.simulatorType == "FBA" || gameEntity.simulatorType == "FBN") {
|
||||
val apkEntity = gameEntity.getApk()[0]
|
||||
intent.putExtra("rom_name", apkEntity.packageName)
|
||||
}
|
||||
@ -157,16 +159,42 @@ object SimulatorGameManager {
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun recordDownloadSimulatorGames(gameId: String) {
|
||||
fun recordDownloadSimulatorGames(gameId: String, type: String) {
|
||||
val requestMap = hashMapOf<String, Any>()
|
||||
requestMap["game_id"] = gameId
|
||||
requestMap["package"] = "-"
|
||||
val body = requestMap.createRequestBodyAny()
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api
|
||||
.downloadSimulatorGames(HaloApp.getInstance().gid, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(EmptyResponse())
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
refreshSimulatorGame(gameId, type)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun refreshSimulatorGame(gameId: String, type: String) {
|
||||
val simulatorGameDao = AppDatabase.getInstance(HaloApp.getInstance()).simulatorGameDao()
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api
|
||||
.getSimulatorGames(HaloApp.getInstance().gid, 1, getFilter(type))
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<List<GameEntity>>() {
|
||||
override fun onSuccess(data: List<GameEntity>) {
|
||||
val simulatorGameRecordList = ArrayList<SimulatorGameRecordEntity>()
|
||||
data.forEach {
|
||||
val entity = it.convertSimulatorGameRecordEntity()
|
||||
entity.isRecentlyPlayed = it.id == gameId
|
||||
simulatorGameRecordList.add(entity)
|
||||
}
|
||||
simulatorGameDao.addSimulatorGameList(simulatorGameRecordList)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun getFilter(type: String): String {
|
||||
return UrlFilterUtils.getFilterQuery("type", type)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,8 +209,7 @@ object SimulatorGameManager {
|
||||
val body = requestMap.toRequestBody()
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api
|
||||
.postPlayedGame(UserManager.getInstance().userId, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.compose(singleToMain())
|
||||
.subscribe(EmptyResponse())
|
||||
}
|
||||
}
|
||||
@ -223,6 +250,7 @@ object SimulatorGameManager {
|
||||
/**
|
||||
* 批量删除设备下载模拟器游戏的记录
|
||||
*/
|
||||
@JvmStatic
|
||||
@SuppressLint("CheckResult")
|
||||
fun deleteSimulatorGames(gameIds: List<String>, callback: () -> Unit) {
|
||||
val requestMap = hashMapOf<String, Any>()
|
||||
|
||||
@ -80,7 +80,7 @@ class ExampleAdapter(context: Context) : ListAdapter<AnswerEntity>(context), ISy
|
||||
ItemViewType.ITEM_FOOTER -> {
|
||||
val footerViewHolder = holder as FooterViewHolder
|
||||
footerViewHolder.initItemPadding()
|
||||
footerViewHolder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint)
|
||||
footerViewHolder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
package com.gh.common.tracker
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
|
||||
// TODO SplashActivity 没有回调 onStart 和 onStop
|
||||
class ActivityLifecycleWatcher(private val mTrack: ITrack) : Application.ActivityLifecycleCallbacks {
|
||||
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
mTrack.onActivityStarted(activity)
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
mTrack.onActivityStopped(activity)
|
||||
}
|
||||
|
||||
override fun onActivityDestroyed(activity: Activity) {}
|
||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
|
||||
override fun onActivityPaused(activity: Activity) {}
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
|
||||
override fun onActivityResumed(activity: Activity) {}
|
||||
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
package com.gh.common.tracker
|
||||
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
|
||||
/**
|
||||
* 应用声明周期观察者
|
||||
*/
|
||||
class AppLifecycleWatcher(private val mTrack: ITrack) : DefaultLifecycleObserver {
|
||||
|
||||
private var mWatchVisibleCount = 0 // 检查是否满足上传可见的次数
|
||||
|
||||
private val mLastVisibleTime by lazy { AtomicLong(0L) } // 最后可见时间
|
||||
private val mIsVisible by lazy { AtomicBoolean(false) } // 当前是否可见
|
||||
private val mWatchInterval by lazy { AtomicLong(MIN_WATCH_VISIBLE_INTERVAL) } // 与上次上报可见的间隔时间
|
||||
|
||||
init {
|
||||
fixedRateTimer(FIXED_RATE_TIMER_NAME, initialDelay = MIN_WATCH_VISIBLE_INTERVAL, period = MIN_WATCH_VISIBLE_INTERVAL) {
|
||||
if (mIsVisible.get()) {
|
||||
// 单位间隔发送
|
||||
val meetLogVisibleInterval = (mWatchVisibleCount++) * MIN_WATCH_VISIBLE_INTERVAL == mWatchInterval.get()
|
||||
|
||||
val equalToMinVisibleInterval = mWatchInterval.get() == MIN_WATCH_VISIBLE_INTERVAL
|
||||
val equalToMaxVisibleInterval = mWatchInterval.get() == MAX_WATCH_VISIBLE_INTERVAL
|
||||
|
||||
if (meetLogVisibleInterval || equalToMinVisibleInterval) {
|
||||
// 上报完重置计数
|
||||
mWatchVisibleCount = 0
|
||||
mTrack.onAppVisible(mWatchInterval.get() / 1000)
|
||||
if (!equalToMaxVisibleInterval) {
|
||||
mWatchInterval.set(mWatchInterval.get() * 2) // 间隔递增两倍
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
super.onStart(owner)
|
||||
|
||||
if (mLastVisibleTime.get() == 0L
|
||||
|| (mLastVisibleTime.get() + SESSION_ALIVE_INTERVAL) < System.currentTimeMillis() / 1000) {
|
||||
mTrack.onSessionChanged(UUID.randomUUID().toString())
|
||||
}
|
||||
mIsVisible.set(true)
|
||||
|
||||
mTrack.onAppStarted()
|
||||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
super.onStop(owner)
|
||||
|
||||
mIsVisible.set(false)
|
||||
mLastVisibleTime.set(System.currentTimeMillis() / 1000)
|
||||
mWatchInterval.set(MIN_WATCH_VISIBLE_INTERVAL)
|
||||
|
||||
mTrack.onAppStopped()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val FIXED_RATE_TIMER_NAME = "APP_TRACKER_TIMER"
|
||||
|
||||
private const val SESSION_ALIVE_INTERVAL = 30L // 30s
|
||||
private const val MIN_WATCH_VISIBLE_INTERVAL = 5000L // 5s
|
||||
private const val MAX_WATCH_VISIBLE_INTERVAL = 320000L // 320s
|
||||
}
|
||||
|
||||
}
|
||||
8
app/src/main/java/com/gh/common/tracker/IBusiness.kt
Normal file
8
app/src/main/java/com/gh/common/tracker/IBusiness.kt
Normal file
@ -0,0 +1,8 @@
|
||||
package com.gh.common.tracker
|
||||
|
||||
import androidx.annotation.Nullable
|
||||
|
||||
interface IBusiness {
|
||||
@Nullable
|
||||
fun getBusinessId(): Pair<String, String>
|
||||
}
|
||||
14
app/src/main/java/com/gh/common/tracker/ITrack.kt
Normal file
14
app/src/main/java/com/gh/common/tracker/ITrack.kt
Normal file
@ -0,0 +1,14 @@
|
||||
package com.gh.common.tracker
|
||||
|
||||
import android.app.Activity
|
||||
|
||||
interface ITrack {
|
||||
fun onActivityStarted(activity: Activity)
|
||||
fun onActivityStopped(activity: Activity)
|
||||
|
||||
fun onAppStarted()
|
||||
fun onAppVisible(interval: Long)
|
||||
fun onAppStopped()
|
||||
|
||||
fun onSessionChanged(sessionId: String)
|
||||
}
|
||||
70
app/src/main/java/com/gh/common/tracker/Tracker.kt
Normal file
70
app/src/main/java/com/gh/common/tracker/Tracker.kt
Normal file
@ -0,0 +1,70 @@
|
||||
package com.gh.common.tracker
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import java.util.*
|
||||
|
||||
object Tracker : ITrack {
|
||||
|
||||
private var mSessionId: String = ""
|
||||
private val mLaunchId by lazy { UUID.randomUUID().toString() }
|
||||
|
||||
val sessionId: String
|
||||
get() = mSessionId
|
||||
|
||||
val launchId: String
|
||||
get() = mLaunchId
|
||||
|
||||
private var mIsInitialized = false
|
||||
|
||||
@JvmStatic
|
||||
fun init(application: Application) {
|
||||
if (mIsInitialized) {
|
||||
return
|
||||
}
|
||||
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleWatcher(this))
|
||||
application.registerActivityLifecycleCallbacks(ActivityLifecycleWatcher(this))
|
||||
mIsInitialized = true
|
||||
}
|
||||
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
val businessId = if (activity is IBusiness) activity.getBusinessId() else null
|
||||
|
||||
TrackerLogger.logActivityStart(
|
||||
mLaunchId,
|
||||
mSessionId,
|
||||
System.identityHashCode(activity).toString(),
|
||||
activity::class.java.simpleName,
|
||||
businessId)
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
val businessId = if (activity is IBusiness) activity.getBusinessId() else null
|
||||
|
||||
TrackerLogger.logActivityStop(
|
||||
mLaunchId,
|
||||
mSessionId,
|
||||
System.identityHashCode(activity).toString(),
|
||||
activity::class.java.simpleName,
|
||||
businessId)
|
||||
}
|
||||
|
||||
override fun onAppStarted() {
|
||||
TrackerLogger.logAppStart(mLaunchId, mSessionId)
|
||||
}
|
||||
|
||||
override fun onAppVisible(interval: Long) {
|
||||
TrackerLogger.logAppVisible(mLaunchId, mSessionId, interval)
|
||||
}
|
||||
|
||||
override fun onAppStopped() {
|
||||
TrackerLogger.logAppStop(mLaunchId, mSessionId)
|
||||
}
|
||||
|
||||
override fun onSessionChanged(sessionId: String) {
|
||||
mSessionId = sessionId
|
||||
}
|
||||
|
||||
}
|
||||
178
app/src/main/java/com/gh/common/tracker/TrackerLogger.kt
Normal file
178
app/src/main/java/com/gh/common/tracker/TrackerLogger.kt
Normal file
@ -0,0 +1,178 @@
|
||||
package com.gh.common.tracker
|
||||
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.exposure.meta.MetaUtil.getBase64EncodedAndroidId
|
||||
import com.gh.common.exposure.meta.MetaUtil.getBase64EncodedIMEI
|
||||
import com.gh.common.loghub.LoghubUtils
|
||||
import com.gh.common.util.tryCatchInRelease
|
||||
import com.lightgame.utils.Utils
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
object TrackerLogger {
|
||||
|
||||
private const val LOG_STORE = "launch_activity"
|
||||
|
||||
fun logAppStart(launchId: String, sessionId: String) {
|
||||
logAppVisible(launchId, sessionId, 0)
|
||||
}
|
||||
|
||||
fun logAppVisible(launchId: String, sessionId: String, interval: Long) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("interval", interval)
|
||||
|
||||
jsonObject.put("event", "app_visible")
|
||||
jsonObject.put("payload", payloadObject)
|
||||
jsonObject.put("meta", getMeta())
|
||||
}
|
||||
uploadToLoghub(jsonObject, true)
|
||||
}
|
||||
|
||||
fun logAppStop(launchId: String, sessionId: String) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
|
||||
jsonObject.put("event", "app_invisible")
|
||||
jsonObject.put("payload", payloadObject)
|
||||
jsonObject.put("meta", getMeta())
|
||||
}
|
||||
uploadToLoghub(jsonObject, true)
|
||||
}
|
||||
|
||||
fun logActivityStart(launchId: String,
|
||||
sessionId: String,
|
||||
activityId: String,
|
||||
activityName: String,
|
||||
activityBusinessId: Pair<String, String>? = null) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("activity_id", activityId)
|
||||
payloadObject.put("activity_name", activityName)
|
||||
if (activityBusinessId != null) {
|
||||
payloadObject.put("activity_primary_business_id", activityBusinessId.first)
|
||||
if (activityBusinessId.second.isNotEmpty()) {
|
||||
payloadObject.put("activity_secondary_business_id", activityBusinessId.second)
|
||||
}
|
||||
}
|
||||
|
||||
jsonObject.put("event", "activity_visible")
|
||||
jsonObject.put("payload", payloadObject)
|
||||
jsonObject.put("meta", getMeta())
|
||||
}
|
||||
uploadToLoghub(jsonObject, false)
|
||||
}
|
||||
|
||||
fun logActivityStop(launchId: String,
|
||||
sessionId: String,
|
||||
activityId: String,
|
||||
activityName: String,
|
||||
activityBusinessId: Pair<String, String>? = null) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("activity_id", activityId)
|
||||
payloadObject.put("activity_name", activityName)
|
||||
if (activityBusinessId != null) {
|
||||
payloadObject.put("activity_primary_business_id", activityBusinessId.first)
|
||||
if (activityBusinessId.second.isNotEmpty()) {
|
||||
payloadObject.put("activity_secondary_business_id", activityBusinessId.second)
|
||||
}
|
||||
}
|
||||
|
||||
jsonObject.put("event", "activity_invisible")
|
||||
jsonObject.put("payload", payloadObject)
|
||||
jsonObject.put("meta", getMeta())
|
||||
}
|
||||
uploadToLoghub(jsonObject, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logHomeTabSelected(launchId: String,
|
||||
sessionId: String,
|
||||
tabPosition: Int,
|
||||
tabContent: String) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("tab_position", tabPosition)
|
||||
payloadObject.put("tab_content", tabContent)
|
||||
|
||||
jsonObject.put("event", "home_tab_select")
|
||||
jsonObject.put("payload", payloadObject)
|
||||
jsonObject.put("meta", getMeta())
|
||||
}
|
||||
uploadToLoghub(jsonObject, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logAppLaunch(launchId: String, sessionId: String) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
|
||||
jsonObject.put("event", "app_launch")
|
||||
jsonObject.put("payload", payloadObject)
|
||||
jsonObject.put("meta", getMeta())
|
||||
}
|
||||
uploadToLoghub(jsonObject, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logAppLaunchSuccessful(launchId: String, sessionId: String) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
|
||||
jsonObject.put("event", "app_launch_successful")
|
||||
jsonObject.put("payload", payloadObject)
|
||||
jsonObject.put("meta", getMeta())
|
||||
}
|
||||
uploadToLoghub(jsonObject, true)
|
||||
}
|
||||
|
||||
private fun uploadToLoghub(jsonObject: JSONObject, uploadImmediately: Boolean) {
|
||||
jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
|
||||
|
||||
Utils.log("Tracker -> $jsonObject")
|
||||
LoghubUtils.log(jsonObject, LOG_STORE, uploadImmediately)
|
||||
}
|
||||
|
||||
private fun getMeta(): JSONObject {
|
||||
val (_, _, model, manufacturer, _, _, android_version, network, _, gid, _, channel, appVersion, userId) = MetaUtil.getMeta()
|
||||
val metaObject = JSONObject()
|
||||
try {
|
||||
metaObject.put("dia", getBase64EncodedAndroidId())
|
||||
metaObject.put("android_version", android_version)
|
||||
metaObject.put("app_version", appVersion)
|
||||
metaObject.put("channel", channel)
|
||||
metaObject.put("gid", gid)
|
||||
metaObject.put("jnfj", getBase64EncodedIMEI())
|
||||
metaObject.put("manufacturer", manufacturer)
|
||||
metaObject.put("model", model)
|
||||
metaObject.put("network", network)
|
||||
metaObject.put("user_id", userId)
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return metaObject
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,148 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -1,16 +1,14 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.common.avoidcallback.Callback;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.gamecenter.LoginActivity;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by khy on 28/06/17.
|
||||
@ -24,11 +22,15 @@ public class CheckLoginUtils {
|
||||
LogUtils.login("dialog", null, entrance);
|
||||
LogUtils.login("activity", null, entrance);
|
||||
|
||||
// 有可能App未启动
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
bundle.putString(EntranceUtils.KEY_TO, LoginActivity.class.getName());
|
||||
EntranceUtils.jumpActivity(context, bundle);
|
||||
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
|
||||
QuickLoginHelper.startLogin(context, entrance);
|
||||
} else {
|
||||
// 有可能App未启动
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
bundle.putString(EntranceUtils.KEY_TO, LoginActivity.class.getName());
|
||||
EntranceUtils.jumpActivity(context, bundle);
|
||||
}
|
||||
} else {
|
||||
if (listener != null) {
|
||||
listener.onLogin();
|
||||
|
||||
@ -118,13 +118,13 @@ object CommentHelper {
|
||||
}
|
||||
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val layout = inflater.inflate(R.layout.comment_more_option, null)
|
||||
val layout = inflater.inflate(R.layout.layout_popup_container, null)
|
||||
val popupWindow = BugFixedPopupWindow(layout,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
val container = layout.findViewById<LinearLayout>(R.id.container)
|
||||
for (text in dialogOptions) {
|
||||
val item = inflater.inflate(R.layout.comment_more_option_item, container, false)
|
||||
val item = inflater.inflate(R.layout.layout_popup_option_item, container, false)
|
||||
container.addView(item)
|
||||
|
||||
val hitText = item.findViewById<TextView>(R.id.hint_text)
|
||||
|
||||
@ -2,88 +2,37 @@ package com.gh.common.util
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.TextView
|
||||
import com.gh.common.dialog.TrackableDialog
|
||||
import com.gh.common.util.DialogUtils.checkDialogContext
|
||||
import com.gh.gamecenter.AboutActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.DialogAlertDefaultBinding
|
||||
|
||||
object DialogHelper {
|
||||
|
||||
/**
|
||||
* Material Design 风格弹窗
|
||||
* 光环常规弹窗
|
||||
*
|
||||
* @param context
|
||||
* @param title 标题
|
||||
* @param content 内容
|
||||
* @param positiveText 确认按钮文本
|
||||
* @param negativeText 取消按钮文本
|
||||
* @param positiveClickCallback 确认按钮监听
|
||||
* @param negativeClickCallback 取消按钮监听
|
||||
* @param trackMtaEvent 是否记录出现、关闭弹窗MTA事件
|
||||
* @param mtaEvent MTA 的事件名
|
||||
* @param mtaKey MTA 的事件 Key
|
||||
* extraConfig,可选标题居中、内容居中、是否显示关闭按钮以及是否显示正文辅助文本等
|
||||
*
|
||||
* uiModificationCallback,可用来手动微调样式的回调,可使用 binding 来修改颜色、文字大小等
|
||||
*/
|
||||
fun showDialog(context: Context,
|
||||
title: String,
|
||||
content: CharSequence,
|
||||
positiveText: String,
|
||||
negativeText: String,
|
||||
positiveClickCallback: (() -> Unit)? = null,
|
||||
negativeClickCallback: (() -> 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, null)
|
||||
val contentTv = contentView.findViewById<TextView>(R.id.dialog_content)
|
||||
val titleTv = contentView.findViewById<TextView>(R.id.dialog_title)
|
||||
val negativeTv = contentView.findViewById<TextView>(R.id.dialog_negative)
|
||||
val positiveTv = contentView.findViewById<TextView>(R.id.dialog_positive)
|
||||
contentTv.text = content
|
||||
titleTv.text = title
|
||||
negativeTv.text = negativeText
|
||||
positiveTv.text = positiveText
|
||||
|
||||
negativeTv.setOnClickListener {
|
||||
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击" + negativeText)
|
||||
|
||||
negativeClickCallback?.invoke()
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
positiveTv.setOnClickListener {
|
||||
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击$positiveText")
|
||||
|
||||
positiveClickCallback?.invoke()
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
dialog.setContentView(contentView)
|
||||
dialog.show()
|
||||
return dialog
|
||||
}
|
||||
|
||||
fun showRoundedCornerDialog(
|
||||
fun showDialog(
|
||||
context: Context,
|
||||
title: String,
|
||||
content: CharSequence,
|
||||
hint: String? = "",
|
||||
confirmText: String,
|
||||
cancelText: String,
|
||||
confirmClickCallback: (() -> Unit)? = null,
|
||||
cancelClickCallback: (() -> Unit)? = null,
|
||||
hintClickCallback: (() -> Unit)? = null,
|
||||
extraConfig: Config? = null,
|
||||
uiModificationCallback: ((binding: DialogAlertDefaultBinding) -> Unit)? = null,
|
||||
trackMtaEvent: Boolean = false,
|
||||
mtaEvent: String = "",
|
||||
mtaKey: String = ""): Dialog {
|
||||
@ -95,40 +44,58 @@ object DialogHelper {
|
||||
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()
|
||||
val binding = DialogAlertDefaultBinding.inflate(LayoutInflater.from(solidContext))
|
||||
val contentView = binding.root
|
||||
binding.contentTv.text = content
|
||||
binding.titleTv.text = title
|
||||
|
||||
extraConfig?.let {
|
||||
if (it.hint.isNotEmpty()) {
|
||||
binding.hintTv.visibility = View.VISIBLE
|
||||
binding.hintTv.text = it.hint
|
||||
}
|
||||
|
||||
if (it.centerTitle) {
|
||||
binding.titleTv.gravity = Gravity.CENTER
|
||||
}
|
||||
|
||||
if (it.centerContent) {
|
||||
binding.contentTv.gravity = Gravity.CENTER
|
||||
}
|
||||
|
||||
if (it.showCloseIcon) {
|
||||
binding.closeContainer.visibility = View.VISIBLE
|
||||
binding.closeContainer.setOnClickListener { dialog.dismiss() }
|
||||
}
|
||||
}
|
||||
cancelTv.text = cancelText
|
||||
confirmTv.text = confirmText
|
||||
|
||||
cancelTv.setOnClickListener {
|
||||
if (cancelText.isEmpty()) {
|
||||
binding.cancelTv.visibility = View.GONE
|
||||
binding.centerDivider.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.cancelTv.text = cancelText
|
||||
binding.confirmTv.text = confirmText
|
||||
|
||||
binding.cancelTv.setOnClickListener {
|
||||
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击$cancelText")
|
||||
|
||||
cancelClickCallback?.invoke()
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
confirmTv.setOnClickListener {
|
||||
binding.confirmTv.setOnClickListener {
|
||||
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击$confirmText")
|
||||
|
||||
confirmClickCallback?.invoke()
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
uiModificationCallback?.invoke(binding)
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
dialog.setContentView(contentView)
|
||||
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
dialog.show()
|
||||
return dialog
|
||||
}
|
||||
@ -137,6 +104,7 @@ object DialogHelper {
|
||||
* For legacy java invocation
|
||||
*/
|
||||
@JvmStatic
|
||||
@Deprecated("Kotlin 中请使用其它方法调用")
|
||||
fun showDialog(context: Context,
|
||||
title: String,
|
||||
content: CharSequence,
|
||||
@ -147,7 +115,87 @@ object DialogHelper {
|
||||
trackMtaEvent: Boolean = false,
|
||||
mtaEvent: String = "",
|
||||
mtaKey: String = ""): Dialog {
|
||||
return showDialog(context, title, content, positiveText, negativeText, { positiveClickCallback.onCallback() }, { negativeClickCallback.onCallback() }, trackMtaEvent, mtaEvent, mtaKey)
|
||||
return showDialog(
|
||||
context = context,
|
||||
title = title,
|
||||
content = content,
|
||||
confirmText = positiveText,
|
||||
cancelText = negativeText,
|
||||
confirmClickCallback = { positiveClickCallback.onCallback() },
|
||||
cancelClickCallback = { negativeClickCallback.onCallback() },
|
||||
trackMtaEvent = trackMtaEvent,
|
||||
mtaEvent = mtaEvent,
|
||||
mtaKey = mtaKey)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showSignatureConflictDialog(context: Context,
|
||||
confirmClickCallback: (() -> Unit)? = null) {
|
||||
showDialog(
|
||||
context,
|
||||
"温馨提示",
|
||||
"检测到安装包与已安装应用的签名不一致,需要卸载后才能安装,是否立即卸载",
|
||||
"卸载",
|
||||
"取消",
|
||||
{ confirmClickCallback?.invoke() },
|
||||
null,
|
||||
Config(hint = "注意:卸载会让游戏数据丢失,请提前做好备份"),
|
||||
{ binding -> binding.hintTv.setTextColor(R.color.theme_font.toColor()) }
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showPluginDialog(context: Context,
|
||||
confirmClickCallback: (() -> Unit)? = null) {
|
||||
MtaHelper.onEvent("插件化", "插件化安装弹窗", "出现弹窗提示")
|
||||
showDialog(
|
||||
context,
|
||||
"插件化安装",
|
||||
"您将进行插件化安装以实现插件功能,此过程将卸载当前使用的版本并安装插件版本",
|
||||
"确认,开始插件化",
|
||||
"取消",
|
||||
{
|
||||
confirmClickCallback?.invoke()
|
||||
MtaHelper.onEvent("插件化", "插件化安装弹窗", "确认并开始")
|
||||
},
|
||||
{ MtaHelper.onEvent("插件化", "插件化安装弹窗", "取消") },
|
||||
Config(hint = "注意:卸载前请妥善保存游戏账号与密码"),
|
||||
{ binding -> binding.hintTv.setTextColor(R.color.text_FF0000.toColor()) }
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showUpgradeDialog(context: Context) {
|
||||
showDialog(
|
||||
context,
|
||||
"提示",
|
||||
"当前版本暂不支持该功能,\n建议您升级到最新版本体验哦",
|
||||
"检查升级",
|
||||
"取消",
|
||||
confirmClickCallback = { context.startActivity(AboutActivity.getIntent(context, true)); },
|
||||
uiModificationCallback = {
|
||||
it.titleTv.gravity = Gravity.CENTER
|
||||
it.contentTv.gravity = Gravity.CENTER
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@JvmStatic
|
||||
fun showDowngradeHintDialog(context: Context,
|
||||
confirmClickCallback: (() -> Unit)? = null) {
|
||||
showDialog(
|
||||
context,
|
||||
"温馨提示",
|
||||
"您已安装较高版本,若要安装历史版本需先卸载再安装\n",
|
||||
"我知道了",
|
||||
"",
|
||||
{ confirmClickCallback?.invoke() })
|
||||
}
|
||||
|
||||
data class Config(val hint: String = "",
|
||||
val showCloseIcon: Boolean = false,
|
||||
val centerTitle: Boolean = false,
|
||||
val centerContent: Boolean = false)
|
||||
|
||||
}
|
||||
@ -46,6 +46,7 @@ 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;
|
||||
|
||||
@ -63,8 +64,11 @@ import com.gh.gamecenter.AboutActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.SuggestionActivity;
|
||||
import com.gh.gamecenter.adapter.viewholder.PrivacyPolicyItemViewHolder;
|
||||
import com.gh.gamecenter.databinding.DialogBindPhoneBinding;
|
||||
import com.gh.gamecenter.databinding.DialogOverseaConfirmationBinding;
|
||||
import com.gh.gamecenter.databinding.DialogPackageParseErrorBinding;
|
||||
import com.gh.gamecenter.databinding.DialogQuickLoginPermissionBinding;
|
||||
import com.gh.gamecenter.databinding.DialogReceiveLibaoSuccessBinding;
|
||||
import com.gh.gamecenter.databinding.DialogReportReasonBinding;
|
||||
import com.gh.gamecenter.databinding.ImprintContentItemBinding;
|
||||
import com.gh.gamecenter.databinding.PrivacyItemBinding;
|
||||
@ -322,33 +326,6 @@ public class DialogUtils {
|
||||
showCancelListenerDialog(context, "取消关注", content, "确定取消", "暂不取消", listener, cancelListener);
|
||||
}
|
||||
|
||||
public static void showPluginDialog(Context context, final ConfirmListener listener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
MtaHelper.onEvent("插件化", "插件化安装弹窗", "出现弹窗提示");
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_plugin, null);
|
||||
TextView negativeTv = contentView.findViewById(R.id.dialog_negative);
|
||||
TextView positiveTv = contentView.findViewById(R.id.dialog_positive);
|
||||
negativeTv.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
MtaHelper.onEvent("插件化", "插件化安装弹窗", "取消");
|
||||
});
|
||||
positiveTv.setOnClickListener(view -> {
|
||||
if (listener != null) {
|
||||
listener.onConfirm();
|
||||
}
|
||||
dialog.dismiss();
|
||||
MtaHelper.onEvent("插件化", "插件化安装弹窗", "确认并开始");
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* ios 风格弹窗
|
||||
*
|
||||
@ -809,33 +786,6 @@ public class DialogUtils {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showLowVersionDialog(Context context) {
|
||||
final Context activityContext = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(activityContext, R.style.GhAlertDialog);
|
||||
|
||||
View contentView = LayoutInflater.from(activityContext).inflate(R.layout.dialog_alert, 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("链接超出范围,请检查升级至最新版本的光环助手");
|
||||
titleTv.setText("提示");
|
||||
negativeTv.setText("关闭");
|
||||
positiveTv.setText("检查升级");
|
||||
|
||||
negativeTv.setOnClickListener(view -> dialog.dismiss());
|
||||
|
||||
positiveTv.setOnClickListener(view -> {
|
||||
activityContext.startActivity(AboutActivity.getIntent(activityContext, true));
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showLowSystemVersionDialog(Context context) {
|
||||
final Context activityContext = checkDialogContext(context);
|
||||
@ -1109,7 +1059,7 @@ public class DialogUtils {
|
||||
topContent.setText(entity.getTopContent());
|
||||
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)) {
|
||||
@ -2161,6 +2111,77 @@ public class DialogUtils {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showBindPhoneDialog(Context context, ConfirmListener listener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
DialogBindPhoneBinding binding = DialogBindPhoneBinding.inflate(LayoutInflater.from(context));
|
||||
|
||||
binding.positiveTv.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
listener.onConfirm();
|
||||
});
|
||||
|
||||
binding.closeIv.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(binding.getRoot());
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showReceiveLibaoSuccessDialog(Context context, String title, String des, String libaoCode, ConfirmListener listener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
DialogReceiveLibaoSuccessBinding binding = DialogReceiveLibaoSuccessBinding.inflate(LayoutInflater.from(context));
|
||||
binding.title.setText(title);
|
||||
binding.libaoCodeTv.setText(libaoCode);
|
||||
binding.desTv.setText(des);
|
||||
|
||||
binding.confirm.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
listener.onConfirm();
|
||||
});
|
||||
|
||||
binding.cancel.setOnClickListener(v -> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public static void showQuickLoginPermissionDialog(Context context, ConfirmListener confirmListener, CancelListener cancelListener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
DialogQuickLoginPermissionBinding binding = DialogQuickLoginPermissionBinding.inflate(LayoutInflater.from(context));
|
||||
|
||||
binding.confirmBtn.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
confirmListener.onConfirm();
|
||||
});
|
||||
|
||||
binding.cancelBtn.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
cancelListener.onCancel();
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(binding.getRoot());
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context may be is application context
|
||||
* @return activity context
|
||||
|
||||
@ -25,6 +25,7 @@ import com.gh.gamecenter.*
|
||||
import com.gh.gamecenter.amway.AmwayActivity
|
||||
import com.gh.gamecenter.catalog.CatalogActivity
|
||||
import com.gh.gamecenter.category.CategoryDirectoryActivity
|
||||
import com.gh.gamecenter.category2.CategoryV2Activity
|
||||
import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.eventbus.EBReuse
|
||||
@ -52,6 +53,7 @@ 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.GameServerTestActivity
|
||||
import com.gh.gamecenter.servers.GameServersActivity
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
import com.gh.gamecenter.suggest.SuggestType
|
||||
@ -209,6 +211,8 @@ object DirectUtils {
|
||||
|
||||
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
|
||||
|
||||
"category_v2" -> directCategoryV2(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
|
||||
|
||||
"block", "版块" -> {
|
||||
if (linkEntity.link.isNullOrEmpty()) return
|
||||
directToBlock(context,
|
||||
@ -238,7 +242,7 @@ object DirectUtils {
|
||||
|
||||
"libao", "礼包" -> directToGiftDetail(context, linkEntity.link ?: "", entrance)
|
||||
|
||||
"feedback" -> directToFeedback(context, linkEntity.name, linkEntity.text, entrance)
|
||||
"feedback" -> directToFeedback(context, linkEntity.name, linkEntity.text, false, entrance)
|
||||
|
||||
"qa", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
|
||||
|
||||
@ -302,6 +306,9 @@ object DirectUtils {
|
||||
|
||||
"toolkit" -> context.startActivity(ToolBoxActivity.getIntent(context, entrance))
|
||||
|
||||
"column_test" -> context.startActivity(GameServerTestActivity.getIntent(context, linkEntity.link
|
||||
?: "", linkEntity.text ?: "", entrance))
|
||||
|
||||
"toolkit_detail" -> {
|
||||
linkEntity.toolkit?.run {
|
||||
if (url != null && url!!.contains(Config.URL_ARTICLE)) {
|
||||
@ -325,7 +332,7 @@ object DirectUtils {
|
||||
if (unknownCallback != null) {
|
||||
unknownCallback.invoke()
|
||||
} else {
|
||||
DialogUtils.showLowVersionDialog(context)
|
||||
DialogHelper.showUpgradeDialog(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -424,6 +431,20 @@ object DirectUtils {
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到新闻详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToArticle(context: Context, id: String, hideUselessInfo: Boolean, entrance: String? = null) {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, NewsDetailActivity::class.java.simpleName)
|
||||
bundle.putString(KEY_NEWSID, id)
|
||||
bundle.putBoolean(KEY_HIDE_USELESS_INFO, hideUselessInfo)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至个人主页
|
||||
*/
|
||||
@ -438,6 +459,7 @@ object DirectUtils {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToHomeActivity(context: Context, userId: String?, position: Int, entrance: String? = null, path: String? = null) {
|
||||
IntegralLogHelper.log("view_homepage", "个人主页")
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_USER_ID, userId)
|
||||
bundle.putString(KEY_TO, UserHomeActivity::class.java.name)
|
||||
@ -539,21 +561,27 @@ object DirectUtils {
|
||||
// 反馈
|
||||
@JvmStatic
|
||||
fun directToFeedback(context: Context, content: String? = null, entrance: String? = null) {
|
||||
directToFeedback(context, content, null, entrance)
|
||||
directToFeedback(context, content, null, false, entrance)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToFeedback(context: Context, content: String? = null, hintType: String? = null, entrance: String? = null) {
|
||||
fun directToFeedback(context: Context, content: String? = null, hintType: String? = null, isQaFeedback: Boolean = false, entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, SuggestionActivity::class.java.simpleName)
|
||||
bundle.putString(KEY_CONTENT, content)
|
||||
if (TextUtils.isEmpty(hintType)) {
|
||||
bundle.putString(KEY_SUGGEST_HINT_TYPE, KEY_PLUGIN)
|
||||
if (isQaFeedback) {
|
||||
bundle.putBoolean(KEY_IS_QA_FEEDBACK, true)
|
||||
bundle.putSerializable(KEY_SUGGESTTYPE, SuggestType.normal)
|
||||
} else {
|
||||
bundle.putString(KEY_SUGGEST_HINT_TYPE, hintType)
|
||||
bundle.putString(KEY_CONTENT, content)
|
||||
bundle.putSerializable(KEY_SUGGESTTYPE, SuggestType.gameQuestion)
|
||||
if (TextUtils.isEmpty(hintType)) {
|
||||
bundle.putString(KEY_SUGGEST_HINT_TYPE, KEY_PLUGIN)
|
||||
} else {
|
||||
bundle.putString(KEY_SUGGEST_HINT_TYPE, hintType)
|
||||
}
|
||||
}
|
||||
bundle.putSerializable(KEY_SUGGESTTYPE, SuggestType.gameQuestion)
|
||||
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@ -978,6 +1006,20 @@ object DirectUtils {
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转新分类2.0
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directCategoryV2(context: Context, categoryId: String, categoryTitle: String, entrance: String? = null, path: String? = "") {
|
||||
if (categoryId.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, CategoryV2Activity::class.java.name)
|
||||
bundle.putString(KEY_CATEGORY_ID, categoryId)
|
||||
bundle.putString(KEY_CATEGORY_TITLE, categoryTitle)
|
||||
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到问题标签详情
|
||||
*/
|
||||
@ -1267,7 +1309,7 @@ object DirectUtils {
|
||||
} else {
|
||||
Constants.INVITE_FRIENDS_ADDRESS
|
||||
}
|
||||
directToFullScreenWebPage(context, url, false)
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1284,4 +1326,139 @@ object DirectUtils {
|
||||
url = String.format(Locale.CHINA, "%s?timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至兑换规则
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToExchangeRulePage(context: Context) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.EXCHANGE_RULE_ADDRESS
|
||||
} else {
|
||||
Constants.EXCHANGE_RULE_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s×tamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至光能规则
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToEnergyRulePage(context: Context) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.ENERGY_RULE_ADDRESS
|
||||
} else {
|
||||
Constants.ENERGY_RULE_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s×tamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至兑换商品
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToExchangeCommodityPage(context: Context) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.EXCHANGE_COMMODITY_ADDRESS
|
||||
} else {
|
||||
Constants.EXCHANGE_COMMODITY_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s×tamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至抽奖乐园
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToLotteryParadisePage(context: Context) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.LOTTERY_PARADISE_ADDRESS
|
||||
} else {
|
||||
Constants.LOTTERY_PARADISE_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s×tamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至我的奖品
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToMyPrizePage(context: Context) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.MY_PRIZE_ADDRESS
|
||||
} else {
|
||||
Constants.MY_PRIZE_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s×tamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至中奖订单详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToWinOrderDetail(context: Context, orderId: String, activityId: String) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.WIN_ORDER_DETAIL_ADDRESS
|
||||
} else {
|
||||
Constants.WIN_ORDER_DETAIL_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s&order_id=%s&activity_id=%s×tamp=%d", url, orderId, activityId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至地址信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToAddressInfo(context: Context) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.ADDRESS_INFO_ADDRESS
|
||||
} else {
|
||||
Constants.ADDRESS_INFO_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s×tamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至领奖信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToPrizeInfo(context: Context) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.PRIZE_INFO_ADDRESS
|
||||
} else {
|
||||
Constants.PRIZE_INFO_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s×tamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至提现信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToWithdrawInfo(context: Context) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.WITHDRAW_INFO_ADDRESS
|
||||
} else {
|
||||
Constants.WITHDRAW_INFO_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s×tamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
}
|
||||
@ -21,67 +21,74 @@ object DownloadDialogHelper {
|
||||
}
|
||||
|
||||
private fun retrieveAvailableDialog(gameEntity: GameEntity, apkEntity: ApkEntity): GameEntity.Dialog? {
|
||||
if (gameEntity.downloadDialog.isNullOrEmpty()) return null
|
||||
val downloadDialog = if (gameEntity.shouldUseMirrorInfo()) {
|
||||
gameEntity.mirrorData?.downloadDialog
|
||||
} else {
|
||||
gameEntity.downloadDialog
|
||||
}
|
||||
|
||||
for (dialog in gameEntity.downloadDialog!!) {
|
||||
if (downloadDialog.isNullOrEmpty()) return null
|
||||
for (dialog in downloadDialog) {
|
||||
val versionName = PackageUtils.getVersionName()
|
||||
val noticeVersions = dialog.rule.noticeVersions
|
||||
if (noticeVersions.isEmpty() || noticeVersions.contains(versionName)) {
|
||||
// 共有 8 种可能
|
||||
// 1. 不指定包名、机型和系统版本
|
||||
if (dialog.rule.packageName.isEmpty()
|
||||
&& dialog.rule.models.isEmpty()
|
||||
&& dialog.rule.systemVersions.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
|
||||
// 共有 8 种可能
|
||||
// 1. 不指定包名、机型和系统版本
|
||||
if (dialog.rule.packageName.isEmpty()
|
||||
&& dialog.rule.models.isEmpty()
|
||||
&& dialog.rule.systemVersions.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
// 2. 指定包名不管机型和系统
|
||||
if (dialog.rule.packageName == apkEntity.packageName
|
||||
&& dialog.rule.models.isEmpty()
|
||||
&& dialog.rule.systemVersions.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
|
||||
// 2. 指定包名不管机型和系统
|
||||
if (dialog.rule.packageName == apkEntity.packageName
|
||||
&& dialog.rule.models.isEmpty()
|
||||
&& dialog.rule.systemVersions.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
// 3. 指定机型不管包名和系统
|
||||
if (dialog.rule.models.contains(Build.MODEL)
|
||||
&& dialog.rule.packageName.isEmpty()
|
||||
&& dialog.rule.systemVersions.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
|
||||
// 3. 指定机型不管包名和系统
|
||||
if (dialog.rule.models.contains(Build.MODEL)
|
||||
&& dialog.rule.packageName.isEmpty()
|
||||
&& dialog.rule.systemVersions.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
// 4. 指定系统不管包名和机型
|
||||
if (dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
|
||||
&& dialog.rule.packageName.isEmpty()
|
||||
&& dialog.rule.models.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
|
||||
// 4. 指定系统不管包名和机型
|
||||
if (dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
|
||||
&& dialog.rule.packageName.isEmpty()
|
||||
&& dialog.rule.models.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
// 5. 指定包名和机型不管系统
|
||||
if (dialog.rule.packageName == apkEntity.packageName
|
||||
&& dialog.rule.models.contains(Build.MODEL)
|
||||
&& dialog.rule.systemVersions.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
|
||||
// 5. 指定包名和机型不管系统
|
||||
if (dialog.rule.packageName == apkEntity.packageName
|
||||
&& dialog.rule.models.contains(Build.MODEL)
|
||||
&& dialog.rule.systemVersions.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
// 6. 指定包名和系统不管机型
|
||||
if (dialog.rule.packageName == apkEntity.packageName
|
||||
&& dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
|
||||
&& dialog.rule.models.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
|
||||
// 6. 指定包名和系统不管机型
|
||||
if (dialog.rule.packageName == apkEntity.packageName
|
||||
&& dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
|
||||
&& dialog.rule.models.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
|
||||
// 7. 指定机型和系统不管包名
|
||||
if (dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
|
||||
&& dialog.rule.models.contains(Build.MODEL)
|
||||
&& dialog.rule.packageName.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
|
||||
// 8.指定包名、机型和系统版本
|
||||
if (dialog.rule.packageName == apkEntity.packageName
|
||||
&& dialog.rule.models.contains(Build.MODEL)
|
||||
&& dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)) {
|
||||
return dialog
|
||||
}
|
||||
// 7. 指定机型和系统不管包名
|
||||
if (dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
|
||||
&& dialog.rule.models.contains(Build.MODEL)
|
||||
&& dialog.rule.packageName.isEmpty()) {
|
||||
return dialog
|
||||
}
|
||||
|
||||
// 8.指定包名、机型和系统版本
|
||||
if (dialog.rule.packageName == apkEntity.packageName
|
||||
&& dialog.rule.models.contains(Build.MODEL)
|
||||
&& dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)) {
|
||||
return dialog
|
||||
}
|
||||
} else return null
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
@ -28,6 +28,7 @@ import com.gh.common.xapk.XapkInstaller;
|
||||
import com.gh.common.xapk.XapkUnzipStatus;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.download.dialog.DownloadDialog;
|
||||
import com.gh.download.server.BrowserInstallHelper;
|
||||
import com.gh.gamecenter.DownloadManagerActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.WebActivity;
|
||||
@ -36,6 +37,7 @@ import com.gh.gamecenter.entity.ApkEntity;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.LinkEntity;
|
||||
import com.gh.gamecenter.entity.PluginLocation;
|
||||
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.lightgame.download.DownloadConfig;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
@ -136,6 +138,7 @@ public class DownloadItemUtils {
|
||||
holder.gameDownloadBtn.setText("已预约");
|
||||
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(holder.gameDes.getContext(), R.color.aaaaaa));
|
||||
holder.gameDownloadBtn.setBackgroundResource(R.drawable.button_round_f5f5f5);
|
||||
updateItemViewStatus(holder, false, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -545,15 +548,19 @@ public class DownloadItemUtils {
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
}
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(context, () -> {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location);
|
||||
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) context, gameEntity, gameEntity.getInfo(), () -> {
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(context, () -> {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -586,12 +593,18 @@ public class DownloadItemUtils {
|
||||
|
||||
if (str.equals(context.getString(R.string.download))) {
|
||||
// 先弹下载弹窗(如果需要的话)
|
||||
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));
|
||||
RealNameHelper.checkIfAuth(context, gameEntity, () -> {
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) context, gameEntity, gameEntity.getInfo(), () -> {
|
||||
BrowserInstallHelper.showBrowserInstallHintDialog(context, () -> {
|
||||
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity, () -> {
|
||||
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));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -599,13 +612,19 @@ public class DownloadItemUtils {
|
||||
|
||||
DataLogUtils.uploadGameLog(context, gameEntity.getId(), gameEntity.getName(), entrance);
|
||||
} else if (str.equals(context.getString(R.string.attempt))) {
|
||||
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));
|
||||
RealNameHelper.checkIfAuth(context, gameEntity, () -> {
|
||||
GamePermissionDialogFragment.show((AppCompatActivity) context, gameEntity, gameEntity.getInfo(), () -> {
|
||||
BrowserInstallHelper.showBrowserInstallHintDialog(context, () -> {
|
||||
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity, () -> {
|
||||
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));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -671,6 +690,7 @@ public class DownloadItemUtils {
|
||||
context.startActivity(DownloadManagerActivity.getDownloadMangerIntent(context,
|
||||
apk.getUrl(), entrance + "+(" + location.split(":")[0] + ")"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//下载
|
||||
@ -692,8 +712,6 @@ 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);
|
||||
}
|
||||
@ -732,7 +750,10 @@ public class DownloadItemUtils {
|
||||
}
|
||||
adapter.notifyItemChanged(position);
|
||||
} else if (PackageUtils.isCanPluggable(apkEntity)) {
|
||||
DialogUtils.showPluginDialog(context, () -> PackageInstaller.uninstall(context, path));
|
||||
DialogHelper.showPluginDialog(context, () -> {
|
||||
PackageInstaller.uninstall(context, path);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
PackageInstaller.install(context, downloadEntity);
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ 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.util.EnergyTaskHelper.postEnergyTask
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.download.DownloadDataHelper
|
||||
import com.gh.download.DownloadManager
|
||||
@ -126,6 +127,7 @@ object DownloadObserver {
|
||||
} else {
|
||||
statDoneEvent(downloadEntity)
|
||||
|
||||
postEnergyTask("download_game", downloadEntity.gameId, downloadEntity.packageName)
|
||||
val platform = PlatformUtils.getInstance(mApplication)
|
||||
.getPlatformName(downloadEntity.platform)
|
||||
if (platform != null) {
|
||||
@ -153,7 +155,7 @@ object DownloadObserver {
|
||||
SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator,
|
||||
SimulatorDownloadManager.SimulatorLocation.LAUNCH, downloadEntity.gameId, gameName, null)
|
||||
}
|
||||
SimulatorGameManager.recordDownloadSimulatorGames(downloadEntity.gameId)
|
||||
SimulatorGameManager.recordDownloadSimulatorGames(downloadEntity.gameId, simulator.type)
|
||||
SimulatorGameManager.postPlayedGame(downloadEntity.gameId, downloadEntity.packageName)
|
||||
} else {
|
||||
val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
|
||||
@ -171,7 +173,11 @@ object DownloadObserver {
|
||||
}
|
||||
} else {
|
||||
// 弹出卸载提示框
|
||||
EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path))
|
||||
if (downloadEntity.isPlugin) {
|
||||
EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path))
|
||||
} else {
|
||||
EventBus.getDefault().post(EBShowDialog(BaseActivity.SIGNATURE_CONFLICT, downloadEntity.path))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,11 +283,12 @@ object DownloadObserver {
|
||||
// "操作", "下载完成",
|
||||
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
|
||||
}
|
||||
|
||||
val isPlatformRecommend = java.lang.Boolean.parseBoolean(downloadEntity.getMetaExtra(Constants.IS_PLATFORM_RECOMMEND))
|
||||
ExposureUtils.logADownloadCompleteExposureEvent(
|
||||
GameEntity(id = downloadEntity.gameId,
|
||||
mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR),
|
||||
gameVersion = downloadEntity.versionName ?: ""),
|
||||
gameVersion = downloadEntity.versionName ?: "",
|
||||
isPlatformRecommend = isPlatformRecommend),
|
||||
downloadEntity.platform,
|
||||
downloadEntity.exposureTrace,
|
||||
downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown",
|
||||
|
||||
@ -99,7 +99,7 @@ object EnergyTaskHelper {
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun postInviteCodeTask(code: String, from: String, successCallback: () -> Unit, failCallback: () -> Unit) {
|
||||
fun postInviteCodeTask(code: String, from: String, callback: (() -> Unit)?) {
|
||||
if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0L) {
|
||||
val taskParams = JSONObject()
|
||||
taskParams.put("action", "enter_invite_code")
|
||||
@ -120,14 +120,9 @@ object EnergyTaskHelper {
|
||||
.subscribe(object : BiResponse<List<EnergyTaskCompleteEntity>>() {
|
||||
override fun onSuccess(data: List<EnergyTaskCompleteEntity>) {
|
||||
SPUtils.setBoolean(Constants.SP_HAS_COMPLETE_INVITE_CODE, true)
|
||||
successCallback.invoke()
|
||||
callback?.invoke()
|
||||
data.forEach { showCompletePopup(it) }
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
failCallback.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -144,7 +139,9 @@ object EnergyTaskHelper {
|
||||
isFocusable = true
|
||||
isFocusableInTouchMode = true
|
||||
setOnClickListener {
|
||||
currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity))
|
||||
if (currentActivity::class.java.simpleName != EnergyCenterActivity::class.java.simpleName) {
|
||||
currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity))
|
||||
}
|
||||
}
|
||||
}
|
||||
val popWindow = PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, 88F.dip2px())
|
||||
|
||||
@ -148,8 +148,10 @@ public class EntranceUtils {
|
||||
public static final String KEY_RECOMMENDS_CONTENTS = "isRecommendsContents";
|
||||
public static final String KEY_VERSION_UPDATE = "versionUpdate";
|
||||
public static final String KEY_CHECK_QUESTION_CONCERN = "check_question_concern";
|
||||
public static final String KEY_IS_COLUMN_COLLECTION = "is_column_collection";//是专题合集
|
||||
public static final String KEY_DRAFT_ID = "draft_id";
|
||||
public static final String KEY_KAIFU_LIST = "kaifuList";
|
||||
public static final String KEY_CATEGORY = "category";
|
||||
public static final String KEY_CATEGORY_ID = "category_id";
|
||||
public static final String KEY_CATEGORY_TITLE = "category_title";
|
||||
public static final String KEY_CATEGORY_INIT_TITLE = "category_init_title";
|
||||
@ -167,6 +169,7 @@ public class EntranceUtils {
|
||||
public static final String KEY_COLUMN_ID = "column_id";
|
||||
public static final String KEY_AUTO_DOWNLOAD = "auto_download";
|
||||
public static final String KEY_HIDE_SUGGEST_HINT = "hide_suggest_hint";
|
||||
public static final String KEY_HIDE_USELESS_INFO = "hide_useless_info";
|
||||
public static final String KEY_COMMUNITY_ARTICLE_ID = "communityArticleId";
|
||||
public static final String KEY_ARTICLE_COMMENT_ID = "articleCommentId";
|
||||
public static final String KEY_SHOW_ARTICLE_COMMENT = "showArticleComment";
|
||||
@ -190,6 +193,7 @@ public class EntranceUtils {
|
||||
public static final String KEY_UUID = "uuid";
|
||||
public static final String KEY_IS_HOME_VIDEO = "isHomeVideo";
|
||||
public static final String KEY_IS_HOME = "isHome";
|
||||
public static final String KEY_TAB_COUNT = "tab_count";
|
||||
public static final String KEY_WEB_SHARE = "webShare";
|
||||
public static final String KEY_ACTIVITY_NAME = "activityName";//活动名称
|
||||
public static final String KEY_PAGINATION_TYPE = "paginationType";//活动分页方式
|
||||
@ -212,6 +216,7 @@ public class EntranceUtils {
|
||||
public static final String KEY_CHANGE_PHONE = "changePhone";
|
||||
public static final String KEY_CONFLICT_PHONE = "conflictPhone";
|
||||
public static final String KEY_CONFLICT_USER = "conflictUser";
|
||||
public static final String KEY_EXPOSURE_SOURCE = "exposure_source";
|
||||
public static final String KEY_BBS_ID = "bbs_id";
|
||||
public static final String KEY_DIAGNOSIS = "diagnosis";
|
||||
public static final String KEY_SIMULATOR = "simulator";
|
||||
@ -224,6 +229,13 @@ public class EntranceUtils {
|
||||
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 final String KEY_IS_CHOOSE_APK = "is_choose_apk";
|
||||
public static final String KEY_TAB_INDEX = "tab_index";
|
||||
public static final String KEY_IS_CATEGORY_V2 = "is_category_v2";
|
||||
public static final String KEY_SUB_CATEGORY_ID = "sub_category_id";
|
||||
public static final String KEY_IS_QA_FEEDBACK = "is_qa_feedback";
|
||||
public static final String KEY_IS_CLICK_RECEIVE_BTN = "is_click_receive_btn";
|
||||
public static final String KEY_SHOW_QUICK_LOGIN = "show_quick_login";
|
||||
|
||||
public static void jumpActivity(Context context, Bundle bundle) {
|
||||
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
|
||||
|
||||
@ -4,6 +4,9 @@ import android.animation.Animator
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Build
|
||||
import android.text.*
|
||||
@ -67,11 +70,16 @@ inline fun <reified VM : ViewModel> FragmentActivity.viewModelProvider(
|
||||
|
||||
/**
|
||||
* 创建以 activity 为观察者上下文的 viewModel
|
||||
* 额外的 key: 用于区分单 activity 多 viewModel 的情况 (如首页tab)
|
||||
*/
|
||||
inline fun <reified VM : ViewModel> Fragment.viewModelProviderFromParent(
|
||||
provider: ViewModelProvider.Factory? = null
|
||||
) =
|
||||
ViewModelProviders.of(requireActivity(), provider).get(VM::class.java)
|
||||
provider: ViewModelProvider.Factory? = null,
|
||||
key: String = ""
|
||||
) = if (key.isEmpty()) {
|
||||
ViewModelProviders.of(requireActivity(), provider).get(VM::class.java)
|
||||
} else {
|
||||
ViewModelProviders.of(requireActivity(), provider).get(key, VM::class.java)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建以 activity 为观察者上下文的 viewModel
|
||||
@ -113,12 +121,16 @@ fun ViewPager.addOnPageChangeListener(onSelected: ((position: Int) -> Unit)? = n
|
||||
addOnPageChangeListener(listener)
|
||||
}
|
||||
|
||||
fun ViewPager.addOnScrollStateChanged(onStateChanged: ((state: Int) -> Unit)? = null) {
|
||||
fun ViewPager.doOnScroll(onStateChanged: ((state: Int) -> Unit)? = null,
|
||||
onPageScrolled: ((position: Int, positionOffset: Float, positionOffsetPixels: Int) -> Unit)? = null,
|
||||
onPageSelected: ((position: Int) -> Unit)? = null) {
|
||||
val listener = object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
onPageScrolled?.invoke(position, positionOffset, positionOffsetPixels)
|
||||
}
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
onPageSelected?.invoke(position)
|
||||
}
|
||||
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
@ -477,6 +489,9 @@ fun Float.sp2px(): Int {
|
||||
return (this * scale + 0.5f).toInt()
|
||||
}
|
||||
|
||||
fun Float.roundTo(n: Int): Float {
|
||||
return "%.${n}f".format(Locale.CHINA, this).toFloat()
|
||||
}
|
||||
|
||||
/**
|
||||
* PopupWindow 自动适配方向
|
||||
@ -534,14 +549,6 @@ 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() {
|
||||
@ -566,14 +573,6 @@ fun FragmentActivity.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
|
||||
})
|
||||
}
|
||||
|
||||
fun FragmentActivity.checkCalendarPermissionBeforeAction(action: (() -> Unit)) {
|
||||
PermissionHelper.checkCalendarPermissionBeforeAction(this, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
action.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* List related.
|
||||
*/
|
||||
@ -628,7 +627,7 @@ fun <T> List<T>.safelyGetInRelease(index: Int): T? {
|
||||
} else {
|
||||
try {
|
||||
this[index]
|
||||
} catch (e : IndexOutOfBoundsException){
|
||||
} catch (e: IndexOutOfBoundsException) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
@ -708,6 +707,10 @@ fun Int.toColor(): Int {
|
||||
return ContextCompat.getColor(HaloApp.getInstance().application, this)
|
||||
}
|
||||
|
||||
fun Int.toDrawable(): Drawable? {
|
||||
return ContextCompat.getDrawable(HaloApp.getInstance().application, this)
|
||||
}
|
||||
|
||||
fun Int.toResString(): String {
|
||||
return HaloApp.getInstance().application.resources.getString(this)
|
||||
}
|
||||
@ -947,4 +950,11 @@ fun <T> singleToMain(): SingleTransformer<T, T> {
|
||||
upstream.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
}
|
||||
|
||||
fun View.getBitmapFromView(): Bitmap? {
|
||||
val bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(bitmap)
|
||||
this.draw(canvas)
|
||||
return bitmap
|
||||
}
|
||||
@ -24,17 +24,24 @@ object HomePluggableHelper {
|
||||
val apkList = gameEntity.getApk()
|
||||
if (apkList.isNotEmpty()) {
|
||||
val apk = apkList.first()
|
||||
val filterData = mHomePluggableFilterDao.getDataByPkgName(apk.packageName)
|
||||
if (filterData?.active == true) {
|
||||
val filterTag = filterData.tag
|
||||
return filterTag != "never" && apk.version != filterTag
|
||||
tryCatchInRelease {
|
||||
val filterData = mHomePluggableFilterDao.getDataByPkgName(apk.packageName)
|
||||
if (filterData?.active == true) {
|
||||
val filterTag = filterData.tag
|
||||
return filterTag != "never" && apk.version != filterTag
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getPermanentInactivePluggablePackage() = mHomePluggableFilterDao.getDataByTag("never")
|
||||
fun getPermanentInactivePluggablePackage(): List<HomePluggableFilterEntity>? {
|
||||
tryCatchInRelease {
|
||||
return mHomePluggableFilterDao.getDataByTag("never")
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun activationFilterData() {
|
||||
|
||||
@ -43,6 +43,8 @@ object ImageUtils {
|
||||
private val LARGE_GIF_SIZE = 80F.dip2px()
|
||||
private val STANDARD_GIF_SIZE = 60F.dip2px()
|
||||
|
||||
const val TARGET_WIDTH = R.dimen.width_placeholder
|
||||
|
||||
private val mImageUrlCacheSet by lazy { FixedSizeLinkedHashSet<String>(maxSize = 200) }
|
||||
|
||||
@JvmStatic
|
||||
@ -86,7 +88,8 @@ 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
|
||||
val webpConfig = Config.getSettings()?.image?.oss?.webp
|
||||
?: Config.getSettings()?.image?.oss?.gif
|
||||
if (jpegConfig != null) {
|
||||
return if (width == 0 || width == null) {
|
||||
"$imageUrl$webpConfig"
|
||||
@ -298,10 +301,14 @@ object ImageUtils {
|
||||
* @param isAutoPlayGif 是否禁止播放动图
|
||||
*/
|
||||
@JvmStatic
|
||||
fun display(view: SimpleDraweeView?, url: String?, isAutoPlayGif: Boolean = true, processor: Postprocessor? = null) {
|
||||
fun display(view: SimpleDraweeView?,
|
||||
url: String?,
|
||||
isAutoPlayGif: Boolean = true,
|
||||
processor: Postprocessor? = null) {
|
||||
if (url == null) return
|
||||
|
||||
val width = view?.layoutParams?.width
|
||||
// 部分自适应宽高图片需要一个 TARGET_WIDTH 来避免加载过小图片
|
||||
val width = (view?.getTag(TARGET_WIDTH) as? Int) ?: view?.layoutParams?.width
|
||||
val height = view?.layoutParams?.height
|
||||
|
||||
var lowResUrl = ""
|
||||
@ -351,7 +358,7 @@ object ImageUtils {
|
||||
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
|
||||
} else {
|
||||
if (width != null && width > 0) {
|
||||
highResUrl = resizeGif(url, view.width, height ?: 0)
|
||||
highResUrl = resizeGif(url, view!!.width, height ?: 0)
|
||||
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
|
||||
} else {
|
||||
view?.post {
|
||||
@ -371,10 +378,10 @@ object ImageUtils {
|
||||
// 加载大小是实际 ImageView 大小两倍的图片真的有意义吗?
|
||||
val transformUrlX2 = addLimitWidth(url, width * 2)
|
||||
val transformUrlX1 = addLimitWidth(url, width)
|
||||
// 当网络为 WIFI 或 4G, 且系统版本大于 5.0 && 手机内存大于 2G 才用高清图片
|
||||
// 当网络为 WIFI 或 4G, 且系统版本大于 5.0 && 手机内存大于 4G 才用超高清图片 (x2)
|
||||
transformUrl = if (NetworkUtils.isWifiOr4GConnected(context)
|
||||
&& Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP
|
||||
&& HaloApp.getInstance().deviceRamSize > 2500) {
|
||||
&& HaloApp.getInstance().deviceRamSize > 4500) {
|
||||
transformUrlX2
|
||||
} else {
|
||||
// 检查X2大图是否被缓存
|
||||
@ -477,4 +484,22 @@ object ImageUtils {
|
||||
fun getVideoSnapshot(videoUrl: String, progress: Long): String {
|
||||
return "$videoUrl?x-oss-process=video/snapshot,t_$progress,f_jpg,w_0,h_0"
|
||||
}
|
||||
|
||||
/**
|
||||
* 虽然在 Application 里有使用子线程初始化但有可能出现初始化超时(卡住?)的情况,
|
||||
* 这里反射获取 sDraweecontrollerbuildersupplier 根据是否有值确定是否被初始化了
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isFrescoInitialized(): Boolean {
|
||||
val clazz = SimpleDraweeView::class.java
|
||||
return try {
|
||||
val field =
|
||||
clazz.getDeclaredField("sDraweecontrollerbuildersupplier")
|
||||
field.isAccessible = true
|
||||
val obj = field[SimpleDraweeView::class.java]
|
||||
obj != null
|
||||
} catch (ignore: java.lang.Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
157
app/src/main/java/com/gh/common/util/IntegralLogHelper.kt
Normal file
157
app/src/main/java/com/gh/common/util/IntegralLogHelper.kt
Normal file
@ -0,0 +1,157 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.gh.common.loghub.LoghubUtils.log
|
||||
import com.gh.common.tracker.Tracker.launchId
|
||||
import com.gh.common.tracker.Tracker.sessionId
|
||||
import com.lightgame.utils.Utils
|
||||
import org.json.JSONObject
|
||||
|
||||
object IntegralLogHelper {
|
||||
|
||||
fun log(event: String, location: String) = log(event, location, null)
|
||||
|
||||
fun log(event: String, location: String, entrance: String? = null) {
|
||||
val json = JSONObject().apply {
|
||||
tryWithDefaultCatch {
|
||||
put("meta", LogUtils.getMetaObject())
|
||||
put("event", event)
|
||||
put("location", location)
|
||||
put("timestamp", System.currentTimeMillis() / 1000)
|
||||
put("launch_id", launchId)
|
||||
put("session_id", sessionId)
|
||||
entrance?.let {
|
||||
put("entrance", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("LogUtils->$json")
|
||||
}
|
||||
log(json, "score", false)
|
||||
}
|
||||
|
||||
fun logTask(event: String, location: String, jobId: String, jobName: String, jobType: String) {
|
||||
val json = JSONObject().apply {
|
||||
tryWithDefaultCatch {
|
||||
put("meta", LogUtils.getMetaObject())
|
||||
put("event", event)
|
||||
put("location", location)
|
||||
put("timestamp", System.currentTimeMillis() / 1000)
|
||||
put("launch_id", launchId)
|
||||
put("session_id", sessionId)
|
||||
put("job_id", jobId)
|
||||
put("job_name", jobName)
|
||||
put("job_type", jobType)
|
||||
}
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("LogUtils->$json")
|
||||
}
|
||||
log(json, "score", false)
|
||||
}
|
||||
|
||||
fun logCommodityCategory(event: String, location: String, entrance: String, categoryId: String, categoryName: String) {
|
||||
val json = JSONObject().apply {
|
||||
tryWithDefaultCatch {
|
||||
put("meta", LogUtils.getMetaObject())
|
||||
put("event", event)
|
||||
put("location", location)
|
||||
put("timestamp", System.currentTimeMillis() / 1000)
|
||||
put("launch_id", launchId)
|
||||
put("session_id", sessionId)
|
||||
put("entrance", entrance)
|
||||
put("goods_species_id", categoryId)
|
||||
put("goods_species_name", categoryName)
|
||||
}
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("LogUtils->$json")
|
||||
}
|
||||
log(json, "score", false)
|
||||
}
|
||||
|
||||
fun logCommodity(event: String, location: String, commodityId: String, categoryId: String, categoryName: String) {
|
||||
val json = JSONObject().apply {
|
||||
tryWithDefaultCatch {
|
||||
put("meta", LogUtils.getMetaObject())
|
||||
put("event", event)
|
||||
put("location", location)
|
||||
put("timestamp", System.currentTimeMillis() / 1000)
|
||||
put("launch_id", launchId)
|
||||
put("session_id", sessionId)
|
||||
put("goods_id", commodityId)
|
||||
put("goods_species_id", categoryId)
|
||||
put("goods_species_name", categoryName)
|
||||
}
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("LogUtils->$json")
|
||||
}
|
||||
log(json, "score", false)
|
||||
}
|
||||
|
||||
fun logEnergyRange(event: String, location: String, range: String) {
|
||||
val json = JSONObject().apply {
|
||||
tryWithDefaultCatch {
|
||||
put("meta", LogUtils.getMetaObject())
|
||||
put("event", event)
|
||||
put("location", location)
|
||||
put("timestamp", System.currentTimeMillis() / 1000)
|
||||
put("launch_id", launchId)
|
||||
put("session_id", sessionId)
|
||||
put("energy_range", range)
|
||||
}
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("LogUtils->$json")
|
||||
}
|
||||
log(json, "score", false)
|
||||
}
|
||||
|
||||
fun logPendent(event: String, location: String, pendentId: String, pendentType: String? = null) {
|
||||
val json = JSONObject().apply {
|
||||
tryWithDefaultCatch {
|
||||
put("meta", LogUtils.getMetaObject())
|
||||
put("event", event)
|
||||
put("location", location)
|
||||
put("timestamp", System.currentTimeMillis() / 1000)
|
||||
put("launch_id", launchId)
|
||||
put("session_id", sessionId)
|
||||
put("pendant_id", pendentId)
|
||||
pendentType?.run {
|
||||
put("pendant_type", this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("LogUtils->$json")
|
||||
}
|
||||
log(json, "score", false)
|
||||
}
|
||||
|
||||
fun logInviteResult(result: String, type: String? = null) {
|
||||
val json = JSONObject().apply {
|
||||
tryWithDefaultCatch {
|
||||
put("meta", LogUtils.getMetaObject())
|
||||
put("event", "invite_result")
|
||||
put("location", "邀请途径面板")
|
||||
put("timestamp", System.currentTimeMillis() / 1000)
|
||||
put("launch_id", launchId)
|
||||
put("session_id", sessionId)
|
||||
put("invitation_result", result)
|
||||
put("invitation_type", type)
|
||||
}
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("LogUtils->$json")
|
||||
}
|
||||
log(json, "score", false)
|
||||
}
|
||||
}
|
||||
@ -28,14 +28,17 @@ import com.gh.gamecenter.manager.UserManager;
|
||||
import com.gh.gamecenter.retrofit.JSONObjectResponse;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
@ -151,9 +154,10 @@ public class LibaoUtils {
|
||||
});
|
||||
}
|
||||
|
||||
public static void setLiBaoBtnStatusRound(final TextView libaoBtn, String status, Context context) {
|
||||
public static void setLiBaoBtnStatusRound(final TextView libaoBtn, LibaoEntity libaoEntity, boolean shouldUpdateStatus, Context context) {
|
||||
String status = shouldUpdateStatus ? updateStatus(libaoEntity) : libaoEntity.getStatus();
|
||||
libaoBtn.setTextColor(Color.WHITE);
|
||||
if (TextUtils.isEmpty(status)) return;
|
||||
if (status == null || TextUtils.isEmpty(status)) return;
|
||||
switch (status) {
|
||||
case "ling":
|
||||
libaoBtn.setText(R.string.libao_ling);
|
||||
@ -180,8 +184,8 @@ public class LibaoUtils {
|
||||
break;
|
||||
case "linged":
|
||||
libaoBtn.setText(R.string.libao_linged);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_border_round_gray);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.button_gray));
|
||||
break;
|
||||
case "taoed":
|
||||
libaoBtn.setText(R.string.libao_taoed);
|
||||
@ -193,22 +197,16 @@ public class LibaoUtils {
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
|
||||
break;
|
||||
case "repeatLing":
|
||||
libaoBtn.setText(R.string.libao_repeat_ling);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
|
||||
break;
|
||||
case "repeatLinged":
|
||||
libaoBtn.setText(R.string.libao_repeat_ling);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
|
||||
break;
|
||||
case "repeatTao":
|
||||
libaoBtn.setText(R.string.libao_repeat_tao);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
|
||||
break;
|
||||
case "repeatTao":
|
||||
case "repeatTaoed":
|
||||
libaoBtn.setText(R.string.libao_repeat_tao);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
|
||||
break;
|
||||
case "unshelve":
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_border_round_gray);
|
||||
@ -227,14 +225,85 @@ public class LibaoUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static void initLibaoBtn(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity,
|
||||
final boolean isInstallRequired, final LibaoDetailAdapter adapter, final String entrance) {
|
||||
public static String updateStatus(LibaoEntity libaoEntity) {
|
||||
String status = libaoEntity.getStatus();
|
||||
setLiBaoBtnStatusRound(libaoBtn, status, context);
|
||||
String beforeStatus = libaoEntity.getBeforeStatus();
|
||||
if (libaoEntity.getRepeat() > 0 && libaoEntity.getMe() != null
|
||||
&& libaoEntity.getMe().getUserDataLibaoList() != null) {
|
||||
|
||||
MeEntity userData = libaoEntity.getMe();
|
||||
List<UserDataLibaoEntity> userDataLibaoList = userData.getUserDataLibaoList();
|
||||
|
||||
int repeat = libaoEntity.getRepeat();
|
||||
int curStatusCount = 0; // 当前状态的领取/淘号数量
|
||||
|
||||
for (UserDataLibaoEntity userDataLibaoEntity : userDataLibaoList) {
|
||||
if (beforeStatus != null && beforeStatus.equals(userDataLibaoEntity.getType())) {
|
||||
curStatusCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// 由领取到淘号的状态转换
|
||||
if (repeat <= curStatusCount || curStatusCount == 0) { // 当前领取/淘号总数是否超过总重复领取次数 / 当前状态的礼包没有领取/淘号过
|
||||
if (curStatusCount == 0 && ("ling".equals(beforeStatus) || "tao".equals(beforeStatus))) {
|
||||
if (isCanLing(libaoEntity)) { // 恢复原始状态
|
||||
return beforeStatus;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((("linged").equals(status) || ("taoed").equals(status)) &&
|
||||
("ling".equals(beforeStatus) || "tao".equals(beforeStatus))) { //检查是否到了重复领取时间
|
||||
if (isCanLing(libaoEntity)) {
|
||||
if ("ling".equals(beforeStatus)) {
|
||||
return "repeatLinged"; // 可以重复领取
|
||||
} else {
|
||||
return "repeatTaoed"; // 可以重复领取
|
||||
}
|
||||
} else {
|
||||
if ("ling".equals(beforeStatus)) {
|
||||
return "repeatLing"; // 预备重复领取
|
||||
} else {
|
||||
return "repeatTao"; // 预备重复领取
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
public static boolean isCanLing(LibaoEntity libaoEntity) {
|
||||
List<UserDataLibaoEntity> userDataLibaoList = libaoEntity.getMe().getUserDataLibaoList();
|
||||
UserDataLibaoEntity userDataLibaoEntity = userDataLibaoList.get(userDataLibaoList.size() - 1);
|
||||
SimpleDateFormat formatDay = new SimpleDateFormat("dd", Locale.CHINA);
|
||||
long lingTime = userDataLibaoEntity.getTime() * 1000;
|
||||
long curTime = Utils.getTime(HaloApp.getInstance()) * 1000;
|
||||
int lingDay = Integer.parseInt(formatDay.format(lingTime));
|
||||
int curDay = Integer.parseInt(formatDay.format(curTime));
|
||||
if (curDay != lingDay || curTime - lingTime > 24 * 60 * 60 * 1000) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void initLibaoBtn(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity,
|
||||
final boolean isInstallRequired, final LibaoDetailAdapter adapter, boolean shouldUpdateStatus, final String entrance) {
|
||||
String status = libaoEntity.getStatus();
|
||||
setLiBaoBtnStatusRound(libaoBtn, libaoEntity, shouldUpdateStatus, context);
|
||||
|
||||
if (adapter != null) {
|
||||
if (libaoBtn.getText().toString().equals("再领")) {
|
||||
libaoBtn.setText("再领一个");
|
||||
}
|
||||
if (libaoBtn.getText().toString().equals("再淘")) {
|
||||
libaoBtn.setText("再淘一个");
|
||||
}
|
||||
}
|
||||
|
||||
libaoBtn.setOnClickListener(v -> {
|
||||
String btnStatus = libaoBtn.getText().toString();
|
||||
|
||||
// 领取限制
|
||||
CheckLoginUtils.checkLogin(context, "礼包详情-[" + btnStatus + "]", () -> {
|
||||
if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) {
|
||||
@ -280,6 +349,7 @@ public class LibaoUtils {
|
||||
Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null);
|
||||
}
|
||||
break;
|
||||
case "再领":
|
||||
case "再领一个":
|
||||
case "领取":
|
||||
if ("repeatLing".equals(status)) {
|
||||
@ -290,136 +360,140 @@ public class LibaoUtils {
|
||||
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
|
||||
}
|
||||
break;
|
||||
case "再淘":
|
||||
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();
|
||||
|
||||
JSONObject responseBody = (JSONObject) response;
|
||||
String libaoCode = null;
|
||||
try {
|
||||
libaoCode = responseBody.getString("code");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(libaoCode)) {
|
||||
try {
|
||||
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;
|
||||
}
|
||||
|
||||
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, "发生异常");
|
||||
}
|
||||
});
|
||||
libaoTao(context, libaoBtn, libaoEntity, isInstallRequired, adapter, status, entrance);
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static void libaoTao(Context context, TextView libaoBtn, LibaoEntity libaoEntity, boolean isInstallRequired, LibaoDetailAdapter adapter, String status, String entrance) {
|
||||
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();
|
||||
|
||||
JSONObject responseBody = (JSONObject) response;
|
||||
String libaoCode = null;
|
||||
boolean hasSame = false;
|
||||
try {
|
||||
hasSame = responseBody.getBoolean("has_same");
|
||||
libaoCode = responseBody.getString("code");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(libaoCode)) {
|
||||
try {
|
||||
String detail = responseBody.getString("detail").toLowerCase();
|
||||
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;
|
||||
}
|
||||
Utils.toast(context, "淘号成功");
|
||||
libaoEntity.setStatus("taoed");
|
||||
EventBus.getDefault().post(new EBReuse("libaoChanged"));
|
||||
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
|
||||
uploadEvent(libaoEntity, true, entrance);
|
||||
final String finalLibaoCode = libaoCode;
|
||||
String des;
|
||||
if (!hasSame) {
|
||||
des = "淘到的礼包码不保证可以兑换,请尽快前往游戏兑换";
|
||||
} else {
|
||||
des = "您已领取过相同的礼包,可能无法成功兑换,请自行尝试";
|
||||
}
|
||||
DialogUtils.showReceiveLibaoSuccessDialog(context, "淘号成功", des, finalLibaoCode, () -> {
|
||||
copyLink(finalLibaoCode, context);
|
||||
if (isInstallRequired) {
|
||||
libaoBtn.postDelayed(() -> {
|
||||
Spanned msg = Html.fromHtml(
|
||||
context.getString(R.string.taoed_copy_dialog
|
||||
, finalLibaoCode));
|
||||
lunningAppDialog(context
|
||||
, msg, libaoEntity);
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@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").toLowerCase();
|
||||
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, "发生异常");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void libaoLing(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity, final LibaoDetailAdapter adapter,
|
||||
final boolean isInstallRequired, String captchaCode, final String entrance) {
|
||||
|
||||
@ -435,45 +509,56 @@ public class LibaoUtils {
|
||||
if (loadingDialog != null) loadingDialog.dismiss();
|
||||
|
||||
JSONObject responseBody = (JSONObject) response;
|
||||
boolean hasSame = false; //是否领取过相同的礼包
|
||||
String libaoCode = null;
|
||||
int gameApkSize = 1;//游戏apk的size,大于1为“多版本插件游戏”,否则为“非插件游戏/单版本插件游戏”
|
||||
try {
|
||||
hasSame = responseBody.getBoolean("has_same");
|
||||
libaoCode = responseBody.getString("code");
|
||||
gameApkSize = responseBody.getInt("game_apk_size");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(libaoCode)) {
|
||||
Utils.toast(context, "领取异常");
|
||||
return;
|
||||
}
|
||||
libaoEntity.setAvailable(libaoEntity.getAvailable() - 1);
|
||||
|
||||
libaoEntity.setStatus("linged");
|
||||
|
||||
EventBus.getDefault().post(new EBReuse("libaoChanged"));
|
||||
|
||||
uploadEvent(libaoEntity, false, entrance);
|
||||
|
||||
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "ling", Utils.getTime(context)));
|
||||
adapter.notifyDataSetChanged();
|
||||
final String finalLibaoCode = libaoCode;
|
||||
boolean finalHasSame = hasSame;
|
||||
int finalGameApkSize = gameApkSize;
|
||||
NotificationHelper.showNotificationHintDialog(NotificationUgc.GIFT, isShow -> {
|
||||
if (!isShow) {
|
||||
DialogUtils.showWarningDialog(context, "领取成功", Html.fromHtml(context.getString(R.string.linged_dialog, finalLibaoCode))
|
||||
, "关闭", " 复制礼包码"
|
||||
, () -> {
|
||||
copyLink(finalLibaoCode, context);
|
||||
if (isInstallRequired) {
|
||||
libaoBtn.postDelayed(() -> {
|
||||
Spanned msg = Html.fromHtml(context.getString(R.string.linged_copy_dialog, finalLibaoCode));
|
||||
lunningAppDialog(context
|
||||
, msg, libaoEntity);
|
||||
}, 300);
|
||||
}
|
||||
}, null);
|
||||
String des;
|
||||
if (!finalHasSame) {
|
||||
if (finalGameApkSize > 1) {
|
||||
des = "礼包码将于60分钟后进入淘号池,部分礼包兑换有平台限制,请根据使用说明兑换";
|
||||
} else {
|
||||
des = "礼包码将于60分钟后进入淘号池,请尽快前往游戏兑换";
|
||||
}
|
||||
} else {
|
||||
des = "您已领取过相同的礼包,可能无法成功兑换,请自行尝试";
|
||||
}
|
||||
DialogUtils.showReceiveLibaoSuccessDialog(context, "领取成功", des, finalLibaoCode, () -> {
|
||||
copyLink(finalLibaoCode, context);
|
||||
if (isInstallRequired) {
|
||||
libaoBtn.postDelayed(() -> {
|
||||
Spanned msg = Html.fromHtml(context.getString(R.string.linged_copy_dialog, finalLibaoCode));
|
||||
lunningAppDialog(context
|
||||
, msg, libaoEntity);
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -486,7 +571,7 @@ public class LibaoUtils {
|
||||
try {
|
||||
String string = exception.response().errorBody().string();
|
||||
JSONObject errorJson = new JSONObject(string);
|
||||
String detail = errorJson.getString("detail");
|
||||
String detail = errorJson.getString("detail").toLowerCase();
|
||||
switch (detail) {
|
||||
case "coming":
|
||||
Utils.toast(context, "礼包领取时间未开始");
|
||||
@ -516,7 +601,7 @@ public class LibaoUtils {
|
||||
DialogUtils.showHintDialog(context, "礼包已领光"
|
||||
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
|
||||
libaoEntity.setStatus("used_up");
|
||||
initLibaoBtn(context, libaoBtn, libaoEntity, isInstallRequired, adapter, entrance);
|
||||
initLibaoBtn(context, libaoBtn, libaoEntity, isInstallRequired, adapter, false, entrance);
|
||||
break;
|
||||
case "maintaining":
|
||||
Utils.toast(context, "网络状态异常,请稍后再试");
|
||||
@ -544,6 +629,24 @@ public class LibaoUtils {
|
||||
}, captchaCode);
|
||||
}
|
||||
|
||||
private static void uploadEvent(LibaoEntity libaoEntity, boolean isTao, String entrance) {
|
||||
String location = "";
|
||||
if (!libaoEntity.getClickReceiveBtnIn()) {
|
||||
location = "礼包详情";
|
||||
} else {
|
||||
if (entrance.contains("游戏详情")) {
|
||||
location = "游戏详情";
|
||||
} else if (entrance.contains("礼包中心:最新")) {
|
||||
location = "礼包中心-最新";
|
||||
} else if (entrance.contains("礼包中心:关注")) {
|
||||
location = "礼包中心-关注";
|
||||
}
|
||||
}
|
||||
String event = isTao ? "game_gift_dig_successful" : "game_gift_get_successful";
|
||||
LogUtils.uploadReceiveGift(event, libaoEntity.getId(), libaoEntity.getName(), location,
|
||||
libaoEntity.getGame() == null ? "" : libaoEntity.getGame().getId(), libaoEntity.getGame() == null ? "" : libaoEntity.getGame().getName());
|
||||
}
|
||||
|
||||
public static boolean isAppInstalled(Context context, String packageName) {
|
||||
List<PackageInfo> pinfo = PackageUtils.getInstalledPackages(context, 0);
|
||||
if (pinfo != null) {
|
||||
|
||||
@ -16,7 +16,9 @@ import com.gh.common.loghub.LoghubUtils;
|
||||
import com.gh.common.loghub.SimpleLogContainerEntity;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.entity.CommunityEntity;
|
||||
import com.gh.gamecenter.entity.DetectionObjectEntity;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.PackageDialogEntity;
|
||||
import com.gh.gamecenter.entity.ShareResultEntity;
|
||||
import com.gh.gamecenter.entity.SpecialColumn;
|
||||
import com.gh.gamecenter.entity.StartupAdEntity;
|
||||
@ -27,6 +29,7 @@ import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@ -236,6 +239,10 @@ public class LogUtils {
|
||||
object.put("game_name", gameEntity.getName());
|
||||
object.put("game_id", gameEntity.getId());
|
||||
object.put("game_platform", gameEntity.getPlatform());
|
||||
if (event != null) {
|
||||
object.put("sequence", event.getPayload().getSequence());
|
||||
object.put("outer_sequence", event.getPayload().getOuterSequence());
|
||||
}
|
||||
object.put("download_open", gameEntity.getDownloadOffStatus() == null ? "true" : "false");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
@ -265,6 +272,7 @@ public class LogUtils {
|
||||
object.put("device_model", android.os.Build.MODEL);
|
||||
object.put("jnfj", MetaUtil.getBase64EncodedIMEI());
|
||||
object.put("G_ID", UserManager.getInstance().getDeviceId());
|
||||
object.put("oaid", HaloApp.getInstance().getOAID());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -595,6 +603,7 @@ public class LogUtils {
|
||||
metaObject.put("network", meta.getNetwork());
|
||||
metaObject.put("os", meta.getOs());
|
||||
metaObject.put("userId", meta.getUserId());
|
||||
metaObject.put("oaid", HaloApp.getInstance().getOAID());
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
@ -705,6 +714,120 @@ public class LogUtils {
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void logGameDetailStrategyButtonEvent(String gameId,
|
||||
String gameName,
|
||||
String text) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("event", "game_detail_click_strategy_button");
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("game_id", gameId);
|
||||
object.put("game_name", gameName);
|
||||
object.put("text", text);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void logServerTestAccessEvent(String entrance,
|
||||
String entranceDetail,
|
||||
String serverTestName,
|
||||
String serverTestNote) {
|
||||
JSONObject payload = new JSONObject();
|
||||
try {
|
||||
payload.put("server_test_name", serverTestName);
|
||||
payload.put("server_test_note", serverTestNote);
|
||||
payload.put("entrance", entrance);
|
||||
payload.put("entrance_detail", entranceDetail);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
logServerTestEvent("access_to_server_test", payload);
|
||||
}
|
||||
|
||||
public static void logServerTestSelectTypeEvent(String buttonText,
|
||||
String serverTestName,
|
||||
String serverTestNote) {
|
||||
JSONObject payload = new JSONObject();
|
||||
try {
|
||||
payload.put("server_test_name", serverTestName);
|
||||
payload.put("server_test_note", serverTestNote);
|
||||
payload.put("button_text", buttonText);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
logServerTestEvent("server_test_select_type", payload);
|
||||
}
|
||||
|
||||
public static void logServerTestSelectTimeEvent(String buttonText,
|
||||
String serverTestName,
|
||||
String serverTestNote) {
|
||||
JSONObject payload = new JSONObject();
|
||||
try {
|
||||
payload.put("server_test_name", serverTestName);
|
||||
payload.put("server_test_note", serverTestNote);
|
||||
payload.put("button_text", buttonText);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
logServerTestEvent("server_test_select_time", payload);
|
||||
}
|
||||
|
||||
public static void logServerTestClickAllEvent(String serverTestName,
|
||||
String serverTestNote) {
|
||||
JSONObject payload = new JSONObject();
|
||||
try {
|
||||
payload.put("server_test_name", serverTestName);
|
||||
payload.put("server_test_note", serverTestNote);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
logServerTestEvent("server_test_click_all", payload);
|
||||
}
|
||||
|
||||
public static void logServerTestClickMoreEvent(String serverTestName,
|
||||
String serverTestNote,
|
||||
String redirectType,
|
||||
String redirectLink) {
|
||||
JSONObject payload = new JSONObject();
|
||||
try {
|
||||
payload.put("server_test_name", serverTestName);
|
||||
payload.put("server_test_note", serverTestNote);
|
||||
payload.put("redirect_type", redirectType);
|
||||
payload.put("redirect_link", redirectLink);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
logServerTestEvent("server_test_click_more", payload);
|
||||
}
|
||||
|
||||
private static void logServerTestEvent(String event, JSONObject payload) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("event", event);
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
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 logNewCatalogAppearanceEvent(String entrance, String key) {
|
||||
logCatalogEvent("access_to_classification", entrance, key, -1, -1, -1, -1);
|
||||
}
|
||||
@ -812,4 +935,228 @@ public class LogUtils {
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void logRecommendClick(String entrance, String recommendName, String linkType, String linkTitle, int sequence) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("event", "recommend_click");
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("entrance", entrance);
|
||||
object.put("recommend_name", recommendName);
|
||||
object.put("link_type", linkType);
|
||||
object.put("link_title", linkTitle);
|
||||
object.put("sequence", sequence);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void uploadPackageCheck(String event, String action, GameEntity gameEntity, String linkTitle, String linkDesc, String downloadGameId, String downloadGameName) {
|
||||
if (gameEntity == null) return;
|
||||
|
||||
PackageDialogEntity packageDialog = gameEntity.getPackageDialog();
|
||||
if (packageDialog == null) return;
|
||||
JSONObject object = new JSONObject();
|
||||
JSONObject payloadObject = new JSONObject();
|
||||
try {
|
||||
object.put("event", event);
|
||||
object.put("action", action);
|
||||
|
||||
payloadObject.put("game_id", gameEntity.getId());
|
||||
payloadObject.put("game_name", gameEntity.getName());
|
||||
payloadObject.put("link_title", linkTitle);
|
||||
payloadObject.put("link_desc", linkDesc);
|
||||
payloadObject.put("download_game_id", downloadGameId);
|
||||
payloadObject.put("download_game_name", downloadGameName);
|
||||
JSONArray detectionArray = new JSONArray();
|
||||
for (DetectionObjectEntity entity : packageDialog.getDetectionObjects()) {
|
||||
JSONObject detectionObject = new JSONObject();
|
||||
detectionObject.put("text", entity.getText());
|
||||
detectionObject.put("packages", new JSONArray(GsonUtils.toJson(entity.getPackages())));
|
||||
detectionArray.put(detectionObject);
|
||||
}
|
||||
payloadObject.put("detection_objects", detectionArray);
|
||||
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("payload", payloadObject);
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void logCategoryV2AppearanceEvent(String entrance, String classification) {
|
||||
logCategoryV2Event("access_to_classification_v2", entrance, classification, "", "", "", "", "", -1, -1, -1, -1);
|
||||
}
|
||||
|
||||
public static void logCategoryV2ClickSideEvent(String entrance, String classification, String sideClassification, int seq) {
|
||||
logCategoryV2Event("click_side", entrance, classification, sideClassification, "", "", "", "", seq, -1, -1, -1);
|
||||
}
|
||||
|
||||
public static void logCategoryV2ClickClassificationEvent(String entrance, String classification, String sideClassification, String classification1, String classification2, int seq1, int seq2) {
|
||||
logCategoryV2Event("click_classification", entrance, classification, sideClassification, classification1, classification2, "", "", -1, -1, seq1, seq2);
|
||||
}
|
||||
|
||||
public static void logCategoryV2ClickClassificationDeleteEvent(String entrance, String classification, String classification1, String classification2, String location) {
|
||||
logCategoryV2Event("click_classification_delete", entrance, classification, "", classification1, classification2, "", location, -1, -1, -1, -1);
|
||||
}
|
||||
|
||||
public static void logCategoryV2ClickDetermineEvent(String entrance, String classification, String classification2) {
|
||||
logCategoryV2Event("click_determine", entrance, classification, "", "", classification2, "", "", -1, -1, -1, -1);
|
||||
}
|
||||
|
||||
public static void logCategoryV2ClickResetEvent(String entrance, String classification, String classification2, String location) {
|
||||
logCategoryV2Event("click_reset", entrance, classification, "", "", classification2, "", location, -1, -1, -1, -1);
|
||||
}
|
||||
|
||||
public static void logSpecialCategoryV2BannerClickEvent(String entrance, String classification, String detail, int seq) {
|
||||
logCategoryV2Event("category_lunbo_click_v2", entrance, classification, "", "", "", detail, "", seq, -1, -1, -1);
|
||||
}
|
||||
|
||||
public static void logSpecialCategoryV2ContentClickEvent(String entrance, String classification, String detail, int seq) {
|
||||
logCategoryV2Event("click_content_v2", entrance, classification, "", "", "", detail, "", seq, -1, -1, -1);
|
||||
}
|
||||
|
||||
public static void logSpecialCategoryV2SpecificContentClickEvent(String entrance, String classification, String detail, int seq, int outSeq) {
|
||||
logCategoryV2Event("click_content_list_v2", entrance, classification, "", "", "", detail, "", seq, outSeq, -1, -1);
|
||||
}
|
||||
|
||||
public static void logCategoryV2Event(String event,
|
||||
String entrance,
|
||||
String classification,
|
||||
String sideClassification,
|
||||
String classification1,
|
||||
String classification2,
|
||||
String detail,
|
||||
String location,
|
||||
int seq,
|
||||
int outSeq,
|
||||
int seq1,
|
||||
int seq2) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("event", event);
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
|
||||
object.put("entrance", entrance);
|
||||
object.put("classification", classification);
|
||||
object.put("side_classification", sideClassification);
|
||||
object.put("classification_1st", classification1);
|
||||
object.put("classification_2nd", classification2);
|
||||
object.put("detail", detail);
|
||||
object.put("location", location);
|
||||
object.put("sequence", seq);
|
||||
object.put("outer_sequence", outSeq);
|
||||
object.put("seq_1st", seq1);
|
||||
object.put("seq_2nd", seq2);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void logGameDetailFixedTopArticleClick(String gameId, String gameName, String url) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("event", "game_detail_click_top_strategy");
|
||||
object.put("game_id", gameId);
|
||||
object.put("game_name", gameName);
|
||||
object.put("top_strategy_url", url);
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void logHomeTopTabClick(String tabName, String linkType, String linkTitle, int sequence) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("event", "top_tab_click");
|
||||
object.put("tab_name", tabName);
|
||||
object.put("link_type", linkType);
|
||||
object.put("link_title", linkTitle);
|
||||
object.put("sequence", sequence);
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void uploadRecommendPopup(String event, String popupId, String gameId, String gameName,
|
||||
String linkType, String linkTitle, String downloadGameId, String downloadGameName) {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONObject payloadObject = new JSONObject();
|
||||
try {
|
||||
object.put("event", event);//recommend_pop_show推荐弹窗出现、recommend_pop_close推荐弹窗手动关闭、recommend_pop_link_click点击推荐弹窗链接、recommend_pop_download推荐弹窗下载开始、recommend_pop_download_complete推荐弹窗下载完成
|
||||
payloadObject.put("recommend_pop_id", popupId);
|
||||
payloadObject.put("game_id", gameId);
|
||||
payloadObject.put("game_name", gameName);
|
||||
if (!TextUtils.isEmpty(linkType)) {
|
||||
payloadObject.put("link_type", linkType);
|
||||
}
|
||||
if (!TextUtils.isEmpty(linkTitle)) {
|
||||
payloadObject.put("link_title", linkTitle);
|
||||
}
|
||||
if (!TextUtils.isEmpty(downloadGameId)) {
|
||||
payloadObject.put("download_game_id", downloadGameId);
|
||||
}
|
||||
if (!TextUtils.isEmpty(downloadGameName)) {
|
||||
payloadObject.put("download_game_name", downloadGameName);
|
||||
}
|
||||
object.put("payload", payloadObject);
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void uploadReceiveGift(String event, String giftId, String giftName, String location, String gameId, String gameName) {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONObject payloadObject = new JSONObject();
|
||||
try {
|
||||
object.put("event", event);//game_gift_get_successful领取礼包、game_gift_dig_successful淘号
|
||||
payloadObject.put("gift_id", giftId);
|
||||
payloadObject.put("gift_name", giftName);
|
||||
payloadObject.put("location", location);
|
||||
payloadObject.put("game_id", gameId);
|
||||
payloadObject.put("game_name", gameName);
|
||||
object.put("payload", payloadObject);
|
||||
object.put("meta", getMetaObject());
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
|
||||
@ -69,6 +70,9 @@ public class MessageShareUtils {
|
||||
private PopupWindow mPopupWindow;
|
||||
private Bitmap shareBm; //分享截图
|
||||
private String picName;
|
||||
private ShareWay shareWay;
|
||||
private boolean isFromInviteFriends = false;
|
||||
private String mWriteBitmapPath;
|
||||
|
||||
|
||||
private String[] mArrLabel = {"微信好友", "朋友圈", "QQ好友", "QQ空间", "保存"};
|
||||
@ -80,15 +84,39 @@ public class MessageShareUtils {
|
||||
R.drawable.share_save
|
||||
};
|
||||
|
||||
public enum ShareWay {
|
||||
qq("qq"),
|
||||
qqZone("qq空间"),
|
||||
weibo("微博"),
|
||||
wechat("微信"),
|
||||
wechatMoments("朋友圈");
|
||||
|
||||
private String name;
|
||||
|
||||
ShareWay(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
//QQ或者QQ空间分享回调处理
|
||||
public IUiListener QqShareListener = new IUiListener() {
|
||||
@Override
|
||||
public void onComplete(Object o) {
|
||||
Utils.toast(mContext, "分享成功");
|
||||
if (isFromInviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("成功", shareWay.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(UiError uiError) {
|
||||
if (isFromInviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("失败", shareWay.getName());
|
||||
}
|
||||
// 单分享图片不支持显示未安装弹窗,手动调出
|
||||
if (mActivity != null) {
|
||||
Activity activity = mActivity.get();
|
||||
@ -109,6 +137,9 @@ public class MessageShareUtils {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
Utils.toast(mContext, R.string.share_cancel_hint);
|
||||
if (isFromInviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("取消", shareWay.getName());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -125,6 +156,12 @@ public class MessageShareUtils {
|
||||
mTencent = Tencent.createInstance(Config.TENCENT_APPID, context); //初始化QQ分享
|
||||
mIWXAPI = WXAPIFactory.createWXAPI(context, Config.WECHAT_APPID); //初始化微信分享
|
||||
mContext = context.getApplicationContext();
|
||||
// 安卓11无法访问Android/data目录
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
mWriteBitmapPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/ShareImg/";
|
||||
} else {
|
||||
mWriteBitmapPath = context.getExternalCacheDir().getPath() + "/ShareImg/";
|
||||
}
|
||||
}
|
||||
|
||||
public static MessageShareUtils getInstance(Context context) {
|
||||
@ -214,10 +251,16 @@ public class MessageShareUtils {
|
||||
});
|
||||
}
|
||||
|
||||
public void shareInviteFriends(Activity activity, String type) {
|
||||
isFromInviteFriends = true;
|
||||
shareFromWeb(activity, type);
|
||||
}
|
||||
|
||||
public void shareFromWeb(Activity activity, String type) {
|
||||
this.mActivity = new WeakReference<>(activity);
|
||||
|
||||
if ("weibo".equals(type)) {
|
||||
shareWay = ShareWay.weibo;
|
||||
weiboShare();
|
||||
} else {
|
||||
// base64转bitmap
|
||||
@ -229,7 +272,7 @@ public class MessageShareUtils {
|
||||
this.shareBm = bitmap;
|
||||
|
||||
// 保存图片
|
||||
File file = new File(activity.getExternalCacheDir().getPath() + "/ShareImg");
|
||||
File file = new File(mWriteBitmapPath);
|
||||
if (!file.isDirectory()) {
|
||||
file.delete();
|
||||
file.mkdirs();
|
||||
@ -242,15 +285,19 @@ public class MessageShareUtils {
|
||||
// 分享
|
||||
switch (type) {
|
||||
case "qq" :
|
||||
shareWay = ShareWay.qq;
|
||||
qqShare();
|
||||
break;
|
||||
case "qq_zone" :
|
||||
shareWay = ShareWay.qqZone;
|
||||
qZoneShare();
|
||||
break;
|
||||
case "wechat" :
|
||||
shareWay = ShareWay.wechat;
|
||||
wechatShare();
|
||||
break;
|
||||
case "wechat_moments" :
|
||||
shareWay = ShareWay.wechatMoments;
|
||||
wechatMomentsShare();
|
||||
break;
|
||||
case "save" :
|
||||
@ -267,7 +314,7 @@ public class MessageShareUtils {
|
||||
Bundle params = new Bundle();
|
||||
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE,
|
||||
QQShare.SHARE_TO_QQ_TYPE_IMAGE);
|
||||
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
|
||||
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, mWriteBitmapPath + picName);
|
||||
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, mContext.getString(R.string.app_name));
|
||||
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT,
|
||||
QQShare.SHARE_TO_QQ_FLAG_QZONE_ITEM_HIDE);
|
||||
@ -287,7 +334,7 @@ public class MessageShareUtils {
|
||||
Bundle params = new Bundle();
|
||||
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE,
|
||||
QQShare.SHARE_TO_QQ_TYPE_IMAGE);
|
||||
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
|
||||
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, mWriteBitmapPath + picName);
|
||||
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, mContext.getString(R.string.app_name));
|
||||
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT,
|
||||
QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN);
|
||||
@ -312,7 +359,7 @@ public class MessageShareUtils {
|
||||
|
||||
//官方分享
|
||||
WXImageObject imgObj = new WXImageObject();
|
||||
imgObj.setImagePath(mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
|
||||
imgObj.setImagePath(mWriteBitmapPath + picName);
|
||||
WXMediaMessage msg = new WXMediaMessage();
|
||||
msg.mediaObject = imgObj;
|
||||
|
||||
@ -347,7 +394,7 @@ public class MessageShareUtils {
|
||||
}
|
||||
|
||||
WXImageObject imgObj = new WXImageObject();
|
||||
imgObj.setImagePath(mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
|
||||
imgObj.setImagePath(mWriteBitmapPath + picName);
|
||||
WXMediaMessage msg = new WXMediaMessage();
|
||||
msg.mediaObject = imgObj;
|
||||
|
||||
|
||||
@ -5,6 +5,11 @@ import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import com.cmic.sso.sdk.auth.AuthnHelper;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class NetworkUtils {
|
||||
|
||||
/**
|
||||
@ -75,6 +80,26 @@ public class NetworkUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否打开数据流量(一键登录必须要打开流量才能获取到手机号码)
|
||||
*
|
||||
* AuthnHelper的getNetworkType方法用于获取用户当前的网络环境和运营商,返回的是JSONObject,其中
|
||||
* operatorType字段获取网络运营商: 0.未知 1.移动流量 2.联通流量 3.电信流量,
|
||||
* networkType字段获取网络状态:0.未知;1.流量 2.wifi;3.数据流量+wifi
|
||||
*/
|
||||
public static boolean isOpenMobileData(Context context){
|
||||
AuthnHelper helper = AuthnHelper.getInstance(context);
|
||||
JSONObject jsonObject = helper.getNetworkType(context);
|
||||
int net;
|
||||
try {
|
||||
net = Integer.parseInt(jsonObject.getString("networkType"));
|
||||
if (net == 1 || net == 3) return true;
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前网络连接的类型信息
|
||||
*
|
||||
|
||||
@ -58,7 +58,7 @@ object NotificationHelper {
|
||||
when (ugc) {
|
||||
NotificationUgc.LOGIN -> {
|
||||
if (!isShowedLogin) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_LOGIN, true)
|
||||
// 设置今天的时间,表示今天已经触发过了
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
@ -68,7 +68,7 @@ object NotificationHelper {
|
||||
}
|
||||
NotificationUgc.QUESTION -> {
|
||||
if (!isShowedQuestion) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_QUESTION, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
@ -77,7 +77,7 @@ object NotificationHelper {
|
||||
}
|
||||
NotificationUgc.ANSWER -> {
|
||||
if (!isShowedAnswer) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_ANSWER, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
@ -86,7 +86,7 @@ object NotificationHelper {
|
||||
}
|
||||
NotificationUgc.ARTICLE -> {
|
||||
if (!isShowedArticle) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_ARTICLE, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
@ -95,7 +95,7 @@ object NotificationHelper {
|
||||
}
|
||||
NotificationUgc.VIDEO -> {
|
||||
if (!isShowedVideo) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_VIDEO, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
@ -104,7 +104,7 @@ object NotificationHelper {
|
||||
}
|
||||
NotificationUgc.RATING -> {
|
||||
if (!isShowedRating) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_RATING, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
@ -113,7 +113,7 @@ object NotificationHelper {
|
||||
}
|
||||
NotificationUgc.GIFT -> {
|
||||
if (!isShowedGift) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_GIFT, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
@ -122,7 +122,7 @@ object NotificationHelper {
|
||||
}
|
||||
NotificationUgc.RESERVE_GAME -> {
|
||||
if (!isShowedReserveGame) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_RESERVE_GAME, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
@ -131,7 +131,7 @@ object NotificationHelper {
|
||||
}
|
||||
NotificationUgc.FEEDBACK -> {
|
||||
if (!isShowedFeedback) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_FEEDBACK, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
|
||||
@ -11,6 +11,7 @@ import androidx.core.content.FileProvider
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.dialog.InstallPermissionDialogFragment
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.download.server.BrowserInstallHelper
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadEntity
|
||||
@ -21,7 +22,6 @@ import java.io.File
|
||||
|
||||
object PackageInstaller {
|
||||
|
||||
|
||||
/**
|
||||
* 为了兼容java代码
|
||||
*/
|
||||
@ -55,7 +55,7 @@ object PackageInstaller {
|
||||
if (isXapk) {
|
||||
XapkInstaller.install(context, downloadEntity, showUnzipToast)
|
||||
} else {
|
||||
install(context, downloadEntity.path)
|
||||
install(context, downloadEntity.isPlugin, downloadEntity.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -68,16 +68,30 @@ object PackageInstaller {
|
||||
* 除非你已经确定该文件一定是Apk
|
||||
*/
|
||||
@JvmStatic
|
||||
fun install(context: Context, pkgPath: String) {
|
||||
fun install(context: Context, isPluggin: Boolean = false, pkgPath: String) {
|
||||
try {
|
||||
// 判断是否需要使用浏览器来进行安装
|
||||
if (BrowserInstallHelper.isUseBrowserToInstallEnabled()
|
||||
&& BrowserInstallHelper.shouldUseBrowserToInstall()) {
|
||||
BrowserInstallHelper.downloadFile(pkgPath)
|
||||
return
|
||||
}
|
||||
|
||||
if (PackageUtils.isCanLaunchSetup(context, pkgPath)) {
|
||||
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
|
||||
|
||||
val installIntent = getInstallIntent(context, pkgPath)
|
||||
context.startActivity(installIntent)
|
||||
} else {
|
||||
DialogUtils.showPluginDialog(context) {
|
||||
uninstall(context, pkgPath)
|
||||
if (isPluggin) {
|
||||
DialogHelper.showPluginDialog(context) {
|
||||
uninstall(context, pkgPath)
|
||||
}
|
||||
} else {
|
||||
// 非插件化的同包名不同签名冲突
|
||||
DialogHelper.showSignatureConflictDialog(context) {
|
||||
uninstall(context, pkgPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
@ -295,7 +295,7 @@ 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)) {
|
||||
@ -305,46 +305,45 @@ public class PackageUtils {
|
||||
}
|
||||
return getPackageNameByPathAlternative(path);
|
||||
}
|
||||
|
||||
|
||||
PackageManager packageManager = context.getApplicationContext().getPackageManager();
|
||||
PackageInfo info = packageManager.getPackageArchiveInfo(path, 0);
|
||||
if (info != null) {
|
||||
ApplicationInfo appInfo = info.applicationInfo;
|
||||
return appInfo.packageName;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 此设备是否不能调用 packageManager.getPackageArchiveInfo 来获取 APK 信息
|
||||
*
|
||||
* <p>
|
||||
* 部分设备 (已知 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) {
|
||||
&& 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
|
||||
*
|
||||
* <p>
|
||||
* 令人迷惑的点:
|
||||
* 1. 同样的代码,同样的 APK 在 demo 包里调用 packageManager.getPackageArchiveInfo 并不会 ANR
|
||||
* 2. 把 packageManager.getPackageArchiveInfo 放在子线程调用一样会出现 ANR
|
||||
* 3. demo 里 manifest 中 application 配置和 targetSdk 也改成与光环一样也不会出现 ANR
|
||||
*
|
||||
* <p>
|
||||
* 大概是光环的某个配置触发了系统的 bug ?
|
||||
*
|
||||
*/
|
||||
private static String getPackageNameByPathAlternative(String path) {
|
||||
ApkFile apkParser = null;
|
||||
@ -353,7 +352,7 @@ public class PackageUtils {
|
||||
ApkMeta apkMeta = apkParser.getApkMeta();
|
||||
apkParser.close();
|
||||
return apkMeta.getPackageName();
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
@ -446,6 +445,31 @@ public class PackageUtils {
|
||||
return list;
|
||||
}
|
||||
|
||||
public static ArrayList<String> getAllPackageNameIncludeGh(Context context) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
list.add(packageInfo.packageName);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/*
|
||||
* 获取所有已安装的软件的包名(包括系统应用)
|
||||
*/
|
||||
public static ArrayList<String> getAllPackageNameIncludeSystemApps(Context context) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if (!context.getPackageName().equals(packageInfo.packageName)) {
|
||||
list.add(packageInfo.packageName);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static JSONArray getAppList(Context context) {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
try {
|
||||
@ -544,7 +568,7 @@ public class PackageUtils {
|
||||
gh_version = gh_version.substring(2);
|
||||
try {
|
||||
return Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion()) && apkEntity
|
||||
.getForce() && gh_id.equals(gameId);
|
||||
.getForce() && gh_id.equals(gameId);
|
||||
} catch (NumberFormatException exception) {
|
||||
// gh_id 可能出錯
|
||||
exception.printStackTrace();
|
||||
@ -554,6 +578,45 @@ public class PackageUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isNonPluginUpdatable(ApkEntity apkEntity, GameEntity gameEntity) {
|
||||
// 非插件游戏更新
|
||||
// ghVersion 不存在即是非插件游戏
|
||||
if (TextUtils.isEmpty(apkEntity.getGhVersion())) {
|
||||
String versionFromRequest = apkEntity.getVersion();
|
||||
String versionFromInstalledApp = getVersionByPackage(apkEntity.getPackageName());
|
||||
|
||||
// 是否需要显示更新
|
||||
boolean shouldShowUpdate = apkEntity.getForce();
|
||||
|
||||
if (shouldShowUpdate && !TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp)) {
|
||||
// 根据版本判断是否需要更新
|
||||
shouldShowUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
|
||||
|
||||
if (shouldShowUpdate) {
|
||||
GameUpdateEntity updateEntity = new GameUpdateEntity();
|
||||
updateEntity.setId(gameEntity.getId());
|
||||
updateEntity.setName(gameEntity.getName());
|
||||
updateEntity.setIcon(gameEntity.getIcon());
|
||||
updateEntity.setPackageName(apkEntity.getPackageName());
|
||||
updateEntity.setSize(apkEntity.getSize());
|
||||
updateEntity.setVersion(apkEntity.getVersion());
|
||||
updateEntity.setGhVersion(apkEntity.getGhVersion());
|
||||
updateEntity.setUrl(apkEntity.getUrl());
|
||||
updateEntity.setPlatform(apkEntity.getPlatform());
|
||||
updateEntity.setEtag(apkEntity.getEtag());
|
||||
updateEntity.setBrief(gameEntity.getBrief());
|
||||
updateEntity.setTag(gameEntity.getTag());
|
||||
updateEntity.setTagStyle(gameEntity.getTagStyle());
|
||||
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
|
||||
updateEntity.setPluginDesc(gameEntity.getPluginDesc());
|
||||
updateEntity.setFormat(apkEntity.getFormat());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* todo 统一判断
|
||||
* <p>
|
||||
@ -621,13 +684,6 @@ 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.
|
||||
|
||||
35
app/src/main/java/com/gh/common/util/PageSwitchDataHelper.kt
Normal file
35
app/src/main/java/com/gh/common/util/PageSwitchDataHelper.kt
Normal file
@ -0,0 +1,35 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.lightgame.utils.AppManager
|
||||
|
||||
/**
|
||||
* 用来简单获取上一个跳转页面的跳转信息的辅助类
|
||||
* 简单解藕,不想层层传递数据可以把简单数据放这里面
|
||||
* 暂只支持单页面(上一 activity)记录,不支持连续跨页
|
||||
*/
|
||||
object PageSwitchDataHelper {
|
||||
|
||||
const val PAGE_BUSINESS_NAME = "page_business_name"
|
||||
const val PAGE_BUSINESS_TYPE = "page_business_type"
|
||||
const val PAGE_GAME_DETAIL_RECOMMEND = "page_game_detail_recommend"
|
||||
|
||||
private var mDataFromTheLastPage: Pair<String, HashMap<String, String>>? = null
|
||||
|
||||
@JvmStatic
|
||||
fun popLastPageData(): HashMap<String, String>? {
|
||||
AppManager.getInstance().previousActivity()?.let {
|
||||
if (System.identityHashCode(it).toString() == mDataFromTheLastPage?.first
|
||||
&& mDataFromTheLastPage?.second != null) {
|
||||
return mDataFromTheLastPage!!.second.also { mDataFromTheLastPage = null }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun pushCurrentPageData(data: HashMap<String, String>) {
|
||||
AppManager.getInstance().currentActivity()?.let {
|
||||
mDataFromTheLastPage = Pair(System.identityHashCode(it).toString(), data)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -9,8 +9,10 @@ import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.gamecenter.R
|
||||
import com.tbruyelle.rxpermissions2.RxPermissions
|
||||
|
||||
object PermissionHelper {
|
||||
@ -103,7 +105,7 @@ object PermissionHelper {
|
||||
@JvmStatic
|
||||
fun checkReadPhoneStateAndStoragePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
|
||||
if (context is FragmentActivity) {
|
||||
if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
|
||||
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) == 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()
|
||||
@ -143,7 +145,7 @@ object PermissionHelper {
|
||||
fun checkReadPhoneStatePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
|
||||
if (context is FragmentActivity) {
|
||||
|
||||
if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
|
||||
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
|
||||
emptyCallback.onCallback()
|
||||
} else {
|
||||
val rxPermission = RxPermissions(context)
|
||||
@ -173,48 +175,6 @@ object PermissionHelper {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun checkCalendarPermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
|
||||
if (context is FragmentActivity) {
|
||||
val rxPermission = RxPermissions(context)
|
||||
|
||||
tryWithDefaultCatch {
|
||||
rxPermission
|
||||
.requestEachCombined(Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CALENDAR)
|
||||
.subscribe { permission ->
|
||||
when {
|
||||
permission.granted -> {
|
||||
emptyCallback.onCallback()
|
||||
}
|
||||
permission.shouldShowRequestPermissionRationale -> {
|
||||
DialogUtils.showPermissionDialog(context,
|
||||
"权限申请",
|
||||
"光环助手需要日历权限,以保证能正常使用相关功能",
|
||||
"重试",
|
||||
"放弃",
|
||||
{ checkCalendarPermissionBeforeAction(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到权限设置
|
||||
*
|
||||
@ -262,19 +222,21 @@ object PermissionHelper {
|
||||
}
|
||||
|
||||
private fun showDialogBeforeRequestingStorageDialog(context: FragmentActivity, emptyCallback: EmptyCallback) {
|
||||
DialogHelper.showRoundedCornerDialog(
|
||||
DialogHelper.showDialog(
|
||||
context,
|
||||
title = "权限申请",
|
||||
content = "光环助手将向您申请开启设备的存储权限,以保证能正常使用相关功能。拒绝授权将无法正常使用部分功能。",
|
||||
hint = "查看权限应用场景",
|
||||
cancelText = "放弃",
|
||||
confirmText = "去授权",
|
||||
hintClickCallback = {
|
||||
DirectUtils.directToWebView(context, Constants.PERMISSION_SCENARIO_ADDRESS, "(权限弹窗)")
|
||||
},
|
||||
cancelClickCallback = null,
|
||||
confirmClickCallback = {
|
||||
checkStoragePermissionBeforeAction(context, emptyCallback)
|
||||
confirmClickCallback = { checkStoragePermissionBeforeAction(context, emptyCallback) },
|
||||
extraConfig = DialogHelper.Config(hint = "查看权限应用场景"),
|
||||
uiModificationCallback = {
|
||||
it.hintTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
|
||||
it.hintTv.setOnClickListener {
|
||||
DirectUtils.directToWebView(context, Constants.PERMISSION_SCENARIO_ADDRESS, "(权限弹窗)")
|
||||
}
|
||||
it.contentTv.setTextColor(ContextCompat.getColor(context, R.color.text_333333))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
320
app/src/main/java/com/gh/common/util/QuickLoginHelper.kt
Normal file
320
app/src/main/java/com/gh/common/util/QuickLoginHelper.kt
Normal file
@ -0,0 +1,320 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Color
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import com.cmic.sso.sdk.AuthThemeConfig
|
||||
import com.cmic.sso.sdk.auth.AuthnHelper
|
||||
import com.cmic.sso.sdk.auth.LoginClickListener
|
||||
import com.cmic.sso.sdk.auth.TokenListener
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.PermissionHelper.checkReadPhoneStatePermissionBeforeAction
|
||||
import com.gh.common.util.ToastUtils.toast
|
||||
import com.gh.gamecenter.LoginActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.DialogQuickLoginBinding
|
||||
import com.gh.gamecenter.databinding.SetWaitDialogBinding
|
||||
import com.gh.gamecenter.entity.LoginTokenEntity
|
||||
import com.gh.gamecenter.user.ApiResponse
|
||||
import com.gh.gamecenter.user.LoginTag
|
||||
import com.gh.gamecenter.user.UserRepository
|
||||
import com.lightgame.utils.AppManager
|
||||
import com.lightgame.utils.Utils
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* 一键登录辅助类
|
||||
* 1.取号请求
|
||||
* 2.授权请求
|
||||
* 3.获取token
|
||||
* 4.请求登录接口
|
||||
*/
|
||||
object QuickLoginHelper {
|
||||
|
||||
private var mAuthnHelper: AuthnHelper? = null
|
||||
private var mTokenListener: TokenListener? = null
|
||||
private var mPreDialog: Dialog? = null
|
||||
private var mDialog: Dialog? = null
|
||||
private var mToken: String = ""
|
||||
private var mOpenAuthPageSuccess = false
|
||||
private const val REQUEST_GET_PHONE_INFO_CODE = 100
|
||||
private const val REQUEST_LOGIN_AUTH_CODE = 101
|
||||
private const val ENTRANCE_DEFAULT = "一键登录"
|
||||
private const val ENTRANCE_PERMISSION_DIALOG = "一键登录权限弹窗"
|
||||
private const val AUTH_ACTIVITY_NAME = "com.cmic.sso.sdk.activity.LoginAuthActivity"
|
||||
|
||||
@JvmStatic
|
||||
fun startLogin(context: Context, entrance: String) {
|
||||
// 防止短时间多次调用
|
||||
if (ClickUtils.isFastDoubleClick(991)) return
|
||||
|
||||
mOpenAuthPageSuccess = false
|
||||
|
||||
if (isPublishEnv()) {
|
||||
AuthnHelper.setDebugMode(false)
|
||||
} else {
|
||||
AuthnHelper.setDebugMode(true)
|
||||
}
|
||||
mAuthnHelper = AuthnHelper.getInstance(context.applicationContext)
|
||||
mAuthnHelper?.run {
|
||||
authThemeConfig = getConfig(context, entrance)
|
||||
// 授权页面的回调方法
|
||||
setPageInListener { code, _ ->
|
||||
// 返回码200087代表授权页成功拉起
|
||||
if (code == "200087") {
|
||||
if (mPreDialog != null && mPreDialog!!.isShowing) {
|
||||
mPreDialog?.dismiss()
|
||||
}
|
||||
mOpenAuthPageSuccess = true
|
||||
} else { // 不成功就调起验证码登录页
|
||||
toastCode(code)
|
||||
startCodeLoginPage(context, true)
|
||||
}
|
||||
}
|
||||
|
||||
// token回调
|
||||
mTokenListener = TokenListener { requestCode: Int, jsonObject: JSONObject ->
|
||||
val code = jsonObject.optString("resultCode")
|
||||
// “103000”为成功
|
||||
if (code == "103000") {
|
||||
when (requestCode) {
|
||||
REQUEST_GET_PHONE_INFO_CODE -> {
|
||||
SPUtils.setBoolean(Constants.SP_HAS_GET_PHONE_INFO, true)
|
||||
// 2.授权请求
|
||||
mAuthnHelper!!.loginAuth(Config.QUICK_LOGIN_APPID, Config.QUICK_LOGIN_APPKEY, mTokenListener, REQUEST_LOGIN_AUTH_CODE)
|
||||
}
|
||||
|
||||
REQUEST_LOGIN_AUTH_CODE -> {
|
||||
// 3.获取token
|
||||
mToken = jsonObject.optString("token")
|
||||
}
|
||||
}
|
||||
} else if (code != "200020") { // 不成功就调起验证码登录页(200020代表授权页关闭)
|
||||
toastCode(code)
|
||||
startCodeLoginPage(context, true)
|
||||
}
|
||||
}
|
||||
|
||||
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
|
||||
getPhoneInfo(context)
|
||||
} else {
|
||||
DialogUtils.showQuickLoginPermissionDialog(
|
||||
context,
|
||||
{
|
||||
checkReadPhoneStatePermissionBeforeAction(context, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
getPhoneInfo(context)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
startCodeLoginPage(
|
||||
context,
|
||||
entrance = ENTRANCE_PERMISSION_DIALOG,
|
||||
isFinishAuth = false,
|
||||
isFromPermission = true
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPhoneInfo(context: Context) {
|
||||
mPreDialog = Dialog(context, R.style.DialogWindowTransparent).apply {
|
||||
val binding = SetWaitDialogBinding.inflate(LayoutInflater.from(context)).apply {
|
||||
setWaitMessage.text = "请求登录中"
|
||||
}
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
setContentView(binding.root)
|
||||
setCanceledOnTouchOutside(false)
|
||||
show()
|
||||
}
|
||||
// 1.取号请求
|
||||
mAuthnHelper!!.getPhoneInfo(Config.QUICK_LOGIN_APPID, Config.QUICK_LOGIN_APPKEY, mTokenListener, REQUEST_GET_PHONE_INFO_CODE)
|
||||
}
|
||||
|
||||
private fun getConfig(context: Context, entrance: String): AuthThemeConfig{
|
||||
return AuthThemeConfig.Builder()
|
||||
.setStatusBar(Color.WHITE, true) //状态栏颜色、是否高亮
|
||||
.setAuthContentView(getCustomView(context)) //自定义布局
|
||||
// 服务条款标题栏
|
||||
.setClauseLayoutResID(R.layout.layout_quick_login_navigation, "backIv") //服务条款标题栏
|
||||
.setNavTextColor(Color.BLACK) //服务条款标题颜色
|
||||
.setNavTextSize(18) //服务条款标题字体大小
|
||||
// 手机号码
|
||||
.setNumberSize(20, true) //手机号码字体大小
|
||||
.setNumberColor(R.color.text_333333.toColor()) //手机号码字体颜色
|
||||
.setNumFieldOffsetY(95) //号码栏Y偏移量
|
||||
// 登录按钮
|
||||
.setLogBtnImgPath("login_btn_bg") //登录按钮背景
|
||||
.setLogBtnText("本机号码一键登录", Color.WHITE, 16, false) //登录按钮相关
|
||||
.setLogBtnOffsetY(170) //登录按钮Y偏移量
|
||||
.setLogBtn(1000, 44) //登录按钮相关宽高
|
||||
.setLogBtnMargin(20, 20) //登录按钮相对于屏幕左右边缘边距
|
||||
// 回调
|
||||
.setBackPressedListener {} //返回键回调
|
||||
.setLogBtnClickListener(object : LoginClickListener {
|
||||
override fun onLoginClickStart(context: Context, jsonObj: JSONObject?) {
|
||||
LogUtils.login("logging", "一键登录", entrance)
|
||||
mDialog = Dialog(context, R.style.DialogWindowTransparent).apply {
|
||||
val binding = SetWaitDialogBinding.inflate(LayoutInflater.from(context)).apply {
|
||||
setWaitMessage.text = R.string.logging.toResString()
|
||||
}
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
setContentView(binding.root)
|
||||
setCanceledOnTouchOutside(false)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoginClickComplete(context: Context, jsonObj: JSONObject?) {
|
||||
if (mToken.isNotBlank()) {
|
||||
val params = HashMap<String, String>()
|
||||
params["token"] = mToken
|
||||
|
||||
// 4.请求登录接口
|
||||
UserRepository.getInstance(context).login(
|
||||
JSONObject(params as Map<*, *>),
|
||||
LoginTag.oauth,
|
||||
object : BiCallback<LoginTokenEntity, ApiResponse<LoginTokenEntity>> {
|
||||
override fun onFirst(first: LoginTokenEntity) {
|
||||
if (mDialog != null && mDialog!!.isShowing) {
|
||||
mDialog?.dismiss()
|
||||
}
|
||||
|
||||
SPUtils.setBoolean(Constants.SP_HAS_GET_PHONE_INFO, false)
|
||||
|
||||
LogUtils.login("success", "一键登录", entrance)
|
||||
finishAuthActivity()
|
||||
}
|
||||
|
||||
override fun onSecond(second: ApiResponse<LoginTokenEntity>) {
|
||||
if (mDialog != null && mDialog!!.isShowing) {
|
||||
mDialog?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
if (mDialog != null && mDialog!!.isShowing) {
|
||||
mDialog?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}) //登录按钮回调
|
||||
.setCheckBoxListener { _: Context?, _: JSONObject? ->
|
||||
toast("请先勾选同意《${getOperatorType(context)}认证服务协议》《用户协议》《隐私政策》")
|
||||
} //勾选回调
|
||||
// 勾选框
|
||||
.setCheckTipText("") //设置未勾选时弹出提示
|
||||
.setCheckBoxImgPath("ic_quick_login_check", "ic_quick_login_uncheck", 12, 12) //勾选图片
|
||||
// 服务条款、用户协议、隐私政策
|
||||
.setPrivacyState(false) //默认不勾选
|
||||
.setPrivacyAlignment("阅读并同意 " + AuthThemeConfig.PLACEHOLDER + " 用户协议 隐私政策",
|
||||
"用户协议", R.string.disclaimer_url.toResString(),
|
||||
"隐私政策", R.string.privacy_policy_url.toResString(),
|
||||
"", "", "", "") //隐私条款的协议文本,自定义条款,自定义条款链接(支持四份条款)
|
||||
.setPrivacyText(11, R.color.text_999999.toColor(), R.color.theme_font.toColor(), true, false) //条款文本设置
|
||||
.setPrivacyMargin(30, 32) //隐私条款距离手机左右边缘的边距
|
||||
.setPrivacyOffsetY(280) //隐私条款Y偏移量
|
||||
// 语言
|
||||
.setAppLanguageType(0) //0.中文简体1.中文繁体2.英文
|
||||
// 转场动画
|
||||
.setAuthPageActIn("anim_auth_in","anim_auth_out")
|
||||
// .setAuthPageActOut("anim_auth_in","anim_auth_out")
|
||||
// 整体布局
|
||||
.setAuthPageWindowMode(WindowManager.LayoutParams.MATCH_PARENT, 360) //授权页窗口宽高比例
|
||||
.setWindowBottom(1) //授权页是否居于底部,0=居中;1=底部,设置为1Y轴的偏移 失效
|
||||
.setFitsSystemWindows(false)
|
||||
.setThemeId(R.style.quickLoginDialog) //授权页弹窗主题
|
||||
.build()
|
||||
}
|
||||
|
||||
// 获取自定义布局View
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun getCustomView(context: Context): View {
|
||||
return DialogQuickLoginBinding.inflate(LayoutInflater.from(context)).apply {
|
||||
closeIv.setOnClickListener {
|
||||
finishAuthActivity()
|
||||
}
|
||||
changeLoginBtn.setOnClickListener {
|
||||
startCodeLoginPage(context, false)
|
||||
}
|
||||
descTv.text = "${getOperatorType(context)}提供认证服务"
|
||||
}.root
|
||||
}
|
||||
|
||||
// 获取运营商名称
|
||||
private fun getOperatorType(context: Context): String {
|
||||
mAuthnHelper?.run {
|
||||
val jsonObject = getNetworkType(context)
|
||||
tryWithDefaultCatch {
|
||||
val net = jsonObject.optString("operatorType").toInt()
|
||||
if (net == 1) return "中国移动"
|
||||
if (net == 2) return "中国联通"
|
||||
if (net == 3) return "中国电信"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
private fun startCodeLoginPage(context: Context, isFinishAuth: Boolean) {
|
||||
startCodeLoginPage(context, ENTRANCE_DEFAULT, isFinishAuth, false)
|
||||
}
|
||||
|
||||
private fun startCodeLoginPage(context: Context, entrance: String, isFinishAuth: Boolean, isFromPermission: Boolean) {
|
||||
if (mPreDialog != null && mPreDialog!!.isShowing) {
|
||||
tryWithDefaultCatch {
|
||||
mPreDialog?.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
if (isFinishAuth) {
|
||||
finishAuthActivity()
|
||||
}
|
||||
|
||||
val status = when {
|
||||
isFromPermission -> LoginActivity.STATUS_FROM_QUICK_LOGIN_PERMISSION
|
||||
|
||||
mOpenAuthPageSuccess -> LoginActivity.STATUS_FROM_QUICK_LOGIN_PAGE
|
||||
|
||||
|
||||
else -> LoginActivity.STATUS_DEFAULT
|
||||
}
|
||||
|
||||
context.startActivity(LoginActivity.getIntent(context, entrance, status))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun finishAuthActivity() {
|
||||
mAuthnHelper?.quitAuthActivity()
|
||||
// 调用quitAuthActivity()方法有概率会关不掉授权页,所以使用在调用quitAuthActivity()方法后,判断当前Activity是否还是AuthActivity,如果是则finish
|
||||
AppManager.getInstance().recentActiveActivity?.run {
|
||||
if (localClassName == AUTH_ACTIVITY_NAME) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun toastCode(code: String) {
|
||||
debugOnly {
|
||||
Utils.log("QuickLoginHelper -> code = $code")
|
||||
}
|
||||
|
||||
// if (code == "200023" || code == "200028") {
|
||||
// toast("验证码登录")
|
||||
// } else {
|
||||
// toast(code)
|
||||
// }
|
||||
}
|
||||
}
|
||||
50
app/src/main/java/com/gh/common/util/RealNameHelper.kt
Normal file
50
app/src/main/java/com/gh/common/util/RealNameHelper.kt
Normal file
@ -0,0 +1,50 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.gamecenter.UserInfoEditActivity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.user.UserViewModel
|
||||
import java.util.*
|
||||
|
||||
object RealNameHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun checkIfAuth(context: Context, gameEntity: GameEntity, callback: EmptyCallback) {
|
||||
if (gameEntity.auth?.switch == "on") {
|
||||
if ((gameEntity.auth?.timeStart == "00:00" && gameEntity.auth?.timeEnd == "00:00")
|
||||
|| withinTimeRange(gameEntity.auth?.timeStart, gameEntity.auth?.timeEnd)) {
|
||||
context.ifLogin("") {
|
||||
if (!UserManager.getInstance().isAuth) {
|
||||
context.startActivity(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD))
|
||||
} else {
|
||||
callback.onCallback()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
callback.onCallback()
|
||||
}
|
||||
} else {
|
||||
callback.onCallback()
|
||||
}
|
||||
}
|
||||
|
||||
private fun withinTimeRange(timeStart: String?, timeEnd: String?): Boolean {
|
||||
val realTimeEnd = if (timeEnd == "00:00") "23:59" else timeEnd
|
||||
|
||||
val startHourAndMinuteArray = timeStart?.split(":")
|
||||
val endHourAndMinuteArray = realTimeEnd?.split(":")
|
||||
|
||||
val calStart = Calendar.getInstance().apply {
|
||||
set(Calendar.HOUR_OF_DAY, startHourAndMinuteArray?.first()!!.toInt())
|
||||
set(Calendar.MINUTE, startHourAndMinuteArray.secondOrNull()!!.toInt())
|
||||
}
|
||||
val calEnd = Calendar.getInstance().apply {
|
||||
set(Calendar.HOUR_OF_DAY, endHourAndMinuteArray?.first()!!.toInt())
|
||||
set(Calendar.MINUTE, endHourAndMinuteArray.secondOrNull()!!.toInt())
|
||||
}
|
||||
|
||||
return (Calendar.getInstance().after(calStart) && Calendar.getInstance().before(calEnd))
|
||||
}
|
||||
|
||||
}
|
||||
144
app/src/main/java/com/gh/common/util/RecommendPopupHelper.kt
Normal file
144
app/src/main/java/com/gh/common/util/RecommendPopupHelper.kt
Normal file
@ -0,0 +1,144 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.dialog.DeviceRemindDialog
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
object RecommendPopupHelper {
|
||||
|
||||
fun getRecommendPopup(gameEntity: GameEntity?, popups: ArrayList<RecommendPopupEntity>?): RecommendPopupEntity? {
|
||||
if (gameEntity == null || popups.isNullOrEmpty()) return null
|
||||
|
||||
//判断是否触发设备弹窗
|
||||
val pair = DeviceRemindDialog.shouldShowDeviceRemindDialog(gameEntity)
|
||||
if (pair.first) return null
|
||||
|
||||
//判断是否为多版本游戏
|
||||
if (gameEntity.getApk().isEmpty() || gameEntity.getApk().size > 1) return null
|
||||
|
||||
val downloadBtnText = GameUtils.getDownloadBtnText(HaloApp.getInstance(), gameEntity, PluginLocation.only_game)
|
||||
val filterEntities = arrayListOf<RecommendPopupEntity>()
|
||||
|
||||
loop@ for (entity in popups) {
|
||||
//判断是否符合下载类型
|
||||
val downloadType = entity.recommendPackage.getDownloadType()
|
||||
if (!downloadType.contains(downloadBtnText)) continue
|
||||
|
||||
//判断是否符合安装包大小限制
|
||||
val minSize = entity.recommendPackage.minSize
|
||||
val sizeStr = gameEntity.getApk()[0].size ?: continue
|
||||
val size = sizeStr.substring(0, sizeStr.length - 2).toFloat()
|
||||
if (size < minSize) continue
|
||||
|
||||
//判断是否符合包名限制
|
||||
val nameRule = entity.recommendPackage.nameRule
|
||||
val packages = entity.recommendPackage.details
|
||||
val installedPackages = PackageUtils.getAllPackageNameIncludeGh(HaloApp.getInstance())
|
||||
var isMatchSuccess = true
|
||||
val checkInstalled: (splitPackages: List<String>) -> Boolean = {
|
||||
var isInstalled = false
|
||||
it.forEach { packageName ->
|
||||
if (installedPackages.contains(packageName)) {
|
||||
isInstalled = true
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
isInstalled
|
||||
}
|
||||
when (nameRule) {
|
||||
"installed" -> {
|
||||
//设备上安装了指定的包名才生效(需全部满足)
|
||||
packages.forEach {
|
||||
val splitPackages = it.split("、")
|
||||
val isInstalled = checkInstalled(splitPackages)
|
||||
if (!isInstalled) {
|
||||
isMatchSuccess = false
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
}
|
||||
"uninstalled" -> {
|
||||
//设备上未安装指定的包名才生效(需全部满足)
|
||||
packages.forEach {
|
||||
val splitPackages = it.split("、")
|
||||
val isInstalled = checkInstalled(splitPackages)
|
||||
if (isInstalled) {
|
||||
isMatchSuccess = false
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
isMatchSuccess = true
|
||||
}
|
||||
}
|
||||
if (!isMatchSuccess) continue
|
||||
|
||||
filterEntities.add(entity)
|
||||
}
|
||||
|
||||
return if (filterEntities.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
val recommendPopupEntity = filterEntities[0]
|
||||
if (checkFrequencyIsMatch(recommendPopupEntity)) {
|
||||
recommendPopupEntity
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkFrequencyIsMatch(entity: RecommendPopupEntity): Boolean {
|
||||
//判断是否符合通知频率 一次once, 累计次数count, 每周一次weekly, 每天一次daily, 每次always
|
||||
val plan = entity.notice.plan
|
||||
val times = entity.notice.times
|
||||
//[{"popupId":"6074ff265b58135844aec523","showTime":1618391319457,"count":1}]
|
||||
val recordStr = SPUtils.getString(Constants.SP_RECOMMEND_POPUP)
|
||||
val type = object : TypeToken<ArrayList<RecommendRecord>>() {}.type
|
||||
val records = GsonUtils.gson.fromJson<ArrayList<RecommendRecord>>(recordStr, type)
|
||||
?: arrayListOf()
|
||||
val recommendRecord = records.find { it.popupId == entity.id }
|
||||
val showTime = recommendRecord?.showTime ?: 0L
|
||||
val count = recommendRecord?.count ?: 0
|
||||
when (plan) {
|
||||
"once" -> {
|
||||
if (recommendRecord != null) return false
|
||||
}
|
||||
"count" -> {
|
||||
if (count >= times) return false
|
||||
}
|
||||
"weekly" -> {
|
||||
if (TimeUtils.isThisWeek(showTime)) return false
|
||||
}
|
||||
"daily" -> {
|
||||
if (TimeUtils.isToday(showTime)) return false
|
||||
}
|
||||
"always" -> {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun saveRecord(popup: RecommendPopupEntity) {
|
||||
val plan = popup.notice.plan
|
||||
val recordStr = SPUtils.getString(Constants.SP_RECOMMEND_POPUP)
|
||||
val type = object : TypeToken<ArrayList<RecommendRecord>>() {}.type
|
||||
val records = GsonUtils.gson.fromJson<ArrayList<RecommendRecord>>(recordStr, type)
|
||||
?: arrayListOf()
|
||||
val recommendRecord = records.find { it.popupId == popup.id }
|
||||
if (recommendRecord == null) {
|
||||
records.add(RecommendRecord(popup.id, System.currentTimeMillis(), 1))
|
||||
} else {
|
||||
if (plan == "count") {
|
||||
recommendRecord.count = recommendRecord.count + 1
|
||||
}
|
||||
recommendRecord.showTime = System.currentTimeMillis()
|
||||
|
||||
}
|
||||
SPUtils.setString(Constants.SP_RECOMMEND_POPUP, GsonUtils.toJson(records))
|
||||
}
|
||||
}
|
||||
@ -104,6 +104,24 @@ public class ShareUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public enum ShareType {
|
||||
qq("qq"),
|
||||
qqZone("qq空间"),
|
||||
weibo("微博"),
|
||||
wechat("微信"),
|
||||
wechatMoments("朋友圈");
|
||||
|
||||
private String name;
|
||||
|
||||
ShareType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private String[] arrLabel = {"微信好友", "朋友圈", "QQ好友", "QQ空间", "新浪微博", "短信", "复制链接", "取消"};
|
||||
|
||||
private WeakReference<PopupWindow> popupWindow;
|
||||
@ -113,6 +131,7 @@ public class ShareUtils {
|
||||
public static ShareEntrance shareEntrance;//分享入口(事件上报和视频分享统计用)
|
||||
public static String resourceId = "";//分享内容的id(事件上报用)
|
||||
public static ShareEntity shareEntity;//分享信息(事件上报用)
|
||||
private static ShareType mShareType;//分享类型(事件上报用)
|
||||
|
||||
private WeakReference<Activity> mActivity;
|
||||
|
||||
@ -126,6 +145,9 @@ public class ShareUtils {
|
||||
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());
|
||||
if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("成功", mShareType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -133,6 +155,9 @@ public class ShareUtils {
|
||||
Utils.toast(mContext, R.string.share_fail_hint);
|
||||
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "fail",
|
||||
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
|
||||
if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("失败", mShareType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -140,6 +165,9 @@ public class ShareUtils {
|
||||
Utils.toast(mContext, R.string.share_cancel_hint);
|
||||
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "cancel",
|
||||
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
|
||||
if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("取消", mShareType.getName());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -188,18 +216,23 @@ public class ShareUtils {
|
||||
// 分享
|
||||
switch (way) {
|
||||
case "qq" :
|
||||
mShareType = ShareType.qq;
|
||||
qqShare();
|
||||
break;
|
||||
case "qq_zone" :
|
||||
mShareType = ShareType.qqZone;
|
||||
qZoneShare();
|
||||
break;
|
||||
case "wechat" :
|
||||
mShareType = ShareType.wechat;
|
||||
wechatShare();
|
||||
break;
|
||||
case "wechat_moments" :
|
||||
mShareType = ShareType.wechatMoments;
|
||||
wechatMomentsShare();
|
||||
break;
|
||||
case "weibo" :
|
||||
mShareType = ShareType.weibo;
|
||||
sinaWeiboShare();
|
||||
break;
|
||||
}
|
||||
@ -693,6 +726,10 @@ public class ShareUtils {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public String getShareUrl() {
|
||||
return shareUrl;
|
||||
}
|
||||
|
||||
private class ShareRecyclerViewAdapter extends RecyclerView.Adapter<ShareRecyclerViewAdapter.ViewHolder> {
|
||||
|
||||
private OnItemClickListener listener;
|
||||
|
||||
@ -48,6 +48,12 @@ object TimeUtils {
|
||||
return testDate
|
||||
}
|
||||
|
||||
//获取当前的小时(24小时制)
|
||||
fun getCurrentHour(): Int {
|
||||
val calendar = Calendar.getInstance()
|
||||
return calendar.get(Calendar.HOUR_OF_DAY)
|
||||
}
|
||||
|
||||
//判断是不是今天
|
||||
fun isToday(timestamp: Long): Boolean {
|
||||
val format = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)
|
||||
@ -60,6 +66,15 @@ object TimeUtils {
|
||||
return false
|
||||
}
|
||||
|
||||
//判断是不是本周
|
||||
fun isThisWeek(timestamp: Long): Boolean {
|
||||
val calendar = Calendar.getInstance()
|
||||
val currentWeek = calendar[Calendar.WEEK_OF_YEAR]
|
||||
calendar.time = Date(timestamp)
|
||||
val paramWeek = calendar[Calendar.WEEK_OF_YEAR]
|
||||
return paramWeek == currentWeek
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断时间戳是多少天前
|
||||
*/
|
||||
@ -77,6 +92,23 @@ object TimeUtils {
|
||||
return days.toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断传入时间戳与当前日期的差值,返回单位为天
|
||||
*/
|
||||
fun getDaysOffset(timestamp: Long): Int {
|
||||
var days: Long = 0
|
||||
val format = SimpleDateFormat("yyyyMMdd", Locale.getDefault())
|
||||
try {
|
||||
val today = format.parse(format.format(Date())).time
|
||||
val day = timestamp * 1000
|
||||
days = (day - today) / 86400000
|
||||
} catch (e: ParseException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return days.toInt()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 格式化视频时长
|
||||
|
||||
@ -51,6 +51,7 @@ public class TimestampUtils {
|
||||
whiteList.add(".*tasks:check.*");
|
||||
whiteList.add(".*novice_tasks.*");
|
||||
whiteList.add(".*daily_tasks.*");
|
||||
whiteList.add(".*fixed_tasks.*");
|
||||
whiteList.add(".*energies.*");
|
||||
}
|
||||
|
||||
|
||||
@ -2,21 +2,17 @@ package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.facebook.drawee.drawable.ScalingUtils
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
|
||||
import com.facebook.drawee.generic.RoundingParams
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.ImageUtils
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.px2dip
|
||||
import com.gh.common.util.toColor
|
||||
import com.gh.gamecenter.R
|
||||
|
||||
|
||||
@ -25,6 +21,8 @@ class AvatarBorderView : ConstraintLayout {
|
||||
var avatarView: SimpleDraweeView? = null
|
||||
var borderView: SimpleDraweeView? = null
|
||||
var badgeView: SimpleDraweeView? = null
|
||||
var avatarContainer: CardView? = null
|
||||
var avatarBorderView: View? = null
|
||||
private var mAvatarWidth = 100f
|
||||
private var mBadgeWidth = 30f
|
||||
private var mAvatarBorderColor = Color.parseColor("#ffffff")
|
||||
@ -61,21 +59,39 @@ class AvatarBorderView : ConstraintLayout {
|
||||
avatarView = findViewById(R.id.avatarView)
|
||||
borderView = findViewById(R.id.borderView)
|
||||
badgeView = findViewById(R.id.badgeView)
|
||||
avatarContainer = findViewById(R.id.avatarContainer)
|
||||
avatarBorderView = findViewById(R.id.avatarBorderView)
|
||||
|
||||
changeLayoutParams()
|
||||
}
|
||||
|
||||
private fun changeLayoutParams() {
|
||||
avatarContainer?.apply {
|
||||
radius = mAvatarWidth / 2
|
||||
cardElevation = 0F
|
||||
}
|
||||
avatarView?.apply {
|
||||
val params = layoutParams
|
||||
params.width = mAvatarWidth.toInt()
|
||||
params.height = mAvatarWidth.toInt()
|
||||
layoutParams = params
|
||||
val roundingParams = RoundingParams.asCircle()
|
||||
val roundingParams = RoundingParams.fromCornersRadius(mAvatarWidth)
|
||||
roundingParams.borderColor = mAvatarBorderColor
|
||||
roundingParams.borderWidth = mAvatarBorderWidth
|
||||
hierarchy?.roundingParams = roundingParams
|
||||
}
|
||||
avatarBorderView?.apply {
|
||||
val params = layoutParams
|
||||
params.width = mAvatarWidth.toInt()
|
||||
params.height = mAvatarWidth.toInt()
|
||||
layoutParams = params
|
||||
val drawable = GradientDrawable().apply {
|
||||
setColor(R.color.transparent.toColor())
|
||||
shape = GradientDrawable.OVAL
|
||||
setStroke(mAvatarBorderWidth.toInt(), mAvatarBorderColor)
|
||||
}
|
||||
background = drawable
|
||||
}
|
||||
borderView?.apply {
|
||||
val params = layoutParams
|
||||
if (mRatio > 0) {
|
||||
|
||||
226
app/src/main/java/com/gh/common/view/CategoryFilterView.kt
Normal file
226
app/src/main/java/com/gh/common/view/CategoryFilterView.kt
Normal file
@ -0,0 +1,226 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.toColor
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.SidebarsEntity
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
|
||||
class CategoryFilterView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private var mTypeTv: TextView
|
||||
private var mCatalogTv: TextView
|
||||
private var mSizeTv: TextView
|
||||
private var mTypeContainer: View
|
||||
private var mCatalogContainer: View
|
||||
private var mSizeContainer: View
|
||||
|
||||
private var mTypeFilterArray = arrayOf(SortType.RECOMMENDED, SortType.NEWEST, SortType.RATING)
|
||||
private var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
|
||||
|
||||
private var mOnCategoryFilterSetupListener: OnCategoryFilterSetupListener? = null
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.layout_category_filter, this)
|
||||
|
||||
mTypeTv = findViewById(R.id.type_tv)
|
||||
mCatalogTv = findViewById(R.id.catalog_tv)
|
||||
mSizeTv = findViewById(R.id.size_tv)
|
||||
mTypeContainer = findViewById(R.id.container_type)
|
||||
mCatalogContainer = findViewById(R.id.container_category)
|
||||
mSizeContainer = findViewById(R.id.container_size)
|
||||
mTypeTv.text = mTypeFilterArray[0].value
|
||||
|
||||
mTypeContainer.setOnClickListener {
|
||||
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
|
||||
}
|
||||
|
||||
mCatalogContainer.setOnClickListener {
|
||||
mOnCategoryFilterSetupListener?.onSetupSortCategory()
|
||||
}
|
||||
|
||||
mSizeContainer.setOnClickListener {
|
||||
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun setOnConfigSetupListener(onCategoryFilterSetupListener: OnCategoryFilterSetupListener) {
|
||||
mOnCategoryFilterSetupListener = onCategoryFilterSetupListener
|
||||
}
|
||||
|
||||
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
|
||||
if (highlightIt) {
|
||||
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
|
||||
targetTextView.setTextColor(Color.WHITE)
|
||||
} else {
|
||||
targetTextView.background = null
|
||||
targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_757575))
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectTypePopupWindow(containerView: View, typeTv: TextView, typeText: String) {
|
||||
val drawableUp = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_up)
|
||||
val drawableDown = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_down)
|
||||
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
|
||||
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
|
||||
|
||||
typeTv.setTextColor(R.color.theme_font.toColor())
|
||||
typeTv.setCompoundDrawables(null, null, drawableUp, null)
|
||||
|
||||
val inflater = LayoutInflater.from(typeTv.context)
|
||||
val layout = inflater.inflate(R.layout.layout_filter_size, null)
|
||||
val windowWidth = typeTv.context.resources.displayMetrics.widthPixels - 80F.dip2px()
|
||||
val popupWindow = PopupWindow(
|
||||
layout,
|
||||
windowWidth,
|
||||
LayoutParams.WRAP_CONTENT)
|
||||
|
||||
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
|
||||
val backgroundView = layout.findViewById<View>(R.id.background)
|
||||
|
||||
backgroundView.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
for (type in mTypeFilterArray) {
|
||||
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
|
||||
|
||||
// 单列 3 个,强行设置宽度为屏幕的 1/3
|
||||
val width = windowWidth / 3
|
||||
val height = item.layoutParams.height
|
||||
|
||||
item.layoutParams = ViewGroup.LayoutParams(width, height)
|
||||
flexboxLayout.addView(item)
|
||||
|
||||
val tv = item.findViewById<TextView>(R.id.size_tv)
|
||||
tv.text = type.value
|
||||
|
||||
toggleHighlightedTextView(tv, typeText == type.value)
|
||||
|
||||
tv.tag = type.value
|
||||
|
||||
item.setOnClickListener {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
popupWindow.dismiss()
|
||||
typeTv.text = type.value
|
||||
|
||||
mOnCategoryFilterSetupListener?.onSetupSortType(type)
|
||||
}
|
||||
}
|
||||
|
||||
popupWindow.setOnDismissListener {
|
||||
typeTv.setTextColor(R.color.text_757575.toColor())
|
||||
typeTv.setCompoundDrawables(null, null, drawableDown, null)
|
||||
}
|
||||
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.isFocusable = true
|
||||
popupWindow.animationStyle = 0
|
||||
popupWindow.showAsDropDown(containerView, 0, 0)
|
||||
}
|
||||
|
||||
private fun showSelectSizePopupWindow(containerView: View, sizeTv: TextView, sizeText: String) {
|
||||
val drawableUp = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_up)
|
||||
val drawableDown = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_down)
|
||||
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
|
||||
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
|
||||
|
||||
sizeTv.setTextColor(R.color.theme_font.toColor())
|
||||
sizeTv.setCompoundDrawables(null, null, drawableUp, null)
|
||||
|
||||
val inflater = LayoutInflater.from(sizeTv.context)
|
||||
val layout = inflater.inflate(R.layout.layout_filter_size, null)
|
||||
val windowWidth = sizeTv.context.resources.displayMetrics.widthPixels - 80F.dip2px()
|
||||
val popupWindow = PopupWindow(
|
||||
layout,
|
||||
windowWidth,
|
||||
LayoutParams.WRAP_CONTENT)
|
||||
|
||||
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
|
||||
val backgroundView = layout.findViewById<View>(R.id.background)
|
||||
|
||||
sizeFilterArray = if (sizeFilterArray == null) {
|
||||
getDefaultSizeFilterArray()
|
||||
} else {
|
||||
sizeFilterArray?.apply {
|
||||
if (firstOrNull()?.text != "全部大小") {
|
||||
add(0, SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backgroundView.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
for (size in sizeFilterArray!!) {
|
||||
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
|
||||
|
||||
// 单列 3 个,强行设置宽度为屏幕的 1/3
|
||||
val width = windowWidth / 3
|
||||
val height = item.layoutParams.height
|
||||
|
||||
item.layoutParams = ViewGroup.LayoutParams(width, height)
|
||||
flexboxLayout.addView(item)
|
||||
|
||||
val tv = item.findViewById<TextView>(R.id.size_tv)
|
||||
tv.text = size.text
|
||||
|
||||
toggleHighlightedTextView(tv, sizeText == size.text)
|
||||
|
||||
tv.tag = size.text
|
||||
|
||||
item.setOnClickListener {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
popupWindow.dismiss()
|
||||
sizeTv.text = size.text
|
||||
|
||||
mOnCategoryFilterSetupListener?.onSetupSortSize(size)
|
||||
}
|
||||
}
|
||||
|
||||
popupWindow.setOnDismissListener {
|
||||
sizeTv.setTextColor(R.color.text_757575.toColor())
|
||||
sizeTv.setCompoundDrawables(null, null, drawableDown, null)
|
||||
}
|
||||
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.isFocusable = true
|
||||
popupWindow.animationStyle = 0
|
||||
popupWindow.showAsDropDown(containerView, 0, 0)
|
||||
}
|
||||
|
||||
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
|
||||
return arrayListOf<SubjectSettingEntity.Size>().apply {
|
||||
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
|
||||
add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下"))
|
||||
add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M"))
|
||||
add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M"))
|
||||
add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G"))
|
||||
add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上"))
|
||||
}
|
||||
}
|
||||
|
||||
interface OnCategoryFilterSetupListener {
|
||||
fun onSetupSortSize(sortSize: SubjectSettingEntity.Size)
|
||||
fun onSetupSortType(sortType: SortType)
|
||||
fun onSetupSortCategory()
|
||||
}
|
||||
|
||||
enum class SortType(val value: String) {
|
||||
RECOMMENDED("热门推荐"),
|
||||
NEWEST("最新上线"),
|
||||
RATING("最高评分")
|
||||
}
|
||||
}
|
||||
199
app/src/main/java/com/gh/common/view/FilterView.kt
Normal file
199
app/src/main/java/com/gh/common/view/FilterView.kt
Normal file
@ -0,0 +1,199 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.toColor
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.ItemFilterBinding
|
||||
import com.gh.gamecenter.databinding.LayoutFilterBinding
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
|
||||
// TODO 把 ConfigFilterView 的上层实现切换到继承这个类实现
|
||||
class FilterView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
|
||||
: ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private var mBinding: LayoutFilterBinding? = null
|
||||
|
||||
private var mMainFilterList: ArrayList<String> = arrayListOf()
|
||||
private var mSubFilterList: ArrayList<String> = arrayListOf()
|
||||
|
||||
private var mSelectedMainFilter: String = ""
|
||||
private var mSelectedSubFilter: String = ""
|
||||
|
||||
init {
|
||||
mBinding = LayoutFilterBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
}
|
||||
|
||||
fun setupFilter(mainFilterList: ArrayList<String>,
|
||||
defaultSelectedMainFilter: String? = null,
|
||||
subFilterList: ArrayList<String>,
|
||||
subFilterText: String,
|
||||
mainFilterSelectedCallback: ((String) -> Unit),
|
||||
subFilterSelectedCallback: ((String) -> Unit)) {
|
||||
mMainFilterList = mainFilterList
|
||||
mSubFilterList = subFilterList
|
||||
|
||||
mBinding?.subFilterTv?.text = subFilterText
|
||||
mBinding?.subFilterTv?.setOnClickListener {
|
||||
showSelectionPopupWindow(this, it as TextView, mSelectedSubFilter) { selectedText ->
|
||||
subFilterSelectedCallback.invoke(selectedText)
|
||||
}
|
||||
}
|
||||
|
||||
mBinding?.filterRecyclerView?.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
mBinding?.filterRecyclerView?.adapter = FilterAdapter(
|
||||
context,
|
||||
mMainFilterList,
|
||||
defaultSelectedMainFilter ?: mainFilterList.first()) {
|
||||
mainFilterSelectedCallback.invoke(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSelectedMainFilter(filter: String) {
|
||||
mSelectedMainFilter = filter
|
||||
(mBinding?.filterRecyclerView?.adapter as? FilterAdapter)?.updateSelectedFilter(filter)
|
||||
mBinding?.filterRecyclerView?.smoothScrollToPosition(mMainFilterList.indexOf(filter))
|
||||
}
|
||||
|
||||
fun updateSelectedSubFilter(filter: String) {
|
||||
mSelectedSubFilter = filter
|
||||
mBinding?.subFilterTv?.text = filter
|
||||
}
|
||||
|
||||
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
|
||||
if (highlightIt) {
|
||||
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
|
||||
targetTextView.setTextColor(Color.WHITE)
|
||||
} else {
|
||||
targetTextView.background = null
|
||||
targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_757575))
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectionPopupWindow(containerView: View,
|
||||
subFilterTv: TextView,
|
||||
subFilterText: String,
|
||||
selectedCallback: ((String) -> Unit)) {
|
||||
val drawableUp = ContextCompat.getDrawable(subFilterTv.context, R.drawable.ic_filter_arrow_up)
|
||||
val drawableDown = ContextCompat.getDrawable(subFilterTv.context, R.drawable.ic_filter_arrow_down)
|
||||
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
|
||||
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
|
||||
|
||||
subFilterTv.setTextColor(R.color.theme_font.toColor())
|
||||
subFilterTv.setCompoundDrawables(null, null, drawableUp, null)
|
||||
|
||||
val inflater = LayoutInflater.from(subFilterTv.context)
|
||||
val layout = inflater.inflate(R.layout.layout_filter_size, null)
|
||||
val popupWindow = PopupWindow(
|
||||
layout,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
|
||||
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
|
||||
val backgroundView = layout.findViewById<View>(R.id.background)
|
||||
|
||||
flexboxLayout.setPadding(16F.dip2px(), 0, 0, 8F.dip2px())
|
||||
|
||||
backgroundView.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
for (filter in mSubFilterList) {
|
||||
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
|
||||
|
||||
val height = item.layoutParams.height
|
||||
|
||||
item.layoutParams = ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, height)
|
||||
flexboxLayout.addView(item)
|
||||
|
||||
val tv = item.findViewById<TextView>(R.id.size_tv)
|
||||
tv.text = filter
|
||||
|
||||
if (subFilterText == filter) {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
} else {
|
||||
toggleHighlightedTextView(tv, false)
|
||||
}
|
||||
|
||||
tv.tag = filter
|
||||
|
||||
item.setOnClickListener {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
popupWindow.dismiss()
|
||||
subFilterTv.text = filter
|
||||
|
||||
updateSelectedSubFilter(filter)
|
||||
selectedCallback.invoke(filter)
|
||||
}
|
||||
}
|
||||
|
||||
popupWindow.setOnDismissListener {
|
||||
subFilterTv.setTextColor(R.color.text_757575.toColor())
|
||||
subFilterTv.setCompoundDrawables(null, null, drawableDown, null)
|
||||
}
|
||||
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.isFocusable = true
|
||||
popupWindow.animationStyle = 0
|
||||
// 在模拟器上会有 1dp 的位移
|
||||
popupWindow.showAsDropDown(containerView, 0, -6)
|
||||
}
|
||||
|
||||
class FilterAdapter(val context: Context,
|
||||
private val mFilterList: ArrayList<String>,
|
||||
private val mDefaultSelectedFilter: String,
|
||||
private val mClickCallback: (String) -> Unit)
|
||||
: RecyclerView.Adapter<FilterAdapter.FilterViewHolder>() {
|
||||
|
||||
private var mSelectedFilter = mDefaultSelectedFilter
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FilterViewHolder {
|
||||
return FilterViewHolder(ItemFilterBinding.inflate(LayoutInflater.from(context)))
|
||||
}
|
||||
|
||||
override fun getItemCount() = mFilterList.size
|
||||
|
||||
override fun onBindViewHolder(holder: FilterViewHolder, position: Int) {
|
||||
if (mSelectedFilter == "") {
|
||||
mSelectedFilter = mFilterList.first()
|
||||
}
|
||||
|
||||
if (mSelectedFilter == mFilterList[position]) {
|
||||
holder.binding.titleTv.setBackgroundResource(R.drawable.bg_tag_text)
|
||||
holder.binding.titleTv.setTextColor(R.color.white.toColor())
|
||||
} else {
|
||||
holder.binding.titleTv.setBackgroundColor(Color.WHITE)
|
||||
holder.binding.titleTv.setTextColor(R.color.text_777777.toColor())
|
||||
}
|
||||
|
||||
holder.binding.titleTv.text = mFilterList[position]
|
||||
|
||||
holder.binding.root.setOnClickListener {
|
||||
mClickCallback.invoke(mFilterList[position])
|
||||
updateSelectedFilter(mFilterList[position])
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSelectedFilter(incomingSelectedFilter: String) {
|
||||
if (mSelectedFilter != incomingSelectedFilter) {
|
||||
mSelectedFilter = incomingSelectedFilter
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
class FilterViewHolder(var binding: ItemFilterBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,11 +5,11 @@ import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.facebook.drawee.generic.RoundingParams
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.ImageUtils
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.goneIf
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
@ -17,7 +17,7 @@ import kotlinx.android.synthetic.main.layout_game_icon.view.*
|
||||
|
||||
class GameIconView : ConstraintLayout {
|
||||
|
||||
private var mCornerRadius = 10
|
||||
private var mCornerRadius = 0
|
||||
private var mBorderColor = 0
|
||||
private var mGameIconOverlayColor = 0
|
||||
private var mBorderWidth = 1
|
||||
@ -36,24 +36,13 @@ class GameIconView : ConstraintLayout {
|
||||
View.inflate(context, R.layout.layout_game_icon, this)
|
||||
|
||||
val ta = context.obtainStyledAttributes(attrs, R.styleable.GameIconView)
|
||||
mCornerRadius = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconCornerRadius, DisplayUtils.dip2px(10F))
|
||||
mCornerRadius = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconCornerRadius, DisplayUtils.dip2px(0F))
|
||||
mBorderColor = ta.getColor(R.styleable.GameIconView_gameIconBorderColor, 0)
|
||||
mGameIconOverlayColor = ta.getColor(R.styleable.GameIconView_gameIconOverlayColor, 0)
|
||||
mBorderWidth = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconBorderWidth, 1)
|
||||
mFadeDuration = ta.getInt(R.styleable.GameIconView_gameIconFadeDuration, -1)
|
||||
ta.recycle()
|
||||
|
||||
val roundingParams = RoundingParams.fromCornersRadius(mCornerRadius.toFloat())
|
||||
if (mGameIconOverlayColor != 0) {
|
||||
roundingParams.overlayColor = mGameIconOverlayColor
|
||||
}
|
||||
|
||||
if (mBorderColor != 0) {
|
||||
roundingParams.setBorder(mBorderColor, mBorderWidth.toFloat())
|
||||
}
|
||||
gameIconIv.hierarchy.roundingParams = roundingParams
|
||||
gameIconDecoratorIv.hierarchy.roundingParams = roundingParams
|
||||
|
||||
if (mFadeDuration != -1) {
|
||||
gameIconIv.hierarchy.fadeDuration = mFadeDuration
|
||||
}
|
||||
@ -77,4 +66,59 @@ class GameIconView : ConstraintLayout {
|
||||
|
||||
fun getIconDecoratorIv(): SimpleDraweeView = gameIconDecoratorIv
|
||||
|
||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||
super.onSizeChanged(w, h, oldw, oldh)
|
||||
|
||||
val cornerRadius = getCornerRadius(w)
|
||||
|
||||
// 一些设备(没错,又是 vivo),代码设置 CardView 的 radius 无效(xml 设置有效)
|
||||
// 被迫再设置一次 SimpleDraweeView 的 radius :(
|
||||
val roundingParams = RoundingParams.fromCornersRadius(cornerRadius)
|
||||
if (mGameIconOverlayColor != 0) {
|
||||
roundingParams.overlayColor = mGameIconOverlayColor
|
||||
}
|
||||
|
||||
if (mBorderColor != 0) {
|
||||
roundingParams.setBorder(mBorderColor, mBorderWidth.toFloat())
|
||||
}
|
||||
gameIconIv.hierarchy.roundingParams = roundingParams
|
||||
gameIconDecoratorIv.hierarchy.roundingParams = roundingParams
|
||||
}
|
||||
|
||||
private fun getCornerRadius(width: Int): Float {
|
||||
// XML 的圆角设置优先级更高
|
||||
if (mCornerRadius != 0) {
|
||||
return mCornerRadius.toFloat()
|
||||
}
|
||||
|
||||
return when {
|
||||
width <= SIZE_36 -> RADIUS_8
|
||||
width >= SIZE_88 -> RADIUS_20
|
||||
width >= SIZE_80 -> RADIUS_18
|
||||
width >= SIZE_72 -> RADIUS_16
|
||||
width >= SIZE_64 -> RADIUS_14
|
||||
width >= SIZE_48 -> RADIUS_12
|
||||
width >= SIZE_40 -> RADIUS_10
|
||||
else -> RADIUS_8
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val RADIUS_8 = 8F.dip2px().toFloat()
|
||||
val RADIUS_10 = 10F.dip2px().toFloat()
|
||||
val RADIUS_12 = 12F.dip2px().toFloat()
|
||||
val RADIUS_14 = 14F.dip2px().toFloat()
|
||||
val RADIUS_16 = 16F.dip2px().toFloat()
|
||||
val RADIUS_18 = 18F.dip2px().toFloat()
|
||||
val RADIUS_20 = 20F.dip2px().toFloat()
|
||||
|
||||
val SIZE_36 = 36F.dip2px()
|
||||
val SIZE_40 = 40F.dip2px()
|
||||
val SIZE_48 = 48F.dip2px()
|
||||
val SIZE_64 = 64F.dip2px()
|
||||
val SIZE_72 = 72F.dip2px()
|
||||
val SIZE_80 = 80F.dip2px()
|
||||
val SIZE_88 = 88F.dip2px()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ class ImageContainerView : LinearLayout {
|
||||
|
||||
//图片之间的间距
|
||||
private val mItemSpace = 4f.dip2px()
|
||||
private var mOffset = 0
|
||||
private var index = 0
|
||||
|
||||
constructor(context: Context) : this(context, null)
|
||||
@ -50,12 +51,21 @@ class ImageContainerView : LinearLayout {
|
||||
private fun initView(attrs: AttributeSet?) {
|
||||
orientation = HORIZONTAL
|
||||
val ta = context.obtainStyledAttributes(attrs, R.styleable.ImageContainerView)
|
||||
val offset = ta.getDimensionPixelSize(R.styleable.ImageContainerView_offset, 0)
|
||||
mDefaultWidth = (DisplayUtils.getScreenWidth() - offset.toFloat() - mItemSpace * 2) / 3
|
||||
mFixdWidth = (DisplayUtils.getScreenWidth() - offset.toFloat() - mItemSpace * 2) * 2 / 3
|
||||
mOffset = ta.getDimensionPixelSize(R.styleable.ImageContainerView_offset, 0)
|
||||
calculateWidth()
|
||||
ta.recycle()
|
||||
}
|
||||
|
||||
private fun calculateWidth() {
|
||||
mDefaultWidth = (DisplayUtils.getScreenWidth() - mOffset.toFloat() - mItemSpace * 2) / 3
|
||||
mFixdWidth = (DisplayUtils.getScreenWidth() - mOffset.toFloat() - mItemSpace * 2) * 2 / 3
|
||||
}
|
||||
|
||||
fun setOffset(offset: Float) {
|
||||
mOffset = offset.dip2px()
|
||||
calculateWidth()
|
||||
}
|
||||
|
||||
fun bindData(entity: AnswerEntity, entrance: String = "", path: String = "") {
|
||||
mAnswerEntity = entity
|
||||
mEntrance = entrance
|
||||
|
||||
@ -60,6 +60,8 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
|
||||
private static final AccessibilityDelegate ACCESSIBILITY_DELEGATE = new AccessibilityDelegate();
|
||||
private Boolean mIsParentViewImplNestedScrolling = false;
|
||||
|
||||
private boolean mInterceptHorizontalScrollDispatch = true;
|
||||
|
||||
public NestedScrollWebView2(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
@ -97,7 +99,9 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
getParent().requestDisallowInterceptTouchEvent(true);
|
||||
if (mInterceptHorizontalScrollDispatch) {
|
||||
getParent().requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@ -825,4 +829,8 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void enableHorizontalScrollDispatch() {
|
||||
mInterceptHorizontalScrollDispatch = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.forEach
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
|
||||
class NoDefaultMinWidthTabLayout : TabLayout {
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
)
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
if (tabCount > 5) {
|
||||
val tabLayout = getChildAt(0) as ViewGroup
|
||||
val childCount = tabLayout.childCount
|
||||
if (childCount > 0) {
|
||||
val widthPixels = MeasureSpec.getSize(widthMeasureSpec)
|
||||
val tabMinWidth = widthPixels / childCount
|
||||
var remainderPixels = widthPixels % childCount
|
||||
tabLayout.forEach {
|
||||
if (remainderPixels > 0) {
|
||||
it.minimumWidth = tabMinWidth + 1
|
||||
remainderPixels--
|
||||
} else {
|
||||
it.minimumWidth = tabMinWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,9 @@ import android.view.ViewGroup;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
@ -34,6 +36,8 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
|
||||
|
||||
private int mIndicatorColor = 0;
|
||||
|
||||
private boolean mDisableIndicatorScaling = false;
|
||||
|
||||
private GradientDrawable mGradientDrawable;
|
||||
private Drawable mCustomDrawable;
|
||||
|
||||
@ -48,9 +52,11 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
|
||||
public TabIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
mIndicatorWidth = (int) context.getResources().getDimension(R.dimen.default_tab_indicator_width);
|
||||
|
||||
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabIndicatorView);
|
||||
if (a.hasValue(R.styleable.TabIndicatorView_indicatorColor)) {
|
||||
mIndicatorColor = a.getColor(R.styleable.TabIndicatorView_indicatorColor, 0);
|
||||
mIndicatorColor = a.getColor(R.styleable.TabIndicatorView_indicatorColor, ContextCompat.getColor(context, R.color.theme_font));
|
||||
mGradientDrawable = new GradientDrawable();
|
||||
mGradientDrawable.setShape(GradientDrawable.RECTANGLE);
|
||||
mGradientDrawable.setColor(mIndicatorColor);
|
||||
@ -59,6 +65,9 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
|
||||
if (a.hasValue(R.styleable.TabIndicatorView_indicatorDrawable)) {
|
||||
mCustomDrawable = a.getDrawable(R.styleable.TabIndicatorView_indicatorDrawable);
|
||||
}
|
||||
if (a.hasValue(R.styleable.TabIndicatorView_disableIndicatorScaling)) {
|
||||
mDisableIndicatorScaling = a.getBoolean(R.styleable.TabIndicatorView_disableIndicatorScaling, false);
|
||||
}
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@ -68,6 +77,11 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
|
||||
mIndicatorHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
}
|
||||
|
||||
public void updateIndicatorDrawable(Drawable drawable) {
|
||||
mCustomDrawable = drawable;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setupWithTabLayout(final TabLayout tableLayout) {
|
||||
mTabLayout = tableLayout;
|
||||
|
||||
@ -119,7 +133,23 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
|
||||
} else {
|
||||
drawable = getResources().getDrawable(R.drawable.ask_tab_indicator_bg); // 固定Indicator背景 有需要可以自行更改
|
||||
}
|
||||
drawable.setBounds(l, t, r, b);
|
||||
|
||||
// 是否需要禁用指示器拉伸
|
||||
if (mDisableIndicatorScaling) {
|
||||
int currentWidth = r - l;
|
||||
int newLeft = l;
|
||||
int newRight = r;
|
||||
|
||||
if (currentWidth != mIndicatorWidth) {
|
||||
int widthOffset = currentWidth - mIndicatorWidth;
|
||||
newLeft = l + (widthOffset / 2);
|
||||
newRight = newLeft + mIndicatorWidth;
|
||||
}
|
||||
drawable.setBounds(newLeft, t, newRight, b);
|
||||
} else {
|
||||
drawable.setBounds(l, t, r, b);
|
||||
}
|
||||
|
||||
drawable.draw(canvas);
|
||||
}
|
||||
|
||||
|
||||
99
app/src/main/java/com/gh/common/view/ThumbProgressBar.kt
Normal file
99
app/src/main/java/com/gh/common/view/ThumbProgressBar.kt
Normal file
@ -0,0 +1,99 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.ProgressBar
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.gamecenter.R
|
||||
|
||||
class ThumbProgressBar : ProgressBar {
|
||||
private var mThumbDrawable: Drawable? = null
|
||||
|
||||
//Thumb的宽度
|
||||
private var mThumbDrawableWidth = 0
|
||||
|
||||
//Thumb的高度
|
||||
private var mThumbDrawableHeight = 0
|
||||
|
||||
//进度条高度
|
||||
private var mProgressBarHeight = 12f.dip2px()
|
||||
|
||||
//Thumb偏移量
|
||||
private val mDefaultThumbOffset = 13f.dip2px()
|
||||
|
||||
//ProgressBar左右偏移量
|
||||
private val mProgressBarPadding = 12f.dip2px()
|
||||
|
||||
private var mPaint: Paint
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
)
|
||||
|
||||
init {
|
||||
mThumbDrawable = ContextCompat.getDrawable(context, R.drawable.icon_package_check_rocket)
|
||||
mThumbDrawableWidth = mThumbDrawable?.intrinsicWidth ?: 0
|
||||
mThumbDrawableHeight = mThumbDrawable?.intrinsicHeight ?: 0
|
||||
mPaint = Paint()
|
||||
mPaint.isAntiAlias = true
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val dh = if (mThumbDrawableHeight > mProgressBarHeight) mThumbDrawableHeight else mProgressBarHeight
|
||||
setMeasuredDimension(
|
||||
View.getDefaultSize(0, widthMeasureSpec),
|
||||
dh
|
||||
)
|
||||
//LayerDrawable使用setBounds可能无效
|
||||
if (progressDrawable is LayerDrawable) {
|
||||
(progressDrawable as LayerDrawable).setLayerInset(0,
|
||||
mProgressBarPadding,
|
||||
(mThumbDrawableHeight - mProgressBarHeight) / 2,
|
||||
mProgressBarPadding,
|
||||
(mThumbDrawableHeight - mProgressBarHeight) / 2
|
||||
)
|
||||
(progressDrawable as LayerDrawable).setLayerInset(1,
|
||||
mProgressBarPadding,
|
||||
(mThumbDrawableHeight - mProgressBarHeight) / 2,
|
||||
mProgressBarPadding,
|
||||
(mThumbDrawableHeight - mProgressBarHeight) / 2
|
||||
)
|
||||
} else {
|
||||
progressDrawable.setBounds(
|
||||
mProgressBarPadding,
|
||||
(mThumbDrawableHeight - mProgressBarHeight) / 2,
|
||||
measuredWidth - mProgressBarPadding,
|
||||
measuredHeight - (mThumbDrawableHeight - mProgressBarHeight) / 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
val percent = progress.toFloat() / max
|
||||
val progressWidth = measuredWidth - paddingLeft - paddingRight - mProgressBarPadding * 2
|
||||
var offsetX =
|
||||
progressWidth * percent + paddingLeft - mDefaultThumbOffset + mProgressBarPadding
|
||||
|
||||
if (offsetX < 0) {
|
||||
offsetX = 0f
|
||||
}
|
||||
if (offsetX > measuredWidth - mThumbDrawableWidth) {
|
||||
offsetX = (measuredWidth - mThumbDrawableWidth).toFloat()
|
||||
}
|
||||
|
||||
val bitmapDrawable = mThumbDrawable as BitmapDrawable
|
||||
val bitmap = bitmapDrawable.bitmap
|
||||
canvas.drawBitmap(bitmap, offsetX, 0f, mPaint)
|
||||
}
|
||||
}
|
||||
@ -67,6 +67,7 @@ public class DWebView extends WebView {
|
||||
private ArrayList<CallInfo> callInfoList;
|
||||
private InnerJavascriptInterface innerJavascriptInterface = new InnerJavascriptInterface();
|
||||
private Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
private OnScrollChangedListener mOnScrollChangedCallback;
|
||||
|
||||
private class InnerJavascriptInterface {
|
||||
|
||||
@ -1045,4 +1046,21 @@ public class DWebView extends WebView {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
||||
super.onScrollChanged(l, t, oldl, oldt);
|
||||
if (mOnScrollChangedCallback != null) {
|
||||
mOnScrollChangedCallback.onScroll(l - oldl, t - oldt);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnScrollChangedListener(
|
||||
final OnScrollChangedListener onScrollChangedCallback) {
|
||||
mOnScrollChangedCallback = onScrollChangedCallback;
|
||||
}
|
||||
|
||||
public interface OnScrollChangedListener {
|
||||
void onScroll(int dx, int dy);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,8 +120,8 @@ public class PagerLayoutManager extends LinearLayoutManager {
|
||||
if (viewIdle != null) {
|
||||
positionIdle = getPosition(viewIdle);
|
||||
}
|
||||
int childCount = getChildCount();
|
||||
// if (mOnViewPagerListener != null && childCount == 1) {
|
||||
// int childCount = getChildCount();
|
||||
int childCount = getItemCount();
|
||||
if (mOnViewPagerListener != null && positionIdle != mLastPosition) {
|
||||
mOnViewPagerListener.onPageSelected(positionIdle,
|
||||
positionIdle == childCount - 1);
|
||||
|
||||
@ -121,9 +121,14 @@ object XapkInstaller : IXapkUnzipListener {
|
||||
DownloadManager.getInstance(mContext).updateDownloadEntity(downloadEntity)
|
||||
}
|
||||
|
||||
SentryHelper.onEvent("XAPK_UNZIP_ERROR",
|
||||
// 仅官网渠道上报 XAPK 异常信息
|
||||
if (HaloApp.getInstance().channel == "GH_206") {
|
||||
SentryHelper.onEvent(
|
||||
"XAPK_UNZIP_ERROR",
|
||||
"gameName", downloadEntity.name,
|
||||
"errorDigest", exception.localizedMessage)
|
||||
"errorDigest", exception.localizedMessage
|
||||
)
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("unzip", "onFailure->$exception")
|
||||
@ -142,7 +147,7 @@ object XapkInstaller : IXapkUnzipListener {
|
||||
return@execute
|
||||
}
|
||||
|
||||
PackageInstaller.install(mContext, pkgPath)
|
||||
PackageInstaller.install(mContext, downloadEntity.isPlugin, pkgPath)
|
||||
|
||||
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
|
||||
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.SUCCESS.name
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.common.xapk
|
||||
|
||||
import android.os.Environment
|
||||
import com.gh.common.util.debounceActionWithInterval
|
||||
import com.gh.common.util.getExtension
|
||||
import com.gh.common.util.throwException
|
||||
import com.gh.common.util.throwExceptionInDebug
|
||||
@ -91,7 +92,10 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
|
||||
mUnzipListener.onCancel(mDownloadEntity)
|
||||
return
|
||||
} else {
|
||||
mUnzipListener.onProgress(mDownloadEntity, outputFile.path, unzipSize, unzipProgress)
|
||||
// 防止多次短时间内多次触发onProgress方法导致阻塞主线程(低端机会出现十分明显的卡顿)
|
||||
debounceActionWithInterval(-1, 500) {
|
||||
mUnzipListener.onProgress(mDownloadEntity, outputFile.path, unzipSize, unzipProgress)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -203,8 +207,10 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
|
||||
|
||||
private fun getUnzipSize(path: String): Long {
|
||||
var totalSize = 0L
|
||||
for (entry in ZipFile(File(path)).entries()) {
|
||||
totalSize += entry.size
|
||||
ZipFile(File(path)).use {
|
||||
for (entry in it.entries()) {
|
||||
totalSize += entry.size
|
||||
}
|
||||
}
|
||||
return totalSize
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ import com.gh.common.util.HomePluggableHelper;
|
||||
import com.gh.common.util.NetworkUtils;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.PageSwitchDataHelper;
|
||||
import com.gh.common.util.SPUtils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.entity.ApkEntity;
|
||||
@ -279,11 +280,18 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.DOWNLOAD_ID, downloadId);
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.RAW_GAME_ICON, gameEntity.getRawIcon());
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_ICON_SUBSCRIPT, gameEntity.getIconSubscript());
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.IS_PLATFORM_RECOMMEND, apkEntity.getRecommend() != null ? "true" : "false");
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_NAME, gameEntity.getName());
|
||||
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.SIMULATOR_GAME, apkEntity.getFormat());
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.SIMULATOR, GsonUtils.toJson(gameEntity.getSimulator()));
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_NAME, gameEntity.getName());
|
||||
}
|
||||
|
||||
HashMap<String, String> map = PageSwitchDataHelper.popLastPageData();
|
||||
if (map != null && map.containsKey(PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND)) {
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND, "true");
|
||||
}
|
||||
|
||||
int installed = 0;
|
||||
for (ApkEntity apk : gameEntity.getApk()) {
|
||||
if (PackagesManager.isInstalled(apk.getPackageName())) {
|
||||
@ -295,13 +303,15 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
// todo 不是应该实时判断吗?
|
||||
if (PackageUtils.isCanPluggable(apkEntity)) {
|
||||
downloadEntity.setPluggable(true);
|
||||
} else if (PackageUtils.isCanUpdate(apkEntity, gameEntity.getId())) {
|
||||
} else if (PackageUtils.isCanUpdate(apkEntity, gameEntity.getId())
|
||||
|| PackageUtils.isNonPluginUpdatable(apkEntity, gameEntity)) {
|
||||
downloadEntity.setUpdate(true);
|
||||
}
|
||||
|
||||
downloadEntity.setPlugin(!TextUtils.isEmpty(apkEntity.getGhVersion()));
|
||||
|
||||
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, gameEntity.getId());
|
||||
gameEntity.setIsPlatformRecommend(apkEntity.getRecommend() != null);
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, downloadType);
|
||||
|
||||
// 将下载事件放入 downloadEntity 中供下载完成时取出使用
|
||||
@ -658,7 +668,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
// 将原来安装完成后在 downloadService 完成的功能放到这里,尝试避免因为 ANR 造成闪退
|
||||
AppExecutor.getUiExecutor().executeWithDelay(() -> {
|
||||
mDownloadDao.removeErrorMessage(entry.getUrl());
|
||||
|
||||
|
||||
DownloadTask task = DataChanger.INSTANCE.getDownloadingTasks().get(entry.getUrl());
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
@ -669,7 +679,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
DataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl());
|
||||
DataChanger.INSTANCE.notifyDataChanged(entry);
|
||||
DownloadStatusManager.getInstance().onTaskCancelled(entry);
|
||||
|
||||
|
||||
Utils.log(DownloadManager.class.getSimpleName(), "cancel");
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import com.gh.common.constant.Constants
|
||||
import com.gh.common.loghub.LoghubUtils
|
||||
import com.gh.common.runOnIoThread
|
||||
import com.gh.common.util.*
|
||||
import com.gh.download.server.BrowserInstallHelper
|
||||
import com.gh.gamecenter.entity.GameDigestEntity
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
@ -74,6 +75,8 @@ object PackageObserver {
|
||||
if ("安装" == busFour.type) {
|
||||
mPackageViewModel.addInstalledGame(packageName)
|
||||
|
||||
BrowserInstallHelper.onApkInstalled(mDownloadEntity?.path)
|
||||
|
||||
if (mDownloadEntity != null) {
|
||||
if (mDownloadEntity.isPluggable) {
|
||||
val kv6: MutableMap<String, Any> = HashMap()
|
||||
@ -121,10 +124,11 @@ object PackageObserver {
|
||||
|
||||
if ("卸载" == busFour.type) {
|
||||
mPackageViewModel.addUninstalledGame(packageName)
|
||||
if (mDownloadEntity != null && mDownloadEntity.isPluggable) {
|
||||
val kv6: MutableMap<String, Any> = HashMap()
|
||||
kv6["安装或卸载"] = "卸载完成"
|
||||
DataUtils.onEvent(application, "插件化", mDownloadEntity.name, kv6)
|
||||
mDownloadEntity?.let {
|
||||
if (it.isPluggable || it.isUpdate) {
|
||||
val kv6: MutableMap<String, Any> = HashMap()
|
||||
kv6["安装或卸载"] = "卸载完成"
|
||||
DataUtils.onEvent(application, "插件化", mDownloadEntity.name, kv6)
|
||||
|
||||
// DataUtils.onMtaEvent(this,
|
||||
// "插件化_新",
|
||||
@ -132,7 +136,8 @@ object PackageObserver {
|
||||
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
|
||||
// "操作", "卸载完成",
|
||||
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
PackageInstaller.install(application, mDownloadEntity)
|
||||
PackageInstaller.install(application, mDownloadEntity)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新已安装游戏
|
||||
|
||||
@ -70,9 +70,9 @@ object ExoCacheManager {
|
||||
if (requestLength == bytesCached) {
|
||||
threads.remove(videoUri)
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("$requestLength--$bytesCached--$newBytesCached")
|
||||
}
|
||||
// if (BuildConfig.DEBUG) {
|
||||
// Utils.log("$requestLength--$bytesCached--$newBytesCached")
|
||||
// }
|
||||
}, threads[videoUri])
|
||||
} catch (e: Throwable) {
|
||||
threads.remove(videoUri)
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package com.gh.download.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
@ -14,14 +13,15 @@ import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.*
|
||||
import androidx.recyclerview.widget.RecyclerView.SmoothScroller
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.TimeElapsedHelper
|
||||
import com.gh.common.dialog.BaseDraggableDialogFragment
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.util.*
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.DialogDownloadBinding
|
||||
import com.gh.gamecenter.entity.ApkEntity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.halo.assistant.HaloApp
|
||||
@ -34,8 +34,7 @@ import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import java.util.*
|
||||
|
||||
|
||||
class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
class DownloadDialog : BaseDraggableDialogFragment() {
|
||||
|
||||
private lateinit var mGameEntity: GameEntity
|
||||
private lateinit var mViewModel: DownloadViewModel
|
||||
@ -43,8 +42,6 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
|
||||
private lateinit var mElapsedHelper: TimeElapsedHelper
|
||||
|
||||
private lateinit var mGestureDetector: GestureDetector
|
||||
|
||||
private var mAdapter: DownloadDialogAdapter? = null
|
||||
private var mTraceEvent: ExposureEvent? = null
|
||||
|
||||
@ -61,7 +58,6 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
private var mEntrance: String = "" // 入口位置
|
||||
private var mLocation: String = "" // 最终位置
|
||||
|
||||
private var mInitPositionY = 0f
|
||||
|
||||
private val mDataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
@ -84,16 +80,6 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val createDialog = super.onCreateDialog(savedInstanceState)
|
||||
createDialog.setCanceledOnTouchOutside(true)
|
||||
|
||||
val window = createDialog.window
|
||||
window?.setGravity(Gravity.BOTTOM)
|
||||
window?.setWindowAnimations(R.style.community_publication_animation)
|
||||
return createDialog
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
EventBus.getDefault().register(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -105,6 +91,9 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
|
||||
val factory = DownloadViewModel.Factory(HaloApp.getInstance().application, mGameEntity)
|
||||
mViewModel = ViewModelProviders.of(this, factory).get(DownloadViewModel::class.java)
|
||||
if (savedInstanceState != null) {
|
||||
mViewModel.getAllPackageName()
|
||||
}
|
||||
mViewModel.listLiveData.observeNonNull(this, callback = { itemList ->
|
||||
mAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, false, mTraceEvent, mEntrance, mLocation)
|
||||
mBinding.contentList.layoutManager = createLayoutManager(itemList)
|
||||
@ -121,8 +110,18 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
|
||||
val itemList: MutableList<DownloadDialogItemData> = ArrayList()
|
||||
saveApkList?.forEach { apk ->
|
||||
mViewModel.setSortValueToApkEntity(apk)
|
||||
itemList.add(DownloadDialogItemData(normal = apk))
|
||||
}
|
||||
val count = itemList.count { it.normal?.recommend != null }
|
||||
if (count % 2 != 0) {
|
||||
itemList.add(DownloadDialogItemData(normal = ApkEntity(order = DownloadViewModel.SORT_RECOMMEND_EMPTY)))
|
||||
}
|
||||
|
||||
itemList.sortWith(Comparator { o1, o2 ->
|
||||
(o2.normal?.order ?: 0) - (o1.normal?.order ?: 0)
|
||||
})
|
||||
|
||||
if (collection.downloadInstruction.isNotEmpty()) {
|
||||
itemList.add(DownloadDialogItemData(instruction = collection.downloadInstruction))
|
||||
}
|
||||
@ -176,8 +175,6 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
mGestureDetector = GestureDetector(requireContext(), SingleTapConfirm())
|
||||
mBinding.dragClose.setOnTouchListener(this)
|
||||
mBinding.back.setOnTouchListener(this)
|
||||
mBinding.downloadNotice.setOnTouchListener(this)
|
||||
|
||||
@ -289,13 +286,6 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
// }
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val width = HaloApp.getInstance().application.resources.displayMetrics.widthPixels
|
||||
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
dialog?.window?.setLayout(width, height)
|
||||
}
|
||||
|
||||
override fun onBack(): Boolean {
|
||||
if (mCollectionAdapter != null && mAdapter != null) {
|
||||
postBrowseMta()
|
||||
@ -305,55 +295,9 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
return super.onBack()
|
||||
}
|
||||
|
||||
// dialog drag animation
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
||||
if (mGestureDetector.onTouchEvent(event) && mBinding.root.y == 0F) {
|
||||
v.performClick()
|
||||
return true
|
||||
}
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
mInitPositionY = mBinding.root.y - event.rawY
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
val offsetY = event.rawY + mInitPositionY
|
||||
val dialogY = mBinding.root.y
|
||||
if (dialogY + offsetY > 0) {
|
||||
mBinding.root.animate()
|
||||
.y(offsetY)
|
||||
.setDuration(0)
|
||||
.start()
|
||||
} else {
|
||||
resetDialogPosition()
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_CANCEL,
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_OUTSIDE -> {
|
||||
if (mBinding.root.y >= mBinding.root.height / 2) {
|
||||
dismissAllowingStateLoss()
|
||||
} else {
|
||||
resetDialogPosition(300)
|
||||
}
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun resetDialogPosition(duration: Long = 0) {
|
||||
mBinding.root.animate()
|
||||
.y(0F)
|
||||
.setDuration(duration)
|
||||
.start()
|
||||
}
|
||||
|
||||
private class SingleTapConfirm : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onSingleTapUp(event: MotionEvent): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
override fun getRootView(): View = mBinding.root
|
||||
override fun getDragCloseView(): View = mBinding.dragClose
|
||||
|
||||
//安装、卸载事件
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
||||
@ -8,6 +8,7 @@ import com.gh.base.OnViewClickListener
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.throwExceptionInDebug
|
||||
import com.gh.gamecenter.NewsDetailActivity
|
||||
import com.gh.gamecenter.QaActivity
|
||||
@ -74,6 +75,14 @@ class DownloadDialogAdapter(context: Context,
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is DownloadDialogSectionItemViewHolder -> {
|
||||
(holder.binding.root.layoutParams as RecyclerView.LayoutParams).apply {
|
||||
topMargin = if (position > 0) {
|
||||
if (position - 1 >= 0 && (listData[position - 1].installed != null || listData[position - 1].normal != null)) {
|
||||
4f.dip2px()
|
||||
} else 12f.dip2px()
|
||||
} else 0
|
||||
holder.binding.root.layoutParams = this
|
||||
}
|
||||
holder.binding.type = listData[position].section
|
||||
}
|
||||
is DownloadDialogLinkItemViewHolder -> {
|
||||
@ -102,7 +111,7 @@ class DownloadDialogAdapter(context: Context,
|
||||
}
|
||||
}
|
||||
is DownloadDialogInstructionItemViewHolder -> {
|
||||
holder.bindItem(listData[position].instruction!!)
|
||||
holder.bindItem(listData, position, mEntrance)
|
||||
}
|
||||
is DownloadDialogPlatformRequestItemViewHolder -> {
|
||||
holder.bindItem(viewModel.gameEntity)
|
||||
@ -112,7 +121,7 @@ class DownloadDialogAdapter(context: Context,
|
||||
throwExceptionInDebug("合集页面不应该存在该条数据", isCollectionPage)
|
||||
}
|
||||
is DownloadDialogItemViewHolder -> {
|
||||
holder.bindItem(listData[position].normal!!, viewModel, isCollectionPage, mTraceEvent, mEntrance, mPath, mLocation)
|
||||
holder.bindItem(listData, position, viewModel, isCollectionPage, mTraceEvent, mEntrance, mPath, mLocation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ class DownloadDialogInstalledItemViewHolder(val binding: DownloadDialogInstalled
|
||||
binding.launch.visibility = View.GONE
|
||||
if (apkCollection != null) {
|
||||
binding.remark.goneIf(apkCollection.remark.isEmpty())
|
||||
binding.root.setBackgroundResource(R.drawable.download_dialog_item_collection_background)
|
||||
// binding.root.setBackgroundResource(R.drawable.download_dialog_item_collection_background)
|
||||
} else {
|
||||
binding.remark.goneIf(apkEntity.remark.isEmpty())
|
||||
}
|
||||
|
||||
@ -1,18 +1,36 @@
|
||||
package com.gh.download.dialog
|
||||
|
||||
import android.graphics.Color
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.base.BaseRecyclerViewHolder
|
||||
import com.gh.common.DefaultUrlHandler
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.gamecenter.databinding.DownloadDialogInstructionItemBinding
|
||||
|
||||
class DownloadDialogInstructionItemViewHolder(val binding: DownloadDialogInstructionItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
|
||||
|
||||
fun bindItem(instruction: String) {
|
||||
fun bindItem(listData: List<DownloadDialogItemData>, position: Int, entrance: String) {
|
||||
val instruction = listData[position].instruction
|
||||
binding.webView.loadDataWithBaseURL(
|
||||
null,
|
||||
"<body style='margin:0;padding:0;'>$instruction</body>",
|
||||
"<body style='margin:0;padding:0;color:#666666;font-size:12px;line-height:18px;'>$instruction</body>",
|
||||
"text/html",
|
||||
"utf-8", null)
|
||||
binding.webView.settings
|
||||
binding.webView.setBackgroundColor(Color.TRANSPARENT)
|
||||
binding.webView.webViewClient = object : WebViewClient() {
|
||||
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
|
||||
return DefaultUrlHandler.interceptUrl(binding.root.context, url ?: "", entrance)
|
||||
}
|
||||
}
|
||||
|
||||
val topOffset = if (position - 1 >= 0 && (listData[position - 1].normal?.url.isNullOrEmpty() || listData[position - 1].normal?.recommend != null)) 0 else 12f.dip2px()
|
||||
(binding.root.layoutParams as RecyclerView.LayoutParams).apply {
|
||||
topMargin = topOffset
|
||||
binding.root.layoutParams = this
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,10 @@ package com.gh.download.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.base.BaseActivity
|
||||
import com.gh.base.BaseRecyclerViewHolder
|
||||
import com.gh.common.constant.Config
|
||||
@ -13,6 +16,7 @@ import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DirectUtils.directToLinkPage
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.download.server.BrowserInstallHelper
|
||||
import com.gh.gamecenter.DownloadManagerActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.DownloadDialogItemBinding
|
||||
@ -29,7 +33,8 @@ import com.lightgame.utils.Utils
|
||||
|
||||
class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
|
||||
|
||||
fun bindItem(apkEntity: ApkEntity,
|
||||
fun bindItem(listData: List<DownloadDialogItemData>,
|
||||
position: Int,
|
||||
viewModel: DownloadViewModel,
|
||||
isCollectionPage: Boolean,
|
||||
traceEvent: ExposureEvent?,
|
||||
@ -37,6 +42,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
path: String,
|
||||
location: String) {
|
||||
|
||||
val apkEntity = listData[position].normal!!
|
||||
val gameEntity = viewModel.gameEntity
|
||||
val apkLink = apkEntity.apkLink
|
||||
val apkCollection = apkEntity.apkCollection
|
||||
@ -49,38 +55,45 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
apkCollection != null -> ApkEntity(
|
||||
platformIcon = apkCollection.newIcon,
|
||||
platformName = apkCollection.name,
|
||||
recommend = apkCollection.recommend,
|
||||
remark = apkCollection.remark)
|
||||
else -> apkEntity
|
||||
}
|
||||
binding.root.setBackgroundResource(R.drawable.download_dialog_item_background)
|
||||
binding.containerView.setBackgroundResource(R.drawable.download_dialog_item_background)
|
||||
binding.status.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
|
||||
changeRecommendUI(apkEntity, listData, position)
|
||||
|
||||
if (apkLink != null) {
|
||||
binding.downloadStatusIcon.visibility = View.VISIBLE
|
||||
binding.downloadStatusIcon.visibility = View.GONE
|
||||
binding.status.visibility = View.VISIBLE
|
||||
binding.progressbar.visibility = View.GONE
|
||||
binding.install.visibility = View.GONE
|
||||
binding.remark.goneIf(apkLink.remark.isEmpty())
|
||||
|
||||
binding.status.text = "点击查看"
|
||||
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_collection_status_link)
|
||||
binding.root.setBackgroundResource(R.drawable.download_dialog_installed_background)
|
||||
binding.status.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(binding.status.context, R.drawable.download_dialog_collection_status_link), null)
|
||||
binding.containerView.setBackgroundResource(R.drawable.download_dialog_installed_background)
|
||||
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.LINK)
|
||||
} else if (apkCollection != null || (!isCollectionPage && apkEntity.downloadInstruction.isNotEmpty())) {
|
||||
binding.root.visibility = View.VISIBLE
|
||||
binding.downloadStatusIcon.visibility = View.VISIBLE
|
||||
binding.progressbar.visibility = View.GONE
|
||||
binding.install.visibility = View.GONE
|
||||
binding.status.visibility = View.GONE
|
||||
if (apkCollection != null) {
|
||||
binding.remark.goneIf(apkCollection.remark.isEmpty())
|
||||
binding.root.setBackgroundResource(R.drawable.download_dialog_item_collection_background)
|
||||
} else {
|
||||
binding.remark.goneIf(apkEntity.remark.isEmpty())
|
||||
}
|
||||
|
||||
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_status_collection)
|
||||
binding.downloadStatusIcon.setImageResource(if (apkEntity.recommend != null) R.drawable.download_dialog_status_collection else R.drawable.download_dialog_status_collection_gray)
|
||||
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.COLLECTION)
|
||||
} else {
|
||||
|
||||
if (apkEntity.url.isNullOrEmpty()) {
|
||||
binding.root.visibility = View.INVISIBLE
|
||||
return
|
||||
}
|
||||
binding.root.visibility = View.VISIBLE
|
||||
val downloadEntity = DownloadManager.getInstance(HaloApp.getInstance().application).getDownloadEntityByUrl(apkEntity.url)
|
||||
if (downloadEntity != null) {
|
||||
binding.downloadStatusIcon.visibility = View.VISIBLE
|
||||
@ -104,17 +117,17 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
binding.remark.goneIf(apkEntity.remark.isEmpty())
|
||||
|
||||
if (PackageUtils.isCanUpdate(apkEntity, gameEntity.id)) {
|
||||
binding.downloadStatusIcon.visibility = View.VISIBLE
|
||||
binding.status.visibility = View.VISIBLE
|
||||
|
||||
binding.status.text = "可更新"
|
||||
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_collection_status_update)
|
||||
binding.status.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(binding.status.context, R.drawable.download_dialog_collection_status_update), null)
|
||||
binding.downloadStatusIcon.visibility = View.GONE
|
||||
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.UPDATE)
|
||||
} else if (PackageUtils.getGhId(apkEntity.packageName) == gameEntity.id ||
|
||||
PackagesManager.isInstalled(apkEntity.packageName) && Config.getSettings()?.gameDownloadBlackList?.contains(apkEntity.packageName) == true) {
|
||||
binding.downloadStatusIcon.visibility = View.GONE
|
||||
binding.status.visibility = View.VISIBLE
|
||||
binding.root.setBackgroundResource(R.drawable.download_dialog_installed_background)
|
||||
binding.containerView.setBackgroundResource(R.drawable.download_dialog_installed_background)
|
||||
|
||||
var isFilter = false
|
||||
Config.getSettings()?.gameDownloadBlackList?.forEach { pkgName ->
|
||||
@ -131,12 +144,13 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
// 点击启动
|
||||
binding.status.text = "点击启动"
|
||||
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.LAUNCH)
|
||||
binding.status.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(binding.status.context, R.drawable.download_dialog_collection_status_launch), null)
|
||||
}
|
||||
} else {
|
||||
binding.downloadStatusIcon.visibility = View.VISIBLE
|
||||
binding.status.visibility = View.GONE
|
||||
|
||||
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_status_download)
|
||||
binding.downloadStatusIcon.setImageResource(if (apkEntity.recommend != null) R.drawable.download_dialog_status_download else R.drawable.download_dialog_status_download_gray)
|
||||
if (PackageUtils.isCanPluggable(apkEntity)) {
|
||||
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.PLUGGABLE)
|
||||
} else {
|
||||
@ -150,6 +164,25 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
binding.executePendingBindings()
|
||||
}
|
||||
|
||||
private fun changeRecommendUI(apkEntity: ApkEntity, listData: List<DownloadDialogItemData>, position: Int) {
|
||||
(binding.containerView.layoutParams as RelativeLayout.LayoutParams).apply {
|
||||
topMargin = if (apkEntity.recommend != null) 4f.dip2px() else 0
|
||||
binding.containerView.layoutParams = this
|
||||
}
|
||||
(binding.root.layoutParams as RecyclerView.LayoutParams).apply {
|
||||
bottomMargin = if (apkEntity.recommend != null) {
|
||||
if ((position + 1 < listData.size && listData[position + 1].normal?.recommend == null) ||
|
||||
(position + 2 < listData.size && listData[position + 2].normal?.recommend == null)) {
|
||||
20f.dip2px()
|
||||
} else 16f.dip2px()
|
||||
} else 8f.dip2px()
|
||||
binding.root.layoutParams = this
|
||||
}
|
||||
if (apkEntity.recommend != null) {
|
||||
binding.containerView.background = ContextCompat.getDrawable(binding.root.context, R.drawable.bg_download_dialog_item_recommend)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getDownloadingStatusText(downloadEntity: DownloadEntity): String {
|
||||
return when (downloadEntity.status) {
|
||||
@ -212,7 +245,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
DownloadManager.getInstance(it.context).cancel(apkEntity.url)
|
||||
} else {
|
||||
if (PackageUtils.isCanPluggable(apkEntity)) {
|
||||
DialogUtils.showPluginDialog(it.context) {
|
||||
DialogHelper.showPluginDialog(it.context) {
|
||||
PackageInstaller.uninstall(it.context, downloadEntity.path)
|
||||
}
|
||||
} else {
|
||||
@ -278,23 +311,27 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
// todo 有时间存储判断统一处理
|
||||
val msg = FileUtils.isCanDownload(context, apkEntity.size)
|
||||
if (msg.isNullOrEmpty()) {
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
|
||||
BrowserInstallHelper.showBrowserInstallHintDialog(context, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
PackageCheckDialogFragment.show(context as AppCompatActivity, gameEntity.packageDialog, DialogUtils.ConfirmListener {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
|
||||
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
|
||||
DownloadManager.createDownload(
|
||||
context,
|
||||
apkEntity,
|
||||
gameEntity,
|
||||
downloadMethod,
|
||||
entrance,
|
||||
location,
|
||||
isSubscribe, traceEvent)
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
PackageCheckDialogFragment.show(context as AppCompatActivity, gameEntity, DialogUtils.ConfirmListener {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
|
||||
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
|
||||
DownloadManager.createDownload(
|
||||
context,
|
||||
apkEntity,
|
||||
gameEntity,
|
||||
downloadMethod,
|
||||
entrance,
|
||||
location,
|
||||
isSubscribe, traceEvent)
|
||||
|
||||
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
|
||||
}
|
||||
})
|
||||
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,17 +1,16 @@
|
||||
package com.gh.download.dialog
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.*
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.entity.ApkEntity
|
||||
import com.gh.gamecenter.entity.GameCollectionEntity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.Recommend
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadStatus
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@ -35,10 +34,11 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
|
||||
private var mAllApkList: MutableList<ApkEntity> = ArrayList()
|
||||
private var mInstalledApkList: MutableList<ApkEntity> = ArrayList()
|
||||
private var mOtherApkList: MutableList<ApkEntity> = ArrayList()
|
||||
|
||||
private var allPackageName: ArrayList<String>? = null
|
||||
var otherSectionPosition = -1
|
||||
|
||||
init {
|
||||
getAllPackageName()
|
||||
if (gameEntity.pluggableCollection != null) {
|
||||
collectionLiveData.postValue(gameEntity.pluggableCollection)
|
||||
} else {
|
||||
@ -46,6 +46,10 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllPackageName() {
|
||||
allPackageName = PackageUtils.getAllPackageName(HaloApp.getInstance())
|
||||
}
|
||||
|
||||
fun initListData() {
|
||||
mAllApkList = ArrayList()
|
||||
mInstalledApkList = ArrayList()
|
||||
@ -95,6 +99,10 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
|
||||
}
|
||||
|
||||
mInstalledApkList.sortWith(Comparator { o1, o2 -> o2.order - o1.order })
|
||||
val count = mOtherApkList.count { it.recommend != null }
|
||||
if (count % 2 != 0) {
|
||||
mOtherApkList.add(ApkEntity(order = SORT_RECOMMEND_EMPTY, recommend = Recommend()))
|
||||
}
|
||||
mOtherApkList.sortWith(Comparator { o1, o2 -> o2.order - o1.order })
|
||||
|
||||
val itemList: MutableList<DownloadDialogItemData> = ArrayList()
|
||||
@ -126,14 +134,20 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
|
||||
listLiveData.postValue(itemList)
|
||||
}
|
||||
|
||||
private fun setSortValueToApkEntity(apkEntity: ApkEntity) {
|
||||
apkEntity.apkCollection?.saveApkEntity?.forEach { saveApk ->
|
||||
val sortValue = getSortValue(saveApk)
|
||||
if (apkEntity.order < sortValue) {
|
||||
apkEntity.order = sortValue
|
||||
fun setSortValueToApkEntity(apkEntity: ApkEntity) {
|
||||
if (apkEntity.apkCollection?.recommend != null) {
|
||||
apkEntity.recommend = apkEntity.apkCollection?.recommend
|
||||
apkEntity.order = getSortValue(apkEntity)
|
||||
} else {
|
||||
apkEntity.apkCollection?.saveApkEntity?.forEach { saveApk ->
|
||||
val sortValue = getSortValue(saveApk)
|
||||
if (apkEntity.order < sortValue) {
|
||||
apkEntity.order = sortValue
|
||||
apkEntity.recommend = saveApk.recommend
|
||||
apkEntity.apkCollection?.recommend = saveApk.recommend
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (apkEntity.order == 0) {
|
||||
apkEntity.order = getSortValue(apkEntity)
|
||||
}
|
||||
@ -141,34 +155,37 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
|
||||
|
||||
private fun getSortValue(apkEntity: ApkEntity): Int {
|
||||
val packageName = apkEntity.packageName
|
||||
if (apkEntity.recommend != null) {
|
||||
return SORT_RECOMMEND
|
||||
}
|
||||
val downloadEntity = DownloadManager.getInstance(getApplication()).getDownloadEntityByUrl(apkEntity.url)
|
||||
if (downloadEntity == null) {
|
||||
if (PackagesManager.isInstalled(packageName)) {
|
||||
if (PackageUtils.isCanPluggable(apkEntity)) {
|
||||
return SORT_PLUGGABLE
|
||||
} else if (PackageUtils.isCanUpdate(apkEntity, gameEntity.id)) {
|
||||
return SORT_UPDATE
|
||||
} else if (PackageUtils.getGhId(packageName) == gameEntity.id) {
|
||||
return SORT_NORMAL_LAUNCH
|
||||
when {
|
||||
PackageUtils.isCanPluggable(apkEntity) -> {
|
||||
return SORT_PLUGGABLE
|
||||
}
|
||||
PackageUtils.isCanUpdate(apkEntity, gameEntity.id) -> {
|
||||
return SORT_UPDATE
|
||||
}
|
||||
PackageUtils.getGhId(packageName) == gameEntity.id -> {
|
||||
return SORT_NORMAL_LAUNCH
|
||||
}
|
||||
}
|
||||
}
|
||||
return SORT_NORMAL
|
||||
} else {
|
||||
return if (downloadEntity.status == DownloadStatus.done) {
|
||||
if (downloadEntity.isPluggable) {
|
||||
SORT_PLUGGABLE_INSTALL
|
||||
} else if (downloadEntity.isUpdate) {
|
||||
SORT_UPDATE_INSTALL
|
||||
} else {
|
||||
SORT_NORMAL_INSTALL
|
||||
when {
|
||||
downloadEntity.isPluggable -> SORT_PLUGGABLE_INSTALL
|
||||
downloadEntity.isUpdate -> SORT_UPDATE_INSTALL
|
||||
else -> SORT_NORMAL_INSTALL
|
||||
}
|
||||
} else {
|
||||
if (downloadEntity.isPluggable) {
|
||||
SORT_PLUGGABLE_DOWNLOADING
|
||||
} else if (downloadEntity.isUpdate) {
|
||||
SORT_UPDATE_DOWNLOADING
|
||||
} else {
|
||||
SORT_NORMAL_DOWNLOADING
|
||||
when {
|
||||
downloadEntity.isPluggable -> SORT_PLUGGABLE_DOWNLOADING
|
||||
downloadEntity.isUpdate -> SORT_UPDATE_DOWNLOADING
|
||||
else -> SORT_NORMAL_DOWNLOADING
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -243,7 +260,7 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
|
||||
// 仅用于多平台面板的已安装判断
|
||||
private fun isInstalled(packageName: String): Boolean {
|
||||
val ghId = PackageUtils.getGhId(packageName)
|
||||
return PackagesManager.isInstalled(packageName)
|
||||
return (PackagesManager.isInstalled(packageName) || allPackageName?.contains(packageName) == true)
|
||||
&& (ghId == null || ghId == gameEntity.id)
|
||||
&& Config.getSettings()?.gameDownloadBlackList?.contains(packageName) != true
|
||||
}
|
||||
@ -257,6 +274,9 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
|
||||
companion object {
|
||||
|
||||
// 需要修改排序的话,只需要修改以下数值即可(由大到小排序)
|
||||
const val SORT_RECOMMEND = 12
|
||||
const val SORT_RECOMMEND_EMPTY = 11
|
||||
|
||||
const val SORT_PLUGGABLE_INSTALL = 10
|
||||
const val SORT_PLUGGABLE_DOWNLOADING = 9
|
||||
const val SORT_PLUGGABLE = 8
|
||||
|
||||
238
app/src/main/java/com/gh/download/server/BrowserInstallHelper.kt
Normal file
238
app/src/main/java/com/gh/download/server/BrowserInstallHelper.kt
Normal file
@ -0,0 +1,238 @@
|
||||
package com.gh.download.server
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.Base64
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.ExposureEntity
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.loghub.LoghubUtils
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.ShellActivity
|
||||
import com.google.gson.JsonObject
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.net.URLEncoder
|
||||
import java.util.*
|
||||
|
||||
object BrowserInstallHelper {
|
||||
|
||||
// 随便选的 32321 居然在部分 vivo 手机上被占用,喷了
|
||||
private const val PORT = 40705
|
||||
|
||||
private val mServer by lazy { getServer() }
|
||||
private val mFileNameSet by lazy { hashSetOf<String>() }
|
||||
private val mContext by lazy { HaloApp.getInstance().application }
|
||||
|
||||
private val mAllInstalledPackageList: ArrayList<String> by lazy {
|
||||
PackageUtils.getAllPackageNameIncludeSystemApps(HaloApp.getInstance().applicationContext)
|
||||
}
|
||||
|
||||
private fun getServer(): DownloadServer {
|
||||
val server = DownloadServer(PORT)
|
||||
for (packageName in mAllInstalledPackageList) {
|
||||
if (packageName.contains("com.freeme") || packageName.contains("com.zhuoyi")) {
|
||||
server.isBuggyDevice = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return server
|
||||
}
|
||||
|
||||
fun downloadFile(filePath: String) {
|
||||
var fileName = filePath.substringAfterLast(File.separator)
|
||||
// 山寨机没有 .apk 后缀但有 Content-Type 管用,还是给它补上 .apk 后缀
|
||||
if (!mServer.isBuggyDevice) {
|
||||
fileName = fileName.removeSuffix(DownloadServer.APK_SUFFIX)
|
||||
}
|
||||
val downloadUrl = "http://127.0.0.1:$PORT/$fileName"
|
||||
|
||||
if (!mServer.isAlive) startServer()
|
||||
|
||||
mFileNameSet.add(fileName)
|
||||
if (mServer.isBuggyDevice) {
|
||||
val encodedString = Base64.encodeToString(URLEncoder.encode(downloadUrl).trim().toByteArray(), Base64.NO_WRAP)
|
||||
DirectUtils.directToExternalBrowser(mContext, "https://down-and.ghzs.com/redirect?location=base64($encodedString)")
|
||||
} else {
|
||||
DirectUtils.directToExternalBrowser(mContext, downloadUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun shouldUseBrowserToInstall(): Boolean {
|
||||
if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否显示使用浏览器来安装弹窗
|
||||
*/
|
||||
private fun shouldShowUseBrowserToInstallHint(): Boolean {
|
||||
return if (isUseBrowserToInstallEnabled()) {
|
||||
if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
|
||||
false
|
||||
} else {
|
||||
SPUtils.getBoolean(Constants.SP_SHOULD_SHOW_USE_BROWSER_TO_INSTALL_HINT, true)
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否显示游戏详情页使用浏览器安装提示
|
||||
*/
|
||||
fun shouldShowGameDetailUseBrowserToInstallHint(): Boolean {
|
||||
return if (isUseBrowserToInstallEnabled()) {
|
||||
// if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
|
||||
// false
|
||||
// } else {
|
||||
SPUtils.getBoolean(Constants.SP_SHOULD_SHOW_GAMEDETAIL_USE_BROWSER_TO_INSTALL_HINT, true)
|
||||
// }
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun hideGameDetailUseBrowserToInstallHint() {
|
||||
SPUtils.setBoolean(Constants.SP_SHOULD_SHOW_GAMEDETAIL_USE_BROWSER_TO_INSTALL_HINT, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showBrowserInstallHintDialog(context: Context, callback: EmptyCallback) {
|
||||
if (!shouldShowUseBrowserToInstallHint()) {
|
||||
callback.onCallback()
|
||||
return
|
||||
}
|
||||
|
||||
logOrdinaryBrowserEvent(Type.SWITCH_INSTALL_DIALOG)
|
||||
SPUtils.setBoolean(Constants.SP_SHOULD_SHOW_USE_BROWSER_TO_INSTALL_HINT, false)
|
||||
|
||||
val manufacturer = Build.MANUFACTURER.toUpperCase(Locale.CHINA)
|
||||
var contentText = "当前安装方式为助手安装,如果出现游戏无法安装的问题,可选择切换安装方式为“浏览器安装”"
|
||||
if (manufacturer == "OPPO" || manufacturer == "VIVO") {
|
||||
contentText = "当前安装方式为助手安装,下载安装游戏需要验证账户密码或指纹。如需免密码安装,可选择切换安装方式为“浏览器安装”"
|
||||
}
|
||||
|
||||
DialogHelper.showDialog(
|
||||
context,
|
||||
title = "温馨提示",
|
||||
content = contentText,
|
||||
confirmText = "切换安装方式",
|
||||
cancelText = "继续下载",
|
||||
confirmClickCallback = {
|
||||
val intent = ShellActivity.getIntent(context, ShellActivity.Type.SWITCH_INSTALL_METHOD, null)
|
||||
context.startActivity(intent)
|
||||
logOrdinaryBrowserEvent(Type.SWITCH_INSTALL_DIALOG_ACCESS)
|
||||
},
|
||||
cancelClickCallback = {
|
||||
callback.onCallback()
|
||||
logOrdinaryBrowserEvent(Type.SWITCH_INSTALL_DIALOG_QUIT)
|
||||
},
|
||||
extraConfig = DialogHelper.Config(hint = "修改路径:我的光环-设置-切换安装方式")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 浏览器安装的后台开关
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isUseBrowserToInstallEnabled(): Boolean {
|
||||
val settingsEntity = Config.getNewSettingsEntity()
|
||||
|
||||
if (settingsEntity == null) {
|
||||
return false
|
||||
} else {
|
||||
if (settingsEntity.installModel.status == "matched") {
|
||||
return true
|
||||
}
|
||||
|
||||
settingsEntity.installModel.packages?.let {
|
||||
for (packageName in it) {
|
||||
if (mAllInstalledPackageList.contains(packageName)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun onApkInstalled(path: String?) {
|
||||
path?.let {
|
||||
val fileName = path.substringAfterLast(File.separator).removeSuffix(DownloadServer.APK_SUFFIX)
|
||||
// 更新下载名称 set,确定是否需要关闭下载服务
|
||||
mFileNameSet.remove(fileName)
|
||||
stopServerIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
private fun startServer() {
|
||||
try {
|
||||
mServer.start()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Utils.toast(mContext, "浏览器下载服务开启失败")
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopServerIfNeeded() {
|
||||
// 下载的文件都下载完了
|
||||
if (mFileNameSet.size == 0) {
|
||||
mServer.stop()
|
||||
}
|
||||
}
|
||||
|
||||
/**以下为日志相关方法**/
|
||||
fun logWebDownloadStarted(exposureEvent: ExposureEvent, downloadId: String, isDownloadComplete: Boolean) {
|
||||
val jsonObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
jsonObject.put("event", if (isDownloadComplete) "web_download_complete" else "web_download")
|
||||
jsonObject.put("payload", exposureEvent2JSONObject(exposureEvent.payload, downloadId))
|
||||
jsonObject.put("meta", LogUtils.getMetaObject())
|
||||
jsonObject.put("source", JSONArray(GsonUtils.toJson(exposureEvent.source)))
|
||||
jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
|
||||
}
|
||||
Utils.log(jsonObject.toString())
|
||||
LoghubUtils.log(jsonObject, "event", false)
|
||||
}
|
||||
|
||||
private fun exposureEvent2JSONObject(payload: ExposureEntity, downloadId: String): JSONObject {
|
||||
val string = (GsonUtils.gson.toJsonTree(payload) as JsonObject).apply {
|
||||
addProperty("uni_filename", "$downloadId${DownloadServer.APK_SUFFIX}")
|
||||
}.toString()
|
||||
|
||||
return JSONObject(string)
|
||||
}
|
||||
|
||||
fun logOrdinaryBrowserEvent(type: Type) {
|
||||
val jsonObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
jsonObject.put("event", type.toString().toLowerCase(Locale.CHINA))
|
||||
jsonObject.put("meta", LogUtils.getMetaObject())
|
||||
jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
|
||||
}
|
||||
Utils.log(jsonObject.toString())
|
||||
LoghubUtils.log(jsonObject, "event", false)
|
||||
}
|
||||
|
||||
enum class Type {
|
||||
SWITCH_INSTALL_DIALOG,
|
||||
SWITCH_INSTALL_DIALOG_QUIT,
|
||||
SWITCH_INSTALL_DIALOG_ACCESS,
|
||||
SWITCH_INSTALL_GUIDE_ACCESS,
|
||||
SWITCH_INSTALL_GUIDE_QUIT,
|
||||
SWITCH_INSTALL_SETTING,
|
||||
SWITCH_INSTALL_SETTING_APP,
|
||||
SWITCH_INSTALL_SETTING_WEB
|
||||
}
|
||||
|
||||
}
|
||||
109
app/src/main/java/com/gh/download/server/DownloadServer.kt
Normal file
109
app/src/main/java/com/gh/download/server/DownloadServer.kt
Normal file
@ -0,0 +1,109 @@
|
||||
package com.gh.download.server
|
||||
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.util.getMetaExtra
|
||||
import com.gh.common.util.toObject
|
||||
import com.gh.download.DownloadManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.FileUtils
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class DownloadServer(port: Int) : NanoHTTPD(port) {
|
||||
|
||||
private val mPublishSubject: PublishSubject<String> = PublishSubject.create()
|
||||
private val mCompositeDisposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
// 是否是山寨机
|
||||
var isBuggyDevice: Boolean = false
|
||||
|
||||
init {
|
||||
// 某些浏览器会开启多线程下载,如果不 throttle 的话会出现多次调用
|
||||
val disposable = mPublishSubject
|
||||
.distinctUntilChanged()
|
||||
.throttleWithTimeout(500, TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe({
|
||||
logBrowserDownload(it, false)
|
||||
}, {})
|
||||
|
||||
mCompositeDisposable.add(disposable)
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认截掉 .apk 后缀的原因是部分系统判断到 url 后缀为 .apk 就会调用系统下载器而不是浏览器下载 apk (下载完成不会自动触发安装)
|
||||
*/
|
||||
override fun serve(fileName: String?,
|
||||
method: Method?,
|
||||
headers: MutableMap<String, String>?,
|
||||
parms: MutableMap<String, String>?,
|
||||
files: MutableMap<String, String>?): Response {
|
||||
var filePath = FileUtils.getDownloadDir(HaloApp.getInstance()) + fileName
|
||||
if (!filePath.contains(APK_SUFFIX)) {
|
||||
filePath += APK_SUFFIX
|
||||
}
|
||||
var file = File(filePath)
|
||||
// 找不到名字全匹配的文件时,进入文件夹里检索一遍
|
||||
if (!file.exists() && fileName != null && !fileName.contains("favicon")) {
|
||||
// 后台可能上传后缀有为 ".apk.apk" 的包!
|
||||
val fileDir = File(FileUtils.getDownloadDir(HaloApp.getInstance()))
|
||||
fileDir.listFiles { dir, name ->
|
||||
if (name.contains(fileName.removePrefix(File.separator))) {
|
||||
file = File(dir.path + File.separator + name)
|
||||
return@listFiles true
|
||||
}
|
||||
return@listFiles false
|
||||
}
|
||||
}
|
||||
|
||||
mPublishSubject.onNext(filePath)
|
||||
|
||||
return if (file.exists()) {
|
||||
val fileType = FileUtils.getFileMimeType(HaloApp.getInstance().applicationContext, filePath)
|
||||
?: "application/vnd.android.package-archive"
|
||||
|
||||
// TODO 山寨机给了文件长度会下载失败,有空再看看为什么
|
||||
if (isBuggyDevice) {
|
||||
newChunkedResponse(Response.Status.OK, fileType, DownloadFileInputStream(file)).apply {
|
||||
addHeader("Content-Disposition", "inline; filename=\"$filePath")
|
||||
}
|
||||
} else {
|
||||
newFixedLengthResponse(Response.Status.OK, fileType, DownloadFileInputStream(file), file.length())
|
||||
}
|
||||
} else {
|
||||
newFixedLengthResponse("找不到文件")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val APK_SUFFIX = ".apk"
|
||||
|
||||
fun logBrowserDownload(path: String, isDownloadComplete: Boolean) {
|
||||
for (download in DownloadManager.getInstance(HaloApp.getInstance()).allDownloadEntity) {
|
||||
if (download.path == path) {
|
||||
download.exposureTrace?.toObject<ExposureEvent>()?.let {
|
||||
BrowserInstallHelper.logWebDownloadStarted(it, download.getMetaExtra(Constants.DOWNLOAD_ID), isDownloadComplete)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DownloadFileInputStream(val file: File?) : FileInputStream(file) {
|
||||
override fun read(b: ByteArray?, off: Int, len: Int): Int {
|
||||
// 不为 BUFFER_LENGTH 的时候算是下载完了
|
||||
if (len != 16 * 1024) {
|
||||
DownloadServer.logBrowserDownload(file?.path ?: "", true)
|
||||
}
|
||||
return super.read(b, off, len)
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,6 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.entity.SubjectRecommendEntity
|
||||
import com.gh.gamecenter.game.GameFragment
|
||||
|
||||
@ -36,4 +35,8 @@ class BlockActivity : NormalActivity() {
|
||||
return "板块"
|
||||
}
|
||||
|
||||
override fun getBusinessId(): Pair<String, String> {
|
||||
return Pair(targetFragment?.arguments?.getParcelable<SubjectRecommendEntity>(EntranceUtils.KEY_BLOCK_DATA)?.link ?: "", "")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,8 +2,11 @@ package com.gh.gamecenter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.halo.assistant.fragment.ApkCleanerFragment;
|
||||
|
||||
/**
|
||||
@ -13,7 +16,14 @@ public class CleanApkActivity extends NormalActivity {
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context) {
|
||||
return getTargetIntent(context, CleanApkActivity.class, ApkCleanerFragment.class);
|
||||
return getIntent(context, false);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context, Boolean isChooseApk) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean(EntranceUtils.KEY_IS_CHOOSE_APK, isChooseApk);
|
||||
return getTargetIntent(context, CleanApkActivity.class, ApkCleanerFragment.class, bundle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -16,6 +16,8 @@ import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.gamedetail.GameDetailFragment;
|
||||
import com.halo.assistant.HaloApp;
|
||||
|
||||
import kotlin.Pair;
|
||||
|
||||
import static com.gh.common.constant.Constants.GAME_DETAIL_COME_IN;
|
||||
|
||||
/**
|
||||
@ -48,6 +50,7 @@ public class GameDetailActivity extends NormalActivity {
|
||||
public static void startGameDetailActivity(Context context, GameEntity gameEntity, String entrance) {
|
||||
DataUtils.onMtaEvent(context, "详情页面", "游戏详情", gameEntity != null ? gameEntity.getName() : "");
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_GAMEID, gameEntity.getId());
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
bundle.putParcelable(GameEntity.TAG, gameEntity);
|
||||
context.startActivity(getTargetIntent(context, GameDetailActivity.class, GameDetailFragment.class, bundle));
|
||||
@ -117,6 +120,7 @@ public class GameDetailActivity extends NormalActivity {
|
||||
bundle.putInt(EntranceUtils.KEY_TARGET, defaultTab);
|
||||
}
|
||||
|
||||
bundle.putString(EntranceUtils.KEY_GAMEID, gameEntity.getId());
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
bundle.putParcelable(GameEntity.TAG, gameEntity);
|
||||
context.startActivity(getTargetIntent(context, GameDetailActivity.class, GameDetailFragment.class, bundle));
|
||||
@ -187,6 +191,7 @@ public class GameDetailActivity extends NormalActivity {
|
||||
public static void startGameDetailCommentActivity(Context context, GameEntity game, String entrance) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(GameEntity.TAG, game);
|
||||
bundle.putString(EntranceUtils.KEY_GAMEID, game.getId());
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
bundle.putBoolean(EntranceUtils.KEY_SKIP_GAME_COMMENT, true);
|
||||
context.startActivity(getTargetIntent(context, GameDetailActivity.class, GameDetailFragment.class, bundle));
|
||||
@ -198,6 +203,7 @@ public class GameDetailActivity extends NormalActivity {
|
||||
public static void startGameDetailByShortcut(Context context, GameEntity game, int tab, String entrance) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(GameEntity.TAG, game);
|
||||
bundle.putString(EntranceUtils.KEY_GAMEID, game.getId());
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
bundle.putInt(EntranceUtils.KEY_TARGET, tab);
|
||||
context.startActivity(getTargetIntent(context, GameDetailActivity.class, GameDetailFragment.class, bundle));
|
||||
@ -255,6 +261,16 @@ public class GameDetailActivity extends NormalActivity {
|
||||
return "游戏详情";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<String, String> getBusinessId() {
|
||||
GameDetailFragment fragment = (GameDetailFragment) getTargetFragment();
|
||||
if (fragment.getArguments() != null) {
|
||||
return new Pair<>(fragment.getArguments().getString(EntranceUtils.KEY_GAMEID), "");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
super.attachBaseContext(new ContextWrapper(newBase) {
|
||||
|
||||
@ -195,8 +195,9 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
}
|
||||
|
||||
mArticleDetailBtn.setOnClickListener {
|
||||
val intent = ArticleDetailActivity.getIntent(this, CommunityEntity(mAnswerEntity?.communityId
|
||||
?: "", mAnswerEntity?.communityName ?: ""), mAnswerEntity?.id
|
||||
val intent = ArticleDetailActivity.getIntent(this, CommunityEntity(if (!mAnswerEntity?.communityId.isNullOrEmpty()) mAnswerEntity?.communityId
|
||||
?: "" else mAnswerEntity?.articleCommunityId ?: "", mAnswerEntity?.communityName
|
||||
?: ""), mAnswerEntity?.id
|
||||
?: "", mEntrance, "")
|
||||
startActivity(intent)
|
||||
finish()
|
||||
@ -625,9 +626,9 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
var out: OutputStream? = null
|
||||
try {
|
||||
val fileName: String = if (mShowBase64Image) {
|
||||
MD5Utils.getUrlMD5(curUrl!!.substring(0, 50)) + ".png"
|
||||
MD5Utils.getContentMD5(System.currentTimeMillis().toString()) + ".png"
|
||||
} else {
|
||||
curUrl!!.substring(curUrl.lastIndexOf("/"))
|
||||
Uri.parse(curUrl).lastPathSegment.toString()
|
||||
}
|
||||
val savePath = Environment.getExternalStorageDirectory().absolutePath + "/Pictures/ghzhushou/"
|
||||
val file = File(savePath)
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.gamecenter;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
@ -12,6 +13,7 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
@ -21,11 +23,13 @@ import com.gh.base.OnRequestCallBackListener;
|
||||
import com.gh.base.ToolBarActivity;
|
||||
import com.gh.common.filter.RegionSettingHelper;
|
||||
import com.gh.common.util.ApkActiveUtils;
|
||||
import com.gh.common.util.CheckLoginUtils;
|
||||
import com.gh.common.util.DetailDownloadUtils;
|
||||
import com.gh.common.util.DeviceTokenUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.ExtensionsKt;
|
||||
import com.gh.common.util.LibaoUtils;
|
||||
import com.gh.common.view.CustomDividerItemDecoration;
|
||||
import com.gh.common.view.DownloadProgressBar;
|
||||
import com.gh.common.view.VerticalItemDecoration;
|
||||
import com.gh.download.DownloadManager;
|
||||
@ -50,6 +54,7 @@ import com.lightgame.utils.Utils;
|
||||
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
@ -101,6 +106,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
private String mListStatus; // 记录列表领取状态(防止状态在详情改变导致列表状态改变)
|
||||
private String mName;
|
||||
private String mTitle;
|
||||
private boolean isClickReceiveBtnIn = false;//是否点击领取按钮进入
|
||||
|
||||
@Override
|
||||
protected void handleMessage(Message msg) {
|
||||
@ -129,6 +135,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
mLibaoEntity.setStatus("repeatTaoed"); // 可以重复领取
|
||||
}
|
||||
mAdapter.notifyItemChanged(0);
|
||||
performClickReceiveBtn();
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,14 +162,19 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
false, mEntrance, mName, mTitle, null); // 下载按钮ViewHolder
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context, LibaoEntity libaoEntity, String entrance) {
|
||||
public static Intent getIntent(Context context, LibaoEntity libaoEntity, boolean isClickReceiveBtnIn, String entrance) {
|
||||
Intent intent = new Intent(context, LibaoDetailActivity.class);
|
||||
HaloApp.put(LibaoEntity.TAG, libaoEntity);
|
||||
intent.putExtra(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
intent.putExtra(EntranceUtils.KEY_IS_CLICK_RECEIVE_BTN, isClickReceiveBtnIn);
|
||||
return intent;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context, LibaoEntity libaoEntity, String entrance) {
|
||||
return getIntent(context, libaoEntity, false, entrance);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntentById(Context context, String id, String entrance) {
|
||||
Intent intent = new Intent(context, LibaoDetailActivity.class);
|
||||
@ -172,7 +184,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
protected void onSaveInstanceState(@NotNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
HaloApp.put(LibaoEntity.TAG, mAdapter.getLibaoEntity());
|
||||
}
|
||||
@ -183,6 +195,10 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
mName = getString(R.string.libao_detail);
|
||||
setNavigationTitle(mName);
|
||||
mLibaoEntity = (LibaoEntity) HaloApp.get(LibaoEntity.TAG, false);
|
||||
isClickReceiveBtnIn = getIntent().getBooleanExtra(EntranceUtils.KEY_IS_CLICK_RECEIVE_BTN, false);
|
||||
if (mLibaoEntity != null) {
|
||||
mLibaoEntity.setClickReceiveBtnIn(isClickReceiveBtnIn);
|
||||
}
|
||||
|
||||
mIsScroll = true;
|
||||
|
||||
@ -194,14 +210,14 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
return mIsScroll;
|
||||
}
|
||||
});
|
||||
mLibaoDetailRv.addItemDecoration(new VerticalItemDecoration(this, 8, true));
|
||||
mLibaoDetailRv.addItemDecoration(new VerticalItemDecoration(this, 8, false));
|
||||
mLibaoDetailRv.setAdapter(mAdapter);
|
||||
|
||||
mNoConnection.setOnClickListener(v -> {
|
||||
mSkeleton.show();
|
||||
mNoConnection.setVisibility(View.GONE);
|
||||
mLlLoading.setVisibility(View.VISIBLE);
|
||||
mBaseHandler.postDelayed(() -> getGameDigest(), 1000);
|
||||
mBaseHandler.postDelayed(this::getGameDigest, 1000);
|
||||
});
|
||||
|
||||
if (mLibaoEntity == null) {
|
||||
@ -210,10 +226,10 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
getLibaoDigest(id);
|
||||
}
|
||||
} else {
|
||||
getGameDigest();
|
||||
if (!mLibaoEntity.isActive()) {
|
||||
checkLibaoStatus();
|
||||
}
|
||||
getGameDigest();
|
||||
}
|
||||
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mDetailBottom.getLayoutParams();
|
||||
@ -270,6 +286,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
if (isCanLing()) { // 恢复原始状态
|
||||
mLibaoEntity.setStatus(beforeStatus);
|
||||
mAdapter.notifyItemChanged(0);
|
||||
performClickReceiveBtn();
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -288,11 +305,30 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
mLibaoEntity.setStatus("repeatTao"); // 预备重复领取
|
||||
}
|
||||
mAdapter.notifyItemChanged(0);
|
||||
performClickReceiveBtn();
|
||||
|
||||
DeviceTokenUtils.syncServerTime(LibaoDetailActivity.this);
|
||||
mBaseHandler.sendEmptyMessageDelayed(0, 5000);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
performClickReceiveBtn();
|
||||
}
|
||||
}
|
||||
|
||||
private void performClickReceiveBtn() {
|
||||
if (isClickReceiveBtnIn) {
|
||||
CheckLoginUtils.checkLogin(this, mEntrance, () ->
|
||||
mLibaoDetailRv.postDelayed(() -> {
|
||||
if (mAdapter.libaoDetailTopViewHolder != null) {
|
||||
try {
|
||||
mAdapter.libaoDetailTopViewHolder.libaoCopyBtn.performClick();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, 200)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,13 +394,10 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
// 获取游戏摘要
|
||||
private void getGameDigest() {
|
||||
if (mLibaoEntity.getGame() == null) return;
|
||||
|
||||
String gameId = mLibaoEntity.getGame().getId();
|
||||
|
||||
if (RegionSettingHelper.shouldThisGameBeFiltered(gameId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RetrofitManager.getInstance(this).getSensitiveApi().getGameNewsDigest(gameId)
|
||||
.map(ApkActiveUtils.filterMapper)
|
||||
.subscribeOn(Schedulers.io())
|
||||
@ -378,7 +411,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
|
||||
// 添加启动弹窗的相关信息
|
||||
if (mEntrance.contains(EntranceUtils.ENTRANCE_WELCOME)
|
||||
&& ExtensionsKt.countOccurrences(mEntrance,("+")) <= 1) {
|
||||
&& ExtensionsKt.countOccurrences(mEntrance, ("+")) <= 1) {
|
||||
mGameEntity.setWelcomeDialogInfoIfAvailable();
|
||||
}
|
||||
|
||||
@ -422,10 +455,8 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
mLlLoading.setVisibility(View.GONE);
|
||||
mLibaoDetailRv.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
// 从存号箱进入 获取userData后 检查领取状态(是否可以重复领取/重复淘号)
|
||||
if (mLibaoEntity.isActive() && mLibaoEntity.getMe() != null) {
|
||||
|
||||
if ("ling".equals(mLibaoEntity.getStatus()) || "tao".equals(mLibaoEntity.getStatus())) {
|
||||
List<UserDataLibaoEntity> userLibaooList = mLibaoEntity.getMe().getUserDataLibaoList();
|
||||
if (userLibaooList != null && userLibaooList.size() > 0) {
|
||||
@ -437,10 +468,10 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkLibaoStatus();
|
||||
} else {
|
||||
performClickReceiveBtn();
|
||||
}
|
||||
|
||||
mSkeleton.hide();
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,10 @@ import com.gh.gamecenter.fragment.LoginFragment;
|
||||
|
||||
public class LoginActivity extends NormalActivity {
|
||||
|
||||
public static final int STATUS_DEFAULT = 0; // 默认(隐藏一键登录按钮)
|
||||
public static final int STATUS_FROM_QUICK_LOGIN_PAGE = 1; // 从一键登录的授权页过来
|
||||
public static final int STATUS_FROM_QUICK_LOGIN_PERMISSION = 2; // 从一键登录的电话权限弹窗过来
|
||||
|
||||
@Override
|
||||
protected Intent provideNormalIntent() {
|
||||
return getTargetIntent(this, LoginActivity.class, LoginFragment.class);
|
||||
@ -23,8 +27,14 @@ public class LoginActivity extends NormalActivity {
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context, String entrance) {
|
||||
return getIntent(context, entrance, STATUS_DEFAULT);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context, String entrance, int status) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
bundle.putInt(EntranceUtils.KEY_SHOW_QUICK_LOGIN, status);
|
||||
return getTargetIntent(context, LoginActivity.class, LoginFragment.class, bundle);
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import com.gh.base.AppUncaughtHandler;
|
||||
@ -32,6 +33,8 @@ import com.gh.common.avoidcallback.AvoidOnResultManager;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.exposure.meta.MetaUtil;
|
||||
import com.gh.common.history.HistoryDatabase;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
import com.gh.common.repository.ReservationRepository;
|
||||
import com.gh.common.simulator.SimulatorGameManager;
|
||||
import com.gh.common.util.ActivationHelper;
|
||||
@ -48,6 +51,7 @@ import com.gh.common.util.ErrorHelper;
|
||||
import com.gh.common.util.ExtensionsKt;
|
||||
import com.gh.common.util.GsonUtils;
|
||||
import com.gh.common.util.HomePluggableHelper;
|
||||
import com.gh.common.util.ImageUtils;
|
||||
import com.gh.common.util.LogUtils;
|
||||
import com.gh.common.util.LunchType;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
@ -77,10 +81,15 @@ import com.gh.gamecenter.manager.UserManager;
|
||||
import com.gh.gamecenter.normal.NormalFragment;
|
||||
import com.gh.gamecenter.packagehelper.PackageViewModel;
|
||||
import com.gh.gamecenter.qa.CommunityFragment;
|
||||
import com.gh.gamecenter.retrofit.BiResponse;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.gh.gamecenter.room.AppDatabase;
|
||||
import com.gh.gamecenter.room.dao.SimulatorGameDao;
|
||||
import com.gh.gamecenter.suggest.SuggestSelectFragment;
|
||||
import com.gh.gamecenter.suggest.SuggestType;
|
||||
import com.github.piasy.biv.BigImageViewer;
|
||||
import com.github.piasy.biv.loader.fresco.FrescoImageLoader;
|
||||
import com.google.android.exoplayer2.upstream.cache.Cache;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
@ -94,6 +103,7 @@ import com.lightgame.utils.Utils;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@ -103,13 +113,17 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import io.reactivex.SingleSource;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.functions.Function;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import okhttp3.MediaType;
|
||||
@ -162,7 +176,17 @@ public class MainActivity extends BaseActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
setStatusBarColor(Color.TRANSPARENT);
|
||||
|
||||
mMainWrapperFragment = new MainWrapperFragment();
|
||||
if (!ImageUtils.isFrescoInitialized()) {
|
||||
try {
|
||||
BigImageViewer.initialize(FrescoImageLoader.with(this));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Fragment fragmentFromFM = getSupportFragmentManager().findFragmentById(R.id.layout_activity_content);
|
||||
|
||||
mMainWrapperFragment = fragmentFromFM != null ? (MainWrapperFragment) fragmentFromFM : new MainWrapperFragment();
|
||||
if (savedInstanceState != null) {
|
||||
mMainWrapperFragment.setArguments(savedInstanceState);
|
||||
} else if (getIntent() != null) {
|
||||
@ -260,8 +284,11 @@ public class MainActivity extends BaseActivity {
|
||||
// 上传数据
|
||||
DataCollectionManager.getInstance(getApplicationContext()).upload();
|
||||
// 获取默认配置
|
||||
Config.getGhzsSettings();
|
||||
|
||||
|
||||
if (Config.getSettings() == null) {
|
||||
Config.getGhzsSettings();
|
||||
}
|
||||
|
||||
// 初始化PlatformUtils
|
||||
PlatformUtils.getInstance(getApplicationContext());
|
||||
// // 友盟记录启动
|
||||
@ -286,6 +313,58 @@ public class MainActivity extends BaseActivity {
|
||||
SPUtils.setBoolean(Constants.SP_NON_WIFI_TIPS, true);
|
||||
//重置首页视频播放进度
|
||||
SPUtils.setString(Constants.SP_HOME_VIDEO_PLAY_RECORD, "");
|
||||
|
||||
// 重新打开APP重置"显示返回任务悬浮图标"标志位
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
|
||||
|
||||
postAttentionVideoRecord();
|
||||
deleteSimulatorGame();
|
||||
}
|
||||
|
||||
//上传关注视频浏览记录
|
||||
@SuppressLint("CheckResult")
|
||||
private void postAttentionVideoRecord() {
|
||||
if (UserManager.getInstance().isLoggedIn()) {
|
||||
Map<String, Object> requestMap = new HashMap<>();
|
||||
HistoryDatabase.Companion.getInstance().videoHistoryDao()
|
||||
.getAttentionVideoRecord()
|
||||
.flatMap((Function<List<String>, SingleSource<ResponseBody>>) strings -> {
|
||||
requestMap.put("cache_video_ids", strings);
|
||||
RequestBody body = ExtensionsKt.toRequestBody(requestMap);
|
||||
return RetrofitManager.getInstance(HaloApp.getInstance())
|
||||
.getApi()
|
||||
.postAttentionVideoRecord(UserManager.getInstance().getUserId(), body);
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(new BiResponse<ResponseBody>() {
|
||||
@Override
|
||||
public void onSuccess(ResponseBody data) {
|
||||
HistoryHelper.deleteAttentionVideoRecord();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//查询到模拟器游戏表中逻辑删除的数据后,删除服务器中的记录
|
||||
@SuppressLint("CheckResult")
|
||||
private void deleteSimulatorGame() {
|
||||
SimulatorGameDao dao = AppDatabase.getInstance(HaloApp.getInstance()).simulatorGameDao();
|
||||
dao.getSimulatorGameByDeleted()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(new BiResponse<List<String>>() {
|
||||
@Override
|
||||
public void onSuccess(List<String> data) {
|
||||
if (!data.isEmpty()) {
|
||||
SimulatorGameManager.deleteSimulatorGames(data, () -> {
|
||||
for (String id : data) {
|
||||
dao.deleteSimulatorGameById(id);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -367,17 +446,20 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
private void hideAd(boolean forceToHide) {
|
||||
if (forceToHide
|
||||
|| AdHelper.startupAd.getValue() == null) {
|
||||
if (forceToHide || AdHelper.startupAd.getValue() == null) {
|
||||
showAd = false;
|
||||
getIntent().putExtra(SHOW_AD, false);
|
||||
findViewById(R.id.maskContainer).setVisibility(View.GONE);
|
||||
View view = findViewById(R.id.maskContainer);
|
||||
|
||||
if (view != null) {
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
mMainWrapperFragment.getWelcomeDialog();
|
||||
|
||||
|
||||
checkDialog();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkDialog() {
|
||||
// 检查通知权限
|
||||
checkNotificationPermission();
|
||||
@ -393,6 +475,9 @@ public class MainActivity extends BaseActivity {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
containerView.setElevation(500F);
|
||||
}
|
||||
containerView.setOnClickListener(v -> {
|
||||
// do nothing 只是为了点击拦截事件,避免传递到下面的页面
|
||||
});
|
||||
adContentTv.setText(ad.getDesc());
|
||||
adContentTv.setVisibility(View.VISIBLE);
|
||||
if (ad.getButton()) {
|
||||
@ -619,7 +704,7 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
protected void onSaveInstanceState(@NotNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt(CURRENT_PAGE, mMainWrapperFragment.getCurrentItem());
|
||||
if (mMainWrapperFragment != null) {
|
||||
@ -627,6 +712,11 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean preventRecreateFragmentByFragmentManager() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
if (showAd) {
|
||||
@ -839,6 +929,7 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
mPackageViewModel.checkData();
|
||||
deleteSimulatorGame();
|
||||
}
|
||||
}
|
||||
|
||||
@ -878,4 +969,5 @@ public class MainActivity extends BaseActivity {
|
||||
Intent intent = MainActivity.getMainIntent(context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -125,6 +125,8 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
|
||||
private NewsEntity mNewsEntity;
|
||||
private DownloadEntity mDownloadEntity;
|
||||
|
||||
private Boolean mHideUselessInfo = false;
|
||||
|
||||
private Handler handler = new Handler();
|
||||
|
||||
private long[] mHits = new long[2];
|
||||
@ -185,7 +187,6 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
|
||||
intent.putExtra(NewsEntity.TAG, newsEntity);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -247,19 +248,26 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
|
||||
mViewSkeletonScreen = Skeleton.bind(mSkeletonView).shimmer(false).load(R.layout.news_detail_skeleton).show();
|
||||
// init toolbar
|
||||
setNavigationTitle("");
|
||||
setToolbarMenu(R.menu.menu_news_detail);
|
||||
mNewsShare = getMenuItem(R.id.menu_share);
|
||||
mNewsCollection = getMenuItem(R.id.menu_collect);
|
||||
mNewsShare.setVisible(false);
|
||||
mNewsCollection.setVisible(false);
|
||||
|
||||
mNoneDataTv.setText("页面不见了");
|
||||
|
||||
// init RecyclerView
|
||||
mDetailRv.setHasFixedSize(true);
|
||||
mDetailRv.setLayoutManager(new FixLinearLayoutManager(this));
|
||||
mDetailRv.addItemDecoration(new VerticalItemDecoration(this, 8, false));
|
||||
adapter = new NewsDetailAdapter(this, this, mEntrance);
|
||||
|
||||
mHideUselessInfo = getIntent().getBooleanExtra(EntranceUtils.KEY_HIDE_USELESS_INFO, false);
|
||||
|
||||
setToolbarMenu(R.menu.menu_news_detail);
|
||||
mNewsShare = getMenuItem(R.id.menu_share);
|
||||
mNewsCollection = getMenuItem(R.id.menu_collect);
|
||||
mNewsShare.setVisible(false);
|
||||
mNewsCollection.setVisible(false);
|
||||
|
||||
if (mHideUselessInfo) {
|
||||
getMenuItem(R.id.menu_download).setVisible(false);
|
||||
}
|
||||
|
||||
adapter = new NewsDetailAdapter(this, this, mHideUselessInfo, mEntrance);
|
||||
mDetailRv.setAdapter(adapter);
|
||||
|
||||
newsId = getIntent().getStringExtra(EntranceUtils.KEY_NEWSID);
|
||||
@ -277,7 +285,9 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
|
||||
adapter.setType(mNewsEntity.getType());
|
||||
adapter.setTitle(mNewsEntity.getTitle());
|
||||
adapter.getNewsDetail();
|
||||
mNewsShare.setVisible(true);
|
||||
if (!mHideUselessInfo) {
|
||||
mNewsShare.setVisible(true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
getNewsDigest(newsId);
|
||||
@ -447,12 +457,14 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
|
||||
|
||||
@Override
|
||||
public void loadDone() { // 通知更新收藏按钮
|
||||
mNewsCollection.setVisible(true);
|
||||
NewsDetailEntity newsDetailEntity = adapter.getNewsDetailEntity();
|
||||
if (newsDetailEntity.getMe() != null && newsDetailEntity.getMe().isArticleFavorite()) {
|
||||
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_select);
|
||||
} else {
|
||||
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_unselect);
|
||||
if (!mHideUselessInfo) {
|
||||
mNewsCollection.setVisible(true);
|
||||
NewsDetailEntity newsDetailEntity = adapter.getNewsDetailEntity();
|
||||
if (newsDetailEntity.getMe() != null && newsDetailEntity.getMe().isArticleFavorite()) {
|
||||
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_select);
|
||||
} else {
|
||||
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_unselect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -507,7 +519,9 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
|
||||
adapter.setTitle(response.getTitle());
|
||||
adapter.getNewsDetail();
|
||||
|
||||
mNewsShare.setVisible(true);
|
||||
if (!mHideUselessInfo) {
|
||||
mNewsShare.setVisible(true);
|
||||
}
|
||||
|
||||
HistoryHelper.insertNewsEntity(mNewsEntity);
|
||||
|
||||
@ -635,11 +649,16 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
|
||||
public void onResponse(GameEntity response) {
|
||||
ApkActiveUtils.filterHideApk(response);
|
||||
gameEntity = response;
|
||||
adapter.setGameEntity(gameEntity);
|
||||
adapter.notifyItemInserted(1);
|
||||
|
||||
mDetailBottomLl.setVisibility(View.VISIBLE);
|
||||
DetailDownloadUtils.detailInitDownload(getDetailViewHolder(), true);
|
||||
if (!mHideUselessInfo) {
|
||||
adapter.setGameEntity(gameEntity);
|
||||
adapter.notifyItemInserted(1);
|
||||
|
||||
mDetailBottomLl.setVisibility(View.VISIBLE);
|
||||
DetailDownloadUtils.detailInitDownload(getDetailViewHolder(), true);
|
||||
} else {
|
||||
mDetailBottomLl.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// GdtHelper.INSTANCE.logAction(ActionType.PAGE_VIEW,
|
||||
// GdtHelper.CONTENT_TYPE, "ARTICLE",
|
||||
|
||||
@ -126,6 +126,10 @@ public abstract class NormalActivity extends ToolBarActivity {
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
public Fragment getTargetFragment() {
|
||||
return mTargetFragment;
|
||||
}
|
||||
|
||||
public int getFragmentPlaceholderId() {
|
||||
return R.id.normal_content;
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import com.gh.base.ToolBarActivity
|
||||
import com.gh.base.fragment.BaseFragment
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.gamecenter.amway.AmwaySuccessFragment
|
||||
import com.halo.assistant.fragment.SwitchInstallMethodFragment
|
||||
|
||||
/**
|
||||
* ShellActivity 用来包裹那些几乎没有交互且运营也不会想要知道页面访问量的静态 fragment (如安利墙的评论提交成功页面)
|
||||
@ -28,12 +29,11 @@ class ShellActivity : ToolBarActivity() {
|
||||
|
||||
when (intentType) {
|
||||
Type.AMWAY_SUCCESS -> startFragment(AmwaySuccessFragment().with(bundle))
|
||||
Type.SWITCH_INSTALL_METHOD -> startFragment(SwitchInstallMethodFragment())
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.activity_shell
|
||||
}
|
||||
override fun getLayoutId() = R.layout.activity_shell
|
||||
|
||||
private fun startFragment(fragment: BaseFragment<Any>) {
|
||||
mFragment = fragment
|
||||
@ -43,6 +43,7 @@ class ShellActivity : ToolBarActivity() {
|
||||
companion object {
|
||||
const val INTENT_TYPE = "intent_type"
|
||||
|
||||
@JvmStatic
|
||||
fun getIntent(context: Context, type: Type, extraParcelable: Parcelable? = null): Intent {
|
||||
val intent = Intent(context, ShellActivity::class.java)
|
||||
intent.putExtra(INTENT_TYPE, type.value)
|
||||
@ -52,7 +53,8 @@ class ShellActivity : ToolBarActivity() {
|
||||
}
|
||||
|
||||
enum class Type(val value: String) {
|
||||
AMWAY_SUCCESS("amway_success");
|
||||
AMWAY_SUCCESS("amway_success"),
|
||||
SWITCH_INSTALL_METHOD("switch_install_method");
|
||||
|
||||
companion object {
|
||||
fun fromString(typeString: String): Type {
|
||||
|
||||
@ -27,6 +27,8 @@ import com.gh.common.AppExecutor;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.dialog.PrivacyDialogFragment;
|
||||
import com.gh.common.tracker.Tracker;
|
||||
import com.gh.common.tracker.TrackerLogger;
|
||||
import com.gh.common.util.AdHelper;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.common.util.DeviceTokenUtils;
|
||||
@ -104,6 +106,8 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
TrackerLogger.logAppLaunch(Tracker.INSTANCE.getLaunchId(), Tracker.INSTANCE.getSessionId());
|
||||
|
||||
// 处理助手已经在后台运行导致的再次启动助手
|
||||
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
|
||||
finish();
|
||||
@ -287,6 +291,8 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
private void launchMainActivity() {
|
||||
HaloApp.getInstance().postInit(true);
|
||||
|
||||
TrackerLogger.logAppLaunchSuccessful(Tracker.INSTANCE.getLaunchId(), Tracker.INSTANCE.getSessionId());
|
||||
|
||||
getAd();
|
||||
prefetchData();
|
||||
|
||||
@ -343,10 +349,6 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void getUniqueId() {
|
||||
DataUtils.getGid();
|
||||
}
|
||||
|
||||
private void prefetchData() {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
Config.getGhzsSettings();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user