Compare commits

...

464 Commits

Author SHA1 Message Date
d194f969e4 chore: va组件2.0.5-debug 2024-09-10 16:43:57 +08:00
95f66344fb chore: va组件2.0.5 2024-09-10 13:46:15 +08:00
570e2fa9bc Revert "feat:同步商业版代码至:dbc3b8ecaca3e774b1e63f41e70b651f4acfaee1"
This reverts commit 811d42457c.
2024-09-05 15:22:32 +08:00
9e07080043 feat: 调整依赖源顺序 2024-09-04 17:03:37 +08:00
e10a329159 chore: 版本更新至 5.37.5 2024-09-04 16:00:00 +08:00
b3bc7b43f7 Merge branch 'feat/v5.37.5-1095/update-va' into 'release'
feat:同步商业版代码至:dbc3b8ecaca3e774b1e63f41e70b651f4acfaee1

See merge request halo/android/assistant-android!1875
2024-09-04 15:54:34 +08:00
811d42457c feat:同步商业版代码至:dbc3b8ecaca3e774b1e63f41e70b651f4acfaee1 2024-09-04 15:52:46 +08:00
ac0b819ea9 Merge branch 'feat/GHZSCY-6644' into 'release'
feat: 【光环助手】安装相关优化功能埋点事件的属性字段英文错误的问题 https://jira.shanqu.cc/browse/GHZSCY-6644

See merge request halo/android/assistant-android!1874
2024-09-04 15:43:47 +08:00
d931fb5940 feat: 【光环助手】安装相关优化功能埋点事件的属性字段英文错误的问题 https://jira.shanqu.cc/browse/GHZSCY-6644 2024-09-04 14:42:17 +08:00
cea62b55e2 Merge branch 'hotfix/v5.37.4-1094/GHZSCY-6631' into 'release'
fix: 特定场景下首次启动APP未直接打开设置跳转的页面 https://jira.shanqu.cc/browse/GHZSCY-6631

See merge request halo/android/assistant-android!1871
2024-09-04 11:40:58 +08:00
ff6cdb1ba3 Merge branch 'hotfix/v5.37.4-1094/GHZSCY-6613' into 'release'
fix: 客户端启动过程中若首页视频自动播放会置顶显示在开屏广告上 https://jira.shanqu.cc/browse/GHZSCY-6613

See merge request halo/android/assistant-android!1870
2024-09-04 11:40:43 +08:00
b6e531fa96 fix: 特定场景下首次启动APP未直接打开设置跳转的页面 https://jira.shanqu.cc/browse/GHZSCY-6631 2024-09-04 11:06:39 +08:00
e7a37df690 fix: 客户端启动过程中若首页视频自动播放会置顶显示在开屏广告上 https://jira.shanqu.cc/browse/GHZSCY-6613
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-09-03 17:57:38 +08:00
239b056abb Merge branch 'hotfix/v5.37.4-1094/illegal_state_exception' into 'release'
fix: 修复请求所有文件访问权限弹窗弹出偶发的闪退问题...

See merge request halo/android/assistant-android!1864
2024-08-30 10:05:24 +08:00
315be3797c fix: 修复请求所有文件访问权限弹窗弹出偶发的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/406178/?project=22 2024-08-30 09:49:52 +08:00
bdcca58770 build: fix 编译时无法拉取远端依赖的问题 2024-08-29 15:48:16 +08:00
644b93ab02 fix: 编译问题 2024-08-28 15:10:24 +08:00
1ee0f292ba Revert "fix: 修复因为低级失误导致 sentry.onEvent 方法失效的问题"
This reverts commit 0731cc1fde.
2024-08-26 16:06:59 +08:00
f609637f0b Merge branch 'feat/GHZSCY-6578' into 'release'
feat:【光环助手】设备信息显示 https://jira.shanqu.cc/browse/GHZSCY-6578

See merge request halo/android/assistant-android!1860
2024-08-26 14:07:55 +08:00
9d10add8eb feat:【光环助手】设备信息显示 https://jira.shanqu.cc/browse/GHZSCY-6578 2024-08-26 14:07:54 +08:00
f5a39f982e chore: 版本更新至 5.37.4 2024-08-26 10:33:09 +08:00
1a063bb0c1 Merge branch 'hotfix/v5.37.3-1093/sentry_culprit' into 'release'
fix: 修复因为低级失误导致 sentry.onEvent 方法失效的问题,捕抓更多 deadSystemException

See merge request halo/android/assistant-android!1859
2024-08-26 10:30:37 +08:00
86340d603f fix: 捕抓应用安装完成后上报用户玩过的游戏有机率遇到的 deadSystemException 并上报 sentry https://sentry.shanqu.cc/organizations/lightgame/issues/404487
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-26 10:21:42 +08:00
0731cc1fde fix: 修复因为低级失误导致 sentry.onEvent 方法失效的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-26 10:20:00 +08:00
86dfee2ff9 Merge branch 'hotfix/v5.37.3-1093/null_pointer_exception' into 'release'
fix: 修复获取BusinessId时出现的空指针闪退问题...

See merge request halo/android/assistant-android!1858
2024-08-26 09:58:11 +08:00
edf82952ce fix: 修复获取BusinessId时出现的空指针闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/404588/?project=22 2024-08-26 09:54:22 +08:00
4412d159bb Merge branch 'fix/sentry-404504-3' into 'release'
fix: 下载悬浮窗Detach执行图标贴边动画造成的崩溃...

See merge request halo/android/assistant-android!1856
2024-08-23 16:05:11 +08:00
e119b7fecd fix: 下载悬浮窗Detach执行图标贴边动画造成的崩溃... 2024-08-23 16:05:11 +08:00
3fe7c8252e chore: 版本更新至 5.37.3 2024-08-22 11:19:28 +08:00
36ebab77ee Merge branch 'hotfix/v5.37.2-1092/dead_system_exception' into 'release'
fix: catch 部分高频调用的包信息获取方法,遇到 DeadSystemException 时上报 sentry

See merge request halo/android/assistant-android!1853
2024-08-22 11:18:35 +08:00
e84db01984 Merge branch 'hotfix/v5.37.2-1092/view_binding' into 'release'
fix: 用 sentry 记录 SearchToolbarTabWrapperFragment ViewBinding bind 异常时 gid,尝试重试一次

See merge request halo/android/assistant-android!1852
2024-08-22 11:16:36 +08:00
ae605d4a55 fix: 用 sentry 记录 SearchToolbarTabWrapperFragment ViewBinding bind 异常时 gid,尝试重试一次
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-22 11:11:12 +08:00
882bf4b551 fix: catch 部分高频调用的包信息获取方法,遇到 DeadSystemException 时上报 sentry
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-22 10:05:09 +08:00
968164af55 Merge branch 'hotfix/v5.37.2-1092/class_cast_exception' into 'release'
fix: 修复帮助中心分类弹窗弹出时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/405504/?project=22

See merge request halo/android/assistant-android!1850
2024-08-21 10:05:47 +08:00
0119e6f123 fix: 修复帮助中心分类弹窗弹出时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/405504/?project=22 2024-08-21 09:59:40 +08:00
7093552259 Merge branch 'FIX/sentry-404504-2' into 'release'
fix: 悬浮窗Detach时机问题造成的崩溃2

See merge request halo/android/assistant-android!1847
2024-08-20 14:02:02 +08:00
2be52d21ee fix: 悬浮窗Detach时机问题造成的崩溃2 2024-08-20 14:02:02 +08:00
cb093cc3f0 Merge branch 'hotfix/v5.37.1-1091/jobservice_abstract_method_error' into 'release'
fix: 修复 94d0e2b5f19760d22381ead093c9e89778a14bf4 这个版本没有修复的...

See merge request halo/android/assistant-android!1844
2024-08-19 16:08:04 +08:00
3cbdd94189 fix: 修复 94d0e2b5f19760d22381ead093c9e89778a14bf4 这个版本没有修复的 java.lang.AbstractMethodError: abstract method "void android.app.job.IJobService.onNetworkChanged(android.app.job.JobParameters)" 错误。 2024-08-19 16:02:01 +08:00
11013319bf chore: 版本更新至 5.37.2 2024-08-19 12:40:31 +08:00
aa954b3af9 Merge branch 'hotfix/v5.37.1-1091/mmkv_wrong_usage' into 'release'
fix: 修复2.0.3光环启动32位游戏,概率没有初始化mmkv

See merge request halo/android/assistant-android!1843
2024-08-19 11:59:16 +08:00
93f279a384 fix: 修复2.0.3光环启动32位游戏,概率没有初始化mmkv 2024-08-19 11:45:12 +08:00
4e54833cc9 Merge branch 'hotfix/v5.37.1-1091/login_crash' into 'release'
fix: 临时处理登录后 token 为空引起的闪退,并上报相关日志到 sentry

See merge request halo/android/assistant-android!1842
2024-08-19 11:11:31 +08:00
f95862da8b Merge branch 'hotfix/v5.37.1-1091/class_cast_exception' into 'release'
fix: 修复偶发的类型转换异常闪退...

See merge request halo/android/assistant-android!1841
2024-08-19 10:50:23 +08:00
1515df34b5 fix: 临时处理登录后 token 为空引起的闪退,并上报相关日志到 sentry
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-19 10:44:14 +08:00
8a8ef40dc1 fix: 修复偶发的类型转换异常闪退 https://sentry.shanqu.cc/organizations/lightgame/issues/404710/events/?project=22 2024-08-19 09:27:35 +08:00
b6194fed26 Merge branch 'chen/202408/fix-quick-login-crash' into 'release'
fix:点击快速登录有概率出现crash https://sentry.shanqu.cc/organizations/lightgame/issues/404488/?project=22

See merge request halo/android/assistant-android!1840
2024-08-16 17:39:58 +08:00
02752f6c81 fix:点击快速登录有概率出现crash https://sentry.shanqu.cc/organizations/lightgame/issues/404488/?project=22 2024-08-16 17:34:17 +08:00
b33d367dfd Merge branch 'fix/sentry-404504' into 'release'
fix: 悬浮窗Detach时机问题造成的崩溃

See merge request halo/android/assistant-android!1839
2024-08-16 14:04:09 +08:00
d5046ab431 fix: 悬浮窗Detach时机问题造成的崩溃 2024-08-16 14:04:09 +08:00
a53168c9bc Merge branch 'hotfix/v5.37.1-1091/add_game_popup_crash' into 'release'
fix: 修复退出添加游戏弹窗后弹出引导弹窗出现的闪退问题...

See merge request halo/android/assistant-android!1838
2024-08-16 10:47:28 +08:00
3cbc8c2f74 fix: 修复退出添加游戏弹窗后弹出引导弹窗出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/404461/?project=22 2024-08-16 10:42:10 +08:00
7398b83004 Merge branch 'chen/202408/fix-bottom-tab_parse_lottie_crash' into 'release'
fix:当后台bottom tab上传的lottie文件格式不合法时,解析出现crash

See merge request halo/android/assistant-android!1837
2024-08-15 17:19:19 +08:00
8013426ded fix:当后台bottom tab上传的lottie文件格式不合法时,解析出现crash 2024-08-15 17:16:14 +08:00
b86d85b15f chore: 版本更新至 5.37.1-1091
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-15 14:42:55 +08:00
5a73afbab3 Merge branch 'hotfix/v5.37.0-1090-get_meta_data_crash' into 'release'
fix: catch 获取应用 meta data 时的 DeadSystemException 并上报至 sentry...

See merge request halo/android/assistant-android!1836
2024-08-15 14:30:46 +08:00
e19ee25839 fix: catch 获取应用 meta data 时的 DeadSystemException 并上报至 sentry https://sentry.shanqu.cc/organizations/lightgame/issues/390674
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-15 14:26:12 +08:00
61bf39e95f Merge branch 'hotfix/v5.37.0-1090/index_out_of_bounds_exception' into 'release'
fix: 修复数组越界闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/404202/?project=22

See merge request halo/android/assistant-android!1835
2024-08-15 14:20:39 +08:00
ef82ae2378 fix: 修复数组越界闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/404202/?project=22 2024-08-15 14:17:32 +08:00
2dcccc22a8 Merge branch 'fix/sentry-404211' into 'release'
fix: 工作线程显示悬浮窗造成的崩溃问题

See merge request halo/android/assistant-android!1834
2024-08-15 14:09:06 +08:00
cb0e77d204 fix: 工作线程显示悬浮窗造成的崩溃问题 2024-08-15 14:09:06 +08:00
a6ea178609 Merge branch 'fix/sentry-404179' into 'release'
fix: 悬浮窗权限申请弹窗在Activity销毁后弹出造成的崩溃问题

See merge request halo/android/assistant-android!1833
2024-08-15 14:08:58 +08:00
6a62f08891 fix: 悬浮窗权限申请弹窗在Activity销毁后弹出造成的崩溃问题 2024-08-15 14:08:58 +08:00
ddb48481d2 Merge branch 'hotfix/v5.37.0-1090-dual_download_error_issue' into 'release'
fix: 双下载时使用本地下载进行下载时临时屏蔽特殊弹窗和下载悬浮窗 https://jira.shanqu.cc/browse/GHZSCY-6521

See merge request halo/android/assistant-android!1832
2024-08-14 11:36:51 +08:00
48a55a6b31 fix: 双下载时使用本地下载进行下载时临时屏蔽特殊弹窗和下载悬浮窗 2024-08-14 11:35:20 +08:00
50fcb0c3ea fix: 方法入参异常造成的编译问题 2024-08-13 16:20:01 +08:00
e97722b6fb Merge branch 'feat/cw-apk-udpate' into 'release'
feat: 优化畅玩游戏更新逻辑

See merge request halo/android/assistant-android!1790
2024-08-13 15:19:22 +08:00
2163b2ff9e Merge branch 'fix/GHZSCY-6438' into 'release'
fix: 已安装游戏替换问题 https://jira.shanqu.cc/browse/GHZSCY-6438

See merge request halo/android/assistant-android!1831
2024-08-13 15:06:03 +08:00
b9558e2732 Merge branch 'fix/GHZSCY-6414' into 'release'
fix: 安装流程相关优化—2024年8月2日测试组 https://jira.shanqu.cc/browse/GHZSCY-6414

See merge request halo/android/assistant-android!1830
2024-08-13 14:25:51 +08:00
5daddeadda Merge branch 'feat/GHZSCY-6491' into 'dev'
feat: 客户端删除已经不再应用的页面—客户端 https://jira.shanqu.cc/browse/GHZSCY-6491

See merge request halo/android/assistant-android!1827
2024-08-13 12:07:20 +08:00
58b1c0295c feat: 客户端删除已经不再应用的页面—客户端 https://jira.shanqu.cc/browse/GHZSCY-6491 2024-08-13 12:07:20 +08:00
a56082d002 Merge branch 'feat/GHZSCY-6488' into 'dev'
fixed: 跳转链接支持-客户端 https://jira.shanqu.cc/browse/GHZSCY-6488

See merge request halo/android/assistant-android!1826
2024-08-13 12:05:12 +08:00
877ab7cf39 fixed: 跳转链接支持-客户端 https://jira.shanqu.cc/browse/GHZSCY-6488 2024-08-13 12:05:12 +08:00
428e3496d8 Merge branch 'feat/sync-va' into 'dev'
chore: 组件升级到 2.0.4

See merge request halo/android/assistant-android!1828
2024-08-13 11:21:18 +08:00
b33419ea05 chore: 组件升级到 2.0.4 2024-08-13 11:20:41 +08:00
e9bcd0a0d6 Merge branch 'fix/GHZSCY-6470' into 'dev'
fix: 搜索配置顺序显示问题 https://jira.shanqu.cc/browse/GHZSCY-6470

See merge request halo/android/assistant-android!1825
2024-08-12 10:03:06 +08:00
98b877671a fix: 搜索配置顺序显示问题 https://jira.shanqu.cc/browse/GHZSCY-6470
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-09 16:47:09 +08:00
6c61a62799 Merge branch 'fix/splash_video_flick' into 'dev'
fix: 处理启动时的广告视频图片闪烁问题

See merge request halo/android/assistant-android!1824
2024-08-09 14:24:39 +08:00
391e409ee1 Merge branch 'feat/sync-va' into 'dev'
refactor: sync vasdk

See merge request halo/android/assistant-android!1823
2024-08-09 10:27:17 +08:00
cfd1ee845a refactor: sync vasdk 2024-08-09 10:26:56 +08:00
34b123a0a7 Merge branch 'feat/GHZSCY-6447' into 'dev'
feat: 移除部分已经废弃的 activity 及仅这些 activity 所依赖的资源文件 https://jira.shanqu.cc/browse/GHZSCY-6447

See merge request halo/android/assistant-android!1821
2024-08-09 10:14:54 +08:00
51515171a8 feat: 移除部分已经废弃的 activity 及仅这些 activity 所依赖的资源文件 https://jira.shanqu.cc/browse/GHZSCY-6447 2024-08-09 10:14:54 +08:00
e9139c66e1 fix: 已安装游戏替换问题 https://jira.shanqu.cc/browse/GHZSCY-6438
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-08 17:43:31 +08:00
24941a165a feat: 取消启动时广告视频的循环播放,改为播放完成后停留在最后一帧
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-08 16:40:34 +08:00
9d661eefa7 Merge branch 'fix/GHZSCY-6463' into 'dev'
fix:【光环助手】游戏专题-游戏名称显示问题 https://jira.shanqu.cc/browse/GHZSCY-6463

See merge request halo/android/assistant-android!1820
2024-08-08 16:05:30 +08:00
373fa7fc80 fix:【光环助手】游戏专题-游戏名称显示问题 https://jira.shanqu.cc/browse/GHZSCY-6463 2024-08-08 15:52:56 +08:00
d9743a89d6 fix: 处理启动时的广告视频图片闪烁问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-08 10:39:00 +08:00
0f596836dc Merge branch 'fix/temporaily_fix_long_start_up' into 'dev'
fix: 简单优化启动耗时问题

See merge request halo/android/assistant-android!1815
2024-08-07 18:03:37 +08:00
eb08575f3e fix: 简单优化启动耗时问题 2024-08-07 17:43:09 +08:00
405268bbce Merge branch 'fix/vgame_tab_typo' into 'dev'
fix: 调整畅玩 tab 文案 https://jira.shanqu.cc/browse/GHZSCY-6275

See merge request halo/android/assistant-android!1819
2024-08-07 16:17:34 +08:00
2453e34a74 fix: 调整畅玩 tab 文案 https://jira.shanqu.cc/browse/GHZSCY-6275
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-07 16:16:46 +08:00
2830367826 Merge branch 'ci/add_tokens' into 'dev'
ci: add id_tokens

See merge request halo/android/assistant-android!1818
2024-08-07 16:14:42 +08:00
782d94289f ci: add id_tokens
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-07 15:44:20 +08:00
3e2c2fe18f Merge branch 'fix/GHZSCY-6428' into 'dev'
fix:【光环助手】下载数据神策上报问题 https://jira.shanqu.cc/browse/GHZSCY-6428

See merge request halo/android/assistant-android!1817
2024-08-07 09:22:35 +08:00
1afd154364 fix:【光环助手】下载数据神策上报问题 https://jira.shanqu.cc/browse/GHZSCY-6428 2024-08-07 09:11:08 +08:00
b24cac0cb1 Merge branch 'feat/sync-va' into 'dev'
fix: mmkv初始化时机太晚导致的crash

See merge request halo/android/assistant-android!1816
2024-08-06 17:18:44 +08:00
d5db516112 fix: mmkv初始化时机太晚导致的crash 2024-08-06 17:18:27 +08:00
b2a7a606e5 Merge branch 'fix/GHZSCY-6312' into 'dev'
fix:【光环助手】通用内容合集在深色模式下显示问题 https://jira.shanqu.cc/browse/GHZSCY-6312

See merge request halo/android/assistant-android!1814
2024-08-06 11:44:52 +08:00
219866e195 Merge branch 'fix/GHZSCY-6401' into 'dev'
fix:【光环助手】通用内容合集-轮播banner 背景色显示问题 https://jira.shanqu.cc/browse/GHZSCY-6401

See merge request halo/android/assistant-android!1810
2024-08-06 11:33:22 +08:00
dea7ceb5f6 Merge branch 'feat/sync-va' into 'dev'
fix: 32位埋点没有上报va_version的问题

See merge request halo/android/assistant-android!1813
2024-08-06 10:00:39 +08:00
da1da1c1af fix: 32位埋点没有上报va_version的问题 2024-08-06 09:59:33 +08:00
9b4fa45492 Merge branch 'feat/sync-va' into 'dev'
refactor: update vasdk commit id.

See merge request halo/android/assistant-android!1812
2024-08-05 16:50:57 +08:00
01df42b76b refactor: update vasdk commit id. 2024-08-05 16:50:41 +08:00
cef8aa1968 Merge branch 'fix/GHZSCY-6423' into 'dev'
fix:【光环助手】助手闪退问题(1) https://jira.shanqu.cc/browse/GHZSCY-6423

See merge request halo/android/assistant-android!1811
2024-08-05 15:47:22 +08:00
4147612d9b fix:【光环助手】助手闪退问题(1) https://jira.shanqu.cc/browse/GHZSCY-6423 2024-08-05 15:34:04 +08:00
9b57d10e2d Merge branch 'feature-GHZS-5551' into 'dev'
feat: 评论回复\游戏评分\消息推送需支持链接点击跳转—客户端 https://jira.shanqu.cc/browse/GHZSCY-5551

See merge request halo/android/assistant-android!1743
2024-08-05 11:11:24 +08:00
19f4e70ada feat: 评论回复\游戏评分\消息推送需支持链接点击跳转—客户端 https://jira.shanqu.cc/browse/GHZSCY-5551 2024-08-05 11:11:24 +08:00
49b7e4c245 Merge branch 'feat/sync-va' into 'dev'
fix:32位埋点没有32位版本号的问题,修复32位畅玩助手包可见性的问题

See merge request halo/android/assistant-android!1809
2024-08-05 10:01:03 +08:00
638de59562 fix:32位埋点没有32位版本号的问题,修复32位畅玩助手包可见性的问题 2024-08-05 09:57:05 +08:00
69b092be46 Merge branch 'fix/uid_package_error' into 'dev'
fix: 修复在 UID 不为 0 的时候获取已安装应用卡死的问题

See merge request halo/android/assistant-android!1808
2024-08-02 17:56:19 +08:00
27d1d02d58 fix: 修复在 UID 不为 0 的时候获取已安装应用卡死的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-02 17:55:16 +08:00
e4bfa5e6bf Merge branch 'fix/android_10_crash' into 'dev'
fix: 修复在 android 9~10 设备上重建多 fragment 页面时的闪退问题...

See merge request halo/android/assistant-android!1802
2024-08-02 16:40:23 +08:00
3ea3238011 Merge branch 'feat/sync-va' into 'dev'
fix: sentry捕获到的NPE问题 https://sentry.shanqu.cc/organizations/lightgame/issues/393310

See merge request halo/android/assistant-android!1807
2024-08-02 16:32:42 +08:00
2dcae2168b fix: sentry捕获到的NPE问题 https://sentry.shanqu.cc/organizations/lightgame/issues/393310 2024-08-02 16:31:48 +08:00
4b1c198818 Merge branch 'feat/download-suspend-window-compatibility' into 'dev'
fix: 安装流程优化-悬浮窗-客户端

See merge request halo/android/assistant-android!1806
2024-08-02 15:19:17 +08:00
e42e2fbd56 fix: 安装流程优化-悬浮窗-客户端 2024-08-02 15:19:17 +08:00
713e4157db Merge branch 'feat/sync-va' into 'dev'
fix:修复王国守卫者闪退

See merge request halo/android/assistant-android!1805
2024-08-02 14:58:29 +08:00
76cf7dce1d fix:修复王国守卫者闪退 2024-08-02 14:58:02 +08:00
f492d2ea97 fix: 安装流程相关优化—2024年8月2日测试组 https://jira.shanqu.cc/browse/GHZSCY-6414
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-02 14:49:59 +08:00
37a3689a2c Merge branch 'feat/sync-va' into 'dev'
fix:多用户模式下获取userId错误

See merge request halo/android/assistant-android!1804
2024-08-02 14:39:23 +08:00
7429f17538 fix:多用户模式下获取userId错误 2024-08-02 14:38:59 +08:00
32ba015686 Merge branch 'feat/annotation' into 'dev'
feat: 添加Nullable注解到icon字段

See merge request halo/android/assistant-android!1803
2024-08-02 14:35:58 +08:00
e5365fd527 feat: 添加Nullable注解到icon字段 2024-08-02 14:35:31 +08:00
1c873d0194 fix: 修复在 android 9~10 设备上重建多 fragment 页面时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/396730/events/83ef86539ca34141a926afe44f161cf2
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-02 11:42:14 +08:00
1424ee2b45 Merge branch 'fix/GHZSCY-6413' into 'dev'
fix: downloadEntity.icon NPE...

See merge request halo/android/assistant-android!1801
2024-08-02 11:34:19 +08:00
69cb916364 fix: downloadEntity.icon NPE 问题,给kotlin方法传参时,如果定义的是String而不是String?类型触发。https://jira.shanqu.cc/browse/GHZSCY-6413 2024-08-02 11:27:38 +08:00
04f1d712cd Merge branch 'feat/GHZSCY-6357' into 'dev'
fix: 安装流程相关优化-2024/7/30-验收问题 https://jira.shanqu.cc/browse/GHZSCY-6357

See merge request halo/android/assistant-android!1794
2024-08-02 11:25:22 +08:00
ee14ae51be feat: 安装流程优化-2024/7/31-优化补充 https://jira.shanqu.cc/browse/GHZSCY-6368
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-02 11:05:59 +08:00
4683217e44 fix:【光环助手】通用内容合集-轮播banner 背景色显示问题 https://jira.shanqu.cc/browse/GHZSCY-6401 2024-08-01 17:26:23 +08:00
df94d6677a Merge branch 'chen/202408/GHZSCY-6396-2' into 'dev'
fix:按需求将倒计时延长1s,视频广告时长不够就循环播放 https://jira.shanqu.cc/browse/GHZSCY-6396

See merge request halo/android/assistant-android!1797
2024-08-01 11:30:12 +08:00
6f85e12edf fix:按需求将倒计时延长1s,视频广告时长不够就循环播放 https://jira.shanqu.cc/browse/GHZSCY-6396 2024-08-01 11:26:57 +08:00
020c826f1d Merge branch 'chen/202408/GHZSCY-6396' into 'dev'
fix:启动广告图相关优化—0731验收问题-客户端 https://jira.shanqu.cc/browse/GHZSCY-6396

See merge request halo/android/assistant-android!1796
2024-08-01 11:17:15 +08:00
5640d778a2 fix:启动广告图相关优化—0731验收问题-客户端 https://jira.shanqu.cc/browse/GHZSCY-6396 2024-08-01 11:14:28 +08:00
2300475a9e Merge branch 'feat/GHZSCY-6356' into 'dev'
fix: 【光环助手】QQ小游戏闪退问题 https://jira.shanqu.cc/browse/GHZSCY-6356

See merge request halo/android/assistant-android!1788
2024-07-31 17:09:01 +08:00
612b4061d5 fix: 【光环助手】QQ小游戏闪退问题 https://jira.shanqu.cc/browse/GHZSCY-6356 2024-07-31 17:09:01 +08:00
49c7ff8f8e Merge branch 'feat/GHZSCY-6340' into 'dev'
新游开测测试验收优化&修复

See merge request halo/android/assistant-android!1792
2024-07-31 09:32:08 +08:00
1c408f3966 Merge branch 'fix/GHZSCY-6346' into 'dev'
fix: QA图片放大显示问题-客户端 https://jira.shanqu.cc/browse/GHZSCY-6346

See merge request halo/android/assistant-android!1793
2024-07-31 09:31:35 +08:00
055f5b23da fix: QA图片放大显示问题-客户端 https://jira.shanqu.cc/browse/GHZSCY-6346 2024-07-31 09:31:34 +08:00
9810b3e8fe fix: 新游开测相关功能优化(第三期)-0730测试验收-客户端(2) https://jira.shanqu.cc/browse/GHZSCY-6364 2024-07-31 09:16:28 +08:00
dba7042b12 fix: 新游开测相关功能优化(第三期)-0730测试验收-客户端 https://jira.shanqu.cc/browse/GHZSCY-6364 2024-07-31 09:16:28 +08:00
6695dc596e Merge branch 'fix/sentry-virtualruntime-crash' into 'dev'
fix: 主进程远程调用失败时闪退,这里需要catch异常,不能影响光环闪退

See merge request halo/android/assistant-android!1791
2024-07-30 18:23:09 +08:00
079ba014f8 fix: 主进程远程调用失败时闪退,这里需要catch异常,不能影响光环闪退 2024-07-30 17:36:10 +08:00
46955685bb feat: 优化畅玩游戏更新逻辑 2024-07-30 16:54:30 +08:00
14eeb00539 Merge branch 'chen/202407/GHZSCY-6365' into 'dev'
fix:通用内容合集组件优化—前端部分-0730验收—客户端 https://jira.shanqu.cc/browse/GHZSCY-6365

See merge request halo/android/assistant-android!1789
2024-07-30 16:20:02 +08:00
56843f18d4 fix:通用内容合集组件优化—前端部分-0730验收—客户端 https://jira.shanqu.cc/browse/GHZSCY-6365 2024-07-30 16:18:18 +08:00
53a46892a4 feat: 新游开测相关功能优化(第三期)-0729测试优化-客户端 https://jira.shanqu.cc/browse/GHZSCY-6340 2024-07-30 15:19:26 +08:00
a2153761c2 fix: 安装流程相关优化-2024/7/30-验收问题 https://jira.shanqu.cc/browse/GHZSCY-6357
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-30 14:21:07 +08:00
26a8c0abd8 Merge branch 'fix/GHZSCY-6351' into 'dev'
fix: 页面tab增加引导文案-0729验收—客户端 https://jira.shanqu.cc/browse/GHZSCY-6351

See merge request halo/android/assistant-android!1787
2024-07-30 11:22:05 +08:00
21bf0fd8e9 fix: 页面tab增加引导文案-0729验收—客户端 https://jira.shanqu.cc/browse/GHZSCY-6351 2024-07-30 11:22:05 +08:00
9787d23ea0 Merge branch 'fix/download_button_overlay_issue' into 'dev'
fix: 修复下载畅玩游戏也会显示未安装提示的问题

See merge request halo/android/assistant-android!1786
2024-07-30 11:04:29 +08:00
6ae34b81db fix: 修复下载畅玩游戏也会显示未安装提示的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-30 10:23:33 +08:00
0b1e770c03 Merge branch 'fix/download_button_overlay_issue' into 'dev'
fix: 修复游戏详情页双下载按钮时的文案重叠问题

See merge request halo/android/assistant-android!1785
2024-07-29 18:03:52 +08:00
f4681dab31 fix: 修复开启纯净模式的华为设备无法使用快速安装的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-29 17:56:29 +08:00
79a7f994eb fix: 修复进入下载管理自动下载已暂停游戏的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-29 17:56:29 +08:00
3276fca27c fix: 修复游戏详情页双下载按钮时的文案重叠问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-29 17:56:28 +08:00
372db8e52c Merge branch 'chen/202407/fix-resource' into 'dev'
fix:恢复common库中的shape文件(在完成专题组件优化时,改到了common库中的shape文件)

See merge request halo/android/assistant-android!1784
2024-07-29 17:00:31 +08:00
9b6d986f1c fix:恢复common库中的shape文件(在完成专题组件优化时,改到了common库中的shape文件) 2024-07-29 16:58:11 +08:00
0e88db1600 Merge branch 'feat/sync-va' into 'dev'
feat: 畅玩阿里云替换为火山云

See merge request halo/android/assistant-android!1783
2024-07-29 14:37:45 +08:00
05b59c8732 feat: 畅玩阿里云替换为火山云 2024-07-29 14:37:01 +08:00
28f68cae95 Merge branch 'feat/revert_get_installed_list' into 'dev'
feat: 还原无网络恢复时重新获取已收录应用列表的功能

See merge request halo/android/assistant-android!1782
2024-07-29 11:16:53 +08:00
22713db44e feat: 还原无网络恢复时重新获取已收录应用列表的功能 2024-07-29 11:14:55 +08:00
d9389ac4aa Merge branch 'feat/GHZSCY-5307' into 'dev'
feat: 页面tab增加引导文案—客户端 https://jira.shanqu.cc/browse/GHZSCY-5307

See merge request halo/android/assistant-android!1734
2024-07-26 14:38:20 +08:00
31ec9311fc feat: 页面tab增加引导文案—客户端 https://jira.shanqu.cc/browse/GHZSCY-5307 2024-07-26 14:38:20 +08:00
fca62df263 Merge branch 'feat/GHZSCY-6277' into 'dev'
feat: 畅玩游戏相关文案提示优化 GHZSCY-6277 https://jira.shanqu.cc/browse/GHZSCY-6277

See merge request halo/android/assistant-android!1781
2024-07-26 14:29:14 +08:00
978c01d7dc Merge branch 'feat/GHZSCY-5554' into 'dev'
feat: 新游开测相关功能优化(第三期)—客户端 https://jira.shanqu.cc/browse/GHZSCY-5554

See merge request halo/android/assistant-android!1774
2024-07-26 14:28:42 +08:00
b7a24e331a feat: 新游开测相关功能优化(第三期)—客户端 https://jira.shanqu.cc/browse/GHZSCY-5554 2024-07-26 14:28:42 +08:00
b1eac6a043 Merge branch 'chen/202407/remove-useless-log' into 'dev'
移除多余的日志

See merge request halo/android/assistant-android!1780
2024-07-26 09:46:10 +08:00
9f8a712be6 移除多余的日志 2024-07-26 09:45:32 +08:00
930ab904ed Merge branch 'feat/GHZSCY-5389' into 'dev'
feat: 安装流程相关优化 https://jira.shanqu.cc/browse/GHZSCY-6005

See merge request halo/android/assistant-android!1749
2024-07-25 17:34:03 +08:00
3c207244e6 feat: 安装流程相关优化 https://jira.shanqu.cc/browse/GHZSCY-6005 2024-07-25 17:34:03 +08:00
0f59e03afa Merge branch 'feat/GHZSCY-5302-pr' into 'dev'
Resolve GHZSCY-5302 "Feat/ pr"

See merge request halo/android/assistant-android!1777
2024-07-25 17:33:01 +08:00
c5d99fa304 Merge branch 'feat/GHZSCY-5302-pr' into 'dev' 2024-07-25 17:33:01 +08:00
a313cd8050 Merge branch 'feat/GHZSCY-5310-pr' into 'dev'
Resolve GHZSCY-5310 "Feat/ pr"

See merge request halo/android/assistant-android!1779
2024-07-25 16:58:02 +08:00
ce477e2bd0 Resolve GHZSCY-5310 "Feat/ pr" 2024-07-25 16:58:02 +08:00
7cf2adaa37 Merge branch 'feat/GHZSCY-5564' into 'dev'
feat: XApk游戏解压相关优化 https://jira.shanqu.cc/browse/GHZSCY-5564

See merge request halo/android/assistant-android!1770
2024-07-25 15:54:05 +08:00
0852497df2 feat: XApk游戏解压相关优化 https://jira.shanqu.cc/browse/GHZSCY-5564 2024-07-25 15:17:32 +08:00
592df6ea44 Merge branch 'feat/GHZSCY-5834-pr' into 'dev'
feat:通用内容合集组件优化—前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5294

See merge request halo/android/assistant-android!1775
2024-07-25 15:13:03 +08:00
7b5d1b1bf3 feat:通用内容合集组件优化—前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5294 2024-07-25 15:13:03 +08:00
5b1a614eb7 Merge branch 'feat/GHZSCY-5594-pr' into 'dev'
feat:启动广告图相关优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-5594

See merge request halo/android/assistant-android!1776
2024-07-25 15:07:01 +08:00
ae9fbfb8c4 Merge branch 'feat/GHZSCY-5733-pr' into 'dev'
feat:一键登录优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-5733

See merge request halo/android/assistant-android!1772
2024-07-25 14:41:28 +08:00
48b118d342 feat:一键登录优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-5733 2024-07-25 14:41:28 +08:00
39625369d7 fix:【光环助手】通用内容合集在深色模式下显示问题 https://jira.shanqu.cc/browse/GHZSCY-6312 2024-07-25 14:16:02 +08:00
05b9920f6d feat:启动广告图相关优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-5594 2024-07-25 10:20:46 +08:00
8a5fa2c31a Merge branch 'feature-hotfix-gitlab-ci' into 'dev'
feat: 清除gitlab测试分支信息

See merge request halo/android/assistant-android!1773
2024-07-25 09:48:26 +08:00
c2dc6d7dbe feat: 清除gitlab测试分支信息 2024-07-25 09:48:06 +08:00
a027442ae6 Merge branch 'feature-GHZS-5666' into 'dev'
feat: 用户设备信息展示及复制功能—客户端 https://jira.shanqu.cc/browse/GHZSCY-5666

See merge request halo/android/assistant-android!1730
2024-07-25 09:45:41 +08:00
ba1584f642 feat: 用户设备信息展示及复制功能—客户端 https://jira.shanqu.cc/browse/GHZSCY-5666 2024-07-25 09:45:41 +08:00
4124d571b7 Merge branch 'feat/GHZSCY-6311' into 'dev'
fix: 【光环助手】下载云存档的进度条ui显示异常 https://jira.shanqu.cc/browse/GHZSCY-6311

See merge request halo/android/assistant-android!1771
2024-07-25 09:45:15 +08:00
a545401ca3 fix: 【光环助手】下载云存档的进度条ui显示异常 https://jira.shanqu.cc/browse/GHZSCY-6311 2024-07-25 09:44:32 +08:00
4b7f2401dd Merge branch 'feat/GHZSCY-5559' into 'dev'
feat: 游戏单功能优化(第三期)—客户端 https://jira.shanqu.cc/browse/GHZSCY-5559

See merge request halo/android/assistant-android!1769
2024-07-24 14:51:03 +08:00
daa1e4fc64 feat: 游戏单功能优化(第三期)—客户端 https://jira.shanqu.cc/browse/GHZSCY-5559 2024-07-24 14:51:03 +08:00
064135a057 Merge branch 'feat/GHZSCY-6271' into 'dev'
feat: 网游登录插件-埋点补充—客户端 https://jira.shanqu.cc/browse/GHZSCY-6271

See merge request halo/android/assistant-android!1768
2024-07-24 14:46:28 +08:00
b56946d6f0 feat: 网游登录插件-埋点补充—客户端 https://jira.shanqu.cc/browse/GHZSCY-6271 2024-07-24 14:46:28 +08:00
1a46d371e4 Merge branch 'feat/GHZSCY-5313' into 'dev'
feat: 首页弹窗&下拉推送 支持按指定用户推送—客户端 https://jira.shanqu.cc/browse/GHZSCY-5313

See merge request halo/android/assistant-android!1735
2024-07-24 14:45:33 +08:00
d2a062907a feat: 首页弹窗&下拉推送 支持按指定用户推送—客户端 https://jira.shanqu.cc/browse/GHZSCY-5313 2024-07-24 14:45:33 +08:00
56e945eb43 Merge branch 'feat/sync-va' into 'dev'
feat: va组件版本升级到 2.0.4-debug

See merge request halo/android/assistant-android!1766
2024-07-24 10:25:29 +08:00
91579194a4 feat: va组件版本升级到 2.0.4-debug 2024-07-24 10:25:01 +08:00
c42a7d5963 Merge branch 'fix/dup-res-uibroken' into 'dev'
fix: 合并va之后,color被覆盖的问题https://jira.shanqu.cc/browse/GHZSCY-6113

See merge request halo/android/assistant-android!1765
2024-07-23 18:14:50 +08:00
d2293bd881 fix: 合并va之后,color被覆盖的问题https://jira.shanqu.cc/browse/GHZSCY-6113
https://jira.shanqu.cc/browse/GHZSCY-6114
2024-07-23 18:14:04 +08:00
db4eb9f811 feat: 畅玩游戏相关文案提示优化 GHZSCY-6277 https://jira.shanqu.cc/browse/GHZSCY-6277
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-23 16:51:23 +08:00
24d95b8e95 Merge branch 'feat/GHZSCY-5546' into 'dev'
feat: 帮助与反馈第三期迭代—客户端 https://jira.shanqu.cc/browse/GHZSCY-5546

See merge request halo/android/assistant-android!1764
2024-07-23 13:37:04 +08:00
435dac11a1 feat: 帮助与反馈第三期迭代—客户端 https://jira.shanqu.cc/browse/GHZSCY-5546 2024-07-23 13:37:04 +08:00
bffa2dab7f Merge branch 'feat/GHZSCY-6011' into 'dev'
feat: 帮助与反馈埋点事件补充—客户端 https://jira.shanqu.cc/browse/GHZSCY-6011

See merge request halo/android/assistant-android!1763
2024-07-23 10:11:12 +08:00
136975c067 feat: 帮助与反馈埋点事件补充—客户端 https://jira.shanqu.cc/browse/GHZSCY-6011 2024-07-23 10:11:12 +08:00
f389fcc206 Merge branch 'fix/rejected_crash' into 'dev'
fix: 临时修复由于移除安装广播监听后手动检查安装状态导致的 RejectedExecutionException 问题...

See merge request halo/android/assistant-android!1761
2024-07-22 10:33:30 +08:00
9c5ef246a4 fix: 临时修复由于移除安装广播监听后手动检查安装状态导致的 RejectedExecutionException 问题 https://sentry.shanqu.cc/organizations/lightgame/issues/396151
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-22 10:22:01 +08:00
5f71f52fe1 Merge branch 'feat/update_honor_push_sdk' into 'dev'
feat: 更新荣耀推送SDK版本

See merge request halo/android/assistant-android!1760
2024-07-19 15:31:02 +08:00
2bfa0c1031 feat: 更新荣耀推送SDK版本 2024-07-19 15:28:13 +08:00
97c9dd9923 Merge branch 'fix/android14_debug_lag' into 'dev'
fix: 临时修复在 Android 14 上 debug 包超级卡顿的问题 https://mp.weixin.qq.com/s/qVaQKa90QiKIQg8XRATUTA

See merge request halo/android/assistant-android!1759
2024-07-17 17:59:56 +08:00
cc3733e6fe fix: 临时修复在 Android 14 上 debug 包超级卡顿的问题 https://mp.weixin.qq.com/s/qVaQKa90QiKIQg8XRATUTA
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-17 17:26:01 +08:00
cacdc13b9a Merge branch 'feat/dev-vaplugin-build' into 'dev'
refactor: 下载1.0.2版本的插件构建InternalRelease包

See merge request halo/android/assistant-android!1758
2024-07-17 16:56:53 +08:00
ab3ebd7b37 refactor: 下载1.0.2版本的插件构建InternalRelease包 2024-07-17 16:41:32 +08:00
08879b63da Merge branch 'feat/sync-va' into 'dev'
feat: 使用picasso替换glide,避免多个图片框架集成

See merge request halo/android/assistant-android!1757
2024-07-17 16:08:35 +08:00
ca8d41bac2 feat: 使用picasso替换glide,避免多个图片框架集成 2024-07-17 16:08:35 +08:00
31c54b8f3b Merge branch 'refactor/optimize-application-interface' into 'dev'
fix: 修复合并[https://git.shanqu.cc/halo/android/assistant-android/-/merge_requests/1754]漏了部分模块修改

See merge request halo/android/assistant-android!1756
2024-07-17 15:47:30 +08:00
038da5dae2 fix: feature:qq_game onCreate去掉主进程才执行的判断 2024-07-17 15:46:52 +08:00
3bcf332dfa fix: 修复合并[https://git.shanqu.cc/halo/android/assistant-android/-/merge_requests/1754]漏了部分模块修改 2024-07-17 15:40:37 +08:00
ee7723a4d8 Merge branch 'refactor/optimize-application-interface' into 'dev'
fix: 修复多进程的Application onCreate函数没有调用

See merge request halo/android/assistant-android!1755
2024-07-17 15:28:25 +08:00
aed68e3268 fix: 主进程设置线程的UncaughtExceptionHandler 2024-07-17 15:25:21 +08:00
6902e748e4 fix: 修复多进程的Application onCreate函数没有调用 2024-07-17 15:17:23 +08:00
fa9186cb54 Merge branch 'refactor/optimize-application-interface' into 'dev'
refactor: IApplication的attachbasecontext方法添加context参数

See merge request halo/android/assistant-android!1754
2024-07-16 18:26:51 +08:00
119a684112 refactor: IApplication的attachbasecontext方法添加context参数 2024-07-16 18:21:43 +08:00
72d8016c4b Merge branch 'feat/sync-va' into 'dev'
feat: xcrash接入,暂时上报process_dead和server_dead两种类型

See merge request halo/android/assistant-android!1753
2024-07-16 18:13:35 +08:00
6569eecbb1 feat: xcrash接入,暂时上报process_dead和server_dead两种类型 2024-07-16 18:11:48 +08:00
83cb925be2 Merge branch 'fixed/va-auth-dependency' into 'dev'
fixed: 修复登录登出闪退

See merge request halo/android/assistant-android!1751
2024-07-15 11:49:19 +08:00
a98b54269a fixed: 修复登录登出闪退 2024-07-15 11:45:53 +08:00
570cf800e5 Merge branch 'feat/remove_resguard' into 'dev'
Feat/remove resguard

See merge request halo/android/assistant-android!1748
2024-07-12 14:20:42 +08:00
83ec4414f9 Merge branch 'feat/sync-va' into 'dev'
feat: 同步5.37.0的va相关内容

See merge request halo/android/assistant-android!1747
2024-07-12 13:46:31 +08:00
004bd3421a feat: 同步5.37.0的va相关内容 2024-07-12 13:46:00 +08:00
f365a80a84 feat: 移除 andResGuard 2024-07-12 11:48:46 +08:00
ff078ab2a1 Merge branch 'feat/GHZSCY-5986' into 'dev'
feat: 畅玩启动事件埋点位置信息补充 https://jira.shanqu.cc/browse/GHZSCY-5986

See merge request halo/android/assistant-android!1746
2024-07-12 10:33:21 +08:00
0ba49550b3 feat: 畅玩启动事件埋点位置信息补充 https://jira.shanqu.cc/browse/GHZSCY-5986 2024-07-11 20:43:37 +08:00
251e867833 Merge branch 'CWZS-113-rebase-710' into 'dev'
feat: VA组件化

See merge request halo/android/assistant-android!1742
2024-07-11 20:41:15 +08:00
ca20d7e2a3 revert: 废弃新增的畅玩更新逻辑 2024-07-11 20:35:55 +08:00
8fb4b373d3 fix: 重构导致的错误 2024-07-11 19:49:26 +08:00
58fa40fe08 Merge branch 'fix/download_crash' into 'dev'
fix: 修复下载文件时进度无穷大导致的闪退问题...

See merge request halo/android/assistant-android!1744
2024-07-11 19:07:42 +08:00
cd4f2783b5 fix: 修复下载文件时进度无穷大导致的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/367452/activity/?project=22&query=∞&referrer=issue-stream&statsPeriod=14d
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-11 19:06:32 +08:00
4ee735b8cd feat: VA组件化
refactor: 正式包5.36.4同步 va组件

refactor: sync vasdk

chore: 修改为debug打包

feat: merge va
2024-07-11 15:50:16 +08:00
605b886315 Merge branch 'feat/GHZSCY-5974' into 'dev'
feat: 安装包清理功能-权限获取优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-5974

See merge request halo/android/assistant-android!1741
2024-07-11 15:19:11 +08:00
54eb44d072 feat: 安装包清理功能-权限获取优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-5974 2024-07-11 15:19:11 +08:00
5866b0d28a Merge branch 'feat/optimise_debug_process' into 'dev'
feat: 支持 debug 状态下动态启用/禁用非核心模块

See merge request halo/android/assistant-android!1739
2024-07-10 14:40:05 +08:00
9f47f30f38 feat: 支持 debug 状态下动态启用/禁用非核心模块 2024-07-10 13:42:12 +08:00
dcb3fa3910 Merge remote-tracking branch 'refs/remotes/origin/release' into dev 2024-07-09 17:36:07 +08:00
12bbd008d8 Merge branch 'hotfix/v5.36.3-1073/start_activity_crash' into 'release'
fix: 暴力 catch ComponentActivity startActivityForResult 的所有类型 exception

See merge request halo/android/assistant-android!1736
2024-07-08 19:13:31 +08:00
49b35b2837 Merge branch 'fix/download_entity_mis_update' into 'dev'
fix: 修复下载任务暂停时,下载实体可能会被脏数据覆盖的问题

See merge request halo/android/assistant-android!1733
2024-07-08 17:48:32 +08:00
1269560541 fix: 暴力 catch ComponentActivity startActivityForResult 的所有类型 exception
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-08 17:25:04 +08:00
a788b7b485 fix: 修复下载任务暂停时,下载实体会被脏数据覆盖的问题 2024-07-08 17:00:36 +08:00
f47a2db92b Merge branch 'fix/icon_too_large_exception' into 'dev'
fix: 修复应用图标过大时导致的 bitmap 显示问题 https://sentry.shanqu.cc/organizations/lightgame/issues/396209

See merge request halo/android/assistant-android!1731
2024-07-08 16:00:07 +08:00
aa41551c4e fix: 修复应用图标过大时导致的 bitmap 显示问题 https://sentry.shanqu.cc/organizations/lightgame/issues/396209 2024-07-08 15:39:48 +08:00
813634379a Merge branch 'fix/video_cache_error' into 'dev'
fix: 修复视频播放没有使用本地缓存的问题,相关变更 https://git.shanqu.cc/halo/android/assistant-android/-/merge_requests/1459

See merge request halo/android/assistant-android!1725
2024-07-08 10:11:41 +08:00
e884e9b45a Merge branch 'chen/202407/fix-395638-22' into 'release'
fix:安卓8.0设置orientation闪退问题...

See merge request halo/android/assistant-android!1729
2024-07-08 10:11:30 +08:00
e86a301d10 fix:安卓8.0设置orientation闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/395638/?project=22 2024-07-08 10:06:42 +08:00
89bdafe7ed fix: 修复视频播放没有进行本地缓存的问题,相关变更 https://git.shanqu.cc/halo/android/assistant-android/-/merge_requests/1459 2024-07-05 17:30:42 +08:00
8dc4b86790 Merge remote-tracking branch 'refs/remotes/origin/release' into dev
# Conflicts:
#	dependencies.gradle
2024-07-05 17:00:03 +08:00
989d1578ef Merge branch 'feat/GHZSCY-5975' into 'release'
feat: 极光SDK-已安装列表权限处理—客户端 https://jira.shanqu.cc/browse/GHZSCY-5975

See merge request halo/android/assistant-android!1728
2024-07-05 13:42:49 +08:00
ba3b86a00e feat: 极光SDK-已安装列表权限处理—客户端 https://jira.shanqu.cc/browse/GHZSCY-5975 2024-07-05 13:41:14 +08:00
2a279762e1 Merge branch 'feat/GHZSCY-5975' into 'dev'
feat: 极光SDK-已安装列表权限处理—客户端 https://jira.shanqu.cc/browse/GHZSCY-5975

See merge request halo/android/assistant-android!1727
2024-07-05 13:35:15 +08:00
574ae0eece feat: 极光SDK-已安装列表权限处理—客户端 https://jira.shanqu.cc/browse/GHZSCY-5975 2024-07-05 13:35:15 +08:00
9412c255eb Merge branch 'chen/202407/fix-395354' into 'release'
fix:https://sentry.shanqu.cc/organizations/lightgame/issues/395354/?project=22

See merge request halo/android/assistant-android!1726
2024-07-05 10:35:28 +08:00
c2c6901b04 fix:https://sentry.shanqu.cc/organizations/lightgame/issues/395354/?project=22
原因分析:当用户进入NewsDetailFragment,迅速点击分享按钮;此时,如果mNewsDetailEntity加载完毕,mGameEntity还未赋值,会出现NullPointerException
2024-07-05 10:26:57 +08:00
e8cca4b491 Merge branch 'feat/optimise_get_packages' into 'dev'
feat: 优化已安装应用列表的调用

See merge request halo/android/assistant-android!1718
2024-07-04 10:59:10 +08:00
b4e2685f19 feat: 优化包名获取逻辑 2024-07-04 10:25:49 +08:00
8f9c5fac95 Merge branch 'fix/GHZSCY-5885' into 'dev'
fix: 自定义页面组件【排行榜】切换默认&深色模式会显示为默认背景 https://jira.shanqu.cc/browse/GHZSCY-5885

See merge request halo/android/assistant-android!1723
2024-07-03 09:40:37 +08:00
e28a4a8fed Merge branch 'fix/sentry_business_id' into 'dev'
fix: 修复sentry上报businessId不准确的问题

See merge request halo/android/assistant-android!1722
2024-07-03 09:40:14 +08:00
45b4d1214e fix: 修复sentry上报businessId不准确的问题 2024-07-02 20:59:03 +08:00
a7dc78b969 fix: 自定义页面组件【排行榜】切换默认&深色模式会显示为默认背景 https://jira.shanqu.cc/browse/GHZSCY-5885 2024-07-01 16:47:55 +08:00
11a0d55d12 chore: 版本更新至 5.36.3 2024-06-27 16:35:08 +08:00
398ff16f76 Merge remote-tracking branch 'refs/remotes/origin/release' into dev 2024-06-27 16:28:35 +08:00
5d7056735a Merge branch 'hotfix/v5.36.2-1072/install_status_update' into 'release'
fix: 修复列表游戏的安装状态更新问题

See merge request halo/android/assistant-android!1720
2024-06-27 16:28:19 +08:00
3bd0444dde fix: 修复列表游戏的安装状态更新问题 2024-06-27 16:19:16 +08:00
4d2d3d24ee Merge branch 'chen/202406/fix-follow-crash' into 'release'
fix:修复线上crash:https://sentry.shanqu.cc/organizations/lightgame/issues/393670/?project=22

See merge request halo/android/assistant-android!1719
2024-06-27 10:59:29 +08:00
7310056d2e fix:修复线上crash:https://sentry.shanqu.cc/organizations/lightgame/issues/393670/?project=22 2024-06-27 10:55:05 +08:00
5cf8b80ea4 Merge branch 'chen/202406/GHZSCY-5808' into 'dev'
fix:【光环助手】轮播图神策上报问题 https://jira.shanqu.cc/browse/GHZSCY-5808

See merge request halo/android/assistant-android!1717
2024-06-26 13:53:39 +08:00
bf5b7ced89 fix:【光环助手】轮播图神策上报问题 https://jira.shanqu.cc/browse/GHZSCY-5808 2024-06-26 13:50:35 +08:00
b1e44ea89b Merge branch 'chen/202406/GHZSCY-5808' into 'dev'
fix:【光环助手】轮播图神策上报问题 https://jira.shanqu.cc/browse/GHZSCY-5808

See merge request halo/android/assistant-android!1716
2024-06-26 11:15:29 +08:00
1f5b9bde3e fix:【光环助手】轮播图神策上报问题 https://jira.shanqu.cc/browse/GHZSCY-5808 2024-06-26 11:12:19 +08:00
c57063bcfe Merge remote-tracking branch 'refs/remotes/origin/release' into dev
# Conflicts:
#	dependencies.gradle
2024-06-26 09:50:21 +08:00
5fd7d0bb62 fix: 移除极光推送定位权限的申请 2024-06-25 17:38:06 +08:00
a45d6ce0b4 Merge branch 'feature-GHZS-5816' into 'release'
feat:【光环助手】QQ小游戏登录 https://jira.shanqu.cc/browse/GHZSCY-5816

See merge request halo/android/assistant-android!1715
2024-06-25 17:24:08 +08:00
dcff648d37 feat:【光环助手】QQ小游戏登录 https://jira.shanqu.cc/browse/GHZSCY-5816 2024-06-25 17:24:08 +08:00
513938da99 feat: 增加 js 查询推送 id 方法 2024-06-25 16:54:39 +08:00
6490111940 feat: 还原穿山甲 SDK https://git.shanqu.cc/halo/android/assistant-android/-/merge_requests/1672 2024-06-25 16:24:59 +08:00
56437855d8 Merge branch 'hotfix/v5.35.5-1055/jpush_first_launch_skip' into 'release'
fix: 修复首次安装启动收到极光推送时点击无法跳转APP的问题

See merge request halo/android/assistant-android!1674
2024-06-25 16:14:49 +08:00
29facb49df Merge branch 'hotfix/v5.35.1-1051/disable_jcore_auto_init' into 'release'
feat: 恢复极光推送,移除极光自动初始化 https://jira.shanqu.cc/browse/GHZSCY-5342

See merge request halo/android/assistant-android!1658
2024-06-25 16:14:40 +08:00
f023a315b9 chore: 版本更新至 5.36.2 2024-06-25 10:02:13 +08:00
b9d217d773 Merge branch 'hotfix/v5.36.1-1071/revert_mr_1672' into 'release'
revert: "fix: 修复图片显示问题"  https://git.shanqu.cc/halo/android/assistant-android/-/merge_requests/1672

See merge request halo/android/assistant-android!1714
2024-06-25 09:48:21 +08:00
cbdab7cd50 Merge branch 'feature-GHZS-5696' into 'release'
feat: QQ小游戏SDK更新—客户端 https://jira.shanqu.cc/browse/GHZSCY-5696

See merge request halo/android/assistant-android!1705
2024-06-25 09:43:32 +08:00
5b2f710be8 feat: QQ小游戏SDK更新—客户端 https://jira.shanqu.cc/browse/GHZSCY-5696 2024-06-25 09:43:32 +08:00
b15dafb852 revert: "fix: 修复图片显示问题" https://git.shanqu.cc/halo/android/assistant-android/-/merge_requests/1672 2024-06-24 18:25:00 +08:00
37b36a9632 chore: 版本更新至 5.36.1 2024-06-21 14:37:06 +08:00
17495e3699 Merge branch 'hotfix/v5.36.0-1070/craches' into 'release'
fix: 修复 5.36.0 线上闪退问题

See merge request halo/android/assistant-android!1713
2024-06-21 14:36:00 +08:00
d9ee277e82 fix: 处理多线程操作 tag 造成 View.getTag 数组越界异常,并上报 sentry 供后续分析 https://sentry.shanqu.cc/organizations/lightgame/issues/392564 2024-06-21 14:28:58 +08:00
bb6bdb1351 fix: 简单捕抓 getPackageForUid 的异常 https://sentry.shanqu.cc/organizations/lightgame/issues/392558 2024-06-21 13:49:17 +08:00
204300ca98 chore: 版本更新至 5.37.0 2024-06-20 14:35:11 +08:00
24815cd398 Merge remote-tracking branch 'origin/release' into dev 2024-06-20 14:26:11 +08:00
b963281eb6 Merge branch 'feature-GHZS-5775' into 'dev'
feat: 【光环助手】部分专题封面图不展示问题 https://jira.shanqu.cc/browse/GHZSCY-5775

See merge request halo/android/assistant-android!1711
2024-06-20 14:24:30 +08:00
95721268f7 feat: 【光环助手】部分专题封面图不展示问题 https://jira.shanqu.cc/browse/GHZSCY-5775 2024-06-20 14:24:30 +08:00
dfd542f5df Merge branch 'fix-qq-game-recently-played' into 'dev'
fix: 修复QQ小游戏首页最近在玩刷新异常问题

See merge request halo/android/assistant-android!1712
2024-06-20 10:22:13 +08:00
14522e5d07 fix: 修复QQ小游戏首页最近在玩刷新异常问题 2024-06-20 10:19:12 +08:00
71efe3b69a Merge branch 'hotfix/v5.35.5-1055/pack-info-error' into 'release'
fix: 特殊包判断的异常问题

See merge request halo/android/assistant-android!1710
2024-06-17 16:07:54 +08:00
b8cbbc0301 fix: 特殊包判断的异常问题 2024-06-17 16:07:02 +08:00
2fe8051280 Merge remote-tracking branch 'refs/remotes/origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/ndownload/NDownloadBridge.kt
2024-06-17 11:15:12 +08:00
0d4a893552 Merge branch 'feat/GHZSCY-5250' into 'dev'
feat: 合规调整-已安装列表权限 https://jira.shanqu.cc/browse/GHZSCY-5250

See merge request halo/android/assistant-android!1703
2024-06-17 11:11:49 +08:00
e07216365a feat: 合规调整-已安装列表权限 https://jira.shanqu.cc/browse/GHZSCY-5250 2024-06-17 11:11:25 +08:00
1c04e966d9 Merge branch 'hotfix/v5.35.5-1055/download_dialog_crash' into 'release'
fix: 捕抓下载弹窗自动触发下载时的数组越界异常 https://sentry.shanqu.cc/organizations/lightgame/issues/365000/

See merge request halo/android/assistant-android!1709
2024-06-17 10:50:20 +08:00
ba0ad10f61 fix: 捕抓下载弹窗自动触发下载时的数组越界异常 https://sentry.shanqu.cc/organizations/lightgame/issues/365000/ 2024-06-17 10:49:47 +08:00
9592731033 Merge branch 'feature-GHZS-5704' into 'dev'
feat: 同步正式问题—微小后台无内购等数据—客户端 https://jira.shanqu.cc/browse/GHZSCY-5704

See merge request halo/android/assistant-android!1708
2024-06-17 10:18:26 +08:00
0dc9fb1aa3 feat: 同步正式问题—微小后台无内购等数据—客户端 https://jira.shanqu.cc/browse/GHZSCY-5704 2024-06-17 10:18:26 +08:00
fd450f0d67 Merge branch 'hotfix/v5.35.5-1055/sentry_crashes' into 'release'
fix: 捕抓下载时获取回调 header 时的异常 https://sentry.shanqu.cc/organizations/lightgame/issues/371082

See merge request halo/android/assistant-android!1707
2024-06-14 16:31:47 +08:00
57984d160f fix: 捕抓下载时获取回调 header 时的异常 https://sentry.shanqu.cc/organizations/lightgame/issues/371082
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-06-14 15:08:00 +08:00
165ca21926 Merge remote-tracking branch 'refs/remotes/origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt
2024-06-14 14:20:20 +08:00
e19c091532 Merge branch 'hotfix/v5.35.5-1055/filter_crash' into 'release'
fix: 修复游戏屏蔽的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/380904/

See merge request halo/android/assistant-android!1706
2024-06-14 11:32:04 +08:00
5db6b3511f fix: 修复游戏屏蔽的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/380904/
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-06-14 10:44:29 +08:00
8557b230ac Merge branch 'fix-wechat-game-recently-play-refresh' into 'dev'
fix: 自定义页面-微信小游戏-最近在玩列表刷新修复

See merge request halo/android/assistant-android!1704
2024-06-12 17:21:07 +08:00
44a817be12 fix: 自定义页面-微信小游戏-最近在玩列表刷新修复 2024-06-12 17:21:07 +08:00
c76e0b8bfa Merge branch 'feat/GHZSCY-5543' into 'dev'
feat: 鸿蒙系统关闭“纯净模式/增强防护”引导弹窗 https://jira.shanqu.cc/browse/GHZSCY-5543

See merge request halo/android/assistant-android!1694
2024-06-12 15:47:01 +08:00
bbbd77b8ab feat: 鸿蒙系统关闭“纯净模式/增强防护”引导弹窗 https://jira.shanqu.cc/browse/GHZSCY-5543 2024-06-12 14:48:02 +08:00
08ab5ec727 Merge branch 'fix-custom-page-game-item-ui' into 'dev'
fix: 自定义页面-游戏Item UI调整

See merge request halo/android/assistant-android!1702
2024-06-12 09:29:57 +08:00
39afbecce8 fix: 自定义页面-游戏Item UI调整 2024-06-11 18:47:56 +08:00
4229f0e335 Merge branch 'feature-GHZS-5267' into 'dev'
feat: 微信小游戏接入—客户端 https://jira.shanqu.cc/browse/GHZSCY-5267

See merge request halo/android/assistant-android!1684
2024-06-11 18:42:15 +08:00
efae6cb459 feat: 微信小游戏接入—客户端 https://jira.shanqu.cc/browse/GHZSCY-5267 2024-06-11 18:42:15 +08:00
8f8cfb757f Merge branch 'feat/GHZS-5156' into 'dev'
feat: Xapk解压失败弹窗优化-0514优化 https://jira.shanqu.cc/browse/GHZSCY-5383

See merge request halo/android/assistant-android!1639
2024-06-11 17:21:39 +08:00
1e894e1158 feat: Xapk解压失败弹窗优化-0514优化 https://jira.shanqu.cc/browse/GHZSCY-5383 2024-06-11 17:18:34 +08:00
96b479b8f0 Merge branch 'feature-GHZS-5245' into 'dev'
fix: 【光环助手】MIUI优化关闭提示弹窗点击问题 https://jira.shanqu.cc/browse/GHZSCY-5245

See merge request halo/android/assistant-android!1663
2024-06-11 17:10:13 +08:00
342eefe7ba fix: 【光环助手】MIUI优化关闭提示弹窗点击问题 https://jira.shanqu.cc/browse/GHZSCY-5245 2024-06-11 17:10:13 +08:00
e9c9f6f66b Merge branch 'fix/GHZSCY-5405' into 'dev'
fix: 游戏详情页顶部视频播放问题 https://jira.shanqu.cc/browse/GHZSCY-5405

See merge request halo/android/assistant-android!1701
2024-06-11 17:07:38 +08:00
7da90ffb0b fix: 游戏详情页顶部视频播放问题 https://jira.shanqu.cc/browse/GHZSCY-5405 2024-06-11 17:02:50 +08:00
c71f8676dd Merge branch 'feat/GHZSCY-5098-pr' into 'dev'
feat:社区新增关注页面—客户端 https://jira.shanqu.cc/browse/GHZSCY-5098
2024-06-11 16:50:59 +08:00
50555cb217 feat:社区新增关注页面—客户端 https://jira.shanqu.cc/browse/GHZSCY-5098 2024-06-11 16:50:59 +08:00
766e4fc3ab Merge branch 'feature-GHZS-5142' into 'dev'
feat: 【光环助手】第三方落地页数据相关优化 https://jira.shanqu.cc/browse/GHZSCY-5142

See merge request halo/android/assistant-android!1664
2024-06-11 14:20:34 +08:00
c091e496e7 feat: 【光环助手】第三方落地页数据相关优化 https://jira.shanqu.cc/browse/GHZSCY-5142 2024-06-11 14:20:34 +08:00
ecd81ea353 Merge branch 'feat/GHZSCY-5604' into 'dev'
feat: 推广包相关推广平台SDK更新 https://jira.shanqu.cc/browse/GHZSCY-5605

See merge request halo/android/assistant-android!1695
2024-06-11 09:41:53 +08:00
21e7198589 Merge branch 'feat/GHZSCY-5631' into 'dev'
fix: 仅支持32位架构的设备屏蔽畅玩下载方式 https://jira.shanqu.cc/browse/GHZSCY-5631

See merge request halo/android/assistant-android!1696
2024-06-07 15:58:06 +08:00
d6c97bc215 feat: 仅支持32位架构的设备屏蔽畅玩下载方式 https://jira.shanqu.cc/browse/GHZSCY-5631
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-06-07 15:51:54 +08:00
321e9b6ee6 Merge branch 'fix/GHZSCY-5593' into 'dev'
fix: 微信账号登陆后助手后台程序异常 https://jira.shanqu.cc/browse/GHZSCY-5593

See merge request halo/android/assistant-android!1697
2024-06-07 15:49:50 +08:00
7cc3e7ec67 Merge remote-tracking branch 'refs/remotes/origin/dev' into dev 2024-06-07 15:47:53 +08:00
08dac2eb42 Merge branch 'fix/oaid_error' into 'dev'
fix: 修复因为 OAID 获取过慢导致的实名相关信息绑定失败问题

See merge request halo/android/assistant-android!1698
2024-06-07 15:46:37 +08:00
85c7746206 fix: 修复因为 OAID 获取过慢导致的实名相关信息绑定失败问题 https://jira.shanqu.cc/browse/GHZSCY-5629 2024-06-07 15:46:02 +08:00
a35700e2f7 Merge remote-tracking branch 'refs/remotes/origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/manager/DataCollectionManager.java
2024-06-07 15:42:36 +08:00
6a44294338 Merge branch 'fix/GHZSCY-5390' into 'dev'
fix:【光环助手】下拉弹窗弹出时快速上滑页面时的页面显示异常问题 https://jira.shanqu.cc/browse/GHZSCY-5390

See merge request halo/android/assistant-android!1699
2024-06-07 10:31:52 +08:00
b8c275d8fc fix:【光环助手】下拉弹窗弹出时快速上滑页面时的页面显示异常问题 https://jira.shanqu.cc/browse/GHZSCY-5390 2024-06-07 10:31:52 +08:00
638bf86d1e Merge branch 'fix/GHZSCY-5418' into 'dev'
fix: 测试问题-2024/5/20-客户端(问题3) https://jira.shanqu.cc/browse/GHZSCY-5418

See merge request halo/android/assistant-android!1690
2024-06-05 17:29:34 +08:00
158c46f210 fix: 测试问题-2024/5/20-客户端(问题3) https://jira.shanqu.cc/browse/GHZSCY-5418 2024-06-05 17:29:34 +08:00
a28ef7d20b Merge branch 'feat/GHZSCY-5377' into 'dev'
feat: 【光环助手】注销账号-深色模式显示问题(增加js查询深色模式方法) https://jira.shanqu.cc/browse/GHZSCY-5377

See merge request halo/android/assistant-android!1692
2024-06-05 17:29:12 +08:00
bae20a4e7d feat: 【光环助手】注销账号-深色模式显示问题(增加js查询深色模式方法) https://jira.shanqu.cc/browse/GHZSCY-5377 2024-06-05 17:29:12 +08:00
4a2f0896bb Merge branch 'hotfix/v5.35.5-1055/crashes' into 'release'
fix: 修复 5.35.5 线上闪退

See merge request halo/android/assistant-android!1693
2024-06-05 15:00:34 +08:00
51ccc532d5 fix: 修复安装数据上报闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/365934
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-06-05 14:48:54 +08:00
1bf977f3e4 fix: 修复安利墙点赞闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/379887/
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-06-05 14:48:54 +08:00
da2aeeeaf2 feat: 推广包相关推广平台SDK更新 https://jira.shanqu.cc/browse/GHZSCY-5605
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-06-05 11:51:59 +08:00
52d160a0e0 fix: 微信账号登陆后助手后台程序异常 https://jira.shanqu.cc/browse/GHZSCY-5593
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-06-05 10:09:07 +08:00
cbba9c09b5 Merge branch 'docs/GHZSCY-5350' into 'dev'
docs: 补充 Activity 类名注释 https://jira.shanqu.cc/browse/GHZSCY-5350

See merge request halo/android/assistant-android!1689
2024-06-03 17:24:12 +08:00
3c877ada98 Merge branch 'feature-GHZS-5398' into 'dev'
fix:【光环助手】游戏详情-大家都在玩 神策埋点问题 https://jira.shanqu.cc/browse/GHZSCY-5398

See merge request halo/android/assistant-android!1683
2024-05-28 11:18:43 +08:00
9b95e01d33 fix:【光环助手】游戏详情-大家都在玩 神策埋点问题 https://jira.shanqu.cc/browse/GHZSCY-5398 2024-05-28 11:18:42 +08:00
567576fc04 Merge branch 'feat/GHZSCY-5124' into 'dev'
合并消息中心相关需求

See merge request halo/android/assistant-android!1685
2024-05-28 09:59:36 +08:00
1b7913a00e feat: 订阅&推送体系-消息中心不展示隐藏状态或已删除游戏的会话,及其消息—客户端 https://jira.shanqu.cc/browse/GHZSCY-5395 2024-05-28 09:44:22 +08:00
05e2719e1c feat: 订阅&推送体系-消息中心补全消息删除功能—客户端 https://jira.shanqu.cc/browse/GHZSCY-5124 2024-05-28 09:44:22 +08:00
8ed10c411a Merge branch 'feat/GHZS-4308' into 'dev'
feat: 更换日志上报SDK https://jira.shanqu.cc/browse/GHZSCY-4308

See merge request halo/android/assistant-android!1522
2024-05-27 10:10:41 +08:00
f9f4bb84b4 feat: 更换日志上报SDK https://jira.shanqu.cc/browse/GHZS-4308 2024-05-24 16:53:19 +08:00
44a2e616ab Merge branch 'feat/log_all_redirected_host' into 'dev'
feat: 游戏下载host上报 https://jira.shanqu.cc/browse/GHZSCY-5476

See merge request halo/android/assistant-android!1680
2024-05-24 15:54:35 +08:00
fffd3ef789 feat: 游戏下载host上报 https://jira.shanqu.cc/browse/GHZSCY-5476 2024-05-24 15:18:22 +08:00
d53782b8de Merge branch 'fix/GHZSCY-5231' into 'dev'
fix:【光环助手】轮播banner刷新时蒙层消失 https://jira.shanqu.cc/browse/GHZSCY-5231

See merge request halo/android/assistant-android!1679
2024-05-22 15:01:47 +08:00
b16c5d723b fix:【光环助手】轮播banner刷新时蒙层消失 https://jira.shanqu.cc/browse/GHZSCY-5231 2024-05-22 14:44:00 +08:00
1dfd636283 Merge branch 'feature-GHZS-5385' into 'dev'
feat: 【光环助手】QQ小游戏支付唤起问题 https://jira.shanqu.cc/browse/GHZSCY-5385

See merge request halo/android/assistant-android!1668
2024-05-22 11:02:38 +08:00
65feed01f4 feat: 【光环助手】QQ小游戏支付唤起问题 https://jira.shanqu.cc/browse/GHZSCY-5385 2024-05-22 11:02:38 +08:00
2a596bd2a0 Merge branch 'fix/vivo_crash' into 'dev'
fix: 修复在 vivo 的 Android 14  设备上点击剪贴板功能时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/277509

See merge request halo/android/assistant-android!1677
2024-05-21 11:03:28 +08:00
16c4f1016c fix: 修复在 vivo 的 Android 14 设备上点击剪贴板功能时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/277509 2024-05-20 18:19:23 +08:00
1ced82c1f6 Merge branch 'fix/GHZSCY-5372' into 'dev'
fix:【光环助手】开服表bug https://jira.shanqu.cc/browse/GHZSCY-5372

See merge request halo/android/assistant-android!1676
2024-05-20 11:43:37 +08:00
078c9204af fix:【光环助手】开服表bug https://jira.shanqu.cc/browse/GHZSCY-5372 2024-05-20 11:43:37 +08:00
68818b3409 Merge branch 'feat/GHZSCY-5080' into 'dev'
feat:【光环助手】工具新增跳转类型配置 https://jira.shanqu.cc/browse/GHZSCY-4618

See merge request halo/android/assistant-android!1675
2024-05-17 17:53:13 +08:00
7d4aa34d12 feat:【光环助手】工具新增跳转类型配置 https://jira.shanqu.cc/browse/GHZSCY-4618 2024-05-17 17:53:13 +08:00
209c3d7d30 fix: 修复首次安装启动收到极光推送时点击无法跳转APP的问题 2024-05-17 16:43:12 +08:00
2a27e0f467 Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	dependencies.gradle
2024-05-16 16:01:28 +08:00
54ee8a9c69 chore: 版本更新至 5.35.5 2024-05-16 11:36:57 +08:00
2b44efd6b3 Merge branch 'hotfix/v5.35.4-1054/wrong_install_status' into 'release'
fix: 修复安装游戏回到光环时的安装状态更新问题

See merge request halo/android/assistant-android!1673
2024-05-16 11:32:46 +08:00
d62c8beb30 fix: 修复安装游戏回到光环时的安装状态更新问题 2024-05-16 11:22:04 +08:00
155ec08280 Merge branch 'fix/image_display_issue' into 'dev'
fix: 修复图片显示问题

See merge request halo/android/assistant-android!1672
2024-05-16 10:54:14 +08:00
d46aa81dbe chore: 版本更新至 5.35.4 2024-05-15 16:30:39 +08:00
51c0bf27cf Merge branch 'hotfix/v5.35.3-1053/wrong_update_status' into 'release'
fix: 修复使用跳转落地页下载安装的游戏更新时下载按钮的更新问题;修复安装同包名同版本不同游戏 id 的游戏时下载按钮的更新问题

See merge request halo/android/assistant-android!1670
2024-05-15 16:29:48 +08:00
43eb4c88c9 fix: 修复普通图片显示的锯齿问题 (还原为加载 View 大小的图片),移除冗余的图片加载高度入参 2024-05-15 16:21:15 +08:00
06b2d2b416 Merge branch 'hotfix/v5.35.3-1053/packagename_null_crash' into 'release'
fix: 修复部分位置跳转安装因为包名为空而产生的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/385367

See merge request halo/android/assistant-android!1671
2024-05-15 16:00:11 +08:00
af7580a6a6 fix: 修复部分位置跳转安装因为包名为空而产生的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/385367 2024-05-15 15:57:37 +08:00
1e4375ec8a fix: 修复使用跳转落地页下载安装的游戏更新时下载按钮的更新问题;修复安装同包名同版本不同游戏 id 的游戏时下载按钮的更新问题 2024-05-15 15:31:41 +08:00
195247a5c3 fix: 修复重登录时,用户头像不能正常显示的问题 2024-05-14 18:10:58 +08:00
dd65bc8bc2 Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	dependencies.gradle
2024-05-14 17:38:18 +08:00
196e719358 chore: 版本更新至 5.35.3 2024-05-14 17:13:10 +08:00
b1c267b179 Merge branch 'fix/rank_loading_issue' into 'dev'
fix: 修复进入排行榜页面时全量加载所有页面导致页面卡顿的问题

See merge request halo/android/assistant-android!1669
2024-05-14 16:18:34 +08:00
a2679c8dbd fix: 修复进入排行榜页面时全量加载所有页面导致页面卡顿的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-14 16:14:36 +08:00
c9e1816be0 Merge branch 'feat/remove_useless_legacy_code' into 'dev'
feat: 移除部分冗余的历史代码,关闭部分意义不大的日志输出(有需要时再手动开启)

See merge request halo/android/assistant-android!1667
2024-05-14 15:07:00 +08:00
a1f0455d5a feat: 移除部分冗余的历史代码,关闭部分意义不大的日志输出(有需要时再手动开启)
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-14 15:02:00 +08:00
5b3f4b6104 Merge branch 'chen/202405/GHZSCY-5378' into 'dev'
fix:【光环助手】游戏专题点击神策埋点问题 https://jira.shanqu.cc/browse/GHZSCY-5378

See merge request halo/android/assistant-android!1666
2024-05-14 11:02:42 +08:00
fe4e9d9d3b fix:【光环助手】游戏专题点击神策埋点问题 https://jira.shanqu.cc/browse/GHZSCY-5378 2024-05-14 10:58:57 +08:00
dd051b4d13 Merge branch 'hotfix/v5.35.2-1052/logout_crash' into 'release'
fix: 修复退出登录出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/385028/?project=22

See merge request halo/android/assistant-android!1665
2024-05-14 09:45:26 +08:00
e7f756555c fix: 修复退出登录出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/385028/?project=22 2024-05-14 09:39:57 +08:00
9488837e9e Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	dependencies.gradle
2024-05-10 14:14:17 +08:00
b8c4f1403b chore: 版本更新至 5.35.2 2024-05-10 11:18:37 +08:00
b88698c2a3 Merge branch 'hotfix/v5.35.1-1051/crashes' into 'release'
fix: 修复 5.35.1 线上闪退问题

See merge request halo/android/assistant-android!1662
2024-05-10 11:17:13 +08:00
c897d5ad0f fix: 修复多线程更新已安装列表时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/384726 https://sentry.shanqu.cc/organizations/lightgame/issues/384682
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-10 10:53:41 +08:00
037f453a75 fix: 修复小米设备安装 APKS 格式 XAPK 包时候的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/384710
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-10 10:51:38 +08:00
ad3a3c1341 Merge branch 'hotfix/v5.35.1-1051/hot_launch_splash_ad' into 'release'
fix: 修复移除第三方广告SDK后错误展示热启动广告的问题

See merge request halo/android/assistant-android!1661
2024-05-09 17:45:06 +08:00
ba320f7740 fix: 修复移除第三方广告SDK后错误展示热启动广告的问题 2024-05-09 17:19:33 +08:00
f3dbc0b779 Merge branch 'hotfix/v5.35.1-1051/update_notify_issue' into 'release'
fix: 修复更新应用时遗漏模拟卸载监听导致的状态变更异常问题

See merge request halo/android/assistant-android!1660
2024-05-09 15:40:05 +08:00
0c518ac40e fix: 修复更新应用时遗漏模拟卸载监听导致的状态变更异常问题 2024-05-09 15:37:45 +08:00
ccc0140bba docs: 补充 Activity 类名注释 https://jira.shanqu.cc/browse/GHZSCY-5350 2024-05-09 15:12:01 +08:00
bf57118900 Merge branch 'hotfix/v5.35.1-1051/init_crash' into 'release'
fix: 修复部分 downloadEntity versionName 而导致的启动闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/384612

See merge request halo/android/assistant-android!1659
2024-05-09 13:42:04 +08:00
b80a14f2b1 fix: 修复部分 downloadEntity versionName 而导致的启动闪退问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-09 11:48:43 +08:00
2c044d0ee4 feat: 恢复极光推送,移除极光自动初始化 https://jira.shanqu.cc/browse/GHZSCY-5342
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-09 11:14:38 +08:00
1450064640 chore: 版本更新至 5.35.1 2024-05-09 10:26:59 +08:00
90e19d5099 Merge branch 'feat/GHZSCY-5342' into 'release'
feat: 关于移除监听广播后的相关优化 https://jira.shanqu.cc/browse/GHZSCY-5342

See merge request halo/android/assistant-android!1657
2024-05-09 10:25:59 +08:00
383124dc36 feat: 关于移除监听广播后的相关优化(处理错误注释) https://jira.shanqu.cc/browse/GHZSCY-5342
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-09 10:21:28 +08:00
6d6ce2613a feat: 关于移除监听广播后的相关优化 https://jira.shanqu.cc/browse/GHZSCY-5342 2024-05-09 09:21:34 +08:00
8569264b82 feat: 合规调整-已安装列表权限-2024/4/22 https://jira.shanqu.cc/browse/GHZSCY-5250 2024-05-09 09:21:34 +08:00
59667abf09 feat: 合规调整-2024/4/30-后台静默监听行为 https://jira.shanqu.cc/browse/GHZSCY-5331 2024-05-09 09:21:34 +08:00
5201637326 Merge branch 'docs/GHZSCY-5350' into 'dev'
docs: 补充 Activity 类名注释 https://jira.shanqu.cc/browse/GHZSCY-5350

See merge request halo/android/assistant-android!1656
2024-05-08 17:04:41 +08:00
417c41c8a0 docs: 补充 Activity 类名注释 https://jira.shanqu.cc/browse/GHZSCY-5350 2024-05-08 16:59:53 +08:00
b651ef8617 Merge branch 'hotfix/v5.35.0-1050/GHZSCY-5329' into 'release'
fix: 优化 gid 的获取逻辑,避免部分接口请求时因为 gid 为空供导致异常 https://jira.shanqu.cc/browse/GHZSCY-5329

See merge request halo/android/assistant-android!1654
2024-05-08 11:14:46 +08:00
af67894d4e Merge branch 'fix/GHZSCY-5339' into 'dev'
fix: 游戏专题-游戏替换问题 https://jira.shanqu.cc/browse/GHZSCY-5329

See merge request halo/android/assistant-android!1655
2024-05-08 11:10:23 +08:00
76e17eddd7 fix: 优化 gid 的获取逻辑,避免部分接口请求时因为 gid 为空供导致异常 https://jira.shanqu.cc/browse/GHZSCY-5329 2024-05-08 10:03:02 +08:00
f8c9c41eb0 Merge branch 'feat/GHZSCY-5281' into 'dev'
feat: 搜索业务-游戏搜索结果页面补充神策埋点—客户端 https://jira.shanqu.cc/browse/GHZSCY-5281

See merge request halo/android/assistant-android!1653
2024-05-07 18:01:46 +08:00
40ac173389 feat: 搜索业务-游戏搜索结果页面补充神策埋点—客户端 https://jira.shanqu.cc/browse/GHZSCY-5281 2024-05-07 18:01:46 +08:00
c6bc7ca6cc fix: 游戏专题-游戏替换问题 https://jira.shanqu.cc/browse/GHZSCY-5329
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-07 11:51:50 +08:00
f01e08aec9 Merge branch 'hotfix/v5.35.0-1050/crashes' into 'release'
fix: 修复线上闪退问题

See merge request halo/android/assistant-android!1652
2024-05-07 11:02:11 +08:00
faddf5d7b6 fix: 收到卸载广播时移除调用 MutableCollections.removeAll() 方法引起的数组越界异常 (MutableCollections.removeAll()线程不安全) https://sentry.shanqu.cc/organizations/lightgame/issues/242447
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-07 10:38:55 +08:00
81cf2f0ddc fix: 部分镜像游戏开关切换时由于不同接口更新不及时导致的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/378659
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-07 09:56:29 +08:00
198561d15a fix: 收到卸载广播时移除调用 MutableCollections.removeAll() 方法引起的数组越界异常 (MutableCollections.removeAll()线程不安全) https://sentry.shanqu.cc/organizations/lightgame/issues/242447
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-07 09:42:44 +08:00
1e721b699c fix: 修复存储空间不足时进行数据库删除操作引起的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/381076
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-05-06 17:58:50 +08:00
8f48dfd347 Merge branch 'fix-community_browsing_duration_error' into 'release'
fix: 使用ViewPager2导致CommunityBrowsingDuration埋点上报异常的问题

See merge request halo/android/assistant-android!1651
2024-04-30 15:04:50 +08:00
bc811a2882 fix: 使用ViewPager2导致CommunityBrowsingDuration埋点上报异常的问题 2024-04-30 14:56:42 +08:00
bdccbc4c28 chore: 版本更新至 5.36.0 2024-04-29 14:51:06 +08:00
bfd986fdfd Merge remote-tracking branch 'origin/release' into dev 2024-04-28 10:59:46 +08:00
a2bd5e01e0 Merge branch 'hotfix/v5.35.0-1050/jpush_clear_badge' into 'release'
fix: 修复极光推送清除角标提前获取信息的问题

See merge request halo/android/assistant-android!1649
2024-04-28 10:43:11 +08:00
844d227f19 fix: 修复极光推送清除角标提前获取信息的问题 2024-04-28 10:26:20 +08:00
8b1f92e9c4 Merge branch 'chen/202404/GHZSCY-5293' into 'dev'
fix:【光环助手】新游开测右上角显示 https://jira.shanqu.cc/browse/GHZSCY-5293

See merge request halo/android/assistant-android!1648
2024-04-28 10:12:25 +08:00
f5834d440b fix:【光环助手】新游开测右上角显示 https://jira.shanqu.cc/browse/GHZSCY-5293 2024-04-28 10:09:20 +08:00
f982bf6478 Merge branch 'hotfix/v5.35.0-1050/disable_jpush_auto_init' into 'release'
fix: 移除极光推送通过 ContentProvider 自动初始化的问题

See merge request halo/android/assistant-android!1647
2024-04-26 14:01:09 +08:00
33d7afec71 fix: 移除极光推送通过 ContentProvider 自动初始化相关代码 2024-04-26 13:40:16 +08:00
37ef50f323 Merge branch 'feat/GHZSCY-5243' into 'dev'
feat: 穿山甲广告SDK更换新版本与信息流广告优化 https://jira.shanqu.cc/browse/GHZSCY-5243

See merge request halo/android/assistant-android!1641
2024-04-26 10:10:33 +08:00
4c6acdee3a Merge branch 'fix/GHZSCY-5261' into 'dev'
fix: 【光环助手】开屏广告神策埋点数据上报问题 https://jira.shanqu.cc/browse/GHZSCY-5261

See merge request halo/android/assistant-android!1646
2024-04-25 10:36:50 +08:00
6beb060e63 fix: 【光环助手】开屏广告神策埋点数据上报问题 https://jira.shanqu.cc/browse/GHZSCY-5261 2024-04-25 10:31:22 +08:00
a552677e41 Merge branch 'chen/202404/GHZSCY-5187-2' into 'dev'
style:匹配按钮设计规范...

See merge request halo/android/assistant-android!1645
2024-04-24 16:12:37 +08:00
bb148f42b8 style:匹配按钮设计规范 https://jira.shanqu.cc/browse/GHZSCY-5187?focusedCommentId=61918&page=com.atlassian.jira.plugin.system.issuetabpanels%253Acomment-tabpanel#comment-61918 2024-04-24 16:09:44 +08:00
065aa96e18 Merge branch 'fix/GHZSCY-5236' into 'dev'
fix: 多渠道多版本-首次启动跳转问题 https://jira.shanqu.cc/browse/GHZSCY-5236

See merge request halo/android/assistant-android!1640
2024-04-24 11:43:36 +08:00
d9a90ca80b fix: 多渠道多版本-首次启动跳转问题 https://jira.shanqu.cc/browse/GHZSCY-5236 2024-04-24 11:10:39 +08:00
2aeffb1cc4 Merge branch 'chen/202404/GHZSCY-5187' into 'dev'
style:匹配按钮设计规范...

See merge request halo/android/assistant-android!1644
2024-04-23 17:47:19 +08:00
d3188cc3cd style:匹配按钮设计规范 https://jira.shanqu.cc/browse/GHZSCY-5187?focusedCommentId=61918&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-61918 2024-04-23 17:42:52 +08:00
1d7f902a81 feat: 移除一键登录 SDK 依赖 (移除相关无用的资源)
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-04-23 16:19:59 +08:00
13a40806e4 Merge branch 'fix/GHZS-5009' into 'dev'
fix: 插件问题反馈内容默认文案出错 https://jira.shanqu.cc/browse/GHZS-5009

See merge request halo/android/assistant-android!1637
2024-04-23 15:04:29 +08:00
b56e5c4022 Merge branch 'feat/GHZS-5188' into 'dev'
feat: 调整客户端用到的部分域名(同时移除已经从未上线的光能部分相关代码) https://jira.shanqu.cc/browse/GHZS-5188

See merge request halo/android/assistant-android!1638
2024-04-23 15:04:21 +08:00
acca1537da Merge branch 'feat/optimise_package_privacy' into 'dev'
feat: 移除一键登录 SDK 依赖

See merge request halo/android/assistant-android!1642
2024-04-23 15:04:12 +08:00
6e5b639d58 feat: 调整客户端用到的部分域名(同时移除已经从未上线的光能部分相关代码) https://jira.shanqu.cc/browse/GHZS-5188 2024-04-23 14:43:10 +08:00
24000f55af feat: 移除一键登录 SDK 依赖 2024-04-22 17:56:04 +08:00
d11ccba0b7 feat: 穿山甲广告SDK更换新版本与信息流广告优化 https://jira.shanqu.cc/browse/GHZSCY-5243
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-04-22 16:29:42 +08:00
3540c4626d Merge branch 'fix/update_crash' into 'dev'
fix: 修复软更时更新弹窗回到桌面由于下载监听移除不及时导致的闪退问题

See merge request halo/android/assistant-android!1636
2024-04-22 15:34:30 +08:00
e6a2758fdb fix: 修复软更时更新弹窗回到桌面由于下载监听移除不及时导致的闪退问题 2024-04-22 15:08:02 +08:00
a56e2bd16e Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	dependencies.gradle
2024-04-22 14:01:25 +08:00
e038c565ff Merge branch 'hotfix/v5.34.8-1038/authorization_crash' into 'release'
fix: 修复通用授权登陆界面出现的闪退问题...

See merge request halo/android/assistant-android!1635
2024-04-22 13:57:42 +08:00
ec5905bb11 fix: 修复通用授权登陆界面出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/373879/events/b72b2eb3c7ef4426ba8d42ff5a476bbe/?project=22 2024-04-22 13:49:47 +08:00
21f50c4eed Merge branch 'hotfix/v5.34.8-1038/optional_update_crash' into 'release'
fix: 修复软更时取消弹窗切换页面后有机率触发闪退的问题 https://sentry.shanqu.cc/organizations/lightgame/issues/380566

See merge request halo/android/assistant-android!1634
2024-04-22 11:42:21 +08:00
5a93f3671b fix: 修复软更时取消弹窗切换页面后有机率触发闪退的问题 https://sentry.shanqu.cc/organizations/lightgame/issues/380566 2024-04-22 11:04:57 +08:00
6dcb8b6efe Merge branch 'fix/GHZSCY-5244' into 'dev'
fix:【光环助手】5.35验收问题:极光推送触发了APP角标提示,但不能消除 https://jira.shanqu.cc/browse/GHZSCY-5244

See merge request halo/android/assistant-android!1633
2024-04-19 18:06:48 +08:00
d60916b3bc fix:【光环助手】5.35验收问题:极光推送触发了APP角标提示,但不能消除 https://jira.shanqu.cc/browse/GHZSCY-5244 2024-04-19 18:06:48 +08:00
4e00b5db19 chore: 版本更新至 5.34.8 2024-04-17 15:59:16 +08:00
e6a6bbcf97 Merge branch 'feat/GHZS-5229' into 'release'
chore: 神策 SDK 更新至 6.8.0

See merge request halo/android/assistant-android!1629
2024-04-17 15:58:35 +08:00
0eecc4699f chore: 神策 SDK 更新至 6.8.0 2024-04-17 15:56:04 +08:00
920e7a8038 fix: 插件问题反馈内容默认文案出错 https://jira.shanqu.cc/browse/GHZS-5009
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-03-21 10:07:14 +08:00
1347 changed files with 40190 additions and 24802 deletions

4
.gitignore vendored
View File

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

View File

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

6
.gitmodules vendored
View File

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

View File

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

View File

@ -3,7 +3,6 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' // kotlin
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
apply plugin: 'AndResGuard'
import groovy.xml.XmlUtil
@ -75,7 +74,7 @@ android {
versionName rootProject.ext.versionName
applicationId rootProject.ext.applicationId
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt', rootProject.ext.va_proguard_rules
String CORE_EVENT_GAME_CATEGORY = ""
@ -106,6 +105,9 @@ android {
buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\""
buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\""
buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\""
// 一体包的32位畅玩游戏助手包名
buildConfigField "String", "EXT_PACKAGE_NAME", "\"${rootProject.ext.EXT_PACKAGE_NAME}\""
buildConfigField "String", "VA_VERSION_NAME", "\"${rootProject.ext.VA_VERSION}\""
}
// gradle 2.2以上默认同时启用v1和v2优先用于Android N
@ -126,6 +128,10 @@ android {
}
}
packagingOptions {
exclude 'META-INF/gradle/incremental.annotation.processors'
}
buildTypes {
debug {
debuggable true
@ -164,6 +170,15 @@ android {
flavorDimensions("env", "region")
sourceSets {
debug {
assets.srcDirs += 'src/main/assets-debug'
}
release {
assets.srcDirs += 'src/main/assets-release'
}
publish {
java.srcDirs = ['src/main/java', "src/default/java"]
}
@ -303,7 +318,6 @@ dependencies {
kuaishouImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/kuaishou/libs')
gdtImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/gdt/libs')
smImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/sm/libs')
testImplementation 'junit:junit:4.12'
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakcanary}"
debugImplementation "com.squareup.leakcanary:leakcanary-android-process:${leakcanary}"
@ -348,7 +362,7 @@ dependencies {
implementation "com.llew.huawei:verifier:${verifier}"
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:${bytedanceApplog}"
teaImplementation "com.bytedance.applog:RangersAppLog-All-convert:${bytedanceApplog}"
teaImplementation "com.bytedance.ads:AppConvert:${bytedanceAppConvert}"
implementation "net.lingala.zip4j:zip4j:${zip4j}"
@ -357,7 +371,9 @@ dependencies {
implementation "com.lg:easyfloat:${easyFloat}"
implementation "com.lg:apksig:${apksig}"
implementation ("com.lg:apksig:${apksig}") {
exclude group: 'com.google.protobuf'
}
implementation "com.lg:gid:${gid}"
@ -369,52 +385,93 @@ dependencies {
implementation project(':ndownload')
implementation project(':vspace-bridge:vspace')
implementation(project(':feature:xapk-installer'))
implementation (project(':module_common')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_login')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_setting')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':module_setting_compose')) {
// exclude group: 'androidx.swiperefreshlayout'
// }
implementation(project(':module_core_feature')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':module_feedback')) {
// exclude group: 'androidx.swiperefreshlayout'
// }
implementation(project(':feature:new_feedback',)) {
implementation(project(':module_setting')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_sensors_data')) {
exclude group: 'androidx.swiperefreshlayout'
// implementation(project(':module_setting_compose')) {
// exclude group: 'androidx.swiperefreshlayout'
// }
if (!gradle.ext.excludeOptionalModules || gradle.ext.enablePkg) {
implementation(project(':feature:pkg'))
}
implementation(project(':module_message')) {
exclude group: 'androidx.swiperefreshlayout'
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableFeedback) {
implementation(project(':feature:new_feedback')) {
exclude group: 'androidx.swiperefreshlayout'
}
}
// implementation(project(':feature:vpn'))
implementation(project(':feature:pkg'))
implementation(project(':feature:oaid'))
implementation(project(':feature:floating-window'))
implementation(project(':feature:csj_ad'))
// implementation(project(':feature:beizi_startup_ad'))
implementation(project(':feature:xapk-installer'))
implementation(project(':feature:qq_game')) {
exclude group: 'androidx.swiperefreshlayout'
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableMessage) {
implementation(project(':module_message')) {
exclude group: 'androidx.swiperefreshlayout'
}
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableOaid) {
implementation(project(':feature:oaid'))
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableFloatingWindow) {
implementation(project(':feature:floating-window'))
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableSensorData) {
implementation(project(':module_sensors_data')) {
exclude group: 'androidx.swiperefreshlayout'
}
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableCsjAd) {
implementation(project(':feature:csj_ad'))
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableQQGame) {
implementation(project(':feature:qq_game')) {
exclude group: 'androidx.swiperefreshlayout'
}
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enablePush) {
def pushProperty = findProperty('BUILD_PUSH_TYPE')
// 根据BUILD_PUSH_TYPE决定使用哪个推送SDK目前默认使用极光推送
def pushProject = (pushProperty == null || pushProperty == 'jg')
? project(':feature:jg_push') : project(':feature:acloud_push')
implementation(pushProject) {
exclude group: 'androidx.swiperefreshlayout'
}
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableSentry) {
implementation(project(':feature:sentry'))
}
implementation(project(":module_va_api"))
implementation(project(":va-archive-common"))
if(!gradle.ext.excludeOptionalModules || gradle.ext.enableVa) {
implementation(project(":module_va_impl"))
}
debugImplementation "com.bytedance.tools.codelocator:codelocator-core:2.0.3"
internalImplementation(project(':module_internal_test'))
// 根据BUILD_PUSH_TYPE决定使用哪个推送SDK目前默认使用阿里云推送
def pushProject = findProperty('BUILD_PUSH_TYPE') == 'jg'
? project(':feature:jg_push') : project(':feature:acloud_push')
implementation(pushProject) {
exclude group: 'androidx.swiperefreshlayout'
}
debugImplementation 'com.bytedance.android:shadowhook:1.0.9'
debugImplementation 'io.github.shiqos:wytrace:1.0.1'
}
File propFile = file('sign.properties')
@ -474,113 +531,6 @@ if (propFile.exists()) {
// }.each { t -> t.dependsOn generateMetaJson }
//}
andResGuard {
mappingFile = null
use7zip = true
useSign = true
// 打开这个开关会keep住所有资源的原始路径只混淆资源的名字
keepRoot = false
// 设置这个值会把arsc name列混淆成相同的名字减少string常量池的大小
fixedResName = "arg"
// 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源
mergeDuplicatedRes = true
whiteList = [
"R.xml.jpush*",
"R.drawable.jpush*",
"R.layout.jpush*",
"R.layout.push*",
"R.string.jg*",
"R.style.MyDialogStyle",
"R.style.JPushTheme",
"R.drawable.icon",
"R.drawable.ic_bar_back",
"R.drawable.toolbar_search_icon",
"R.drawable.bg_notification_answer_style_1",
"R.drawable.bg_notification_answer_style_2",
"R.drawable.bg_notification_article_style_1",
"R.drawable.bg_notification_article_style_2",
"R.drawable.bg_notification_feedback_style_1",
"R.drawable.bg_notification_feedback_style_2",
"R.drawable.bg_notification_gift_style_1",
"R.drawable.bg_notification_gift_style_2",
"R.drawable.bg_notification_login_style_1",
"R.drawable.bg_notification_login_style_2",
"R.drawable.bg_notification_question_style_1",
"R.drawable.bg_notification_question_style_2",
"R.drawable.bg_notification_rating_style_1",
"R.drawable.bg_notification_rating_style_2",
"R.drawable.bg_notification_reserve_game_style_1",
"R.drawable.bg_notification_reserve_game_style_2",
"R.drawable.bg_notification_video_style_1",
"R.drawable.bg_notification_video_style_2",
"R.drawable.ic_recommend_activity",
"R.drawable.ic_recommend_discount",
"R.drawable.ic_recommend_function",
"R.drawable.ic_recommend_gift",
"R.drawable.ic_recommend_role",
"R.drawable.download_button_normal_style",
"R.drawable.ic_selector_selected",
"R.drawable.ic_selector_default",
"R.id.download_speed",
"R.id.download_percentage",
"R.id.comment",
"R.id.vote",
"R.id.watermark_hint",
"R.id.watermark_sb",
"R.id.bottomShareIv",
"R.id.bottomShareTv",
"R.id.recommendStarPref",
"R.id.recommendStar",
"R.id.iv_vmode_badge",
"R.id.tv_vmode",
"R.id.iv_vmode",
"R.drawable.help_search_delete",
"R.drawable.suggest_type_normal",
"R.drawable.suggest_type_crash",
"R.drawable.suggest_type_game_question",
"R.drawable.suggest_type_game_collect",
"R.drawable.suggest_type_function_suggest",
"R.drawable.suggest_type_article_collect",
"R.drawable.suggest_type_copyright",
"R.drawable.news_comment_detail_read",
"R.drawable.news_comment_detail_comment",
"R.drawable.news_comment_detail_share",
"R.drawable.ic_libao",
"R.drawable.ic_link",
"R.drawable.concern_message_icon",
"R.drawable.reuse_blank_hint",
"R.drawable.ic_concern",
"R.drawable.concern_down",
"R.drawable.concern_up",
"R.drawable.ic_libao_more",
"R.drawable.ic_libao_delete",
"R.drawable.ic_dialog_close",
"R.drawable.occupy2",
"R.drawable.kc_checkbox_unselect",
"R.drawable.kc_checkbox_select",
"R.drawable.ic_type_unselect",
"R.drawable.ic_type_selected",
"R.drawable.suggest_add_pic_icon",
"R.drawable.icon_pic_add",
"R.drawable.ask_search_input_delete",
"R.drawable.suggest_pic_delete",
"R.id.cardIv",
"R.id.cardMask",
"R.id.cardGradientMask",
"R.id.gameIconIv",
"R.id.titleContainer"
]
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
]
sevenzip {
artifact = 'io.github.leon406:SevenZip:1.2.22.5'
}
}
project.afterEvaluate {
def variants = null
try {

View File

@ -28,6 +28,9 @@ object GdtHelper {
} else {
GDTAction.init(application, USER_ACTION_SET_ID, APP_SECRET_ID, channel)
}
GDTAction.start()
Utils.log("init GdtHelper")
}

Binary file not shown.

View File

@ -6,27 +6,69 @@ import android.view.View
import android.view.ViewGroup
import androidx.annotation.Keep
import com.gh.gamecenter.R
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.LayoutPersonalOtherItemBinding
import com.gh.vspace.installexternalgames.InstallExternalGameActivity
import com.lightgame.utils.Utils
import java.io.File
@Keep
class ExternalGameUsage : IExternalGamesUsage {
override fun addInstallExternalGameButton(viewParent: ViewGroup) {
class ExternalGameUsage : ITestCase {
private fun buttonTemplate(viewParent: ViewGroup, id: Int, fn: (LayoutPersonalOtherItemBinding) -> Unit) {
val context = viewParent.context
viewParent.findViewById<View>(R.id.install_game_from_external) ?: run {
viewParent.findViewById<View>(id) ?: run {
val binding = LayoutPersonalOtherItemBinding.inflate(LayoutInflater.from(context)).apply {
root.id = R.id.install_game_from_external
titleTv.text = context.getString(R.string.title_install_external_game)
iconIv.setImageResource(R.drawable.ic_personal_my_game)
root.setOnClickListener {
VHelper.connectService {
context.startActivity(
InstallExternalGameActivity.getIntent(context)
.apply { flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK })
}
}
root.id = id
fn(this)
}
viewParent.addView(binding.root, 0)
}
}
override fun addInstallExternalGameButton(viewParent: ViewGroup) {
val context = viewParent.context
buttonTemplate(viewParent, R.id.install_game_from_external) {
it.titleTv.text = context.getString(R.string.title_install_external_game)
it.iconIv.setImageResource(R.drawable.ic_personal_my_game)
it.root.setOnClickListener {
VHelper.connectService {
context.startActivity(
InstallExternalGameActivity.getIntent(context)
.apply { flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK })
}
}
}
}
override fun addInstallPluginButton(viewParent: ViewGroup) {
buttonTemplate(viewParent, R.id.install_plugin) {
it.titleTv.text = "安装64位插件"
it.root.setOnClickListener {
val file = File("/data/local/tmp/gh-plugins/artifacts.zip")
if (file.exists()) {
Utils.log(VHelper.LOG_TAG, "有本地更新文件: 64位插件")
// TODO: 补充debug插件更新
ToastUtils.showToast("暂未实现debug功能")
} else {
ToastUtils.showToast("data/local/tmp没有push文件")
}
}
}
}
override fun addInstallPlugin32Button(viewParent: ViewGroup) {
buttonTemplate(viewParent, R.id.install_plugin_32) {
it.titleTv.text = "安装32位插件"
it.root.setOnClickListener {
val file = File("/data/local/tmp/gh-plugins/artifacts32.zip")
if (file.exists()) {
// TODO: 补充debug插件更新
ToastUtils.showToast("暂未实现debug功能")
} else {
ToastUtils.showToast("data/local/tmp没有push文件")
}
}
}
}
}

View File

@ -25,6 +25,11 @@ class ExternalGameAdapter(private val games: List<ExternalGameUiState>, private
路径:${item.apkPath}
""".trimIndent()
}
holder.update.setOnClickListener {
onItemClickListener.onItemClick(item, OnItemClickListener.ClickType.CLICK_INSTALL)
}
holder.install.goneIf(item.isInstalled) {
holder.install.setOnClickListener {
onItemClickListener.onItemClick(item, OnItemClickListener.ClickType.CLICK_INSTALL)

View File

@ -8,4 +8,5 @@ class ExternalGameViewHolder(binding: LayoutExternalGameItemBinding) : RecyclerV
val install = binding.btnInstall
val uninstall = binding.btnUninstall
val start = binding.btnStart
val update = binding.btnUpdate
}

View File

@ -16,6 +16,7 @@ import com.gh.gamecenter.databinding.FragmentInstallExternalGamesBinding
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lg.vspace.VirtualAppManager
import com.lightgame.download.DownloadEntity
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
@ -105,6 +106,15 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
private fun install(externalGameUiState: ExternalGameUiState) {
val bit =
externalGameUiState.externalGameEntity.cpuAbi.let { if (it.size == 1 && it.contains("armeabi-v7a")) "32" else "64" }
VHelper.install(requireContext(), DownloadEntity().apply {
externalGameUiState.externalGameEntity.apply {
packageName = apkPackageName
path = apkPath
}
}, true)
if (VHelper.showDialogIfVSpaceIsNeeded(
requireContext(),
"",
@ -144,7 +154,9 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
com.gh.gamecenter.BuildConfig.VERSION_NAME,
HaloApp.getInstance().channel,
"",
""
"",
com.gh.gamecenter.BuildConfig.VA_VERSION_NAME,
HaloApp.getInstance().oaid
)
requireActivity().startActivity(intent)
}

View File

@ -24,6 +24,14 @@
android:visibility="gone"
tools:visibility="visible" />
<Button
android:id="@+id/btn_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_update"
android:visibility="visible"
tools:visibility="visible" />
<Button
android:id="@+id/btn_uninstall"
android:layout_width="wrap_content"

View File

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="install_game_from_external" type="id" />
<item name="install_plugin" type="id" />
<item name="install_plugin_32" type="id" />
</resources>

View File

@ -2,6 +2,7 @@
<resources>
<string name="title_install_external_game">从SD卡安装</string>
<string name="text_install">安装</string>
<string name="text_update">更新</string>
<string name="text_uninstall">卸载</string>
<string name="text_start">启动</string>
</resources>

Binary file not shown.

View File

@ -9,9 +9,17 @@
<queries>
<package android:name="com.lg.vspace" />
<package android:name="com.gh.gamecenter.addon" />
</queries>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
<!-- 华为/荣耀角标 -->
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE " />
<uses-permission android:name="com.hihonor.android.launcher.permission.CHANGE_BADGE" />
<!-- vivo角标 -->
<uses-permission android:name="com.vivo.notification.permission.BADGE_ICON" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<!-- 允许应用程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />
@ -33,7 +41,7 @@
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- 应用安装相关 -->
<uses-permission android:name="com.android.permission.GET_INSTALLED_APPS" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- 前台服务权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
@ -48,6 +56,9 @@
<!-- 如果有视频相关的广告且使用textureView播放请务必添加否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 悬浮窗 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-sdk tools:overrideLibrary="
com.shuyu.gsyvideoplayer,
com.shuyu.gsyvideoplayer.lib,
@ -86,7 +97,33 @@
com.tencent.qqmini,
com.tencent.qqmini.minigame.external,
com.tencent.qqmini.minigame.opensdk,
com.tencent.qqmini.union.ad" />
com.tencent.qqmini.union.ad,
com.lg.vspace,
io.lg.va.common,
com.va.floating,
com.lg.cloud,
com.lg.archive,
com.lg.vclient,
com.va.realname,
com.lg.vspace.flavor,
com.lg.update,
com.lg.login,
com.lg.accelerator,
com.lody.virtual,
com.lg.core,
com.lg.ads,
com.lg.common,
com.lg.vspace.network,
com.lody.virtual.lib.res,
com.va.host,
com.lg.vspace.plugin.host,
com.lg.plugin.constant,
com.bytedance.tools.codelocator,
org.chickenhook.restrictionbypass,
com.lody.virtual.sandhook,
com.lg.vspace.common,
com.lg.vspace.archive.common,
com.wy.lib.wytrace" />
<!-- 去掉 SDK 一些流氓权限 -->
<uses-permission
@ -105,6 +142,14 @@
android:name="android.permission.ACCESS_COARSE_LOCATION"
tools:node="remove" />
<uses-permission
android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
tools:node="remove" />
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"
tools:node="remove" />
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
@ -264,10 +309,6 @@
android:name="com.gh.gamecenter.CleanApkActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SelectUserIconActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.CommentDetailActivity"
android:screenOrientation="portrait"
@ -292,14 +333,6 @@
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden" />
<activity
android:name=".category.CategoryDirectoryActivity"
android:screenOrientation="portrait" />
<activity
android:name=".category.CategoryListActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.UserInfoActivity"
android:screenOrientation="portrait" />
@ -456,9 +489,6 @@
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait"
android:theme="@style/TransparentStatusBarAndNavigationBar" />
<activity
android:name=".gamedetail.myrating.MyRatingActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity"
@ -524,14 +554,6 @@
android:name=".simulatorgame.SimulatorManagementActivity"
android:screenOrientation="portrait" />
<activity
android:name=".catalog.CatalogActivity"
android:screenOrientation="portrait" />
<activity
android:name=".catalog.NewCatalogListActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.search.ForumOrUserSearchActivity"
android:screenOrientation="portrait" />
@ -741,11 +763,11 @@
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qgame.QGameHomeWrapperActivity"
android:name="com.gh.gamecenter.minigame.qq.QGameHomeWrapperActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qgame.QGameSearchActivity"
android:name="com.gh.gamecenter.minigame.MiniGameSearchActivity"
android:screenOrientation="portrait" />
<activity
@ -764,8 +786,18 @@
android:name="com.gh.gamecenter.wrapper.ToolbarWrapperActivity"
android:screenOrientation="portrait" />
<activity android:name=".forum.home.CommunityActivity"
android:screenOrientation="portrait"/>
<activity
android:name=".forum.home.CommunityActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.home.follow.FollowDynamicActivity"
android:theme="@style/Theme.Transparent" />
<activity
android:name=".forum.home.follow.AllFollowedActivity"
android:screenOrientation="portrait"
android:theme="@style/AppCompatTheme.APP" />
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
@ -777,7 +809,8 @@
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"
android:exported="false"
android:grantUriPermissions="true">
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
@ -823,6 +856,8 @@
<service android:name="com.gh.gamecenter.install.InstallService" />
<service android:name="com.gh.download.suspendwindow.DownloadSuspendWindowService" />
<receiver
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
android:exported="false">

View File

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

File diff suppressed because one or more lines are too long

View File

@ -34,18 +34,18 @@ try {
var script = document.createElement("script")
document.body.appendChild(script)
if (isDebug) {
script.src = "https://resource.ghzs.com/js/halo_app_test.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
script.src = "https://dev-and-static.ghzs66.com/web/js/halo.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
} else {
script.src = "https://resource.ghzs.com/js/halo.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
script.src = "https://and-static.ghzs66.com/web/js/halo.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
}
var style = document.createElement("link")
style.rel = "stylesheet"
style.type = "text/css"
if (isDebug) {
style.href = "https://resource.ghzs.com/css/halo_app_test.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
style.href = "https://dev-and-static.ghzs66.com/web/css/halo.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
} else {
style.href = "https://resource.ghzs.com/css/halo.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
style.href = "https://and-static.ghzs66.com/web/css/halo.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
}
document.head.appendChild(style)

View File

@ -28,7 +28,6 @@ import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.provider.IBeiziAdProvider
import com.gh.gamecenter.core.provider.ICsjAdProvider
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.SPUtils
@ -46,14 +45,11 @@ import io.reactivex.schedulers.Schedulers
*
* 由它来分发功能实现到具体的实现
*
* 以最复杂的开屏广告为例,有种实现1. 自有的广告实现 2. 穿山甲的开屏广告实现 3. Beizi 的开屏广告实现
*
* 由于两个广告 SDK 有可能在一次启动中都被使用,所以会根据获取到的广告配置 config 来决定是否需要出是很好两个 SDK
* 以开屏广告为例,有种实现1. 自有的广告实现 2. 穿山甲的开屏广告实现
*/
object AdDelegateHelper {
private var mCsjAdImpl: ICsjAdProvider? = null
private var mBeiziAdImpl: IBeiziAdProvider? = null
private val mAdConfigList: ArrayList<AdConfig> by lazy { arrayListOf() }
@ -65,8 +61,10 @@ object AdDelegateHelper {
val vGameLaunchAd: AdConfig?
get() = mVGameLaunchAd
val splashAdDisplayInterval: Int
get() = mSplashAd?.ownerAd?.startAd?.displayInterval ?: 3
private const val AD_SDK_CSJ = "穿山甲"
private const val AD_SDK_BEIZI = "倍孜"
const val AD_TYPE_SDK = "third_party_ads" // 第三方 SDK 广告
const val AD_TYPE_OWNER = "owner_ads" // 自有广告
@ -80,13 +78,6 @@ object AdDelegateHelper {
var gameSearchKeyword = ""
fun initAdSdk(context: Context) {
// 初始化 Beizi
if (mBeiziAdImpl == null) {
mBeiziAdImpl =
ARouter.getInstance().build(RouteConsts.provider.beiziAd).navigation() as? IBeiziAdProvider
mBeiziAdImpl?.initSDK(context)
}
// 初始化穿山甲
if (mCsjAdImpl == null) {
mCsjAdImpl =
@ -191,10 +182,11 @@ object AdDelegateHelper {
}
/**
* 热启动是否需要显示开屏广告
* 热启动是否需要显示开屏广告(目前只展示第三方广告)
*/
private fun shouldShowStartUpAdWhenHotLaunch() =
mSplashAd?.displayRule?.hotStartSplashAd?.type == AD_TYPE_SDK && mSplashAd?.hotStartThirdPartyAd != null
private fun shouldShowStartUpAdWhenHotLaunch() = (mCsjAdImpl != null)
&& mSplashAd?.displayRule?.hotStartSplashAd?.type == AD_TYPE_SDK
&& mSplashAd?.hotStartThirdPartyAd != null
/**
* 是否需要显示下载管理广告
@ -203,6 +195,10 @@ object AdDelegateHelper {
return mDownloadManagerAd != null && !isMatchAdFreeRule(mDownloadManagerAd) && isMatchDownloadManagerAdDisplayRule()
}
fun shouldShowHelperLaunchAd(): Boolean {
return mVGameLaunchAd != null && !isMatchAdFreeRule(mVGameLaunchAd) && isMatchAdDisplayRule(mVGameLaunchAd, Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME)
}
/**
* 是否需要显示游戏搜索广告
*/
@ -247,10 +243,11 @@ object AdDelegateHelper {
/**
* 是否大于广告管理展示间隔时长
*/
private fun isMatchDownloadManagerAdDisplayRule(): Boolean {
mDownloadManagerAd?.displayRule?.run {
private fun isMatchDownloadManagerAdDisplayRule(): Boolean = isMatchAdDisplayRule(mDownloadManagerAd, Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME)
private fun isMatchAdDisplayRule(adConfig: AdConfig?, spKey: String): Boolean {
adConfig?.displayRule?.run {
if (adDisplayInterval > 0) {
val lastShowTime = SPUtils.getLong(Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME, 0L)
val lastShowTime = SPUtils.getLong(spKey, 0L)
val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60
return durationInMinutes > adDisplayInterval
} else {
@ -402,10 +399,7 @@ object AdDelegateHelper {
((mSplashAd?.displayRule?.timeout ?: 3.5F) * 1000).toInt()
}
if (thirdPartyAd.sourceName == AD_SDK_BEIZI) {
sdkStartAdContainer.visibility = View.VISIBLE
requestBeiziSplashAd(sdkStartAdContainer, adsViewGroup, adViewWidthInPx, adViewHeightInPx, timeout.toLong(), sdkSplashCallback)
} else if (thirdPartyAd.sourceName == AD_SDK_CSJ) {
if (thirdPartyAd.sourceName == AD_SDK_CSJ) {
sdkStartAdContainer.visibility = View.VISIBLE
requestCsjSplashAd(
activity,
@ -452,24 +446,6 @@ object AdDelegateHelper {
}
}
/**
* 获取 Beizi 的开屏广告
*/
private fun requestBeiziSplashAd(
startAdContainer: View,
adsFl: FrameLayout,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
timeout: Long,
callback: (isSuccess: Boolean) -> Unit,
) {
if (mBeiziAdImpl == null) {
callback.invoke(false)
} else {
mBeiziAdImpl?.requestSplashAd(startAdContainer, adsFl, adViewWidthInPx, adViewHeightInPx, timeout, callback)
}
}
/**
* 显示自有的开屏广告
*/
@ -550,12 +526,15 @@ object AdDelegateHelper {
handler: BaseActivity.BaseHandler,
hideCallback: () -> Unit
) {
val jumpBtn: View = startAdContainer.findViewById(R.id.jumpBtn)
val jumpBtn = startAdContainer.findViewById<TextView>(R.id.jumpBtn)
val jumpDetailBtn: TextView = startAdContainer.findViewById(R.id.jumpDetailBtn)
val adImage: SimpleDraweeView = startAdContainer.findViewById(R.id.adImage)
val adVideo = startAdContainer.findViewById<SplashAdVideoView>(R.id.ad_video)
val icpContainer: View? = startAdContainer.findViewById(R.id.startAdIcpContainer)
startAdContainer.visibility = View.VISIBLE
icpContainer?.visibility = View.VISIBLE
jumpBtn.text = startAdContainer.context.getString(R.string.splash_jump, splashAdDisplayInterval)
jumpDetailBtn.text = ad.desc
jumpDetailBtn.setDrawableEnd(
AppCompatResources.getDrawable(
@ -563,7 +542,16 @@ object AdDelegateHelper {
R.drawable.ic_startup_ad_arrow
), null, null
)
adImage.visibleIf(true)
ImageUtils.display(adImage, ad.img)
if (ad.isImageType) {
adVideo.visibleIf(false)
} else {
adVideo.visibleIf(true)
adVideo.startPlay(ad.video.url)
}
startAdContainer.setOnClickListener {
// 拦截点击事件传递
}
@ -676,7 +664,6 @@ object AdDelegateHelper {
* 取消开屏广告
*/
fun cancelSplashAd(context: Context) {
mBeiziAdImpl?.cancelSplashAd(context)
mCsjAdImpl?.cancelSplashAd(context)
}

View File

@ -0,0 +1,44 @@
package com.gh.ad
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.provider.ILaunchAd
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
@Route(path = RouteConsts.provider.vaAd, name = "畅玩启动页广告")
class LaunchAdImpl : ILaunchAd {
override fun init(context: Context?) {
}
override fun requestAd(fragment: Fragment, container: ViewGroup, maskView: View) {
if (AdDelegateHelper.shouldShowHelperLaunchAd()) {
val launchAd = AdDelegateHelper.vGameLaunchAd
val showThirdPartyAd = launchAd?.displayRule?.adSource == AdDelegateHelper.AD_TYPE_SDK
val thirdPartyAd = launchAd?.thirdPartyAd
if (showThirdPartyAd && thirdPartyAd != null) {
AdDelegateHelper.requestThirdPartyBannerAd(
fragment,
container,
thirdPartyAd,
DisplayUtils.getScreenWidthInDp(fragment.requireActivity()),
) { isSuccess ->
maskView.goneIf(!isSuccess)
if (isSuccess) {
SPUtils.setLong(Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME, System.currentTimeMillis())
}
}
}
}
}
}

View File

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

View File

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

View File

@ -32,9 +32,13 @@ import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.SensorsEvent
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
@ -70,7 +74,7 @@ class DefaultJsApi(
private var mFragment: Fragment? = null,
private var mBbsId: String? = "",
private var mOriginUrl: String? = "",
private val mForumName: String? = ""
private val mForumName: String? = "",
) {
companion object {
@ -90,6 +94,11 @@ class DefaultJsApi(
}
}
@JavascriptInterface
fun isEnableForceDark(msg: Any): Boolean {
return DarkModeUtils.isWebViewForceDarkEnabled
}
@JavascriptInterface
fun isGhzs(msg: Any): String {
return "true"
@ -130,7 +139,7 @@ class DefaultJsApi(
@JavascriptInterface
fun login(msg: Any) {
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
if (NetworkUtils.isQuickLoginEnabled(context)) {
QuickLoginHelper.startLogin(context, "浏览器")
} else {
val intent = LoginActivity.getIntent(context, "浏览器")
@ -220,7 +229,7 @@ class DefaultJsApi(
runOnUiThread {
// 若畅玩列表中安装了,优先启动畅玩游戏
if (VHelper.isInstalled(packageName)) {
if (!VHelper.showDialogIfVSpaceIsNeeded(context, "", "", "", "")) {
VHelper.validateVSpaceBeforeAction(context, packageName, null) {
VHelper.launch(context, packageName)
}
} else {
@ -334,6 +343,12 @@ class DefaultJsApi(
return HaloApp.getInstance().oaid
}
@JavascriptInterface
fun getPushId(): String {
val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
return pushProvider?.getRegistrationId(HaloApp.getInstance()) ?: "unknown"
}
@JavascriptInterface
fun showIncompatibleVersionDialog(msg: Any) {
DialogHelper.showUpgradeDialog(context)

View File

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

View File

@ -16,7 +16,7 @@ class ValidateVSpaceHandler : DownloadChainHandler() {
}
if (asVGame) {
VHelper.validateVSpaceBeforeAction(context, gameEntity) {
VHelper.validateVSpaceBeforeAction(context,gameEntity.getUniquePackageName(), gameEntity) {
closure.invoke()
}
} else {

View File

@ -1,6 +1,7 @@
package com.gh.common.constant;
import android.annotation.SuppressLint;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
@ -14,21 +15,27 @@ import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.constant.CommonConsts;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.common.utils.DarkModeUtils;
import com.gh.gamecenter.common.utils.EnvHelper;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.UrlFilterUtils;
import com.gh.gamecenter.entity.AppEntity;
import com.gh.gamecenter.entity.GameGuidePopupEntity;
import com.gh.gamecenter.entity.NewApiSettingsEntity;
import com.gh.gamecenter.entity.NewSettingsEntity;
import com.gh.gamecenter.entity.VNewSetting;
import com.gh.gamecenter.entity.VSetting;
import com.gh.gamecenter.feature.entity.SettingsEntity;
import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.feature.utils.ContentBlockedHelper;
import com.gh.gamecenter.receiver.PackageChangeBroadcastReceiver;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.retrofit.service.VApiService;
import com.gh.vspace.VHelper;
import com.halo.assistant.HaloApp;
@ -39,8 +46,11 @@ import org.json.JSONObject;
import java.io.IOException;
import java.util.Locale;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
import okhttp3.ResponseBody;
public class Config {
@ -57,8 +67,7 @@ public class Config {
public static final String WEIBO_APPKEY = BuildConfig.WEIBO_APPKEY;
public static final String QUICK_LOGIN_APPID = BuildConfig.QUICK_LOGIN_APPID;
public static final String QUICK_LOGIN_APPKEY = BuildConfig.QUICK_LOGIN_APPKEY;
// http://www.ghzs666.com/article/${articleId}.html
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // ghzs/ghzs666 统一
public static final String URL_ARTICLE = "www.ghzs666.com/article/"; // ghzs/ghzs666 统一
private static final String SETTINGS_KEY = "settingsKey";
@ -69,6 +78,10 @@ public class Config {
private static NewApiSettingsEntity.NightMode mNightModeSetting;
private static SimulatorEntity mNewSimulatorEntity;
private static VSetting mVSetting;
private static VNewSetting mVNewSetting;
private static AppEntity mNew32UpdateEntity;
public static BehaviorSubject<VNewSetting> vNewSettingSubject = BehaviorSubject.create();
private static GameGuidePopupEntity mGameGuidePopupEntity;
private static SharedPreferences mDefaultSharedPreferences;
@ -78,25 +91,11 @@ public class Config {
return !SPUtils.getBoolean(Constants.SP_TEENAGER_MODE);
}
/**
* VPN 开关选项是否开启
*/
public static boolean isVpnOptionEnabled() {
if (mNewApiSettingsEntity == null
|| mNewApiSettingsEntity.getInstall() == null
|| mNewApiSettingsEntity.getInstall().getVpnRequired() == null) {
return false;
}
return mNewApiSettingsEntity.getInstall().getVpnRequired().getShouldShowVpnOption();
}
public static void setSettings(SettingsEntity settingsEntity) {
getPreferences().edit().putString(SETTINGS_KEY, GsonUtils.toJson(settingsEntity)).apply();
mSettingsEntity = settingsEntity;
// 加载完设置后刷新下
PackageHelper.initList();
PackageHelper.refreshPackageNameList();
}
@Nullable
@ -197,6 +196,27 @@ public class Config {
return mVSetting;
}
@Nullable
public static VNewSetting getVNewSettingEntity() {
if (mVNewSetting == null) {
try {
String json = SPUtils.getString(Constants.SP_V_NEW_SETTINGS);
if (!TextUtils.isEmpty(json)) {
mVNewSetting = GsonUtils.fromJson(json, VNewSetting.class);
vNewSettingSubject.onNext(mVNewSetting);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return mVNewSetting;
}
@Nullable
public static AppEntity getNew32UpdateEntity() {
return mNew32UpdateEntity;
}
/**
* 请求网络数据,尝试刷新畅玩相关配置
*/
@ -205,7 +225,6 @@ public class Config {
RetrofitManager.getInstance()
.getVApi().getSettings(BuildConfig.VERSION_NAME, Build.VERSION.SDK_INT)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<VSetting>() {
@Override
public void onSuccess(VSetting data) {
@ -217,6 +236,35 @@ public class Config {
});
}
@SuppressLint("CheckResult")
public static void getNewSetting() {
VApiService vApi = RetrofitManager.getInstance().getVApi();
vApi.getNewSettings(BuildConfig.VERSION_NAME, Build.VERSION.SDK_INT).flatMap(new Function<VNewSetting, SingleSource<AppEntity>>() {
@Override
public SingleSource<AppEntity> apply(VNewSetting data) throws Exception {
mVNewSetting = data;
vNewSettingSubject.onNext(mVNewSetting);
SPUtils.setString(Constants.SP_V_NEW_SETTINGS, GsonUtils.toJson(data));
if (data.getVa() != null && data.getVa().getArch32() != null) {
String versionNameByPackageName = PackageUtils.getVersionNameByPackageName(data.getVa().getArch32().getPackageName());
return vApi.getNewPackageUpdate(
BuildConfig.VERSION_NAME,
versionNameByPackageName != null ? versionNameByPackageName : "",
HaloApp.getInstance().getChannel()
);
}
return Single.error(new IllegalStateException("VNewSetting entity is not expected"));
}
})
.subscribeOn(Schedulers.io())
.subscribe(new BiResponse<AppEntity>() {
@Override
public void onSuccess(AppEntity data) {
mNew32UpdateEntity = data;
}
});
}
@Nullable
public static GameGuidePopupEntity getGameGuidePopupEntity() {
return mGameGuidePopupEntity;
@ -240,7 +288,6 @@ public class Config {
RetrofitManager.getInstance()
.getApi().getSettings(PackageUtils.getGhVersionName(), channel)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<SettingsEntity>() {
@Override
public void onResponse(SettingsEntity response) {
@ -253,7 +300,7 @@ public class Config {
edit.apply();
if (!SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) {
EventBus.getDefault().post(new EBReuse("Refresh"));
AppExecutor.getUiExecutor().execute(() -> EventBus.getDefault().post(new EBReuse("Refresh")));
}
}
});
@ -261,7 +308,6 @@ public class Config {
RetrofitManager.getInstance()
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<NewSettingsEntity>() {
@Override
public void onSuccess(NewSettingsEntity data) {
@ -271,11 +317,11 @@ public class Config {
});
refreshVSettingEntity();
getNewSetting();
RetrofitManager.getInstance()
.getApi().getGameGuidePopup(Build.MANUFACTURER, Build.VERSION.RELEASE, Build.MODEL, channel, BuildConfig.VERSION_NAME)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<GameGuidePopupEntity>() {
@Override
public void onSuccess(GameGuidePopupEntity data) {
@ -287,7 +333,6 @@ public class Config {
if (manufacturer.equals("OPPO") || manufacturer.equals("VIVO")) {
RetrofitManager.getInstance().getNewApi().getBrowserHintUrl(manufacturer)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<ResponseBody>() {
@Override
public void onSuccess(ResponseBody data) {
@ -311,12 +356,13 @@ public class Config {
String filterString = UrlFilterUtils.getFilterQuery(
"manufacturer", Build.MANUFACTURER,
"model", Build.MODEL,
"android_sdk_version", String.valueOf(Build.VERSION.SDK_INT));
"android_sdk_version", String.valueOf(Build.VERSION.SDK_INT),
"rom", MetaUtil.INSTANCE.getRom().name() + " " + MetaUtil.INSTANCE.getRom().getVersionName()
);
RetrofitManager.getInstance()
.getNewApi().getNewSettings(PackageUtils.getGhVersionName(), channel, filterString)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<NewApiSettingsEntity>() {
@Override
public void onSuccess(NewApiSettingsEntity data) {
@ -325,7 +371,7 @@ public class Config {
mNewSimulatorEntity = data.getSimulator();
if (HaloApp.getInstance().isNewForThisVersion && mNightModeSetting != null && mNightModeSetting.getInstall()) {
DarkModeUtils.INSTANCE.updateFollowSystemDarkModeToSp(true);
DarkModeUtils.INSTANCE.initDarkMode();
AppExecutor.getUiExecutor().execute(DarkModeUtils.INSTANCE::initDarkMode);
}
SPUtils.setString(Constants.SP_NEW_API_SETTINGS, GsonUtils.toJson(data));
@ -333,8 +379,31 @@ public class Config {
if (mNewApiSettingsEntity.getGameShieldContents() != null) {
ContentBlockedHelper.INSTANCE.init(mNewApiSettingsEntity.getGameShieldContents());
}
// 更新安装列表是否开启的配置
if (mNewApiSettingsEntity.getInstalledComplianceSwitch() != null) {
PackageHelper.INSTANCE.updateIsGetInstalledPackagesApiAgreedRequired(mNewApiSettingsEntity.getInstalledComplianceSwitch());
} else {
PackageHelper.INSTANCE.updateIsGetInstalledPackagesApiAgreedRequired(false);
}
// 更新包名监听是否开启
if (mNewApiSettingsEntity.isPackageObserveEnable()) {
AppExecutor.getUiExecutor().execute(() -> observePackageChange(mNewApiSettingsEntity.getPackageObserveActions()));
}
}
});
}
}
public static void observePackageChange(NewApiSettingsEntity.PackageObserveActions packageObserveActions) {
PackageChangeBroadcastReceiver receiver = new PackageChangeBroadcastReceiver(packageObserveActions);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(packageObserveActions.getAdd());
intentFilter.addAction(packageObserveActions.getRem());
intentFilter.addAction(packageObserveActions.getRep());
intentFilter.addDataScheme("package");
HaloApp.getInstance().registerReceiver(receiver, intentFilter);
}
}

View File

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

View File

@ -19,6 +19,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.PackageHelper
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
@ -59,7 +60,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private val mDuration = 3000
private var mDisposable: Disposable? = null
private var mAdapter: PackageCheckAdapter? = null
private var mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
private var mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
var gameEntity: GameEntity? = null
var callBack: ConfirmListener? = null
@ -325,7 +326,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
override fun onResume() {
super.onResume()
mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
gameEntity?.packageDialog?.let {
if (isAllPackageInstalled(mAllInstalledPackages, it)) {
callBack?.onConfirm()
@ -363,7 +364,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
mAdapter?.notifyDataSetChanged()
}
}
@ -416,7 +417,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
return
}
val allInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
val allInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
if (isAllPackageInstalled(allInstalledPackages, packageDialogEntity)) {
callBack.onConfirm()
return
@ -453,12 +454,12 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
}
private fun checkDetectionsInstalled(
allInstalledPackages: List<PackageInfo>,
allInstalledPackages: List<String>,
packages: ArrayList<String>
): Boolean {
var isPackagesInstalled = false
packages.forEach { packageName ->
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
val isInstalled = allInstalledPackages.find { it == packageName } != null
if (isInstalled) {
isPackagesInstalled = true
return@forEach
@ -469,7 +470,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
fun isAllPackageInstalled(
allInstalledPackages: List<PackageInfo>,
allInstalledPackages: List<String>,
packageDialogEntity: PackageDialogEntity
): Boolean {
var isAllInstalled = true

View File

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

View File

@ -1,13 +1,13 @@
package com.gh.common.exposure
import com.aliyun.sls.android.producer.Log
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.common.loghub.LoghubHelper
import com.gh.gamecenter.common.loghub.TLogHubHelper
import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.lightgame.utils.Utils
import com.volcengine.model.tls.LogItem
/**
* A handful tool for committing logs to aliyun loghub.
@ -78,19 +78,20 @@ object ExposureManager {
private fun uploadExposures(eventSet: HashSet<ExposureEvent>, forced: Boolean) {
eventSet.forEach {
LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced)
TLogHubHelper.sendLog(buildLog(it), LOG_STORE)
// LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced)
// it.recycle()
}
}
private fun buildLog(event: ExposureEvent) = Log().apply {
putContent("id", event.id)
putContent("payload", event.payload.toJson())
putContent("event", event.event.toString())
putContent("source", eliminateMultipleBrackets(event.source.toJson()))
putContent("meta", event.meta.toJson())
putContent("real_millisecond", event.timeInMillisecond.toString())
putContent(
private fun buildLog(event: ExposureEvent) = LogItem(System.currentTimeMillis()).apply {
addContent("__id", event.id)
addContent("payload", event.payload.toJson())
addContent("event", event.event.toString())
addContent("source", eliminateMultipleBrackets(event.source.toJson()))
addContent("meta", event.meta.toJson())
addContent("real_millisecond", event.timeInMillisecond.toString())
addContent(
"e-traces", if (event.eTrace != null) {
eliminateMultipleBrackets(event.eTrace?.toJson() ?: "")
} else ""

View File

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

View File

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

View File

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

View File

@ -9,13 +9,17 @@ import androidx.fragment.app.FragmentActivity
import com.gh.common.iinterface.ISuperiorChain
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.SplashAdActivity
import com.gh.gamecenter.SplashScreenActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.DialogEntity
import com.gh.gamecenter.feature.entity.WelcomeDialogEntity
import com.gh.gamecenter.hud.PendingInstallHUDHandler
import com.gh.gamecenter.hud.ResumeDownloadHudHandler
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
@ -42,18 +46,21 @@ object GlobalPriorityChainHelper : ISuperiorChain {
return activity is FragmentActivity
&& !activity.isFinishing
&& activity !is SplashScreenActivity
&& activity !is SplashAdActivity
}
/**
* 预启动所有的优先级弹窗管理链
*/
fun preStart() {
fun preStart(withSpecialDelay: Boolean) {
val launchRedirectHandler = LaunchRedirectHandler(-101)
val updateDialogHandler = UpdateDialogHandler(-100)
val privacyPolicyDialogHandler = PrivacyPolicyDialogHandler(-99)
val notificationPermissionDialogHandler = NotificationPermissionDialogHandler(0)
val reserveDialogHandler = ReserveDialogHandler(1)
val welcomeDialogHandler = WelcomeDialogHandler(2)
val pendingInstallHandler = PendingInstallHUDHandler(3)
val resumeDownloadHandler = ResumeDownloadHudHandler(4)
mainChain.addHandler(launchRedirectHandler)
mainChain.addHandler(updateDialogHandler)
@ -61,11 +68,18 @@ object GlobalPriorityChainHelper : ISuperiorChain {
mainChain.addHandler(welcomeDialogHandler)
mainChain.addHandler(reserveDialogHandler)
mainChain.addHandler(notificationPermissionDialogHandler)
mainChain.addHandler(pendingInstallHandler)
mainChain.addHandler(resumeDownloadHandler)
launchRedirectHandler.doPreProcess()
updateDialogHandler.doPreProcess()
requestOpeningDialogData(welcomeDialogHandler, privacyPolicyDialogHandler)
requestReserveDialogData(reserveDialogHandler)
// 首次启动延迟 300ms保证请求首次启动时已经获取到了 GID 、 OAID 等标记
val requestDelay = if (withSpecialDelay) 300L else 0L
AppExecutor.uiExecutor.executeWithDelay({
requestOpeningDialogData(welcomeDialogHandler, privacyPolicyDialogHandler)
requestReserveDialogData(reserveDialogHandler)
}, requestDelay)
}
/**
@ -123,6 +137,17 @@ object GlobalPriorityChainHelper : ISuperiorChain {
mainChain.resume()
}
/**
* 添加新的 handler 到优先级弹窗管理链 (插队!)
*/
fun queueNewHandler(handler: PriorityChainHandler) {
if (mainChain.isHandlerQueueEmpty()) {
observeLifecycle()
}
mainChain.addHandler(handler)
}
/**
* 请求首页启动弹窗相关的数据并执行相关 handler 的 preProcess
*/

View File

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

View File

@ -0,0 +1,28 @@
package com.gh.common.prioritychain
import androidx.fragment.app.FragmentActivity
import com.gh.common.util.PackageHelper
import com.gh.gamecenter.common.base.GlobalActivityManager
class RequestInstalledListPermissionHandler : PriorityChainHandler(-1000) {
init {
updateStatus(STATUS_VALID)
}
override fun onProcess(): Boolean {
val currentActivity = GlobalActivityManager.currentActivity ?: return false
if (currentActivity !is FragmentActivity) return false
PackageHelper.showGetInstallAppsListDialogAndRequestPermissionIfNeeded(
activity = currentActivity,
ignorePermanentlyDenied = true
) {
processNext()
}
return true
}
}

View File

@ -0,0 +1,16 @@
package com.gh.common.prioritychain
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
class VideoHandler(priority: Int, val scrollCalculatorHelper: ScrollCalculatorHelper): PriorityChainHandler(priority) {
init {
updateStatus(STATUS_VALID)
}
override fun onProcess(): Boolean {
scrollCalculatorHelper.enableAndPlayIfValid()
return true
}
}

View File

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

View File

@ -32,5 +32,6 @@ class BuildConfigImpl : IBuildConfigProvider {
override fun getVApiHost(): String = BuildConfig.VAPI_HOST
override fun getVDevApiHost(): String = BuildConfig.DEV_VAPI_HOST
override fun getLogProducerProject(): String = BuildConfig.LOG_HUB_PROJECT
}

View File

@ -0,0 +1,103 @@
package com.gh.common.provider
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.viewbinding.ViewBinding
import com.alibaba.android.arouter.facade.annotation.Route
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.util.ConcernContentUtils
import com.gh.common.view.ImageContainerView
import com.gh.gamecenter.ImageViewerActivity.Companion.getIntent
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.toArrayList
import com.gh.gamecenter.core.provider.IConcernArticleUtilsProvider
import com.gh.gamecenter.databinding.RecyclerGameArticleBinding
import com.gh.gamecenter.R
@Route(path = RouteConsts.provider.concernContentUtils, name = "ConcernContentUtils暴露服务")
class ConcernArticleUtilsProviderImpl : IConcernArticleUtilsProvider {
override fun addContentPic(
context: Context,
linearLayout: LinearLayout,
list: List<String>,
entrance: String,
width: Int
) {
ConcernContentUtils.addContentPic(context, linearLayout, list, entrance, width)
}
override fun createArticleBinding(parent: ViewGroup): ViewBinding {
val inflater = LayoutInflater.from(parent.context)
return RecyclerGameArticleBinding.inflate(inflater, parent, false)
}
override fun initArticleStyle(binding: ViewBinding) {
if (binding is RecyclerGameArticleBinding) {
val context = binding.root.context
binding.root
.setBackground(ContextCompat.getDrawable(context, R.drawable.reuse_listview_item_style))
binding.tvGameName.setTextColor(ContextCompat.getColor(context, R.color.text_primary))
binding.tvTime.setTextColor(ContextCompat.getColor(context, R.color.text_tertiary))
binding.tvTitle.setTextColor(ContextCompat.getColor(context, R.color.text_primary))
binding.tvDescription.setTextColor(ContextCompat.getColor(context, R.color.text_secondary))
binding.tvComment.setTextColor(ContextCompat.getColor(context, R.color.text_tertiary))
binding.tvShare.setTextColor(ContextCompat.getColor(context, R.color.text_tertiary))
}
}
override fun getIvIcon(binding: ViewBinding): View =
(binding as RecyclerGameArticleBinding).ivIcon
override fun getTvGameName(binding: ViewBinding): TextView =
(binding as RecyclerGameArticleBinding).tvGameName
override fun getTvTime(binding: ViewBinding): TextView = (binding as RecyclerGameArticleBinding).tvTime
override fun getTvTitle(binding: ViewBinding): TextView = (binding as RecyclerGameArticleBinding).tvTitle
override fun getTvDescription(binding: ViewBinding): TextView =
(binding as RecyclerGameArticleBinding).tvDescription
override fun bindImgs(binding: ViewBinding, img: List<String>) {
if (binding is RecyclerGameArticleBinding) {
val images = img.map {
ImageContainerView.ImageContainerData.ImageInfo(it, 3, 2)
}
val imageContainerData =
ImageContainerView.ImageContainerData("", false, images, show = images.isNotEmpty())
binding.ivImagesContainer.bindData(imageContainerData,
object : ImageContainerView.OnImageContainerEventListener {
override fun onImageClick(
images: List<String>,
position: Int,
imageViewList: ArrayList<SimpleDraweeView>
) {
val checkIntent = getIntent(
binding.root.context,
images.toArrayList(),
position,
imageViewList,
""
)
binding.root.context.startActivity(checkIntent)
}
override fun onVideoCLick(videoId: String) = Unit
})
}
}
override fun getTvComment(binding: ViewBinding): TextView = (binding as RecyclerGameArticleBinding).tvComment
override fun getTvShare(binding: ViewBinding): TextView = (binding as RecyclerGameArticleBinding).tvShare
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -1,26 +0,0 @@
package com.gh.common.provider
import android.content.Context
import android.widget.LinearLayout
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.ConcernContentUtils
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IConcernContentUtilsProvider
@Route(path = RouteConsts.provider.concernContentUtils, name = "ConcernContentUtils暴露服务")
class ConcernContentUtilsProviderImpl : IConcernContentUtilsProvider {
override fun addContentPic(
context: Context,
linearLayout: LinearLayout,
list: List<String>,
entrance: String,
width: Int
) {
ConcernContentUtils.addContentPic(context, linearLayout, list, entrance, width)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -0,0 +1,55 @@
package com.gh.common.provider
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.viewbinding.ViewBinding
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.provider.IConcernGiftPackUtilsProvider
import com.gh.gamecenter.databinding.RecyclerGiftPackBinding
@Route(path = RouteConsts.provider.concernGiftPackUtils, name = "ConcernGiftPackUtils暴露服务")
class ConcernGiftPackUtilsProviderImpl : IConcernGiftPackUtilsProvider {
override fun createBinding(parent: ViewGroup): ViewBinding {
val inflater = LayoutInflater.from(parent.context)
return RecyclerGiftPackBinding.inflate(inflater, parent, false)
.also {
it.gCode.goneIf(true)
}
}
override fun initStyle(viewBinding: ViewBinding) {
with(viewBinding as RecyclerGiftPackBinding) {
val context = root.context
tvGameName.setTextColor(R.color.text_primary.toColor(context))
tvTime.setTextColor(R.color.text_tertiary.toColor(context))
tvGiftPackName.setTextColor(R.color.text_primary.toColor(context))
tvGiftPackContent.setTextColor(R.color.text_secondary.toColor(context))
}
}
override fun getIvGameIcon(viewBinding: ViewBinding) =
(viewBinding as RecyclerGiftPackBinding).ivIcon
override fun getTvGameName(viewBinding: ViewBinding) =
(viewBinding as RecyclerGiftPackBinding).tvGameName
override fun getTvTime(viewBinding: ViewBinding) =
(viewBinding as RecyclerGiftPackBinding).tvTime
override fun getTvGiftPackName(viewBinding: ViewBinding) =
(viewBinding as RecyclerGiftPackBinding).tvGiftPackName
override fun getTvGiftPackContent(viewBinding: ViewBinding) =
(viewBinding as RecyclerGiftPackBinding).tvGiftPackContent
override fun init(context: Context?) {
// Do Nothing
}
}

View File

@ -0,0 +1,19 @@
package com.gh.common.provider
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IConcernShareNewsProvider
import com.gh.gamecenter.newsdetail.NewsShareDialog
@Route(path = RouteConsts.provider.concernShareNews, name = "ConcernShareNews暴露服务")
class ConcernShareNewsProviderImpl : IConcernShareNewsProvider {
override fun share(activity: AppCompatActivity, shortId: String?, id: String?, gameIcon: String?, title: String?) {
NewsShareDialog.show(activity, shortId, id, gameIcon, title)
}
override fun init(context: Context?) {
// Do Nothing
}
}

View File

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

View File

@ -1,5 +1,6 @@
package com.gh.common.provider
import android.app.Activity
import android.content.Context
import android.os.Bundle
import com.alibaba.android.arouter.facade.annotation.Route
@ -22,34 +23,6 @@ class DirectProviderImpl : IDirectProvider {
DirectUtils.directToQqConversation(context, qq)
}
override fun directToCommodityDetail(context: Context, commodityId: String) {
DirectUtils.directToCommodityDetail(context, commodityId)
}
override fun directToEnergyRecord(context: Context) {
DirectUtils.directToEnergyRecord(context)
}
override fun directToEnergyRulePage(context: Context) {
DirectUtils.directToEnergyRulePage(context)
}
override fun directToInviteFriends(context: Context) {
DirectUtils.directToInviteFriends(context)
}
override fun directToExchangeRulePage(context: Context) {
DirectUtils.directToExchangeRulePage(context)
}
override fun directToExchangeCommodityPage(context: Context) {
DirectUtils.directToExchangeCommodityPage(context)
}
override fun directToLotteryParadisePage(context: Context) {
DirectUtils.directToLotteryParadisePage(context)
}
override fun directDouyin(context: Context, userId: String) {
DirectUtils.directDouyin(context, userId)
}
@ -97,30 +70,18 @@ class DirectProviderImpl : IDirectProvider {
DirectUtils.directToAmway(context, fixedTopAmwayCommentId, entrance, path)
}
override fun directToOrderCenter(context: Context) {
DirectUtils.directToOrderCenter(context)
}
override fun directToOrderDetail(context: Context, orderId: String) {
DirectUtils.directToOrderDetail(context, orderId)
}
override fun directToEnergyRecord(context: Context, position: Int) {
DirectUtils.directToEnergyRecord(context, position)
}
override fun directToMyPrizePage(context: Context) {
DirectUtils.directToMyPrizePage(context)
}
override fun directToWinOrderDetail(context: Context, orderId: String, activityId: String) {
DirectUtils.directToWinOrderDetail(context, orderId, activityId)
}
override fun directToQGame(context: Context) {
override fun directToQQGameHome(context: Context) {
return DirectUtils.directToQGameHome(context)
}
override fun directToQQGameById(activity: Activity, qqAppId: String) {
DirectUtils.directToQQGameById(activity, qqAppId)
}
override fun directToWechatGameById(activity: Activity, qqAppId: String) {
DirectUtils.directToWechatGameById(activity, qqAppId)
}
override fun directToExternalBrowser(context: Context, url: String) {
DirectUtils.directToExternalBrowser(context, url)
}

View File

@ -1,11 +1,16 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import androidx.fragment.app.FragmentActivity
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.common.avoidcallback.Callback
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IEntranceUtilsProvider
import com.lightgame.utils.AppManager
@Route(path = RouteConsts.provider.entranceUtils, name = "EntranceUtils暴露服务")
class EntranceUtilsProviderImpl : IEntranceUtilsProvider {
@ -17,6 +22,19 @@ class EntranceUtilsProviderImpl : IEntranceUtilsProvider {
EntranceUtils.saveShortcut(activityName, bundle)
}
override fun jumpActivityWithCallback(context: Context, bundle: Bundle, callback: () -> Unit) {
if (context is FragmentActivity && !context.supportFragmentManager.isDestroyed) {
EntranceUtils.jumpActivity(context, null, bundle, object : Callback {
override fun onActivityResult(resultCode: Int, data: Intent?) {
callback()
}
})
} else {
EntranceUtils.jumpActivity(AppManager.getInstance().currentActivity(), bundle)
}
}
override fun init(context: Context?) {
// Do nothing
}

View File

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

View File

@ -3,6 +3,7 @@ package com.gh.common.provider
import android.content.Context
import android.content.pm.PackageInfo
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.PackageHelper
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IPackageUtilsProvider
@ -23,7 +24,7 @@ class PackageUtilsProviderImpl : IPackageUtilsProvider {
}
override fun getInstalledPackages(context: Context, flag: Int): List<PackageInfo> {
return PackageUtils.getInstalledPackages(context, flag)
return PackageHelper.getInstalledPackageInfoList(context, flag)
}
override fun getApkSignatureByPackageName(context: Context, packageName: String): Array<String> {
@ -38,6 +39,10 @@ class PackageUtilsProviderImpl : IPackageUtilsProvider {
return PackageUtils.isSignedByGh(context, packageName)
}
override fun isInstalledWithLauncherIcon(context: Context, packageName: String): Boolean {
return PackageUtils.isInstalled(context, packageName)
}
override fun getInstalledTime(context: Context, packageName: String): Long {
return PackageUtils.getInstalledTime(context, packageName)
}

View File

@ -166,162 +166,160 @@ class SimulatorDownloadManager private constructor() {
this.gameName = gameName
this.gameType = gameCategoryChinese
PermissionHelper.checkGetInstalledAppsListBeforeAction(context, object : EmptyCallback {
override fun onCallback() {
val isInstalledNewSimulator =
SimulatorGameManager.isNewSimulatorInstalled(HaloApp.getInstance().application)
//当没有安装新版本模拟器时候 判断是否隐藏
if (simulator?.active == false && !isInstalledNewSimulator) {
showNoneEmulatorDialog(context)
return
}
var isInstalled = PackageUtils.isInstalledFromAllPackage(
context,
simulator?.apk?.packageName
)
//模拟器管理界面还是用之前的逻辑
if (isInstalledNewSimulator && location != SimulatorLocation.SIMULATOR_MANAGE) {
isInstalled = isInstalledNewSimulator
}
// val versionFromInstalledApp = PackageUtils.getVersionNameByPackageName(simulator?.apk?.packageName)
val shouldShowUpdate =
PackageUtils.isInstalledApkMatchedMd5(simulator?.apk?.packageName, simulator?.apk?.md5)
val showAlertTag = SPUtils.getString(SimulatorGameManager.SIMULATOR_UPDATE_SHOW_ALERT_TAG, "") //当天是否弹过
val todayIsShow = showAlertTag == TimeUtils.getToday()
downloadType = if (shouldShowUpdate && isInstalled) "update" else "download"
if (downloadType == "update" && todayIsShow && location != SimulatorLocation.SIMULATOR_MANAGE) {
return
}
if (downloadType == "download" && isInstalled) {
return
}
val title = if (shouldShowUpdate && isInstalled) "更新模拟器" else "安装模拟器"
val message =
if (shouldShowUpdate && isInstalled) "检测到模拟器存在更高版本,是否前往更新" else "模拟器游戏需要先下载安装对应的模拟器,才可以运行"
val positiveText =
if (shouldShowUpdate && isInstalled) "更新(${simulator?.apk?.size}" else "下载(${simulator?.apk?.size}"
val negativeText = if (shouldShowUpdate && isInstalled) "下次再说" else "取消"
val trackableEntity = TrackableEntity(
"模拟器下载",
key = if (shouldShowUpdate && isInstalled) "更新弹窗" else "下载弹窗",
logShowEvent = true
)
if (shouldShowUpdate && isInstalled) {
NewFlatLogUtils.logSimulatorUpdateAlertShow()
}
if (shouldShowUpdate && isInstalled) {
SensorsBridge.trackSimulatorUpdateDialogShow(
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
} else {
SensorsBridge.trackSimulatorInstallDialogShow(
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
DialogHelper.showDialog(
context,
title,
message,
positiveText,
negativeText,
trackMtaEvent = true,
cancelClickCallback = {
if (shouldShowUpdate && isInstalled) {
cancelCallback?.invoke()
NewFlatLogUtils.logSimulatorUpdateAlertClick("取消")
MtaHelper.onEvent(trackableEntity.event, trackableEntity.key, "点击下次再说")
SensorsBridge.trackSimulatorUpdateDialogClick(
buttonName = negativeText,
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
} else {
SensorsBridge.trackSimulatorInstallDialogClick(
buttonName = negativeText,
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
},
confirmClickCallback = {
showDownloadingDialog(context, simulator, gameId, gameName, gameCategoryChinese)
NewFlatLogUtils.logSimulatorUpdateAlertClick("更新")
MtaHelper.onEvent(
trackableEntity.event,
trackableEntity.key,
if (shouldShowUpdate && isInstalled) "点击更新" else "点击下载"
)
if (shouldShowUpdate && isInstalled) {
SensorsBridge.trackSimulatorUpdateDialogClick(
buttonName = positiveText,
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
} else {
SensorsBridge.trackSimulatorInstallDialogClick(
buttonName = positiveText,
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
},
touchOutsideCallback = {
if (shouldShowUpdate && isInstalled) {
SensorsBridge.trackSimulatorUpdateDialogClick(
buttonName = "关闭弹窗",
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
} else {
SensorsBridge.trackSimulatorInstallDialogClick(
buttonName = "关闭弹窗",
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
},
mtaEvent = trackableEntity.event, mtaKey = trackableEntity.key,
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
if (downloadType == "update" && location != SimulatorLocation.SIMULATOR_MANAGE) {
SPUtils.setString(SimulatorGameManager.SIMULATOR_UPDATE_SHOW_ALERT_TAG, TimeUtils.getToday())
}
PermissionHelper.checkGetInstalledAppsListBeforeAction(context) { _ ->
val isInstalledNewSimulator =
SimulatorGameManager.isNewSimulatorInstalled(HaloApp.getInstance().application)
//当没有安装新版本模拟器时候 判断是否隐藏
if (simulator?.active == false && !isInstalledNewSimulator) {
showNoneEmulatorDialog(context)
return@checkGetInstalledAppsListBeforeAction
}
})
var isInstalled = PackageUtils.isInstalledFromAllPackage(
context,
simulator?.apk?.packageName
)
//模拟器管理界面还是用之前的逻辑
if (isInstalledNewSimulator && location != SimulatorLocation.SIMULATOR_MANAGE) {
isInstalled = isInstalledNewSimulator
}
// val versionFromInstalledApp = PackageUtils.getVersionNameByPackageName(simulator?.apk?.packageName)
val shouldShowUpdate =
PackageUtils.isInstalledApkMatchedMd5(simulator?.apk?.packageName, simulator?.apk?.md5)
val showAlertTag = SPUtils.getString(SimulatorGameManager.SIMULATOR_UPDATE_SHOW_ALERT_TAG, "") //当天是否弹过
val todayIsShow = showAlertTag == TimeUtils.getToday()
downloadType = if (shouldShowUpdate && isInstalled) "update" else "download"
if (downloadType == "update" && todayIsShow && location != SimulatorLocation.SIMULATOR_MANAGE) {
return@checkGetInstalledAppsListBeforeAction
}
if (downloadType == "download" && isInstalled) {
return@checkGetInstalledAppsListBeforeAction
}
val title = if (shouldShowUpdate && isInstalled) "更新模拟器" else "安装模拟器"
val message =
if (shouldShowUpdate && isInstalled) "检测到模拟器存在更高版本,是否前往更新" else "模拟器游戏需要先下载安装对应的模拟器,才可以运行"
val positiveText =
if (shouldShowUpdate && isInstalled) "更新(${simulator?.apk?.size}" else "下载(${simulator?.apk?.size}"
val negativeText = if (shouldShowUpdate && isInstalled) "下次再说" else "取消"
val trackableEntity = TrackableEntity(
"模拟器下载",
key = if (shouldShowUpdate && isInstalled) "更新弹窗" else "下载弹窗",
logShowEvent = true
)
if (shouldShowUpdate && isInstalled) {
NewFlatLogUtils.logSimulatorUpdateAlertShow()
}
if (shouldShowUpdate && isInstalled) {
SensorsBridge.trackSimulatorUpdateDialogShow(
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
} else {
SensorsBridge.trackSimulatorInstallDialogShow(
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
DialogHelper.showDialog(
context,
title,
message,
positiveText,
negativeText,
trackMtaEvent = true,
cancelClickCallback = {
if (shouldShowUpdate && isInstalled) {
cancelCallback?.invoke()
NewFlatLogUtils.logSimulatorUpdateAlertClick("取消")
MtaHelper.onEvent(trackableEntity.event, trackableEntity.key, "点击下次再说")
SensorsBridge.trackSimulatorUpdateDialogClick(
buttonName = negativeText,
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
} else {
SensorsBridge.trackSimulatorInstallDialogClick(
buttonName = negativeText,
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
},
confirmClickCallback = {
showDownloadingDialog(context, simulator, gameId, gameName, gameCategoryChinese)
NewFlatLogUtils.logSimulatorUpdateAlertClick("更新")
MtaHelper.onEvent(
trackableEntity.event,
trackableEntity.key,
if (shouldShowUpdate && isInstalled) "点击更新" else "点击下载"
)
if (shouldShowUpdate && isInstalled) {
SensorsBridge.trackSimulatorUpdateDialogClick(
buttonName = positiveText,
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
} else {
SensorsBridge.trackSimulatorInstallDialogClick(
buttonName = positiveText,
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
},
touchOutsideCallback = {
if (shouldShowUpdate && isInstalled) {
SensorsBridge.trackSimulatorUpdateDialogClick(
buttonName = "关闭弹窗",
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
} else {
SensorsBridge.trackSimulatorInstallDialogClick(
buttonName = "关闭弹窗",
gameId = gameId,
gameName = gameName,
gameType = gameCategoryChinese,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
},
mtaEvent = trackableEntity.event, mtaKey = trackableEntity.key,
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
if (downloadType == "update" && location != SimulatorLocation.SIMULATOR_MANAGE) {
SPUtils.setString(SimulatorGameManager.SIMULATOR_UPDATE_SHOW_ALERT_TAG, TimeUtils.getToday())
}
}
}
fun showDownloadingDialog(

View File

@ -19,8 +19,10 @@ import com.gh.gamecenter.databinding.DialogArchiveLoadingBinding
import com.gh.gamecenter.entity.ArchiveEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.va.VCore
import com.gh.vspace.VArchiveHelper
import com.gh.vspace.VHelper
import com.gh.vspace.VHelper.is32
import com.lg.download.DownloadError
import com.lg.download.DownloadStatus
import io.reactivex.schedulers.Schedulers
@ -50,8 +52,6 @@ object ArchiveDownloadButtonHelper {
}
downloadBtn.setOnClickListener {
when {
// 检查是否已安装畅玩助手
!VHelper.isVSpaceInstalled(context) -> showVSpaceTipDialog(context, gameEntity)
// 检查是否已安装游戏
!VHelper.isInstalled(packageName) -> {
// 检查游戏是否在安装中
@ -273,14 +273,19 @@ object ArchiveDownloadButtonHelper {
R.string.archive_apply.toResString(),
R.string.cancel.toResString(),
{
applyArchive(context, entrance, packageName, config, archiveEntity, gameEntity)
NewFlatLogUtils.logCloudArchiveApplyDialogRelated("cloud_save_overwrite_dialog_click", "使用")
SensorsBridge.trackEvent(
"CloudSaveOverwriteDialogClick",
"game_id", gameEntity?.id ?: "",
"game_name", gameEntity?.name ?: "",
"button_name", "使用"
)
if(gameEntity.is32() && VHelper.isInnerInstalled(packageName) && !VCore.getInstance().isExtPackageInstalled()) {
// 32位的游戏 并且 32位畅玩没有安装 并且 一体化
VHelper.newCwValidateVspaceBeforeAction(context, gameEntity) {}
} else {
applyArchive(context, entrance, packageName, config, archiveEntity, gameEntity)
NewFlatLogUtils.logCloudArchiveApplyDialogRelated("cloud_save_overwrite_dialog_click", "使用")
SensorsBridge.trackEvent(
"CloudSaveOverwriteDialogClick",
"game_id", gameEntity?.id ?: "",
"game_name", gameEntity?.name ?: "",
"button_name", "使用"
)
}
},
{
NewFlatLogUtils.logCloudArchiveApplyDialogRelated("cloud_save_overwrite_dialog_click", "取消")

View File

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

View File

@ -7,8 +7,8 @@ import android.widget.LinearLayout;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.gamecenter.ImageViewerActivity;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.common.utils.ImageUtils;
import com.gh.gamecenter.core.utils.DisplayUtils;
import java.util.ArrayList;
import java.util.List;
@ -121,5 +121,4 @@ public class ConcernContentUtils {
}
return imageView;
}
}

View File

@ -1,17 +1,14 @@
package com.gh.common.util;
import android.content.Context;
import android.os.Build;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.utils.NetworkUtils;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.entity.NewsDetailEntity;
import com.gh.gamecenter.feature.utils.PlatformUtils;
import com.gh.gamecenter.manager.DataCollectionManager;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DownloadEntity;
import java.util.HashMap;
@ -32,7 +29,7 @@ public class DataCollectionUtils {
map.put("type", android.os.Build.MODEL);
map.put("system", android.os.Build.VERSION.SDK_INT + "=" + android.os.Build.VERSION.RELEASE);
// WIFI实时
DataCollectionManager.onEvent(context, "error", map, NetworkUtils.isWifiConnected(context));
DataCollectionManager.onEvent(context, "error", map, true);
}
// 上传下载数据(开始、完成)

View File

@ -9,19 +9,18 @@ import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import com.alibaba.android.arouter.launcher.ARouter;
import com.gh.ad.AdDelegateHelper;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.base.GlobalActivityManager;
import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.common.constant.RouteConsts;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.provider.ISentryProvider;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.feature.utils.SentryHelper;
import com.gh.gamecenter.login.entity.IdCardEntity;
import com.gh.gamecenter.login.entity.UserInfoEntity;
import com.gh.gamecenter.provider.GhContentProvider;
@ -32,12 +31,7 @@ import com.halo.assistant.HaloApp;
import com.lightgame.config.CommonDebug;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import io.reactivex.schedulers.Schedulers;
import io.sentry.Sentry;
import io.sentry.android.core.SentryAndroid;
import kotlin.Pair;
/**
* Created by LGT on 2016/6/15.
@ -61,92 +55,58 @@ public class DataUtils {
}
private static void initSentry(Context context, String channel) {
SentryAndroid.init(context, options -> {
// Sentry 疯狂报 ANR (很大一部分还是莫名奇妙的 ANR)严重影响到其它闪退日志的收集
// 这里将它局限到只有官网渠道的包才统计 ANR
if ("GH_206".equals(channel) || "GH_BETA".equals(channel) || com.gh.gamecenter.common.BuildConfig.BUILD_TIME != 0) {
options.setAnrEnabled(true);
options.setAnrTimeoutIntervalMillis(6000);
} else {
options.setAnrEnabled(false);
}
options.setDebug(BuildConfig.DEBUG);
options.setEnableAutoSessionTracking(true);
options.setEnvironment(BuildConfig.FLAVOR);
options.setEnableSystemEventBreadcrumbs(false);
options.setDsn("https://6b1caf0d17c1408e8680f3f73ff80bd0@sentry.shanqu.cc/22");
options.setBeforeSend((event, hint) -> {
if (BuildConfig.DEBUG) {
return null;
} else {
return event;
}
});
options.setBeforeBreadcrumb(((breadcrumb, hint) -> {
if ("ui.lifecycle".equals(breadcrumb.getCategory()) && "started".equals(breadcrumb.getData("state")) && GlobalActivityManager.INSTANCE.getCurrentActivity() instanceof BaseActivity) {
Pair<String, String> businessId = ((BaseActivity) GlobalActivityManager.INSTANCE.getCurrentActivity()).getBusinessId();
if (businessId != null) {
breadcrumb.setData("businessId1", businessId.component1());
breadcrumb.setData("businessId2", businessId.component2());
}
}
return breadcrumb;
}));
});
Sentry.configureScope(scope -> {
if (com.gh.gamecenter.common.BuildConfig.BUILD_TIME != 0L) {
scope.setTag("alias", "内测版" + BuildConfig.VERSION_NAME);
} else {
scope.setTag("alias", "正式版" + BuildConfig.VERSION_NAME);
scope.setTag("channel", channel);
}
});
ISentryProvider sentryProvider = (ISentryProvider) ARouter.getInstance().build(RouteConsts.provider.sentry).navigation();
if (sentryProvider != null) {
sentryProvider.init(context, channel, BuildConfig.FLAVOR, BuildConfig.VERSION_NAME);
}
}
public static void getGid() {
GidHelper.getInstance().registerDevice(HaloApp.getInstance().getApplication(), new GidCallback() {
@Override
public void onSuccess(String gid) {
Utils.log("Gid", gid);
PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit().putString(Constants.DEVICE_KEY, gid).apply();
// 默认用 APP 级已存储的 GID 来使用,不使用外部 GID
String savedGid = SPUtils.getString(Constants.GID);
if (!TextUtils.isEmpty(savedGid)) {
HaloApp.getInstance().setGid(savedGid);
onGidReceived(savedGid);
} else {
GidHelper.getInstance().registerDevice(HaloApp.getInstance().getApplication(), new GidCallback() {
@Override
public void onSuccess(String gid) {
Utils.log("Gid", gid);
PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit().putString(Constants.DEVICE_KEY, gid).apply();
// 默认用 APP 级已存储的 GID 来使用,不使用外部 GID
String savedGid = SPUtils.getString(Constants.GID);
if (!TextUtils.isEmpty(savedGid)) {
gid = savedGid;
} else {
SPUtils.setString(Constants.GID, gid);
onGidReceived(gid);
}
HaloApp.getInstance().setGid(gid);
// 更新广告配置
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
getDeviceCertification(gid);
// 避免初始化顺序问题导致 MetaUtil 一直持有空的 gid
MetaUtil.INSTANCE.refreshMeta();
ContentValues values = new ContentValues();
values.put(GhContentProvider.KEY_GID, gid);
values.put(GhContentProvider.KEY_ANDROID_ID, MetaUtil.getBase64EncodedAndroidId());
try {
HaloApp.getInstance().getContentResolver().insert(Uri.parse("content://com.gh.gamecenter.provider/device"), values);
} catch (Exception exception) {
SentryHelper.INSTANCE.onEvent("DEVICE_INSERT_ERROR", "exception_digest", exception.getLocalizedMessage());
exception.printStackTrace();
@Override
public void onFailure(String s) {
// 更新广告配置
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
}
}
});
}
}
@Override
public void onFailure(String s) {
// 更新广告配置
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
private static void onGidReceived(String gid) {
HaloApp.getInstance().setGid(gid);
// 更新广告配置
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
getDeviceCertification(gid);
// 避免初始化顺序问题导致 MetaUtil 一直持有空的 gid
MetaUtil.INSTANCE.refreshMeta();
AppExecutor.getIoExecutor().execute(() -> {
ContentValues values = new ContentValues();
values.put(GhContentProvider.KEY_GID, gid);
values.put(GhContentProvider.KEY_ANDROID_ID, MetaUtil.getBase64EncodedAndroidId());
try {
HaloApp.getInstance().getContentResolver().insert(Uri.parse("content://com.gh.gamecenter.provider/device"), values);
} catch (Exception exception) {
SentryHelper.INSTANCE.onEvent("DEVICE_INSERT_ERROR", "exception_digest", exception.getLocalizedMessage());
exception.printStackTrace();
}
});
}

View File

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

View File

@ -633,7 +633,19 @@ public class DialogUtils {
binding.gameIcon.displayGameIcon(gameEntity);
binding.gameNameTv.setText(context.getString(R.string.dialog_land_page_address_hint, gameEntity.getName()));
binding.closeIv.setOnClickListener(v -> dialog.dismiss());
AtomicBoolean dismissByButton = new AtomicBoolean(false);
binding.closeIv.setOnClickListener(v -> {
dismissByButton.set(true);
SensorsBridge.INSTANCE.trackJumpLandPageAddressDialogClick(
"取消",
gameEntity.getId(),
gameEntity.getName() != null ? gameEntity.getName() : "",
gameEntity.getCategoryChinese()
);
dialog.dismiss();
});
binding.urlTv.setText(gameEntity.getLandPageAddressDialog().getLink());
@ -643,10 +655,28 @@ public class DialogUtils {
binding.downloadBtn.setText(downloadText);
binding.downloadBtn.setOnClickListener(v -> {
dismissByButton.set(true);
SensorsBridge.INSTANCE.trackJumpLandPageAddressDialogClick(
"前往第三方网站下载游戏",
gameEntity.getId(),
gameEntity.getName() != null ? gameEntity.getName() : "",
gameEntity.getCategoryChinese()
);
listener.onConfirm();
dialog.dismiss();
});
dialog.setOnDismissListener(dialog1 -> {
if (!dismissByButton.get()) {
SensorsBridge.INSTANCE.trackJumpLandPageAddressDialogClick(
"关闭弹窗",
gameEntity.getId(),
gameEntity.getName() != null ? gameEntity.getName() : "",
gameEntity.getCategoryChinese()
);
}
});
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
@ -655,6 +685,12 @@ public class DialogUtils {
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
SensorsBridge.INSTANCE.trackJumpLandPageAddressDialogShow(
gameEntity.getId(),
gameEntity.getName() != null ? gameEntity.getName() : "",
gameEntity.getCategoryChinese()
);
}
public static void showGameH5DownloadDialog(Context context, GameEntity gameEntity, RegionSetting.GameH5Download gameH5Download) {

View File

@ -10,6 +10,7 @@ import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureManager.log
@ -18,8 +19,6 @@ import com.gh.common.util.EntranceUtils.jumpActivity
import com.gh.common.util.EntranceUtils.jumpActivityCompat
import com.gh.gamecenter.*
import com.gh.gamecenter.amway.AmwayActivity
import com.gh.gamecenter.catalog.CatalogActivity
import com.gh.gamecenter.category.CategoryDirectoryActivity
import com.gh.gamecenter.category2.CategoryV2Activity
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.base.activity.BaseActivity_TabLayout
@ -43,11 +42,13 @@ import com.gh.gamecenter.feature.entity.MeEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.feature.provider.IConcernInfoProvider
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.forum.home.CommunityActivity
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailActivity
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailFragment
import com.gh.gamecenter.game.commoncollection.detail.CustomCommonCollectionDetailActivity
import com.gh.gamecenter.game.upload.GameSubmissionActivity
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
@ -63,6 +64,9 @@ import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.help.HelpAndFeedbackBridge
import com.gh.gamecenter.libao.LibaoDetailActivity
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.minigame.MiniGameRecentlyPlayUseCase
import com.gh.gamecenter.minigame.MiniGameSearchActivity
import com.gh.gamecenter.minigame.qq.QGameHomeWrapperActivity
import com.gh.gamecenter.newsdetail.NewsDetailActivity
import com.gh.gamecenter.personalhome.UserHomeActivity
import com.gh.gamecenter.personalhome.background.PersonalityBackgroundActivity
@ -73,9 +77,6 @@ import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
import com.gh.gamecenter.qgame.QGameHomeWrapperActivity
import com.gh.gamecenter.qgame.QGameSearchActivity
import com.gh.gamecenter.qgame.QGameViewModel
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.servers.GameServerTestActivity
import com.gh.gamecenter.servers.GameServersActivity
@ -95,6 +96,8 @@ import com.gh.vspace.VDownloadManagerActivity
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.WebFragment
import com.lightgame.utils.Utils
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
@ -108,8 +111,14 @@ import kotlin.math.roundToInt
object DirectUtils {
@JvmStatic
fun directToLinkPage(context: Context, linkEntity: LinkEntity, entrance: String, path: String, sourceEntrance: String = "") {
directToLinkPage(context, linkEntity, entrance, path, null, sourceEntrance)
fun directToLinkPage(
context: Context,
linkEntity: LinkEntity,
entrance: String,
path: String,
sourceEntrance: String = ""
) {
directToLinkPage(context, linkEntity, entrance, path, null, sourceEntrance)
}
@JvmStatic
@ -140,14 +149,12 @@ object DirectUtils {
"qqqun",
"tag",
"all_community_article",
"category",
"block",
"column_collection",
"server",
"top_game_comment",
"wechat_bind",
"video",
"catalog",
"category_v2",
"common_collection",
"game_list",
@ -243,7 +250,7 @@ object DirectUtils {
path
)
HOST_WEB, HOST_WEB_INURL, HOST_WEB_AL -> {
HOST_WEB, HOST_WEB_INURL, HOST_WEB_AL, HOST_QA_CONTENT -> {
when {
linkEntity.link!!.contains("v.douyin") && PackageHelper.localPackageNameSet.contains("com.ss.android.ugc.aweme") -> {
directDouyin(context, "1402577827140941")
@ -274,10 +281,6 @@ object DirectUtils {
)
)
"category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!)
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
"category_v2" -> directCategoryV2(
context,
linkEntity.link!!,
@ -343,9 +346,9 @@ object DirectUtils {
"feedback" -> directToFeedback(context, linkEntity.name, false, "", false, false, entrance)
"qa", "qa_content", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
"qa", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
"qa_list" -> directToHelpAndFeedback(context)
"qa_list" -> directToHelpAndFeedback(context, bundleOf(KEY_ENTRANCE to entrance))
"qa_collection", "Q&A合集" -> directToQaCollection(
context, linkEntity.text
@ -470,22 +473,28 @@ object DirectUtils {
"column_test_v2" -> context.startActivity(
GameServerTestV2Activity.getIntent(
context,
linkEntity.link ?: "none",
entrance,
exposureEvent
)
)
"qq_mini_game_column" -> directToQGameHome(context)
ColumnCollectionDetailFragment.TYPE_QQ_MINI_GAME_COLUMN -> directToQGameHome(context)
// QQ游戏专题详情页
"qq_mini_game_column_detail" -> {
ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN, ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN -> {
val subjectType = if (linkEntity.type == ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN) {
SubjectData.SubjectType.QQ_GAME
} else {
SubjectData.SubjectType.WECHAT_GAME
}
directToSubject(
context = context,
id = linkEntity.link ?: "",
subjectName = linkEntity.text,
entrance = BaseActivity.mergeEntranceAndPath(entrance, path),
exposureEvent = exposureEvent,
isQQMiniGame = true
subjectType = subjectType
)
}
@ -536,6 +545,10 @@ object DirectUtils {
}
}
"wechat_game" -> linkEntity.link?.let {
MiniGameItemHelper.launchMiniGame(it, Constants.WECHAT_MINI_GAME)
}
"" -> {
// do nothing
}
@ -774,7 +787,12 @@ object DirectUtils {
}
}
if (traceEvent != null) {
val clickEvent = createEvent(GameEntity(id = id, name = name), traceEvent.source, appendTrace(traceEvent), ExposureType.CLICK)
val clickEvent = createEvent(
GameEntity(id = id, name = name),
traceEvent.source,
appendTrace(traceEvent),
ExposureType.CLICK
)
log(clickEvent)
bundle.putParcelable(KEY_TRACE_EVENT, clickEvent)
}
@ -837,12 +855,12 @@ object DirectUtils {
subjectName: String? = "",
entrance: String? = null,
exposureEvent: ExposureEvent? = null,
isQQMiniGame: Boolean = false,
subjectType: SubjectData.SubjectType = SubjectData.SubjectType.NORMAL
) {
if (id.isEmpty()) return
val bundle = Bundle()
val subjectData =
SubjectData(subjectId = id, subjectName = subjectName, isOrder = false, isQQMiniGame = isQQMiniGame)
SubjectData(subjectId = id, subjectName = subjectName, isOrder = false, subjectType = subjectType)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, SubjectActivity::class.java.name)
bundle.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, subjectData)
@ -899,12 +917,16 @@ object DirectUtils {
qaContentId: String? = "",
isPlugin: Boolean = false,
isSmoothGame: Boolean = false,
gameId: String? = "",
gameName: String? = "",
entrance: String? = null
) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putBoolean(KEY_PLUGIN, isPlugin)
bundle.putBoolean(KEY_SMOOTH_GAME, isSmoothGame)
bundle.putString(KEY_GAME_ID, gameId)
bundle.putString(KEY_GAME_NAME, gameName)
if (isPlugin) {
bundle.putString(KEY_HIDE_SUGGEST_HINT, "【插件问题】")
}
@ -991,7 +1013,13 @@ object DirectUtils {
}
@JvmStatic
fun directToQuestionDetail(context: Context, id: String, entrance: String? = null, path: String? = null, sourceEntrance: String = "") {
fun directToQuestionDetail(
context: Context,
id: String,
entrance: String? = null,
path: String? = null,
sourceEntrance: String = ""
) {
if (id.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
@ -1387,47 +1415,6 @@ object DirectUtils {
}
}
/**
* 跳转分类
*/
@JvmStatic
fun directCategoryDirectory(
context: Context,
categoryId: String,
categoryTitle: String,
entrance: String? = null,
path: String? = ""
) {
if (categoryId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, CategoryDirectoryActivity::class.java.name)
bundle.putString(KEY_CATEGORY_ID, categoryId)
bundle.putString(KEY_CATEGORY_TITLE, categoryTitle)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_PATH, path)
jumpActivity(context, bundle)
}
/**
* 跳转新分类
*/
@JvmStatic
fun directCatalog(
context: Context,
catalogId: String,
catalogTitle: String,
entrance: String? = null,
path: String? = "",
) {
if (catalogId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, CatalogActivity::class.java.name)
bundle.putString(KEY_CATALOG_ID, catalogId)
bundle.putString(KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
jumpActivity(context, bundle)
}
/**
* 跳转新分类2.0
*/
@ -1625,211 +1612,6 @@ object DirectUtils {
jumpActivityCompat(context, newBundle)
}
/**
* 跳转至商品详情
*/
@JvmStatic
fun directToCommodityDetail(context: Context, commodityId: String) {
var url: String = if (EnvHelper.isDevEnv) {
Constants.COMMODITY_DETAIL_ADDRESS_DEV
} else {
Constants.COMMODITY_DETAIL_ADDRESS
}
url = String.format(
Locale.CHINA,
"%s&shopid=%s&timestamp=%d",
url,
commodityId,
(Date().time / 1000 / 1000.toFloat()).roundToInt()
)
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至光能记录默认跳到光能记录第一个Tab
*/
@JvmStatic
fun directToEnergyRecord(context: Context) {
directToEnergyRecord(context, 0)
}
@JvmStatic
fun directToEnergyRecord(context: Context, position: Int) {
var url: String = if (EnvHelper.isDevEnv) {
Constants.ENERGY_RECORD_ADDRESS_DEV
} else {
Constants.ENERGY_RECORD_ADDRESS
}
url = String.format(
Locale.CHINA,
"%s&position=%s&timestamp=%d",
url,
position,
(Date().time / 1000 / 1000.toFloat()).roundToInt()
)
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至订单中心
*/
@JvmStatic
fun directToOrderCenter(context: Context) {
val url: String = if (EnvHelper.isDevEnv) {
Constants.ORDER_CENTER_ADDRESS_DEV
} else {
Constants.ORDER_CENTER_ADDRESS
}
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至订单详情
*/
@JvmStatic
fun directToOrderDetail(context: Context, orderId: String) {
var url: String = if (EnvHelper.isDevEnv) {
Constants.ORDER_DETAIL_ADDRESS_DEV
} else {
Constants.ORDER_DETAIL_ADDRESS
}
url = String.format(
Locale.CHINA,
"%s&order_id=%s&timestamp=%d",
url,
orderId,
(Date().time / 1000 / 1000.toFloat()).roundToInt()
)
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至邀请好友
*/
@JvmStatic
fun directToInviteFriends(context: Context) {
val url: String = if (EnvHelper.isDevEnv) {
Constants.INVITE_FRIENDS_ADDRESS_DEV
} else {
Constants.INVITE_FRIENDS_ADDRESS
}
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至等级页面
*/
@JvmStatic
fun directToLevelPage(context: Context) {
var url: String = if (isPublishEnv()) {
Constants.LEVEL_ADDRESS
} else {
Constants.LEVEL_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s?timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至兑换规则
*/
@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&timestamp=%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&timestamp=%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&timestamp=%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&timestamp=%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&timestamp=%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&timestamp=%d",
url,
orderId,
activityId,
(Date().time / 1000 / 1000.toFloat()).roundToInt()
)
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至地址信息
@ -2140,7 +1922,7 @@ object DirectUtils {
}
@JvmStatic
fun directToQGameSearch(
fun directToMiniGameSearch(
context: Context,
hint: String,
sourceEntrance: String,
@ -2152,7 +1934,7 @@ object DirectUtils {
searchBoxPattern: String = ""
) {
context.startActivity(
QGameSearchActivity.getIntent(
MiniGameSearchActivity.getIntent(
context,
hint,
sourceEntrance,
@ -2168,11 +1950,10 @@ object DirectUtils {
@SuppressLint("CheckResult")
@JvmStatic
fun directToQGameById(
fun directToQQGameById(
activity: Activity,
qqGameId: String
qqAppId: String
) {
if (activity !is AppCompatActivity || activity.supportFragmentManager.isDestroyed) {
ToastUtils.toast("启动QQ小游戏失败请稍后再试")
return
@ -2193,25 +1974,40 @@ object DirectUtils {
val qGameProvider = ARouter
.getInstance()
.build(RouteConsts.provider.qGame)
.navigation() as IQGameProvider<*>
qGameProvider.setLoginInfo(activity, userId, userName, userToken)
qGameProvider.launchGame(activity, qqGameId) { _, _ ->
RetrofitManager
.getInstance()
.newApi
.postQGamePlay(qqGameId, userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
QGameViewModel.notifyQGameSubjectUpdate() // 通知QQ小游戏首页列表刷新
},
{}
) // 秒玩记录上报
.navigation() as? IQGameProvider
qGameProvider?.setLoginInfo(activity, userId, userName, userToken)
qGameProvider?.launchGame(activity, qqAppId) { _, _ ->
MiniGameRecentlyPlayUseCase.submitRecentPlayedQGame(qqAppId, userId)
}
}
}
@SuppressLint("CheckResult")
fun directToWechatGameById(
activity: Activity,
wechatAppId: String,
) {
val wxApiProxy = WXAPIFactory.createWXAPI(
activity,
Config.WECHAT_APPID
)
if (!wxApiProxy.isWXAppInstalled) {
ToastUtils.toast("请安装微信客户端")
return
}
wxApiProxy.sendReq(
WXLaunchMiniProgram.Req().apply {
userName = wechatAppId
path = Constants.WECHAT_MINI_GAME_PCS
miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE;
}
)
MiniGameRecentlyPlayUseCase.submitRecentPlayedWGame(wechatAppId, HaloApp.getInstance().gid)
}
@JvmStatic
fun directToMessageCenter(defaultTabIndex: Int) {
ARouter.getInstance().build(RouteConsts.activity.messageWrapperActivity)
@ -2287,7 +2083,7 @@ object DirectUtils {
)
)
BottomTab.SearchStyle.TYPE_QQ_MINI_GAME -> directToQGameSearch(
BottomTab.SearchStyle.TYPE_MINI_GAME -> directToMiniGameSearch(
context,
"请输入小游戏关键词",
sourceEntrance,

View File

@ -27,7 +27,6 @@ import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.callback.CancelListener
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
@ -38,6 +37,7 @@ import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
import com.gh.gamecenter.manager.PackagesManager
@ -247,9 +247,8 @@ object DownloadItemUtils {
}
return
}
if (gameEntity.isQQMiniGame()) {
val isQQMiniGameOffShelve = gameEntity.qqMiniGameAppStatus == 1 // QQ小游戏是否下架
if (isQQMiniGameOffShelve) {
if (gameEntity.isMiniGame()) {
if (gameEntity.isMiniGameOffShelve()) {
downloadBtn.apply {
isClickable = false
text = context.getString(R.string.off_shelve)
@ -698,7 +697,7 @@ object DownloadItemUtils {
// 为 downloadButton 添加游戏实体,供点击的时候上报用
downloadBtn.putObject(gameEntity)
val gamePermissionDialogFragment = (context as AppCompatActivity).supportFragmentManager.findFragmentByTag(
val gamePermissionDialogFragment = (context as? AppCompatActivity)?.supportFragmentManager?.findFragmentByTag(
GamePermissionDialogFragment::class.java.name
) as GamePermissionDialogFragment?
gamePermissionDialogFragment?.dismissAllowingStateLoss()
@ -844,12 +843,11 @@ object DownloadItemUtils {
}
return
}
if (gameEntity.isQQMiniGame()) {
if (gameEntity.isMiniGame()) {
downloadBtn.setOnClickListener {
NewFlatLogUtils.logQGameClick(gameEntity.qqMiniGameAppId, gameEntity.name)
GlobalActivityManager.currentActivity?.let { activity ->
DirectUtils.directToQGameById(activity, gameEntity.qqMiniGameAppId)
}
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
clickCallback?.onCallback()
allStateClickCallback?.onCallback()
}
return
}
@ -1164,7 +1162,11 @@ object DownloadItemUtils {
isSubscribe,
traceEvent
)
ToastUtils.toast(gameEntity.name + "已加入下载队列")
if (asVGame) {
ToastUtils.toast(gameEntity.name + "已加入加载队列")
} else {
ToastUtils.toast(gameEntity.name + "已加入下载队列")
}
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({

View File

@ -499,7 +499,7 @@ object DownloadObserver {
"game_name", downloadEntity.name,
"game_id", downloadEntity.gameId,
"game_type", downloadEntity.categoryChinese,
"game_schema_type", if (downloadEntity.getMetaExtra(VHelper.KEY_BIT) == "32") "32位" else "64位",
"game_schema_type", if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
*kvs
)
} else if (downloadEntity.gameId == Constants.HALO_FUN_GAME_ID) {
@ -508,11 +508,18 @@ object DownloadObserver {
"space_schema_type",
if (downloadEntity.packageName == VHelper.VSPACE_32BIT_PACKAGENAME) "32位" else "64位"
)
} else if(downloadEntity.gameId == Constants.HALO_FUN_NEW_32_GAME_ID) {
SensorsBridge.trackEvent(
"HaloFunDownloadDone",
"space_schema_type",
"32位(新)"
)
}
if (downloadEntity.gameId != Constants.GHZS_GAME_ID
&& downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) != Constants.SIMULATOR_DOWNLOAD
&& downloadEntity.gameId != Constants.HALO_FUN_GAME_ID
&& downloadEntity.gameId != Constants.HALO_FUN_NEW_32_GAME_ID
) {
val trackJson = downloadEntity.customPageTrackDataJson
val kvs = if (!trackJson.isNullOrBlank()) {
@ -527,7 +534,7 @@ object DownloadObserver {
"game_name", downloadEntity.meta[Constants.GAME_NAME] ?: "",
"game_type", downloadEntity.meta[Constants.GAME_CATEGORY_IN_CHINESE] ?: "",
"game_label", downloadEntity.tags.joinToString(","),
"game_schema_type", if (downloadEntity.getMetaExtra(VHelper.KEY_BIT) == "32") "32位" else "64位",
"game_schema_type", if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
"page_name", getCurrentPageEntity().pageName,
"page_id", getCurrentPageEntity().pageId,
"page_business_id", getCurrentPageEntity().pageBusinessId,

View File

@ -105,9 +105,14 @@ public class EntranceUtils {
//TODO:添加FLAG_ACTIVITY_NEW_TASK会导致一跳转页面callback就被调用
//intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent1.putExtras(bundle);
if (context instanceof AppCompatActivity) {
AvoidOnResultManager.Companion.getInstance((AppCompatActivity) context)
.startForResult(intent1, callback);
} else {
// 不要回调,正常跳转
context.startActivity(intent1);
}
AvoidOnResultManager.Companion.getInstance((AppCompatActivity) context)
.startForResult(intent1, callback);
}
} else {
// 应用未在运行

View File

@ -282,7 +282,7 @@ object GameActivityDownloadHelper {
location: String,
traceEvent: ExposureEvent
) {
VHelper.validateVSpaceBeforeAction(context, gameEntity) {
VHelper.validateVSpaceBeforeAction(context,gameEntity.getUniquePackageName(), gameEntity) {
GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
DialogUtils.checkDownload(
context,

View File

@ -7,6 +7,7 @@ import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.SubjectEntity
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
@ -111,6 +112,14 @@ object GameSubstituteRepositoryHelper {
}
}
// 检查是否已安装该游戏 id
if (PackagesManager.getInstalledDataByGameId(game.id) != null) {
// 将该位置的游戏标记为需要替换
positionOfGameToBeReplacedList.add(index)
thisPositionNeedToBeReplaced = true
break
}
// 若此游戏所包含的 apk 没有已安装,那么再检查是否已安装有预设相关包名
if (!thisPositionNeedToBeReplaced) {
var relatedPackageList = arrayListOf<String>()

View File

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

View File

@ -35,8 +35,6 @@ object HomeBottomBarHelper {
text = "游戏库",
name = "游戏库",
position = 2,
iconSelect = "https://resource.ghzs.com/image/game/library/entrance/5e183202913fbd002c75f247.png",
iconUnselect = "https://resource.ghzs.com/image/game/library/entrance/5e1831fd913fbd003024641e.png",
animationCode = animationCode,
default = false,
display = Display()
@ -59,6 +57,10 @@ object HomeBottomBarHelper {
return BottomTab(name = "我的光环", jsCode = animationCode, iconSelector = R.drawable.selector_ic_user, link = LinkEntity(type = TYPE_MY_HALO))
}
fun isDefaultHomeBottomTabDataExist(): Boolean {
return SPUtils.getString(KEY_HOME_BOTTOM_TAB).isNotEmpty()
}
@JvmStatic
fun getDefaultHomeBottomTabData(): List<BottomTab> {
try {

View File

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

View File

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

View File

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

View File

@ -93,12 +93,13 @@ object NewFlatLogUtils {
// 畅玩助手更新弹窗展示事件
@JvmStatic
fun logHaloFunUpdateDialogShow(gameId: String, gameName: String, gameArchitecture: String) {
fun logHaloFunUpdateDialogShow(gameId: String, gameName: String, gameArchitecture: String, targetVaVersion: String) {
val json = json {
KEY_EVENT to "halo_fun_update_dialog_show"
"game_id" to gameId
"game_name" to gameName
"game_architecture" to gameArchitecture
"target_va_version" to targetVaVersion
parseAndPutMeta().invoke(this)
}
log(json)
@ -142,12 +143,13 @@ object NewFlatLogUtils {
// 畅玩助手更新弹窗点击事件
@JvmStatic
fun logHaloFunUpdateDialogClick(dialogType: String, buttonType: String, architecture: String) {
fun logHaloFunUpdateDialogClick(dialogType: String, buttonType: String, architecture: String, targetVaVersion: String) {
val json = json {
KEY_EVENT to "halo_fun_update_dialog_click"
"dialog_type" to dialogType
KEY_BUTTON_TYPE to buttonType
"architecture" to architecture
"target_va_version" to targetVaVersion
parseAndPutMeta().invoke(this)
}
log(json)
@ -2007,29 +2009,6 @@ object NewFlatLogUtils {
log(json, "event", false)
}
// vpn 弹窗显示
fun logVpnHintDialogShow(gameId: String, gameName: String) {
val json = json {
KEY_EVENT to "vpn_pre_access_dialog_show"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
parseAndPutMeta().invoke(this)
}
log(json, "event", false)
}
// vpn 弹窗点击
fun logVpnHintDialogClick(gameId: String, gameName: String, button: String) {
val json = json {
KEY_EVENT to "vpn_pre_access_dialog_click"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
"button" to button
parseAndPutMeta().invoke(this)
}
log(json, "event", false)
}
// 谷歌框架弹窗显示
fun logGAppsDialogShowed(gameId: String, gameName: String) {
val json = json {
@ -2600,17 +2579,6 @@ object NewFlatLogUtils {
log(json)
}
@JvmStatic
fun logQGameClick(qqGameId: String, qqGameName: String?) {
val json = json {
KEY_EVENT to "qq_game_click"
"qq_game_id" to qqGameId
"qq_game_name" to qqGameName ?: ""
parseAndPutMeta().invoke(this)
}
log(json)
}
// 点击个人主页的认证文案事件
@JvmStatic
fun logClickAuthText(linkType: String, linkId: String, linkText: String, userId: String, text: String) {

View File

@ -0,0 +1,240 @@
package com.gh.common.util
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.gh.download.DownloadManager
import com.gh.download.PackageObserver
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.hud.HeadUpDisplayHelper
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.R
import com.gh.gamecenter.hud.HeadUpDisplayLogHelper
import com.lightgame.utils.Utils
import org.greenrobot.eventbus.EventBus
object PackageChangeHelper : DefaultLifecycleObserver {
private const val TAG = "PackageChangeHelper"
private const val INSTALL_PENDING = 1
private const val UNINSTALL_PENDING = 2
private const val UPDATE_PENDING = 3
// <包名pending 类型,应用版本> Triple
private var pendingPackageTriple: Triple<String, Int, String>? = null
private var pendingGhId: String? = null
private var pendingHUDShowed: Boolean = false
/**
* 添加一个等待中,待确定是否已成功安装的应用
*/
fun addInstallPendingPackage(packageName: String) {
val installData = PackagesManager.getInstalledData(packageName)
if (installData == null) {
Utils.log(TAG, "添加了: $packageName 包名等待安装成功")
pendingHUDShowed = false
pendingPackageTriple = Triple(packageName, INSTALL_PENDING, "")
} else {
Utils.log(TAG, "添加了: $packageName 包名等待安装更新成功")
val ghId = PackageUtils.getGhId(packageName)
// 记录光环插件相关信息,用于安装成功后的处理
if (ghId != null) {
pendingGhId = ghId.toString()
}
pendingHUDShowed = false
pendingPackageTriple = Triple(packageName, UPDATE_PENDING, installData.version)
}
}
fun isInstallPendingPackage(packageName: String): Boolean {
return pendingPackageTriple?.first == packageName
}
/**
* 添加一个等待中,待确定是否已成功卸载的应用
*/
fun addUninstallPendingPackage(packageName: String) {
Utils.log(TAG, "添加了: $packageName 包名等待卸载成功")
pendingPackageTriple = Triple(packageName, UNINSTALL_PENDING, "")
}
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
if (pendingPackageTriple != null) {
val packageName = pendingPackageTriple?.first ?: return
val isInstallPending = pendingPackageTriple?.second == INSTALL_PENDING
val isUninstallPending = pendingPackageTriple?.second == UNINSTALL_PENDING
val isUpdatePending = pendingPackageTriple?.second == UPDATE_PENDING
val pendingVersion = pendingPackageTriple?.third ?: ""
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
val isInstalled = installedVersionName != null
if (isInstallPending) {
if (isInstalled) {
pendingPackageTriple = null
pendingGhId = null
PackageRepository.addInstalledGame(PackageRepository.packageFilterManager, packageName)
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
performInstallSuccessAction(packageName)
} else {
// 任务不存在了,将等待更新安装结果的 triple 置为 null
if (DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) == null) {
pendingPackageTriple = null
} else {
showHUDIfNeeded(packageName)
}
}
} else if (isUninstallPending && !isInstalled) {
pendingPackageTriple = null
pendingGhId = null
// 从额外的包名白名单移除,下次启动时不再查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = false)
performUninstallSuccessAction(packageName)
} else if (isUpdatePending) {
val isUpdateValid = if (installedVersionName != pendingVersion) {
true
} else {
!pendingGhId.isNullOrEmpty() && pendingGhId != PackageUtils.getGhId(packageName).toString()
}
pendingPackageTriple = null
pendingGhId = null
if (isUpdateValid) {
performUninstallSuccessAction(packageName)
performInstallSuccessAction(packageName)
} else {
// 任务不存在了,将等待更新安装结果的 triple 置为 null
if (DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) == null) {
pendingPackageTriple = null
} else {
showHUDIfNeeded(packageName)
}
}
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
}
}
}
private fun showHUDIfNeeded(packageName: String) {
if (pendingHUDShowed) return
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) ?: return
val activity = CurrentActivityHolder.getCurrentActivity() ?: return
if (activity is DownloadManagerActivity) return
pendingHUDShowed = true
HeadUpDisplayHelper.showHUD(activity,
downloadEntity.icon ?: "",
activity.getString(R.string.hud_has_pending_install_game),
activity.getString(R.string.hud_head_to_download_manager),
showingCallback = {
HeadUpDisplayLogHelper.trackInstallationShow(downloadEntity, "游戏下载")
},
clickedCallback = {
DirectUtils.directToDownloadManager(activity, "HUD")
HeadUpDisplayLogHelper.trackInstallationClick(downloadEntity, "游戏下载")
})
}
/**
* 对外暴露的方法,用于添加一个安装成功的应用
* @param packageName 包名
* @param cachedGameEntity 缓存的 GameEntity用于快速更新状态
*/
fun addInstall(packageName: String, cachedGameEntity: GameEntity? = null) {
performInstallSuccessAction(packageName, cachedGameEntity)
}
/**
* 对外暴露的方法,用于添加一个卸载成功的应用
* @param packageName 包名
* @param cachedGameEntity 缓存的 GameEntity用于快速更新状态
*/
fun addUpdate(packageName: String, cachedGameEntity: GameEntity? = null) {
performUninstallSuccessAction(packageName)
performInstallSuccessAction(packageName, cachedGameEntity)
}
/**
* 对应包名安装成功后的操作,继承至 PackageChangeBroadcastObserver
* @param packageName 包名
* @param cachedGameEntity 缓存的 GameEntity用于快速更新状态
* @param withLog 是否需要记录日志
*/
private fun performInstallSuccessAction(
packageName: String,
cachedGameEntity: GameEntity? = null,
withLog: Boolean = true
) {
Utils.log(TAG, "安装了: $packageName 包名的程序")
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName)
val gameId = if (downloadEntity != null && downloadEntity.gameId != null) downloadEntity.gameId else ""
val gameName = if (downloadEntity != null && downloadEntity.name != null) downloadEntity.name else ""
if (withLog) {
NewFlatLogUtils.logGameInstallComplete(gameId, gameName)
SensorsBridge.trackInstallGameFinish(gameId, gameName)
}
InstallUtils.getInstance().removeInstall(packageName)
PackageHelper.refreshLocalPackageList()
val versionName = PackageUtils.getVersionNameByPackageName(packageName)
val installEb = EBPackage(EBPackage.TYPE_INSTALLED, packageName, versionName)
PackageObserver.onPackageChanged(installEb, cachedGameEntity)
EventBus.getDefault().post(installEb)
}
fun addUninstall(packageName: String) {
performUninstallSuccessAction(packageName)
}
/**
* 对应包名卸载成功后的操作,继承至 PackageChangeBroadcastObserver
*/
private fun performUninstallSuccessAction(packageName: String, withLog: Boolean = true) {
Utils.log(TAG, "卸载了: $packageName 包名的程序")
val install = PackagesManager.getInstalledData(packageName)
val gameId = if (install?.id != null) install.id else ""
val gameName = if (install?.name != null) install.name else ""
if (withLog) {
NewFlatLogUtils.logGameUninstallComplete(gameId!!, gameName!!)
SensorsBridge.trackUnloadGameFinish(gameId, gameName)
}
InstallUtils.getInstance().removeUninstall(packageName)
PackageHelper.refreshLocalPackageList()
val uninstallEb = EBPackage(EBPackage.TYPE_UNINSTALLED, packageName, "")
PackageObserver.onPackageChanged(uninstallEb)
EventBus.getDefault().post(uninstallEb)
}
}

View File

@ -1,24 +1,108 @@
package com.gh.common.util
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PermissionInfo
import android.os.Build
import android.os.Process
import android.provider.Settings
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.gh.common.constant.Config
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.PermissionHelper
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.core.GHThreadFactory
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.WhitePackageListEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.feature.utils.SentryHelper
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.*
import java.util.HashMap
import java.util.concurrent.Executors
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
object PackageHelper {
private const val TAG = "PackageHelper"
private const val SP_GET_INSTALLED_PACKAGES_AGREED = "get_installed_packages_agreed" // 用户是否同意使用已安装应用列表 API
private const val SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API =
"get_installed_packages_by_alternative_api" // 是否使用另类方式获取已安装应用列表
private const val SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE =
"user_used_get_installed_api_switch_package" // 用户是否使用过含有已安装应用列表获取开关的包
private const val SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST =
"additional_whitelist_package_name_list" // 额外的白名单包名列表 (曾经更正为已安装的包名列表)
private const val UNKNOWN = -1
private const val UNSUPPORTED = 0
private const val SUPPORTED = 1
private const val ENABLED = 2
private const val DISABLED = 3
private var lastSuccessfullyGetInstalledPackagesTimeMills = 0L
private var cachedInstalledPackageInfoList: List<PackageInfo> = arrayListOf() // 缓存的已安装应用列表
private var cachedInstalledPackageNameList: List<String> = arrayListOf() // 缓存的已安装应用包名列表
private var additionalWhiteListPackageNameSet: HashSet<String> = hashSetOf()
private var isGetInstalledPackagesAgreed = false // 用户是否已经同意使用已安装应用列表
private var isGetInstalledPackagesAgreedRequired = UNKNOWN // 需要用户手动授权才获取已安装应用列表的功能的开关
private var isGetInstalledPackagesPermissionSupported = UNKNOWN // 设备是否支持禁用获取已安装应用列表
private var useAlternativeWayToGetInstalledPackages = false
private var cachedPkgNameAndGameEntityMap = HashMap<String, GameEntity>() // 缓存的状态异常包名和游戏实体的映射 (用于免接口请求更新状态)
private val packageExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_PACKAGE_THREAD")) }
private var uploadUIDGapLog = true
// 光环运行的环境是否为默认的 UID (0)
private val isRunningOnDefaultUid by lazy { Process.myUid() / 100000 == 0 }
// 评论黑名单包名列表,避免用户安装了 Xposed Installer 这样的工具,也能在包含该安装包的游戏详情页评论
var commentPackageNameBlackList = arrayListOf<String>()
private var _commentPackageNameBlackList = arrayListOf<String>()
val commentPackageNameBlackList: ArrayList<String>
get() = _commentPackageNameBlackList
// 关闭下载的包列表
var downloadPackageNameBlackList = arrayListOf<String>()
private var _downloadPackageNameBlackList = arrayListOf<String>()
val downloadPackageNameBlackList: ArrayList<String>
get() = _downloadPackageNameBlackList
// 本地已安装的包去掉关闭下载的包后的列表
var validLocalPackageNameSet = hashSetOf<String>()
private var _validLocalPackageNameSet = hashSetOf<String>()
val validLocalPackageNameSet: HashSet<String>
get() = _validLocalPackageNameSet
// 游戏包名匹配列表
var relatedPackageList = arrayListOf<SettingsEntity.GameWithPackages>()
private var _relatedPackageList = arrayListOf<SettingsEntity.GameWithPackages>()
val relatedPackageList: ArrayList<SettingsEntity.GameWithPackages>
get() = _relatedPackageList
// 接口控制的已安装应用列表获取开关状态 (UI 显示)
private var _installedPackageApiSwitchStatusLiveData = MutableLiveData<Boolean>()
val installedPackageApiSwitchStatusLiveData: LiveData<Boolean>
get() = _installedPackageApiSwitchStatusLiveData
// 本地已安装包的列表
var localPackageNameSet = hashSetOf<String>()
@ -31,6 +115,67 @@ object PackageHelper {
}
}
/**
* 检查是否需要忽略接口控制的已安装应用列表获取开关
* 用于覆盖安装首次启动时的检查 https://jira.shanqu.cc/browse/GHZSCY-5694
*/
fun checkIfGetInstalledApiSwitchShouldBeIgnored(context: Context) {
val userHasUsedGetInstalledApiSwitchPackage =
SPUtils.getBoolean(SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE, false)
if (!userHasUsedGetInstalledApiSwitchPackage) {
val isSupportGetInstalledAppsPermission = isSupportGetInstalledAppsPermission(context)
if (!isSupportGetInstalledAppsPermission) {
if (isRunningOnDefaultUid) {
// 设备不支持动态管理获取已安装应用列表,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
}
onGetInstalledPackagesAgreed()
} else if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
if (isRunningOnDefaultUid) {
// 设备支持动态管理获取已安装应用列表但已经授权,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
}
onGetInstalledPackagesAgreed()
}
SPUtils.getBoolean(SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE, true)
}
}
/**
* 获取包名白名单列表(为了在没有已安装应用列表获取能力的时候也能正常判断更新、插件化)
* @param additionalWhiteList 额外的已安装白名单
*/
@SuppressLint("CheckResult")
fun getPackagesWhiteList(additionalWhiteList: HashSet<String>) {
RetrofitManager.getInstance().newApi.installWhitelist
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<WhitePackageListEntity>() {
override fun onSuccess(data: WhitePackageListEntity) {
val installedWhiteList = hashSetOf<String>()
if (additionalWhiteList.isNotEmpty()) {
installedWhiteList.addAll(additionalWhiteList)
}
data.data?.let {
installedWhiteList.addAll(it)
}
addInstalledButMissingPackages(installedWhiteList)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
if (additionalWhiteList.isNotEmpty()) {
addInstalledButMissingPackages(additionalWhiteList)
}
}
})
}
@JvmStatic
fun refreshLocalPackageList() {
localPackageNameSet = getAllPackageName(HaloApp.getInstance().application)
@ -38,38 +183,29 @@ object PackageHelper {
}
@JvmStatic
fun initList() {
Config.getSettings()?.gameCommentBlackList?.let {
commentPackageNameBlackList = ArrayList(it)
}
Config.getSettings()?.gameDownloadBlackList?.let {
downloadPackageNameBlackList = ArrayList(it)
}
Config.getSettings()?.gamePackageMatch?.let {
relatedPackageList = ArrayList(it)
}
fun refreshPackageNameList() {
Config.getSettings()?.gameCommentBlackList?.let { _commentPackageNameBlackList = ArrayList(it) }
Config.getSettings()?.gameDownloadBlackList?.let { _downloadPackageNameBlackList = ArrayList(it) }
Config.getSettings()?.gamePackageMatch?.let { _relatedPackageList = ArrayList(it) }
Config.getSettings()?.gameDownloadBlackList
updateValidPackageNameList()
}
private fun updateValidPackageNameList() {
validLocalPackageNameSet =
_validLocalPackageNameSet =
localPackageNameSet.filterNot { p -> downloadPackageNameBlackList.contains(p) }.toHashSet()
}
/*
/**
* 获取所有已安装的软件的包名、版本(非系统应用)
*/
private fun getAllPackageName(context: Context): HashSet<String> {
val set = HashSet<String>()
return try {
val packageInfos = PackageUtils.getInstalledPackages(context, 0)
for (packageInfo in packageInfos) {
if (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0) {
if (context.packageName != packageInfo.packageName) {
set.add(packageInfo.packageName)
}
val packageNameList = getInstalledPackageNameList(context, 0)
for (packageName in packageNameList) {
if (context.packageName != packageName) {
set.add(packageName)
}
}
set
@ -79,4 +215,613 @@ object PackageHelper {
}
}
/**
* 弃用已安装列表缓存
*/
fun dumpInstalledListCache() {
lastSuccessfullyGetInstalledPackagesTimeMills = 0
}
/**
* 在超时后,若后台没有开启获取已安装应用列表的功能,回落到以接口不控制的方式获取已安装应用列表
*/
fun ignoreInstalledPackageApiSwitchAfterTimeout(timeout: Long) {
CoroutineScope(SupervisorJob()).launch {
delay(timeout)
if (isGetInstalledPackagesAgreedRequired == UNKNOWN && !isGetInstalledPackagesAgreed()) {
Utils.log(TAG, "后台没有开启获取已安装应用列表的功能,超时后回落到以接口不控制的方式获取已安装应用列表")
updateIsGetInstalledPackagesApiAgreedRequired(false)
}
}
}
/**
* 更新已安装应用列表获取开关状态
*/
fun updateIsGetInstalledPackagesApiAgreedRequired(isEnabled: Boolean) {
Utils.log(TAG, "updateIsGetInstalledPackagesApiAgreedRequired 入参为 $isEnabled")
// 状态不变,无需更新
if ((isEnabled == true && isGetInstalledPackagesAgreedRequired == ENABLED)
|| (isEnabled == false && isGetInstalledPackagesAgreedRequired == DISABLED)
) {
Utils.log(TAG, "isGetInstalledPackagesApiAgreedRequired 状态不变,无需更新")
return
}
// 若用户已经同意使用了,无需更新
if (isGetInstalledPackagesAgreed()) {
Utils.log(TAG, "用户已经同意使用了,无需再更新已安装应用列表获取开关状态")
return
}
if (isEnabled) {
Utils.log(TAG, "开启获取已安装应用列表限制")
additionalWhiteListPackageNameSet =
SPUtils.getString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST).toObject() ?: hashSetOf()
Utils.log(TAG, "额外的白名单为 $additionalWhiteListPackageNameSet")
getPackagesWhiteList(additionalWhiteListPackageNameSet)
_installedPackageApiSwitchStatusLiveData.postValue(true)
isGetInstalledPackagesAgreedRequired = ENABLED
} else {
Utils.log(TAG, "不开启获取已安装应用列表限制")
isGetInstalledPackagesAgreedRequired = DISABLED
if (isRunningOnDefaultUid) {
// 启用另类获取已安装应用列表的 API
updateUseAlternativeWayToGetInstalledPackages()
}
onGetInstalledPackagesAgreed()
}
}
/**
* 用户是否已经允许了调用获取已安装应用列表接口
* 优先用内存的值,没有再从 SP 中获取并更新
*/
fun isGetInstalledPackagesAgreed(): Boolean {
return isGetInstalledPackagesAgreed
|| (SPUtils.getBoolean(SP_GET_INSTALLED_PACKAGES_AGREED).also { isGetInstalledPackagesAgreed = it })
}
/**
* 用户是否已经使用另类方式获取已安装应用列表
*/
private fun isUseAlternativeWayToGetInstalledPackages(): Boolean {
return useAlternativeWayToGetInstalledPackages
|| (SPUtils.getBoolean(SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API)
.also { useAlternativeWayToGetInstalledPackages = it })
}
private fun updateUseAlternativeWayToGetInstalledPackages() {
// 启用另类获取已安装应用列表的 API
useAlternativeWayToGetInstalledPackages = true
SPUtils.setBoolean(SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API, true)
}
fun isGetInstalledPackagesAgreedRequired(): Boolean {
return isGetInstalledPackagesAgreedRequired == ENABLED
}
/**
* 获取已安装应用列表
*/
fun getInstalledPackageInfoList(context: Context?, flags: Int): List<PackageInfo> {
return getInstalledListInternal(context, flags, false).first
}
/**
* 获取已安装应用包名列表
*/
fun getInstalledPackageNameList(context: Context?, flags: Int): List<String> {
return getInstalledListInternal(context, flags, true).second
}
private fun getInstalledListInternal(context: Context?,
flags: Int,
packageNameOnly: Boolean): Pair<List<PackageInfo>, List<String>> {
Utils.log(TAG, "即将获取已安装应用列表,仅获取包名 $packageNameOnly")
// 用户未同意使用已安装应用列表 API返回空列表
if (!isGetInstalledPackagesAgreed()) {
Utils.log(TAG, "用户未同意使用已安装应用列表 API返回空列表")
return Pair(cachedInstalledPackageInfoList, cachedInstalledPackageNameList)
}
// 简单 debounce 过于频繁的获取已安装应用列表调用
if (System.currentTimeMillis() - lastSuccessfullyGetInstalledPackagesTimeMills < 20 * 1000) {
// 时间间隔合适且对应的列表不为空,直接返回对应的缓存列表数据
if ((packageNameOnly && cachedInstalledPackageNameList.isNotEmpty())
|| (!packageNameOnly && cachedInstalledPackageInfoList.isNotEmpty())
) {
Utils.log(TAG, "使用了缓存的已安装应用列表")
return Pair(cachedInstalledPackageInfoList, cachedInstalledPackageNameList)
}
}
var shouldGetNewInstalledPackagedList = false
// 当前设备是否支持限制获取已安装应用列表的功能
if (isSupportGetInstalledAppsPermission(context!!)) {
Utils.log(TAG, "当前设备支持动态管理获取已安装应用列表的功能")
// 当前设备是否支持禁用了获取已安装应用列表
if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
Utils.log(TAG, "当前设备支持动态管理但没有限制获取已安装应用列表的功能")
shouldGetNewInstalledPackagedList = true
} else {
Utils.log(TAG, "当前设备支持动态管理且已限制获取已安装应用列表的功能")
}
} else {
Utils.log(TAG, "当前设备不支持动态管理获取已安装应用列表的功能")
shouldGetNewInstalledPackagedList = true
}
if (shouldGetNewInstalledPackagedList) {
lastSuccessfullyGetInstalledPackagesTimeMills = System.currentTimeMillis()
if (packageNameOnly) {
cachedInstalledPackageNameList = getInstalledPackageNameListInternal(context, flags)
Utils.log(TAG, "获取已安装应用列表成功,数量为 ${cachedInstalledPackageNameList.size}")
} else {
cachedInstalledPackageInfoList = getInstalledPackageInfoListInternal(context, flags)
Utils.log(TAG, "获取已安装应用列表成功,数量为 ${cachedInstalledPackageInfoList.size}")
}
}
return Pair(cachedInstalledPackageInfoList, cachedInstalledPackageNameList)
}
/**
* 显示获取已安装应用列表的对话框并请求权限
*/
fun showGetInstallAppsListDialogAndRequestPermissionIfNeeded(
activity: FragmentActivity,
ignorePermanentlyDenied: Boolean = false,
resultClosure: (Boolean) -> Unit
) {
if (isSupportGetInstalledAppsPermission(activity)) {
// 若系统已经授予了获取应用列表的权限,直接执行授权成功回调
if (!PermissionHelper.isGetInstalledListPermissionDisabled(activity)) {
onGetInstalledPackagesAgreed()
resultClosure.invoke(true)
return
}
PermissionHelper.showGetInstalledAppsListPermissionDialog(
activity = activity,
requestPermission = true,
ignorePermanentlyDenied = ignorePermanentlyDenied
) { isGranted ->
if (isGranted) {
SensorsBridge.trackInstalledListPermissionsResult("成功")
onGetInstalledPackagesAgreed()
resultClosure.invoke(true)
trackInstalledListAfterDelay()
} else {
resultClosure.invoke(false)
SensorsBridge.trackInstalledListPermissionsResult("拒绝")
}
}
} else {
val hintDialog = PermissionHelper.showGetInstalledAppsListPermissionDialog(
activity = activity,
requestPermission = false,
) {
// do nothing
}
SensorsBridge.trackInstalledListPermissionsCustomDialogShow()
val noticeDialog = DialogHelper.showGuideDialog(
context = activity,
title = "权限申请",
content = "是否允许“光环助手”获取已安装的应用信息",
confirmText = "开启",
cancelText = "拒绝",
confirmClickCallback = {
SensorsBridge.trackInstalledListPermissionsCustomClick("开启")
onGetInstalledPackagesAgreed()
resultClosure.invoke(true)
trackInstalledListAfterDelay()
},
cancelClickCallback = {
resultClosure.invoke(false)
SensorsBridge.trackInstalledListPermissionsCustomClick("拒绝")
}
)
noticeDialog?.setOnDismissListener {
hintDialog?.dismiss()
}
}
}
/**
* 执行用户授权获取已安装应用列表的操作
*/
private fun onGetInstalledPackagesAgreed() {
isGetInstalledPackagesAgreed = true
SPUtils.setBoolean(SP_GET_INSTALLED_PACKAGES_AGREED, true)
_installedPackageApiSwitchStatusLiveData.postValue(false)
// 进行包名初始化相关的操作
initPackageRelatedData()
}
/**
* 进行包名初始化相关的操作
*/
fun initPackageRelatedData() {
PackageRepository.initData()
refreshLocalPackageList()
refreshPackageNameList()
}
/**
* 延迟5秒后上报已安装应用列表
*/
private fun trackInstalledListAfterDelay() {
CoroutineScope(SupervisorJob()).launch {
delay(5000)
SensorsBridge.trackNumberOfInstalledList(localPackageNameSet.size, localPackageNameSet)
}
}
/**
* 是否支持动态获取已安装应用列表权限
*/
fun isSupportGetInstalledAppsPermission(context: Context): Boolean {
if (isUseAlternativeWayToGetInstalledPackages()) {
// 已经使用另类获取已安装应用列表形式,强制判定为不支持动态获取已安装应用列表权限
return false
}
// 若存在缓存,直接返回缓存结果。
if (isGetInstalledPackagesPermissionSupported != UNKNOWN) {
return isGetInstalledPackagesPermissionSupported != UNSUPPORTED
}
try {
// 根据官方提供的方法来判定是否支持限制获取已安装应用列表
val flag =
Settings.Secure.getInt(context.contentResolver, "oem_installed_apps_runtime_permission_enable", 0)
if (flag == 1) {
isGetInstalledPackagesPermissionSupported = SUPPORTED
return true
}
// 部分未升级的手机没有上面配置项,有定义下面危险权限也认为是支持设备软件列表管控
val packageManager = context.packageManager
val permissionInfo = packageManager.getPermissionInfo("com.android.permission.GET_INSTALLED_APPS", 0)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (permissionInfo.protection == PermissionInfo.PROTECTION_DANGEROUS) {
isGetInstalledPackagesPermissionSupported = SUPPORTED
return true
} else {
isGetInstalledPackagesPermissionSupported = UNSUPPORTED
return false
}
} else {
isGetInstalledPackagesPermissionSupported = UNSUPPORTED
return false
}
} catch (e: PackageManager.NameNotFoundException) {
isGetInstalledPackagesPermissionSupported = UNSUPPORTED
return false
}
}
/**
* 确保指定包名的应用在已安装了的情况下能正常收录
*/
fun addInstalledButMissingPackages(packageNameSet: HashSet<String>) {
Utils.log(TAG, "addInstalledButMissingPackages 检查已安装但未收录的应用")
val installedPackageNameSet: HashSet<String> = hashSetOf()
for (packageName in packageNameSet) {
val installedPkgNameExistInMemory = PackagesManager.isInstalled(packageName)
val packageNameInstalledOnDevice = PackageUtils.getVersionNameByPackageName(packageName) != null
if (!installedPkgNameExistInMemory && packageNameInstalledOnDevice) {
installedPackageNameSet.add(packageName)
}
if (!packageNameInstalledOnDevice) {
additionalWhiteListPackageNameSet.remove(packageName)
}
}
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toJson())
Utils.log(TAG, "addInstalledButMissingPackages 需要请求接口获取的包数量为 ${installedPackageNameSet.size}")
PackageRepository.addInstalledGames(
packageFilterManager = PackageRepository.packageFilterManager,
pkgNameList = ArrayList(installedPackageNameSet),
updateInstallStatus = true
)
}
/**
* 更新额外的白名单包名列表
* @param packageName 包名
* @param isAdd 是否添加
*/
fun updateAdditionalWhiteListPackageName(packageName: String, isAdd: Boolean) {
val isUpdated = if (isAdd) {
additionalWhiteListPackageNameSet.add(packageName)
} else {
additionalWhiteListPackageNameSet.remove(packageName)
}
Utils.log(
TAG,
"updateAdditionalWhiteListPackageName 更新额外的白名单包名列表 $isAdd $packageName ,结果是 $isUpdated"
)
if (isUpdated) {
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toJson())
}
}
/**
* 刷新安装状态异常 (适用于仅存在包名信息的列表)
*/
fun refreshWrongInstallStatus(packageNameSet: MutableSet<String>) {
packageExecutor.execute {
Utils.log(TAG, "refreshWrongInstallStatus 检查安装状态异常的应用")
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
for (packageName in packageNameSet) {
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
if (PackagesManager.isInstalled(packageName)
&& installedVersionName == null
) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName != null
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
) {
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
}
}
Utils.log(
TAG,
"refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}"
)
runOnUiThread {
if (uninstalledButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in uninstalledButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUninstall(packageName)
additionalWhiteListPackageNameSet.remove(packageName)
}
SPUtils.setString(
SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST,
additionalWhiteListPackageNameSet.toString()
)
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUpdate(packageName)
}
}
}
}
}
/**
* 刷新安装状态异常 (适用于存在游戏信息的列表)
*/
fun refreshWrongInstallStatus(gameEntityList: ArrayList<GameEntity>) {
packageExecutor.execute {
Utils.log(TAG, "refreshWrongInstallStatus 检查安装状态异常的应用")
val installedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
for (game in gameEntityList) {
for (apk in game.getApk()) {
val packageName = apk.packageName
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
if (!PackagesManager.isInstalled(packageName)
&& installedVersionName != null
) {
cachedPkgNameAndGameEntityMap.put(packageName, game)
installedButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName == null
) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName != null
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
&& !PackagesManager.isCanUpdate(game.id, packageName, false)
) {
cachedPkgNameAndGameEntityMap.put(packageName, game)
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
}
}
}
Utils.log(
TAG,
"refreshWrongInstallStatus 需要更新已安装状态的包数量为 ${installedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}"
)
runOnUiThread {
if (installedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in installedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addInstall(packageName, cachedPkgNameAndGameEntityMap.remove(packageName))
additionalWhiteListPackageNameSet.add(packageName)
}
SPUtils.setString(
SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST,
additionalWhiteListPackageNameSet.toString()
)
}
if (uninstalledButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in uninstalledButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUninstall(packageName)
additionalWhiteListPackageNameSet.remove(packageName)
}
SPUtils.setString(
SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST,
additionalWhiteListPackageNameSet.toString()
)
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUpdate(packageName, cachedPkgNameAndGameEntityMap.remove(packageName))
}
}
}
}
}
private fun getInstalledPackageInfoListInternal(
context: Context,
flags: Int
): List<PackageInfo> {
return if (isUseAlternativeWayToGetInstalledPackages()) {
Utils.log(TAG, "调用另类系统 API 获取已安装应用列表")
getInstalledPackageByAlternative(context)
} else {
Utils.log(TAG, "调用默认系统 API 获取已安装应用列表")
getInstalledPackageByDefault(context, flags)
}
}
private fun getInstalledPackageNameListInternal(
context: Context,
flags: Int
): List<String> {
if (isUseAlternativeWayToGetInstalledPackages()) {
Utils.log(TAG, "调用另类系统 API 获取已安装应用包名列表")
return getInstalledPackageNameByAlternative(context)
} else {
Utils.log(TAG, "调用默认系统 API 获取已安装应用包名列表")
val packageInfoList = getInstalledPackageByDefault(context, flags)
val packageList = arrayListOf<String>()
for (packageInfo in packageInfoList) {
if (context.packageName != packageInfo.packageName) {
packageList.add(packageInfo.packageName)
}
}
return packageList
}
}
private fun getInstalledPackageByDefault(context: Context, flags: Int): List<PackageInfo> {
val pm = context.packageManager
try {
return pm.getInstalledPackages(flags)
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
return arrayListOf()
}
private fun getInstalledPackageByAlternative(context: Context): ArrayList<PackageInfo> {
val packageManager = context.getPackageManager()
val packageList = arrayListOf<PackageInfo>()
var packagesArray: Array<String>? = null
var uid = android.os.Process.FIRST_APPLICATION_UID
while (uid <= android.os.Process.LAST_APPLICATION_UID) {
try {
packagesArray = packageManager.getPackagesForUid(uid)
if (packagesArray != null && packagesArray.isNotEmpty()) {
for (packageName in packagesArray) {
try {
val packageInfo = packageManager.getPackageInfo(packageName, 0)
if (packageInfo == null) {
break
}
packageList.add(packageInfo)
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
}
}
}
} catch (securityException: SecurityException) {
securityException.printStackTrace()
}
uid++
}
return packageList
}
private fun getInstalledPackageNameByAlternative(context: Context): ArrayList<String> {
val packageManager = context.getPackageManager()
val packageList = arrayListOf<String>()
var packagesArray: Array<String>? = null
var uid = android.os.Process.FIRST_APPLICATION_UID
var lastValidUid = 0
while (uid <= android.os.Process.LAST_APPLICATION_UID) {
try {
packagesArray = packageManager.getPackagesForUid(uid)
if (packagesArray != null && packagesArray.isNotEmpty()) {
lastValidUid = uid
for (packageName in packagesArray) {
packageList.add(packageName)
}
}
} catch (securityException: SecurityException) {
securityException.printStackTrace()
}
uid++
}
if (HaloApp.getInstance().isNewForThisVersion && uploadUIDGapLog) {
// 仅应用该版本第一次启动的第一次方法调用上报日志
uploadUIDGapLog = false
val uidGap = (android.os.Process.LAST_APPLICATION_UID - lastValidUid) / 100 * 100
SentryHelper.onEvent("UID_GAP", "gap", uidGap.toString())
}
return packageList
}
}

View File

@ -6,7 +6,6 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import com.gh.common.dialog.InstallPermissionDialogFragment
@ -20,15 +19,18 @@ import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.install.InstallService
import com.gh.gamecenter.vpn.VpnHelper
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
import java.io.File
// TODO 将弹窗改成以责任链模式来处理
object PackageInstaller {
private val listeners = mutableListOf<OnInstallListener>()
/**
* 为了兼容java代码
*/
@ -59,7 +61,7 @@ object PackageInstaller {
val isDownloadAsVGame = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.VGAME
|| downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.DUAL_DOWNLOAD_VGAME
val currentActivity = CurrentActivityHolder.getCurrentActivity() ?: return
val currentActivity = AppManager.getInstance().currentActivity() ?: return
if (!ignoreAsVGame && isDownloadAsVGame) {
VHelper.install(currentActivity, downloadEntity)
@ -108,6 +110,12 @@ object PackageInstaller {
return
}
val packageName = downloadEntity?.packageName ?: PackageUtils.getPackageNameByPath(context, pkgPath)
packageName?.let {
PackageChangeHelper.addInstallPendingPackage(packageName)
}
try {
// 判断是否需要使用浏览器来进行安装
if (BrowserInstallHelper.isUseBrowserToInstallEnabled()
@ -118,13 +126,14 @@ object PackageInstaller {
}
if (PackageUtils.isCanLaunchSetup(context, pkgPath)) {
val currentActivity = CurrentActivityHolder.getCurrentActivity()
if (VpnHelper.shouldUseVpn() && currentActivity is AppCompatActivity) {
turnOnVpnThenInstall(currentActivity, pkgPath, downloadEntity)
} else {
install(context, pkgPath)
}
installWithPureModeHandled(
context,
pkgPath,
downloadEntity?.packageName,
downloadEntity?.gameId ?: "unknown",
downloadEntity?.name ?: "unknown",
downloadEntity?.categoryChinese ?: "unknown"
)
} else {
if (isPluggin) {
DialogHelper.showPluginDialog(
@ -154,10 +163,26 @@ object PackageInstaller {
}
}
/**
* 处理纯净模式后的安装
*/
private fun installWithPureModeHandled(
context: Context,
pkgPath: String,
pkgName: String?,
gameId: String,
gameName: String,
gameType: String,
) {
PureModeHelper.handlePureModeIfNeeded(context, gameId, gameName, gameType) {
install(context, pkgPath, pkgName)
}
}
/**
* 最终执行安装的方法
*/
private fun install(context: Context, pkgPath: String) {
private fun install(context: Context, pkgPath: String, pkgName: String?) {
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU && Build.MANUFACTURER.lowercase().contains("xiaomi")) {
@ -168,10 +193,13 @@ object PackageInstaller {
val installIntent = getInstallIntent(context, pkgPath)
context.startActivity(installIntent)
dispatchOnInstallListener(pkgPath, pkgName)
}
fun installMultiple(
context: Context,
pkgName: String,
pkgPath: String,
sessionId: Int = -1
) {
@ -194,6 +222,24 @@ object PackageInstaller {
val pendingIntent = PendingIntent.getActivity(context, sessionId, intent, flags)
// 提交数据流并执行安装
session.commit(pendingIntent.intentSender)
dispatchOnInstallListener(pkgName, pkgPath)
}
fun registerOnInstallListener(listener: OnInstallListener) {
if (!listeners.contains(listener)) {
listeners.add(listener)
}
}
fun unregisterOnInstallListener(listener: OnInstallListener) {
listeners.remove(listener)
}
private fun dispatchOnInstallListener(pkgPath: String, pkgName: String?) {
for (listener in listeners) {
listener.onInstalling(pkgName, pkgPath)
}
}
/**
@ -250,6 +296,8 @@ object PackageInstaller {
fun uninstallForPackageName(context: Context, pkn: String?) {
if (pkn.isNullOrEmpty()) return
PackageChangeHelper.addUninstallPendingPackage(pkn)
val uninstallIntent = Intent()
uninstallIntent.action = Intent.ACTION_DELETE
uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT)
@ -283,82 +331,8 @@ object PackageInstaller {
return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis())
}
/**
* 启动 VPN 然后安装应用 (若没有授权会先提醒授权 VPN ,若拒绝授权会回落到直接执行安装)
*/
private fun turnOnVpnThenInstall(currentActivity: AppCompatActivity,
pkgPath: String,
downloadEntity: DownloadEntity?) {
if (VpnHelper.isVpnPermissionGranted(currentActivity) == true) {
VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
if (shouldShowVpnError) {
ToastUtils.toast("安装防护功能启动失败")
}
install(currentActivity, pkgPath)
}
} else {
val isTheFirstTimeToShowVpnHintDialog = VpnHelper.isTheFistTimeToShowVpnHintDialog()
downloadEntity?.let {
NewFlatLogUtils.logVpnHintDialogShow(it.gameId, it.name)
}
// 将 VPN 提示弹窗标记为已读(已读后的下一次显示"不再提醒"按钮)
VpnHelper.setVpnHintDialogShowed()
if (!VpnHelper.shouldShowVpnHintDialog()) {
VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
if (shouldShowVpnError) {
ToastUtils.toast("安装防护功能启动失败")
}
install(currentActivity, pkgPath)
}
} else {
DialogHelper.showGuideDialog(
context = currentActivity,
title = "开启安装防护",
content = "建议您开启安装防护功能该功能有助于帮助您更快的完成安装避免因提示和置换导致的重复下载等问题安装防护功能需要获取您的VPN权限",
confirmText = "立即授权开启防护",
cancelText = "不再提醒",
confirmClickCallback = {
VpnHelper.ignoreVpnHintDialog()
VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
if (shouldShowVpnError) {
ToastUtils.toast("安装防护功能启动失败")
}
install(currentActivity, pkgPath)
}
downloadEntity?.let {
NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "立即授权")
}
},
cancelClickCallback = {
VpnHelper.ignoreVpnFunction()
install(currentActivity, pkgPath)
downloadEntity?.let {
NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "不再提醒")
}
},
extraConfig = DialogHelper.Config(
showCloseIcon = true,
showAlternativeCancelStyle = !isTheFirstTimeToShowVpnHintDialog
),
uiModificationCallback = { binding ->
binding.cancelTv.visibility = View.GONE
binding.closeContainer.setOnClickListener {
binding.markDismissByTouchInside()
install(currentActivity, pkgPath)
binding.dismiss()
downloadEntity?.let {
NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "关闭按钮")
}
}
}
)
}
}
interface OnInstallListener {
fun onInstalling(packageName: String?, packagePath: String)
}
}

View File

@ -7,15 +7,14 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionInfo;
import android.content.pm.Signature;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.AndroidException;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -29,13 +28,11 @@ import com.gh.common.xapk.XapkInstaller;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.PackageFlavorHelper;
import com.gh.gamecenter.common.utils.PermissionHelper;
import com.gh.gamecenter.core.utils.MD5Utils;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.feature.utils.SentryHelper;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.vspace.VHelper;
import com.gh.vspace.db.VGameEntity;
@ -49,12 +46,10 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@ -68,20 +63,14 @@ import java.util.zip.ZipFile;
public class PackageUtils {
private static long mLastInstalledPackageListTime = 0L;
private static List<PackageInfo> mInstalledPackageList = null;
private static final String TAG = "PackageUtils";
// 设备是否支持禁用获取已安装应用列表。-1 代表支持情况未知0 代表不支持, 1 代表支持
private static int mIsSupportGetInstalledListPermission = -1;
public static String getInstallPackageInfoSourceDir(String packageName) {
try {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).applicationInfo.sourceDir;
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return null;
}
@ -234,8 +223,19 @@ public class PackageUtils {
if (metaDate != null) {
return metaDate.get(name);
}
} catch (NameNotFoundException e) {
// e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_META_DATA_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
}
return null;
}
@ -319,7 +319,7 @@ public class PackageUtils {
return new String[]{null, null};
}
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return new String[]{null, null};
}
@ -599,7 +599,7 @@ public class PackageUtils {
.getPackageInfo(packageName, 0);
return packageInfo.firstInstallTime;
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return 0;
}
@ -626,7 +626,7 @@ public class PackageUtils {
return HaloApp.getInstance().getApplication().getPackageManager()
.getPackageInfo(BuildConfig.APPLICATION_ID, 0).lastUpdateTime;
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return 0;
@ -639,8 +639,19 @@ public class PackageUtils {
try {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName;
} catch (NameNotFoundException e) {
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_VERSION_NAME_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
}
return null;
}
@ -652,8 +663,18 @@ public class PackageUtils {
try {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionCode;
} catch (NameNotFoundException e) {
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_VERSION_CODE_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
}
return 0;
}
@ -666,73 +687,49 @@ public class PackageUtils {
try {
PackageManager packageManager = context.getApplicationContext().getPackageManager();
return packageManager.getApplicationIcon(packageName);
} catch (NameNotFoundException e) {
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_ICON_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
}
return null;
}
/*
* 获取所有已安装的软件的包名、版本(非系统应用)
* 获取所有已安装的软件的包名(包括系统应用
*/
public static ArrayList<String> getAllPackageName(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) {
if (!context.getPackageName().equals(packageInfo.packageName)) {
list.add(packageInfo.packageName);
}
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
for (String packageName : packageNameList) {
if (!context.getPackageName().equals(packageName)) {
list.add(packageName);
}
}
return list;
}
public static ArrayList<String> getAllPackageNameIncludeGh(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = 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;
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
return new ArrayList<>(packageNameList);
}
public static JSONArray getAppList(Context context) {
JSONArray jsonArray = new JSONArray();
try {
PackageManager pm = context.getPackageManager();
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
JSONObject jsonObject = new JSONObject();
// 这里的 pm.getApplicationLabel 有极小机率会返回 null 值 (明明方法标示了返回值 nonnull
// Attempt to invoke interface method 'java.lang.String java.lang.CharSequence.toString()' on a null object reference
// 所以要是为空就 continue忽略掉它
if (pm.getApplicationLabel(packageInfo.applicationInfo) == null) {
continue;
}
jsonObject.put("name", pm.getApplicationLabel(packageInfo.applicationInfo).toString());
jsonObject.put("package", packageInfo.packageName);
jsonObject.put("version", packageInfo.versionName);
jsonArray.put(jsonObject);
}
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
for (String packageName : packageNameList) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("package", packageName);
jsonArray.put(jsonObject);
}
} catch (JSONException e) {
e.printStackTrace();
@ -752,13 +749,23 @@ public class PackageUtils {
jsonObject.put("version", packageInfo.versionName);
}
return jsonObject;
} catch (JSONException | NameNotFoundException e) {
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_APP_BASIC_INFO_BY_PACKAGE_NAME",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
return jsonObject;
}
}
/**
* 启动应用
* 请使用 PackageLauncher.launchApp()
@ -778,22 +785,6 @@ public class PackageUtils {
}
}
/*
* 根据包名,获取软件名称
*/
public static String getNameByPackageName(Context context, String packageName) {
try {
PackageManager pm = context.getApplicationContext().getPackageManager();
ApplicationInfo applicationInfo = pm.getApplicationInfo(
packageName, 0);
return applicationInfo.loadLabel(pm).toString();
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* todo 统一判断
* <p>
@ -912,8 +903,8 @@ public class PackageUtils {
String packageName = context.getApplicationContext().getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
// The name of the process that this object is associated with.
if (appProcess.processName.equals(packageName) && appProcess.importance
== ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
if (appProcess.processName.equals(packageName)
&& appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return true;
}
}
@ -924,132 +915,6 @@ public class PackageUtils {
return false;
}
/**
* 弃用已安装列表缓存
*/
public static void dumpInstalledListCache() {
mLastInstalledPackageListTime = 0;
}
public static List<PackageInfo> getInstalledPackages(Context context, int flags) {
Utils.log(TAG, "即将获取已安装应用列表");
// 简单 debounce 掉过于频繁的调用获取已安装列表调用
if (System.currentTimeMillis() - mLastInstalledPackageListTime < 1000
&& mInstalledPackageList != null
&& mInstalledPackageList.size() > 0) {
Utils.log(TAG, "使用了缓存的已安装应用列表");
return new ArrayList<>(mInstalledPackageList);
}
// 是否需要调用系统 API 获取最新的已安装应用列表
boolean shouldGetNewInstalledPackagedList = false;
// 当前设备是否支持限制获取已安装应用列表的功能
if (isSupportGetInstalledAppsPermission(context)) {
Utils.log(TAG, "当前设备支持限制获取已安装应用列表的功能");
// 当前设备是否支持禁用了获取已安装应用列表
if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
Utils.log(TAG, "当前设备没有限制获取已安装应用列表的功能");
shouldGetNewInstalledPackagedList = true;
} else {
Utils.log(TAG, "当前设备已限制获取已安装应用列表的功能");
}
} else {
Utils.log(TAG, "当前设备不支持限制获取已安装应用列表的功能");
shouldGetNewInstalledPackagedList = true;
}
if (shouldGetNewInstalledPackagedList) {
mLastInstalledPackageListTime = System.currentTimeMillis();
mInstalledPackageList = getInstalledPackagesInternal(context, flags);
}
if (mInstalledPackageList == null) {
mInstalledPackageList = new ArrayList<>();
}
return mInstalledPackageList;
}
public static boolean isSupportGetInstalledAppsPermission(Context context) {
// 若存在缓存,直接返回缓存结果。为 0 代表不支持,为 1 代表支持
if (mIsSupportGetInstalledListPermission != -1) {
return mIsSupportGetInstalledListPermission != 0;
}
try {
// 根据官方提供的方法来判定是否支持限制获取已安装应用列表
int flag = Settings.Secure.getInt(context.getContentResolver(), "oem_installed_apps_runtime_permission_enable", 0);
if (flag == 1) {
mIsSupportGetInstalledListPermission = 1;
return true;
}
// 部分未升级的手机没有上面配置项,有定义下面危险权限也认为是支持设备软件列表管控
PackageManager packageManager = context.getPackageManager();
PermissionInfo permissionInfo = packageManager.getPermissionInfo("com.android.permission.GET_INSTALLED_APPS", 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (permissionInfo.getProtection() == PermissionInfo.PROTECTION_DANGEROUS) {
mIsSupportGetInstalledListPermission = 1;
return true;
} else {
mIsSupportGetInstalledListPermission = 0;
return false;
}
} else {
mIsSupportGetInstalledListPermission = 0;
return false;
}
} catch (NameNotFoundException e) {
mIsSupportGetInstalledListPermission = 0;
return false;
}
}
/**
* 在5.1系统手机使用PackageManager获取已安装应用容易发生Package manager has died异常
* https://stackoverflow.com/questions/13235793/transactiontoolargeeception-when-trying-tÏo-get-a-list-of-applications-installed/30062632#30062632
*/
private static List<PackageInfo> getInstalledPackagesInternal(Context context, int flags) {
Utils.log(TAG, "调用系统 API 获取已安装应用列表");
final PackageManager pm = context.getPackageManager();
try {
return pm.getInstalledPackages(flags);
} catch (Exception ignored) {
//we don't care why it didn't succeed. We'll do it using an alternative way instead
}
// use fallback:
Process process;
List<PackageInfo> result = new ArrayList<>();
BufferedReader bufferedReader = null;
try {
process = Runtime.getRuntime().exec("pm list packages");
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
final String packageName = line.substring(line.indexOf(':') + 1);
final PackageInfo packageInfo = pm.getPackageInfo(packageName, flags);
result.add(packageInfo);
}
process.waitFor();
} catch (Exception e) {
e.printStackTrace();
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
} finally {
if (bufferedReader != null)
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
public static String getWebviewPath(Context context) {
final PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(context);
return webViewPackageInfo != null ? webViewPackageInfo.applicationInfo.sourceDir : null;

View File

@ -5,12 +5,12 @@ import android.os.Build;
import android.text.TextUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.retrofit.JSONObjectResponse;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.feature.entity.CommentEntity;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.lightgame.utils.Utils;
import com.walkud.rom.checker.RomIdentifier;
import org.json.JSONObject;
@ -37,7 +37,7 @@ public class PostCommentUtils {
device.put("model", Build.MODEL);
device.put("manufacturer", Build.MANUFACTURER);
device.put("android_version", android.os.Build.VERSION.RELEASE);
device.put("rom", RomIdentifier.getRom().name() + " " + RomIdentifier.getRom().getVersionName());
device.put("rom", MetaUtil.INSTANCE.getRom().name() + " " + MetaUtil.INSTANCE.getRom().getVersionName());
content.put("device", device);
} catch (Exception e) {
e.printStackTrace();

View File

@ -0,0 +1,342 @@
package com.gh.common.util
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.provider.Settings
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.gh.common.constant.Config
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.entity.NewApiSettingsEntity
import com.lightgame.utils.Utils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.enlargeTouchArea
import com.gh.gamecenter.common.utils.setDrawableEnd
import com.gh.gamecenter.core.utils.SPUtils
/**
* 处理厂商纯净/安全模式的辅助类
*/
object PureModeHelper {
private const val TAG = "PureModeHelper"
private const val HW = "HUAWEI"
private const val HW_PURE_MODE_STATE = "pure_mode_state"
private const val HW_PURE_ENHANCED_MODE_STATE = "pure_enhanced_mode_state"
private const val HW_PURE_MODE = "harmony_os_pure_mode"
private const val HW_PURE_ENHANCED_MODE = "harmony_os_pure_enhanced_mode"
private const val SP_USER_IGNORE_GUIDE = "user_ignore_guide"
private const val SWITCH_EXIST = 1
private const val SWITCH_ON = 0
private const val SWITCH_OFF = -1
private var isThisDeviceUsingEnhancedMode = false // 当前设备是否是增强纯净模式
fun handlePureModeIfNeeded(
context: Context,
gameId: String,
gameName: String,
gameType: String,
callback: () -> Unit
) {
// 用户忽略提醒,不再走下面的逻辑
if (SPUtils.getBoolean(SP_USER_IGNORE_GUIDE, false)) {
callback()
return
}
// 仅适用于华为手机
val manufacturer = android.os.Build.MANUFACTURER
if (manufacturer != HW) {
callback.invoke()
return
}
val solidContext = DialogHelper.checkDialogContext(context)
if (solidContext == null) {
callback.invoke()
return
}
if (readState(solidContext, HW_PURE_ENHANCED_MODE_STATE) == SWITCH_ON) {
Utils.log(TAG, "增强纯净模式开启!")
isThisDeviceUsingEnhancedMode = true
val pureModeGuide =
Config.getNewApiSettingsEntity()?.install?.guides?.firstOrNull { it.type == HW_PURE_ENHANCED_MODE }
if (pureModeGuide != null) {
showHWHintDialog(solidContext, pureModeGuide, gameId, gameName, gameType, true, callback)
} else {
callback.invoke()
}
} else if (readState(solidContext, HW_PURE_ENHANCED_MODE_STATE) != SWITCH_EXIST
&& readState(solidContext, HW_PURE_MODE_STATE) == SWITCH_ON
) {
Utils.log(TAG, "纯净模式开启!")
isThisDeviceUsingEnhancedMode = false
val pureModeGuide =
Config.getNewApiSettingsEntity()?.install?.guides?.firstOrNull { it.type == HW_PURE_MODE }
if (pureModeGuide != null) {
showHWHintDialog(solidContext, pureModeGuide, gameId, gameName, gameType, false, callback)
} else {
callback.invoke()
}
} else {
callback()
}
}
private fun showHWHintDialog(
context: Context,
guide: NewApiSettingsEntity.Guide,
gameId: String,
gameName: String,
gameType: String,
isEnhancedMode: Boolean,
callback: () -> Unit
) {
var isIgnored = false
if (context is Activity) {
if (context.isFinishing) {
callback.invoke()
return
}
}
trackDialogShow(isEnhancedMode, gameId, gameName, gameType)
DialogHelper.showGuideDialog(
context = context,
title = guide.title,
content = guide.content,
confirmText = guide.buttonTextSettingJump,
cancelText = guide.buttonTextClose,
uiModificationCallback = { binding ->
binding.hintTv.buildSpannableString {
addText(guide.linkTextPrefix)
addText(guide.linkText) {
setColor(ColorResId(R.color.text_theme))
onClick(false) {
binding.extraHintIv.performClick()
}
}
}
binding.extraHintIv.setImageResource(R.drawable.ic_home_head_arrow)
binding.extraHintIv.setOnClickListener {
directToLink(
context,
guide,
gameId,
gameName,
gameType,
isEnhancedMode,
isIgnored
)
}
binding.extraHintIv.enlargeTouchArea()
binding.extraHintIv.visibility = View.VISIBLE
binding.hintTv.visibility = View.VISIBLE
binding.selectorContainer.visibility = if (guide.dialogFrequency == "once") View.VISIBLE else View.GONE
binding.selectorContainer.setOnClickListener {
binding.selectorContainer.isChecked = !binding.selectorContainer.isChecked
isIgnored = binding.selectorContainer.isChecked
}
binding.confirmTv.setOnClickListener {
toHWPureModeSetting(context)
trackDialogClicked(
isEnhancedMode = isEnhancedMode,
gameId = gameId,
gameName = gameName,
gameType = gameType,
buttonName = guide.buttonTextSettingJump,
isIgnored = isIgnored
)
}
// 监听是否已授权,授权后自动调起安装并 dismiss dialog
if (context is AppCompatActivity) {
val lifecycle = context.lifecycle
lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
val granted = (isThisDeviceUsingEnhancedMode && readState(context, HW_PURE_ENHANCED_MODE_STATE) != SWITCH_ON)
|| (!isThisDeviceUsingEnhancedMode && readState(context, HW_PURE_MODE_STATE) != SWITCH_ON)
if (granted) {
binding.dialog.dismiss()
callback.invoke()
lifecycle.removeObserver(this)
}
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
lifecycle.removeObserver(this)
}
})
}
},
confirmClickCallback = {
// do nothing, 上面 setOnClickListener 处理了
},
cancelClickCallback = {
if (guide.dialogFrequency == "once" && isIgnored) {
SPUtils.setBoolean(SP_USER_IGNORE_GUIDE, true)
}
trackDialogClicked(
isEnhancedMode = isEnhancedMode,
gameId = gameId,
gameName = gameName,
gameType = gameType,
buttonName = guide.buttonTextClose,
isIgnored = isIgnored
)
callback()
},
touchOutsideCallback = {
if (guide.dialogFrequency == "once" && isIgnored) {
SPUtils.setBoolean(SP_USER_IGNORE_GUIDE, true)
}
trackDialogClicked(
isEnhancedMode = isEnhancedMode,
gameId = gameId,
gameName = gameName,
gameType = gameType,
buttonName = "关闭弹窗",
isIgnored = isIgnored
)
callback()
},
extraConfig = DialogHelper.Config(centerTitle = true)
)
}
private fun directToLink(
context: Context,
guide: NewApiSettingsEntity.Guide,
gameId: String,
gameName: String,
gameType: String,
isEnhancedMode: Boolean,
isIgnored: Boolean
) {
DirectUtils.directToLinkPage(context, guide.link, "纯净模式弹窗", "")
trackDialogClicked(
isEnhancedMode,
gameId,
gameName,
gameType,
"跳转链接",
isIgnored,
guide.link.link ?: "",
guide.link.type ?: "",
guide.link.text ?: ""
)
}
private fun trackDialogShow(
isEnhancedMode: Boolean,
gameId: String,
gameName: String,
gameType: String
) {
if (isEnhancedMode) {
SensorsBridge.trackAddedProtectionDialogShow(
gameId = gameId,
gameName = gameName,
gameType = gameType
)
} else {
SensorsBridge.trackPureModeDialogShow(
gameId = gameId,
gameName = gameName,
gameType = gameType
)
}
}
private fun trackDialogClicked(
isEnhancedMode: Boolean,
gameId: String,
gameName: String,
gameType: String,
buttonName: String,
isIgnored: Boolean,
linkId: String? = null,
linkType: String? = null,
linkText: String? = null
) {
if (isEnhancedMode) {
SensorsBridge.trackAddedProtectionDialogClick(
gameId = gameId,
gameName = gameName,
gameType = gameType,
buttonName = buttonName,
isIgnored = isIgnored,
linkId = linkId ?: "",
linkType = linkType ?: "",
linkText = linkText ?: ""
)
} else {
SensorsBridge.trackPureModeDialogClick(
gameId = gameId,
gameName = gameName,
gameType = gameType,
buttonName = buttonName,
isIgnored = isIgnored,
linkId = linkId ?: "",
linkType = linkType ?: "",
linkText = linkText ?: ""
)
}
}
private fun toHWPureModeSetting(context: Context) {
try {
val intent = Intent()
intent.setPackage("com.huawei.security.privacycenter")
intent.setAction("com.huawei.securitycenter.PURE_MODE_ACTIVITY")
intent.putExtra("intent_from_settings", true)
context.startActivity(intent)
} catch (_: Exception) {
toSystemSettings(context)
}
}
private fun toSystemSettings(context: Context) {
try {
val intent = Intent(Settings.ACTION_SETTINGS)
context.startActivity(intent)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun readState(context: Context, key: String): Int {
try {
val result = Settings.Secure.getInt(context.getContentResolver(), key, SWITCH_OFF)
Utils.log(TAG, "readState $key state >>> $result")
return result
} catch (e: Exception) {
e.printStackTrace()
}
return SWITCH_OFF
}
}

View File

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

View File

@ -27,8 +27,8 @@ import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
object SyncDataBetweenPageHelper {
private const val REQUEST_CODE_TAG = "REQUEST_CODE_TAG"
private const val DATA_POSITION_TAG = "DATA_POSITION_TAG"
const val REQUEST_CODE_TAG = "REQUEST_CODE_TAG"
const val DATA_POSITION_TAG = "DATA_POSITION_TAG"
private const val DEFAULT_NUMBER = -1111
fun startActivityForResult(context: Context, intent: Intent, requestCode: Int, dataPosition: Int) {

View File

@ -2,15 +2,16 @@ package com.gh.common.util
import android.os.Bundle
import androidx.fragment.app.Fragment
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.iinterface.ISuperiorChain
import com.gh.gamecenter.amway.AmwayFragment
import com.gh.gamecenter.category2.CategoryV2Fragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.provider.IHelpAndFeedbackProvider
import com.gh.gamecenter.discovery.DiscoveryFragment
import com.gh.gamecenter.entity.SubjectData
import com.gh.gamecenter.feedback.view.help.HelpAndFeedbackFragment
import com.gh.gamecenter.feedback.view.qa.HelpContainerFragment
import com.gh.gamecenter.forum.detail.ForumDetailFragment
import com.gh.gamecenter.forum.home.CommunityHomeFragment
import com.gh.gamecenter.fragment.ReloadFragment
@ -62,7 +63,8 @@ object ViewPagerFragmentHelper {
const val TYPE_GAME_LIST = "game_list" // 游戏单广场
const val TYPE_FEEDBACK = "feedback" // 帮助与反馈
const val TYPE_COLUMN = "column" // 游戏专题详情页
const val TYPE_QQ_MINI_GAME_COLUMN = "qq_mini_game_column_detail" // QQ游戏专题详情页
const val TYPE_QQ_MINI_GAME_COLUMN = "qq_mini_game_column_detail" // QQ游戏专题详情页
const val TYPE_WECHAT_GAME_COLUMN = "wechat_game_column_detail" // 微信小游戏专题详情页
const val TYPE_COLUMN_COLLECTION = "column_collection" // 专题合集详情页
const val TYPE_SERVER = "server" // 开服表
const val TYPE_COLUMN_TEST = "column_test_v2" // 新游开测
@ -124,7 +126,15 @@ object ViewPagerFragmentHelper {
}
// 帮助与反馈
TYPE_FEEDBACK -> {
HelpAndFeedbackFragment().with(bundle)
val helpAndFeedbackProvider =
ARouter.getInstance().build(RouteConsts.provider.helpAndFeedback)
.navigation() as? IHelpAndFeedbackProvider
if (helpAndFeedbackProvider != null) {
helpAndFeedbackProvider.getHelpAndFeedbackFragment().with(bundle)
} else {
// 纯粹是占位用的 fragment
AmwayFragment().with(bundle)
}
}
// 帖子
TYPE_COMMUNITY_ARTICLE -> {
@ -151,11 +161,16 @@ object ViewPagerFragmentHelper {
className = GameCollectionSquareFragment::class.java.name
}
// 游戏专题详情页/QQ游戏专题详情页
TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN -> {
TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN, TYPE_WECHAT_GAME_COLUMN -> {
val subjectType = when(entity.type) {
TYPE_QQ_MINI_GAME_COLUMN -> SubjectData.SubjectType.QQ_GAME
TYPE_WECHAT_GAME_COLUMN -> SubjectData.SubjectType.WECHAT_GAME
else -> SubjectData.SubjectType.NORMAL
}
className = SubjectFragment::class.java.name
bundle.putParcelable(
EntranceConsts.KEY_SUBJECT_DATA,
SubjectData(entity.link, entity.text, false, isQQMiniGame = entity.type == "qq_mini_game_column_detail")
SubjectData(entity.link, entity.text, false, subjectType = subjectType)
)
bundle.putBoolean(EntranceConsts.KEY_SHOW_DOWNLOAD_MENU, !isTabWrapper)
}
@ -175,6 +190,8 @@ object ViewPagerFragmentHelper {
// 新游开测
TYPE_COLUMN_TEST -> {
className = GameServerTestV2Fragment::class.java.name
bundle.putString(EntranceConsts.KEY_ID, entity.link)
bundle.putString(EntranceConsts.KEY_NAME, entity.text)
}
// 分类2.0
TYPE_CATEGORY_V2 -> {
@ -227,9 +244,15 @@ object ViewPagerFragmentHelper {
}
// QA
TYPE_QA -> {
className = HelpContainerFragment::class.java.name
bundle.putString(EntranceConsts.KEY_QA_ID, entity.link)
bundle.putString(EntranceConsts.KEY_NAVIGATION_TITLE, entity.text)
val helpAndFeedbackProvider =
ARouter.getInstance().build(RouteConsts.provider.helpAndFeedback)
.navigation() as? IHelpAndFeedbackProvider
helpAndFeedbackProvider?.let {
className = it.getHelpContainerFragmentClass()
bundle.putString(EntranceConsts.KEY_QA_ID, entity.link)
bundle.putString(EntranceConsts.KEY_NAVIGATION_TITLE, entity.text)
}
}
// 资讯中心
TYPE_ARTICLE_CENTER -> {

View File

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

View File

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

View File

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

View File

@ -6,25 +6,21 @@ import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.debounceActionWithInterval
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toResString
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.TopCutProcess
import com.gh.gamecenter.databinding.ItemCommunityImageBinding
import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.feature.entity.CommunityVideoEntity
import com.gh.gamecenter.feature.entity.ImageInfo
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
class ImageContainerView : LinearLayout {
private var mAnswerEntity: AnswerEntity? = null
private var data: ImageContainerData? = null
//三图默认宽度
private var mDefaultWidth = 0f
@ -41,9 +37,6 @@ class ImageContainerView : LinearLayout {
//长图比例
private var mLongPictureRatio = 9 / 18f
private var mEntrance = ""
private var mPath = ""
//图片之间的间距
private val mItemSpace = 4f.dip2px()
private var mOffset = 0
@ -51,6 +44,8 @@ class ImageContainerView : LinearLayout {
private val imageViewList = arrayListOf<SimpleDraweeView>()
private var onImageContainerEventListener: OnImageContainerEventListener? = null
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
@ -75,40 +70,34 @@ class ImageContainerView : LinearLayout {
calculateWidth()
}
fun bindData(entity: AnswerEntity, entrance: String = "", path: String = "", imageClick: (() -> Unit)? = null) {
fun bindData(
data: ImageContainerData,
listener: OnImageContainerEventListener? = null
) {
this.data = data
onImageContainerEventListener = listener
imageViewList.clear()
if (entity.id != mAnswerEntity?.id) {
removeAllViews()
}
mAnswerEntity = entity
mEntrance = entrance
mPath = path
removeAllViews()
index = 0
if ((entity.user.id == UserManager.getInstance().userId && entity.videos.isNotEmpty()) ||
(entity.user.id != UserManager.getInstance().userId && entity.getPassVideos().isNotEmpty()) ||
entity.images.isNullOrEmpty()
) {
if (!data.show) {
visibility = View.GONE
return
}
visibility = View.VISIBLE
if (mAnswerEntity?.type == "community_article") {
if (data.isPostCard) {
//若文章内容含有图片及视频,则信息流卡片,仅展示图片,且标题后带有‘有视频’标签
//若文章内容仅含有图片,则信息流卡片,仅展示图片,无标签
//若文章内容仅含有视频,则信息流卡片,仅展示视频,无标签
when {
entity.images.isNotEmpty() -> {
val imagesInfo = entity.imagesInfo
val images = entity.images.take(3)
images.forEachIndexed { index, url ->
val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0
val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0
bindImage(url, width, height, images.size == 1, imageClick)
}
data.images.isNotEmpty() -> {
data.images.take(3)
.forEach {
bindImage(it.url, it.width, it.height, data.images.size == 1)
}
}
entity.getPassVideos().isNotEmpty() -> {
val video = entity.getPassVideos()[0]
data.video != null -> {
val video = data.video
bindVideo(video, video.width, video.height, true)
}
@ -120,28 +109,22 @@ class ImageContainerView : LinearLayout {
//若问答内容含有图片及视频,则信息流卡片,同时展示图片及视频,且参考以往排序逻辑(视频优先放置第一位),无标签
//若问答内容仅含有图片,则信息流卡片,仅展示图片,无标签
//若问答内容仅含有视频,则信息流卡片,仅展示视频,无标签
if (entity.getPassVideos().isNotEmpty()) {
val video = entity.getPassVideos()[0]
bindVideo(video, video.width, video.height, mAnswerEntity?.images.isNullOrEmpty())
entity.images.take(2).forEachIndexed { index, url ->
val imagesInfo = entity.imagesInfo
val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0
val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0
bindImage(url, width, height, false, imageClick)
if (data.video != null) {
val video = data.video
bindVideo(video, video.width, video.height, data.images.isNullOrEmpty())
data.images.take(2).forEach {
bindImage(it.url, it.width, it.height, false)
}
} else {
val images = entity.images.take(3)
images.forEachIndexed { index, url ->
val imagesInfo = entity.imagesInfo
val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0
val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0
bindImage(url, width, height, images.size == 1, imageClick)
}
data.images.take(3)
.forEach {
bindImage(it.url, it.width, it.height, data.images.size == 1)
}
}
}
}
private fun bindVideo(video: CommunityVideoEntity, width: Int, height: Int, isChangeRatio: Boolean) {
private fun bindVideo(video: ImageContainerData.VideoInfo, width: Int, height: Int, isChangeRatio: Boolean) {
val oldView = if (childCount == 0 || index >= childCount) null else getChildAt(index)
val binding = if (oldView != null) {
ItemCommunityImageBinding.bind(oldView)
@ -158,16 +141,7 @@ class ImageContainerView : LinearLayout {
displayImage(binding, video.poster, width.toFloat(), height.toFloat(), isChangeRatio, true)
binding.root.setOnClickListener {
debounceActionWithInterval(it.id, 1000) {
if (mAnswerEntity == null) return@debounceActionWithInterval
val videoEntity = mAnswerEntity!!.getPassVideos().firstOrNull()
DirectUtils.directToVideoDetail(
context,
videoEntity?.id ?: "",
VideoDetailContainerViewModel.Location.VIDEO_HOT.value,
showComment = false,
entrance = mEntrance,
path = mPath
)
onImageContainerEventListener?.onVideoCLick(video.id)
}
}
index++
@ -177,8 +151,7 @@ class ImageContainerView : LinearLayout {
url: String,
width: Int,
height: Int,
isChangeRatio: Boolean,
imageClick: (() -> Unit)?
isChangeRatio: Boolean
) {
val oldView = if (childCount == 0 || index >= childCount) null else getChildAt(index)
val binding = if (oldView != null) {
@ -195,25 +168,21 @@ class ImageContainerView : LinearLayout {
binding.videoPlay.visibility = View.GONE
displayImage(binding, url, width.toFloat(), height.toFloat(), isChangeRatio)
binding.root.setOnClickListener {
if (mAnswerEntity?.status == "pending" || mAnswerEntity?.status == "fail") return@setOnClickListener
imageClick?.invoke()
if (data?.status == "pending" || data?.status == "fail") return@setOnClickListener
debounceActionWithInterval(it.id, 1000) {
if (mAnswerEntity == null) return@debounceActionWithInterval
val position = if (mAnswerEntity?.type == "community_article") {
binding.root.tag as Int
} else {
if (mAnswerEntity!!.getPassVideos()
.isNullOrEmpty()
) binding.root.tag as Int else (binding.root.tag as Int) - 1
data?.run {
val position = if (isPostCard) {
binding.root.tag as Int
} else {
if (video == null) binding.root.tag as Int else (binding.root.tag as Int) - 1
}
onImageContainerEventListener?.onImageClick(
images.map(ImageContainerData.ImageInfo::url),
position,
imageViewList
)
}
if (mAnswerEntity?.communityId.isNullOrEmpty()) {
mAnswerEntity?.communityId = mAnswerEntity?.bbs?.id
}
val intent = ImageViewerActivity.getIntent(
context, mAnswerEntity!!.images as ArrayList<String>, position, imageViewList,
if (mAnswerEntity?.type == "community_article") mAnswerEntity else null, mEntrance, true
)
context.startActivity(intent)
}
}
index++
@ -279,7 +248,7 @@ class ImageContainerView : LinearLayout {
}
binding.pendingView.run {
when (mAnswerEntity?.status) {
when (data?.status) {
"pending" -> {
visibility = View.VISIBLE
text = R.string.pending_status.toResString()
@ -297,7 +266,7 @@ class ImageContainerView : LinearLayout {
}
val imageCount = mAnswerEntity?.images?.size ?: 0
val imageCount = data?.images?.size ?: 0
if (!isVideo && index == 2 && imageCount > 3) {
binding.labelIcon.visibility = View.GONE
binding.durationOrNumTv.visibility = View.VISIBLE
@ -308,4 +277,80 @@ class ImageContainerView : LinearLayout {
if (index != 0) params.leftMargin = mItemSpace
binding.root.layoutParams = params
}
companion object {
private const val COMMUNITY_ARTICLE = "community_article"
fun AnswerEntity.toImageContainerData(): ImageContainerData {
val imageInfoList = arrayListOf<ImageContainerData.ImageInfo>()
images.forEachIndexed { index, url ->
if (index < 3) {
imageInfoList.add(ImageContainerData.ImageInfo(url))
}
}
imageInfoList.forEachIndexed { index, imageInfo ->
val item = imagesInfo.getOrNull(index)
if (item != null) {
imageInfo.width = item.width
imageInfo.height = item.height
}
}
val video =
getPassVideos().firstOrNull()?.let {
ImageContainerData.VideoInfo(
it.id,
it.duration,
it.poster,
it.width,
it.height
)
}
val show = !((user.id == UserManager.getInstance().userId && videos.isNotEmpty())
|| (user.id != UserManager.getInstance().userId && getPassVideos().isNotEmpty())
|| images.isNullOrEmpty())
return ImageContainerData(
status = status,
isPostCard = type == COMMUNITY_ARTICLE,
images = imageInfoList,
video = video,
show
)
}
}
data class ImageContainerData(
val status: String,
val isPostCard: Boolean, // 是否是帖子卡片
val images: List<ImageInfo>,
val video: VideoInfo? = null,
val show: Boolean
) {
data class ImageInfo(
val url: String,
var width: Int = 0,
var height: Int = 0
)
data class VideoInfo(
val id: String,
val duration: String,
val poster: String,
var width: Int = 0,
var height: Int = 0,
)
}
interface OnImageContainerEventListener {
fun onImageClick(
images: List<String>,
position: Int,
imageViewList: ArrayList<SimpleDraweeView>
)
fun onVideoCLick(videoId: String)
}
}

View File

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

View File

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

View File

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

View File

@ -6,8 +6,12 @@ import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.text.SpannableStringBuilder
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.text.underline
import androidx.core.view.updateLayoutParams
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.activityresult.ActResultRequest
@ -37,6 +41,14 @@ object XapkDialogHelper {
val previousShowedDialog = mUnzipFailureDialogRef?.get()
val useRebootStyle = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val content = if (useRebootStyle) {
"未授权允许未知来源安装、数据包格式、设备兼容性…等均可能导致解压失败。"
} else {
"未授权允许未知来源安装、数据包格式、设备兼容性…等均可能导致解压失败。\n如果开启权限后仍未能解决,请提交反馈帮助我们改进。"
}
if (previousShowedDialog != null
&& previousShowedDialog.isShowing
&& context == previousShowedDialog.ownerActivity
@ -48,9 +60,9 @@ object XapkDialogHelper {
val dialog = DialogHelper.showGuideDialog(
context = context,
title = "",
content = "未授权允许未知来源安装、数据包格式、设备兼容性…等均可能导致解压失败。\n如果开启权限后仍未能解决,请提交反馈帮助我们改进。",
content = content,
confirmText = "开启权限",
cancelText = "提交反馈",
cancelText = if (useRebootStyle) "重启助手" else "提交反馈",
confirmClickCallback = {
if (context is AppCompatActivity) {
val intent = PermissionHelper.getToInstallPermissionSettingIntent(context)
@ -83,11 +95,7 @@ object XapkDialogHelper {
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val pm = context.packageManager
val restartIntent = pm.getLaunchIntentForPackage(context.packageName)
val mainIntent = Intent.makeRestartActivityTask(restartIntent!!.component)
context.startActivity(mainIntent)
Runtime.getRuntime().exit(0)
restart(context)
} else {
XapkInstaller.install(context, downloadEntity, true)
}
@ -100,27 +108,22 @@ object XapkDialogHelper {
}
},
cancelClickCallback = {
val hint = "游戏安装包解压失败,问题反馈:"
HelpAndFeedbackBridge.startSuggestionActivity(
context,
SuggestType.GAME,
null,
hint,
SimpleGameEntity(downloadEntity.gameId, downloadEntity.name, downloadEntity.icon)
)
NewFlatLogUtils.logXApkUnzipFailedDialogClick(
"提交反馈",
false,
downloadEntity.gameId,
downloadEntity.name
)
if (useRebootStyle) {
// 记录应用重启前需要重解压的信息
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, context.javaClass.name)
SPUtils.setString(Constants.SP_XAPK_URL, downloadEntity.url)
SensorsBridge.trackGameDecompressionFailedDialogClick(
buttonName = "提交反馈",
downloadEntity.gameId,
downloadEntity.name,
downloadEntity.categoryChinese
)
SensorsBridge.trackGameDecompressionFailedDialogClick(
buttonName = "重启助手",
downloadEntity.gameId,
downloadEntity.name,
downloadEntity.categoryChinese
)
restart(context)
} else {
doFeedback(context, downloadEntity)
}
},
uiModificationCallback = { binding ->
binding.headIv.setBackgroundResource(R.drawable.dialog_unzip_failure_head_background)
@ -146,6 +149,30 @@ object XapkDialogHelper {
)
binding.dismiss()
}
if (useRebootStyle) {
val spannableString = SpannableStringBuilder()
.append("未能解决问题?点击 ")
.underline { append("提交反馈") }
.append(" ")
binding.alternativeCancelTv.visibility = View.VISIBLE
binding.alternativeCancelTv.text = spannableString
binding.alternativeCancelTv.setTextColor(R.color.text_secondary.toColor(context))
binding.alternativeCancelTv.setDrawableEnd(R.drawable.ic_right_arrow_xapk)
binding.alternativeCancelTv.setOnClickListener {
doFeedback(context, downloadEntity)
}
binding.hintTv.text = "开启权限后请务必重启光环助手,再进行安装"
binding.hintTv.setTextColor(R.color.text_theme.toColor(context))
binding.hintTv.setTextAppearance(R.style.TextCaption1)
binding.hintTv.visibility = View.VISIBLE
binding.hintTv.updateLayoutParams<ConstraintLayout.LayoutParams> {
topMargin = 8F.dip2px()
}
binding.confirmTv.updateLayoutParams<ConstraintLayout.LayoutParams> {
topMargin = 16F.dip2px()
}
}
},
touchOutsideCallback = {
SensorsBridge.trackGameDecompressionFailedDialogClick(
@ -164,4 +191,37 @@ object XapkDialogHelper {
mUnzipFailureDialogRef = WeakReference(dialog)
}
private fun restart(context: Context) {
val pm = context.packageManager
val restartIntent = pm.getLaunchIntentForPackage(context.packageName)
val mainIntent = Intent.makeRestartActivityTask(restartIntent!!.component)
context.startActivity(mainIntent)
Runtime.getRuntime().exit(0)
}
private fun doFeedback(context: Context, downloadEntity: DownloadEntity) {
val hint = "游戏安装包解压失败,问题反馈:"
HelpAndFeedbackBridge.startSuggestionActivity(
context,
SuggestType.GAME,
null,
hint,
SimpleGameEntity(downloadEntity.gameId, downloadEntity.name, downloadEntity.icon?: "")
)
NewFlatLogUtils.logXApkUnzipFailedDialogClick(
"提交反馈",
false,
downloadEntity.gameId,
downloadEntity.name
)
SensorsBridge.trackGameDecompressionFailedDialogClick(
buttonName = "提交反馈",
downloadEntity.gameId,
downloadEntity.name,
downloadEntity.categoryChinese
)
}
}

View File

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

View File

@ -10,8 +10,8 @@ import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.exposure.meta.MetaUtil.getMeta
import com.gh.gamecenter.common.loghub.LoghubUtils
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.SentryHelper
import com.gh.ndownload.NDataChanger
import com.gh.ndownload.NDownloadBridge
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadConfig
import com.lightgame.download.DownloadEntity
@ -124,6 +124,7 @@ object DownloadDataHelper {
val payloadObject = JSONObject()
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
payloadObject.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
payloadObject.put("game_id", downloadEntity.gameId)
payloadObject.put("gameName", downloadEntity.name)
payloadObject.put("platform", downloadEntity.platform)
@ -212,6 +213,7 @@ object DownloadDataHelper {
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
payloadObject.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
payloadObject.put("game_id", downloadEntity.gameId)
payloadObject.put("gameName", downloadEntity.name)
payloadObject.put("platform", downloadEntity.platform)
@ -251,6 +253,7 @@ object DownloadDataHelper {
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
payloadObject.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
payloadObject.put("game_id", downloadEntity.gameId)
payloadObject.put("gameName", downloadEntity.name)
payloadObject.put("platform", downloadEntity.platform)
@ -315,6 +318,7 @@ object DownloadDataHelper {
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
payloadObject.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
payloadObject.put("game_id", downloadEntity.gameId)
payloadObject.put("gameName", downloadEntity.name)
payloadObject.put("platform", downloadEntity.platform)
@ -357,6 +361,7 @@ object DownloadDataHelper {
sheet = JSONObject()
sheet.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
sheet.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
sheet.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
sheet.put("game_id", downloadEntity.gameId)
sheet.put("platform", downloadEntity.platform)
sheet.put("package", downloadEntity.packageName)
@ -376,6 +381,7 @@ object DownloadDataHelper {
"path",
downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown"
) // 初始化记录的 path 为空
sheet.put("redirected_host_list", downloadEntity.meta[NDownloadBridge.REDIRECTED_HOST_LIST] ?: "unknown")
sheet.put("total_size", downloadEntity.size / 1024 / 1024) // 初始化记录的 total_size 有可能为0
sheet.put("progress_size", downloadEntity.progress / 1024 - progressSize)
sheet.put("current_progress_size", downloadEntity.progress / 1024)

View File

@ -20,9 +20,9 @@ import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.core.GHThreadFactory;
import com.gh.gamecenter.feature.entity.TagStyleEntity;
import com.gh.gamecenter.feature.entity.CustomPageTrackData;
import com.gh.gamecenter.feature.entity.TagStyleEntity;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
import com.gh.common.exposure.ExposureUtils;
import com.gh.common.history.HistoryHelper;
@ -34,20 +34,13 @@ import com.gh.common.util.LunchType;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.base.GlobalActivityManager;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.utils.DeviceUtils;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.FileUtils;
import com.gh.gamecenter.common.utils.NetworkUtils;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.utils.AppDebugConfig;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.download.DownloadedGameIdAndPackageNameDao;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.entity.HomePluggableFilterEntity;
@ -55,7 +48,7 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.PluginLocation;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
import com.gh.gamecenter.feature.utils.SentryHelper;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.gamecenter.packagehelper.PackageRepository;
@ -64,7 +57,6 @@ import com.gh.ndownload.NDownloadBridge;
import com.gh.ndownload.NDownloadService;
import com.gh.vspace.VHelper;
import com.halo.assistant.HaloApp;
import com.lightgame.download.ConnectionUtils;
import com.lightgame.download.DataWatcher;
import com.lightgame.download.DownloadConfig;
import com.lightgame.download.DownloadDao;
@ -85,6 +77,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class DownloadManager implements DownloadStatusListener {
@ -111,6 +105,9 @@ public class DownloadManager implements DownloadStatusListener {
private final Set<String> mUpdateMarks;
private final ExecutorService packageExecutor
= Executors.newSingleThreadExecutor(new GHThreadFactory("GH_DOWNLOAD_MANAGER_THREAD"));
@Override
public void onTaskCancelled(DownloadEntity entity) {
EBDownloadStatus status = new EBDownloadStatus("delete", entity.getName(),
@ -179,9 +176,6 @@ public class DownloadManager implements DownloadStatusListener {
mUpdateMarks = SPUtils.getStringSet(UPDATE_IS_READ_MARK);
// 只有下载模块需要这坨东西,因此移动到这里初始化
ConnectionUtils.initHttpsUrlConnection(mContext);
updateDownloadMetaMap();
lastTimeMap = new ArrayMap<>();
@ -304,7 +298,7 @@ public class DownloadManager implements DownloadStatusListener {
// 下载模拟器游戏配置文件,地址是 "模拟器游戏类型根目录/cheat/"
if (!TextUtils.isEmpty(gameEntity.getSimulatorGameConfig())) {
String configFilePath = SimulatorGameManager.getPathByType(gameEntity.getSimulatorType()) + "/cheat/" + apkEntity.getPackageName() + ".ini";
AppExecutor.getIoExecutor().execute(() -> {
getInstance().packageExecutor.execute(() -> {
FileUtils.downloadFile(gameEntity.getSimulatorGameConfig(), configFilePath);
});
}
@ -362,9 +356,10 @@ public class DownloadManager implements DownloadStatusListener {
ExtensionsKt.addMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE, Constants.VGAME);
ExtensionsKt.addMetaExtra(downloadEntity, DownloadConfig.KEY_PROGRESS_CALLBACK_INTERVAL, "200");
ExtensionsKt.addMetaExtra(downloadEntity, VHelper.KEY_REQUIRED_G_APPS, gameEntity.getGAppsSwitch());
ExtensionsKt.addMetaExtra(downloadEntity, VHelper.KEY_BIT, apkEntity.getBit());
}
ExtensionsKt.addMetaExtra(downloadEntity, Constants.KEY_BIT, apkEntity.getBit());
// 记录是否为双下载按钮模式
if (isDualDownloadTypeEnabled) {
if (asVGame) {
@ -547,6 +542,7 @@ public class DownloadManager implements DownloadStatusListener {
checkDownloadEntryRecordValidate(url);
if (isDownloadCompleted(url)) {
downloadEntity.setStatus(DownloadStatus.done);
mDownloadDao.newOrUpdate(downloadEntity);
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
} else if (!isTaskDownloading(url)) {
DownloadEntity daoEntity = mDownloadDao.get(downloadEntity.getUrl());
@ -661,7 +657,7 @@ public class DownloadManager implements DownloadStatusListener {
* @return 下载任务快照列表
*/
@NonNull
private ArrayList<DownloadEntity> getAllDownloadEntitySnapshots() {
public ArrayList<DownloadEntity> getAllDownloadEntitySnapshots() {
return mDownloadDao.getAllSnapshots();
}
@ -917,7 +913,7 @@ public class DownloadManager implements DownloadStatusListener {
DownloadEntity entry = mDownloadDao.getSnapshot(url);
DownloadDataSimpleHelper.INSTANCE.removeDownloadSimpleEntity(url);
if (entry != null) {
AppExecutor.getIoExecutor().execute(() -> {
getInstance().packageExecutor.execute(() -> {
NDownloadBridge.INSTANCE.cancel(url);
mDownloadDao.delete(url);
@ -959,7 +955,6 @@ public class DownloadManager implements DownloadStatusListener {
// 改任务队列的状态
NDataChanger.INSTANCE.getDownloadingTaskUrlSet().remove(entry.getUrl());
NDataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl());
if (!cancelSilently) {
NDataChanger.INSTANCE.notifyDataChanged(entry);
onTaskCancelled(entry);
@ -972,9 +967,9 @@ public class DownloadManager implements DownloadStatusListener {
* 暂停所有正在下载的任务
*/
public void pauseAll() {
synchronized (NDataChanger.INSTANCE.getDownloadEntries()) {
for (DownloadEntity entity : NDataChanger.INSTANCE.getDownloadEntries().values()) {
pause(entity.getUrl());
synchronized (NDataChanger.INSTANCE.getDownloadingTaskUrlSet()) {
for (String url : NDataChanger.INSTANCE.getDownloadingTaskUrlSet()) {
pause(url);
}
}
Utils.log(DownloadManager.class.getSimpleName(), "pause all");
@ -985,7 +980,7 @@ public class DownloadManager implements DownloadStatusListener {
*/
public void pause(String url) {
checkDownloadEntryRecordValidate(url);
DownloadEntity entry = NDataChanger.INSTANCE.getDownloadEntries().get(url);
DownloadEntity entry = getDownloadEntitySnapshot(url);
if (entry != null) {
startDownloadService(entry, DownloadStatus.pause);
put(url, System.currentTimeMillis());
@ -1001,19 +996,21 @@ public class DownloadManager implements DownloadStatusListener {
* 3.检查是否显示下载通知栏
*/
public void initDownloadService() {
final Set<String> urlSet = NDataChanger.INSTANCE.getDownloadingTaskUrlSet();
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
if (!urlSet.contains(downloadEntity.getUrl())
&& (downloadEntity.getStatus().equals(DownloadStatus.downloading)
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
downloadEntity.setStatus(DownloadStatus.subscribe);
mDownloadDao.newOrUpdate(downloadEntity);
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
packageExecutor.execute(() -> {
final Set<String> urlSet = NDataChanger.INSTANCE.getDownloadingTaskUrlSet();
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
if (!urlSet.contains(downloadEntity.getUrl())
&& (downloadEntity.getStatus().equals(DownloadStatus.downloading)
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
downloadEntity.setStatus(DownloadStatus.subscribe);
mDownloadDao.newOrUpdate(downloadEntity);
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
}
}
}
startDownloadService();
checkAndRetryDownload();
startDownloadService();
checkAndRetryDownload(true);
});
}
/**
@ -1104,13 +1101,15 @@ public class DownloadManager implements DownloadStatusListener {
/**
* 检查并尝试重试下载
*/
public void checkAndRetryDownload() {
public void checkAndRetryDownload(boolean includePausedTask) {
if (!NetworkUtils.isWifiConnected(mContext)) return;
for (DownloadEntity downloadEntity : DownloadManager.getInstance().getAllDownloadEntityExcludeDoneTask()) {
if (DownloadStatus.neterror.equals(downloadEntity.getStatus())
|| DownloadStatus.timeout.equals(downloadEntity.getStatus())
|| DownloadStatus.subscribe.equals(downloadEntity.getStatus())) {
|| DownloadStatus.subscribe.equals(downloadEntity.getStatus())
|| (includePausedTask && DownloadStatus.pause.equals(downloadEntity.getStatus()))
) {
DownloadManager.getInstance().put(downloadEntity.getUrl(), System.currentTimeMillis());
Message msg = Message.obtain();
msg.what = DownloadConfig.CONTINUE_DOWNLOAD_AUTO_TASK;
@ -1215,7 +1214,7 @@ public class DownloadManager implements DownloadStatusListener {
* 标记下载已完成的任务为已读 (用于下载管理页入口的 toolbar 红点显示)
*/
public void markDownloadedTaskAsRead() {
AppExecutor.getIoExecutor().execute(() -> {
getInstance().packageExecutor.execute(() -> {
boolean markHasChanged = false;
List<DownloadEntity> all = getAllDownloadEntityExcludeSilentTask();
@ -1255,7 +1254,7 @@ public class DownloadManager implements DownloadStatusListener {
* 更改下载中任务的已读状态(用于下载页及外部toolbar)
*/
private void markDownloadingTaskAsReadOrUnread(boolean isRead) {
AppExecutor.getIoExecutor().execute(() -> {
getInstance().packageExecutor.execute(() -> {
boolean markHasChanged = false;
List<DownloadEntity> all = getAllDownloadEntityExcludeSilentTask();
@ -1286,7 +1285,7 @@ public class DownloadManager implements DownloadStatusListener {
* 标记可用更新为已读 (用于下载管理页入口的 toolbar 红点显示)
*/
public void markUpdatableTaskAsRead() {
AppExecutor.getIoExecutor().execute(() -> {
getInstance().packageExecutor.execute(() -> {
boolean markHasChanged = false;
ArrayList<GameUpdateEntity> updates = PackageRepository.INSTANCE.getGameUpdate();
@ -1385,7 +1384,7 @@ public class DownloadManager implements DownloadStatusListener {
* 手动触发下载 LiveData 变更
*/
public void notifyDownloadLiveDataChanged() {
AppExecutor.getIoExecutor().execute(() -> mDownloadEntityListLiveData.postValue(getAllDownloadEntity()));
getInstance().packageExecutor.execute(() -> mDownloadEntityListLiveData.postValue(getAllDownloadEntity()));
}
/**

View File

@ -14,12 +14,13 @@ import com.gh.gamecenter.common.retrofit.EmptyResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ThirdPartyPackageHelper
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.GameDigestEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.utils.ConcernUtils
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.manager.PackagesManager
@ -55,7 +56,7 @@ object PackageObserver {
}
@JvmStatic
fun onPackageChanged(busFour: EBPackage) {
fun onPackageChanged(busFour: EBPackage, cachedGameEntity: GameEntity? = null) {
val application = HaloApp.getInstance().application
val packageName = busFour.packageName
val versionName = busFour.versionName
@ -99,7 +100,7 @@ object PackageObserver {
if (EBPackage.TYPE_INSTALLED == busFour.type) {
if (!busFour.isVGame) {
// 非畅玩游戏才执行下面的代码
mPackageViewModel.addInstalledGame(packageName)
mPackageViewModel.addInstalledGame(packageName, cachedGameEntity)
BrowserInstallHelper.onApkInstalled(mDownloadEntity?.path)
}
@ -153,7 +154,7 @@ object PackageObserver {
}
}
runOnIoThread { postNewlyInstalledApp(gameId, packageName) }
AppExecutor.logExecutor.execute { postNewlyInstalledApp(gameId, packageName) }
}
if (EBPackage.TYPE_UNINSTALLED == busFour.type) {

View File

@ -24,6 +24,7 @@ import com.gh.gamecenter.common.base.fragment.BaseDraggableDialogFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.utils.safelyGetInRelease
import com.gh.gamecenter.common.utils.throwExceptionInDebug
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.TimeElapsedHelper
@ -181,7 +182,7 @@ class DownloadDialog : BaseDraggableDialogFragment() {
AppExecutor.uiExecutor.executeWithDelay({
recyclerView.adapter?.let {
for (i in 0 until it.itemCount) {
val apkEntity = itemList[i].normal ?: continue
val apkEntity = itemList.safelyGetInRelease(i)?.normal ?: continue
val apkCollection = apkEntity.apkCollection
val platformName = platformList[0].name
val packageName = platformList[0].packageName

View File

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

View File

@ -28,10 +28,10 @@ import org.json.JSONObject
import java.io.File
import java.net.URLEncoder
import java.util.*
import kotlin.collections.ArrayList
object BrowserInstallHelper {
// 随便选的 32321 居然在部分 vivo 手机上被占用,喷了
private const val PORT = 40705
private const val RESERVE_PORT = 40706
@ -40,15 +40,12 @@ object BrowserInstallHelper {
private val mContext by lazy { HaloApp.getInstance().application }
private var mUseReservePort = false
private val mAllInstalledPackageList: ArrayList<String> by lazy {
PackageUtils.getAllPackageNameIncludeSystemApps(HaloApp.getInstance().applicationContext).apply {
add(HaloApp.getInstance().applicationContext.packageName)
}
}
private var mValidInstalledPackageList: ArrayList<String> = arrayListOf()
private var mValidConditionMatchedCache: Boolean? = null
private fun getServer(port: Int): DownloadServer {
val server = DownloadServer(port)
for (packageName in mAllInstalledPackageList) {
for (packageName in getAllInstalledPackageList()) {
if (packageName.contains("com.freeme") || packageName.contains("com.zhuoyi")) {
server.isBuggyDevice = true
break
@ -57,6 +54,23 @@ object BrowserInstallHelper {
return server
}
private fun getAllInstalledPackageList(): ArrayList<String> {
when {
mValidInstalledPackageList.isNotEmpty() -> {
return mValidInstalledPackageList
}
else -> {
val allInstalledPackageList = PackageUtils.getAllPackageName(mContext)
if (allInstalledPackageList.isNotEmpty()) {
mValidInstalledPackageList = allInstalledPackageList
}
return mValidInstalledPackageList
}
}
}
fun downloadFile(filePath: String) {
if (!::mServer.isInitialized) mServer = if (mUseReservePort) getServer(RESERVE_PORT) else getServer(PORT)
if (!mServer.isAlive && !startServer()) {
@ -80,7 +94,7 @@ object BrowserInstallHelper {
Base64.encodeToString(URLEncoder.encode(downloadUrl).trim().toByteArray(), Base64.NO_WRAP)
DirectUtils.directToExternalBrowser(
mContext,
"https://down-and.ghzs.com/redirect?location=base64($encodedString)"
"https://down-and.ghzs6.com/redirect?location=base64($encodedString)"
)
} else {
DirectUtils.directToExternalBrowser(mContext, downloadUrl)
@ -237,32 +251,43 @@ object BrowserInstallHelper {
* 是否满足开启浏览器安装的条件
*/
private fun isConditionMatched(settingsEntity: NewSettingsEntity): Boolean {
if (mValidConditionMatchedCache != null) {
return mValidConditionMatchedCache!!
}
val packageList = getAllInstalledPackageList()
if (packageList.isEmpty()) return false
settingsEntity.installModel?.whiteList?.let {
for (packageName in it) {
if (mAllInstalledPackageList.contains(packageName)) {
return false
if (packageList.contains(packageName)) {
mValidConditionMatchedCache = false
break
}
}
}
settingsEntity.installModel?.packages?.let {
for (packageName in it) {
if (mAllInstalledPackageList.contains(packageName)) {
return true
if (packageList.contains(packageName)) {
mValidConditionMatchedCache = true
break
}
}
}
// 匹配部分字符串即可
settingsEntity.installModel?.regexPackages?.let {
for (packageNamePieces in it) {
for (installedPackageName in mAllInstalledPackageList) {
for (installedPackageName in packageList) {
if (installedPackageName.contains(packageNamePieces)) {
return true
mValidConditionMatchedCache = true
break
}
}
}
}
return false
return mValidConditionMatchedCache ?: false
}
fun onApkInstalled(path: String?) {

View File

@ -10,6 +10,9 @@ import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.game.GameFragment
/**
* 板块
*/
class BlockActivity : DownloadToolbarActivity() {
companion object {

View File

@ -14,6 +14,7 @@ import com.halo.assistant.fragment.ApkCleanerFragment;
/**
* Created by khy on 2017/1/24.
* 清理安装包
*/
@Route(path = RouteConsts.activity.cleanApkActivity)
public class CleanApkActivity extends ToolBarActivity {

View File

@ -16,6 +16,7 @@ import java.util.ArrayList;
/**
* Created by khy on 18/07/17.
* 我的收藏
*/
public class CollectionActivity extends ToolBarActivity {
@Override

View File

@ -23,6 +23,9 @@ import java.lang.ref.SoftReference;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
/**
* 裁剪图片
*/
public class CropImageActivity extends ToolBarActivity {
protected CropImageCustom mCropImageCustom;

View File

@ -24,7 +24,7 @@ import com.halo.assistant.HaloApp
/**
* Created by khy on 2017/3/24.
* 游戏详情适配器
* 游戏详情
*/
class GameDetailActivity : DownloadToolbarActivity() {
@ -59,8 +59,8 @@ class GameDetailActivity : DownloadToolbarActivity() {
}
override fun getBusinessId(): Pair<String, String> {
val fragment = targetFragment as GameDetailFragment
return if (fragment.arguments != null) {
val fragment = targetFragment as? GameDetailFragment?
return if (fragment?.arguments != null) {
Pair(fragment.requireArguments().getString(EntranceConsts.KEY_GAMEID) ?: "", "")
} else {
super.getBusinessId()

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