Compare commits

..

198 Commits

Author SHA1 Message Date
69e248b389 版本更改为 4.5.3 2020-12-24 11:12:37 +08:00
43f6bfc4c2 Merge branch 'hotfix-v4.5.2-252-updateLogic' into 'release'
Hotfix v4.5.2 252 update logic

See merge request halo/assistant-android!52
2020-12-24 11:09:56 +08:00
c8b81ab56a 优化模拟器游戏在下载按钮中的判断逻辑 2020-12-24 11:08:34 +08:00
aa41fd98e8 重置下载按钮的文字显示优先级 2020-12-24 10:49:49 +08:00
ee8ce87e28 Merge branch 'hotfix-v4.5.2-252-crash' into 'release'
处理一些数组越界闪退

See merge request halo/assistant-android!51
2020-12-23 10:58:40 +08:00
a944a7f730 处理一些数组越界闪退 2020-12-23 10:55:37 +08:00
165ba01afd Merge branch 'hotfix-v4.5.2-252-crash' into 'release'
修复v4.5.2版本闪退问题

See merge request halo/assistant-android!50
2020-12-21 16:36:23 +08:00
a39a8c2cce 1.修复视频流滑动闪退问题 2.修复WebView闪退问题 2020-12-21 16:02:00 +08:00
e4765089fa Merge branch 'hotfix-v4.5.2-252-genericCrash' into 'release'
修复一些空指针和数组越界闪退

See merge request halo/assistant-android!49
2020-12-21 11:23:06 +08:00
721e73ca1e Merge branch 'hotfix-v4.5.2-252-sentry' into 'release'
缩窄 Sentry ANR 的上报条件避免日志轰炸

See merge request halo/assistant-android!48
2020-12-21 11:19:15 +08:00
e406c90027 修复一些空指针和数组越界闪退 2020-12-21 11:17:34 +08:00
e7c4886219 缩窄 Sentry ANR 的上报条件避免日志轰炸 2020-12-21 10:15:20 +08:00
0d9a4baf32 Merge branch 'hotfix-v4.5.2-252-catalogUI' into 'release'
再次调整新分类-精选UI

See merge request halo/assistant-android!47
2020-12-15 18:07:26 +08:00
lyr
3a9132ff8c 再次调整新分类-精选UI 2020-12-15 18:05:35 +08:00
02a6ec9f7d 版本更新至 4.5.2 2020-12-14 17:15:20 +08:00
c779d775e3 Merge branch 'hotfix-v4.5.1-251-downloadANR' into 'release'
尝试修复安装完成触发的 ANR

See merge request halo/assistant-android!46
2020-12-14 17:12:26 +08:00
3fbcd33f98 尝试修复安装完成触发的 ANR 2020-12-14 17:10:55 +08:00
dbcdd7f3cc Merge branch 'hotfix-v4.5.1-251-catalogUI' into 'release'
微调新分类-精选UI

See merge request halo/assistant-android!45
2020-12-14 14:54:50 +08:00
lyr
69d9854b44 微调新分类-精选UI 2020-12-14 14:32:19 +08:00
5246d6e743 版本更新至 4.5.1 2020-12-10 17:02:46 +08:00
b20d598751 Merge branch 'hotfix-v4.5.0-250-crash' into 'release'
Hotfix v4.5.0 250 crash

See merge request halo/assistant-android!44
2020-12-10 16:58:52 +08:00
85e9799f20 Merge branch 'hotfix-v4.5.0-250-diableMTA' into 'release'
再次屏蔽 MTA

See merge request halo/assistant-android!43
2020-12-10 16:58:01 +08:00
6b533c8d09 再次屏蔽 MTA 2020-12-10 16:54:27 +08:00
2797135db4 尝试修复安装完成应用后的 ANR 2020-12-10 16:15:41 +08:00
7507a027da 修复关闭所有页面后下载完成回调触发闪退的问题 2020-12-10 10:50:42 +08:00
9873ae8946 还原 MTA https://git.ghzs.com/pm/halo-app-issues/-/issues/1092 2020-12-07 14:47:51 +08:00
a5ef80ba33 尝试修复启动前台服务造成的闪退 https://git.ghzs.com/halo/assistant-android/-/issues/7 2020-12-07 11:59:43 +08:00
dfdd12bf18 修复使用强制更新时偶尔无法唤起安装的问题和多线程下载更新的冲突问题 2020-12-04 17:22:48 +08:00
9daf01d9a5 处理包名检测弹窗未检测出不可启动的应用 2020-12-04 14:57:31 +08:00
ee7ed1fed2 光环助手V4.5.0-包名检测弹窗和应用跳转(1203测试1,2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1058 2020-12-03 18:10:24 +08:00
08474a660e Merge branch 'dev' of git.ghzs.com:halo/assistant-android into dev 2020-12-03 11:40:53 +08:00
d8dfe00057 光环助手V4.5.0-包名检测弹窗和应用跳转(改为通用链接) https://git.ghzs.com/pm/halo-app-issues/-/issues/1058 2020-12-03 11:40:29 +08:00
6bd175f72b 停用 MTA 2020-12-02 17:59:21 +08:00
72b6b3042a 正式包脚本支持打推广包 2020-12-02 10:50:15 +08:00
lyr
3317b178ac 修改新分类-二级分类详情页无数据问题 2020-12-02 10:40:50 +08:00
c86e7ba6ee Merge branch 'dev-4.5.0' into dev
# Conflicts:
#	app/src/main/java/com/gh/download/DownloadDataHelper.kt
2020-12-02 09:51:41 +08:00
14c5e4e963 Merge branch 'pack-v4.4.0-221-enableGdtAndTea-product' into dev-4.5.0
# Conflicts:
#	app/build.gradle
2020-12-01 18:26:53 +08:00
6db8179f4d 根据product flavor导入不同库 2020-12-01 17:48:35 +08:00
65c2571329 增加打推广打包的用的 product flavor https://git.ghzs.com/halo/assistant-android/-/issues/25 2020-12-01 16:52:09 +08:00
lyr
4810803988 修改新分类-一级分类item样式 2020-11-30 18:23:29 +08:00
f3f030edb1 Merge branch 'dev-4.5.0' of git.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-30 15:22:09 +08:00
2ac2a3bf48 处理视频全屏闪退问题 2020-11-30 15:21:34 +08:00
cd104e4688 修复搜索列表页面重建时的显示问题 2020-11-30 11:37:11 +08:00
e2de8cfb47 正式环境切换到4.5接口 2020-11-30 09:07:12 +08:00
c9f9451dee 修复进程被杀重建时出现的安装状态异常问题 2020-11-27 17:21:21 +08:00
73c39edd3f 修改分类功能的错误上报文案 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1056 2020-11-27 15:03:01 +08:00
7f739798ab 处理Android11打开[允许安装未知应用]权限后自动解压xapk 2020-11-27 11:39:07 +08:00
e41cf76d26 Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-27 10:41:07 +08:00
113d446e47 处理Android11打开[允许安装未知应用]权限后自动解压xapk 2020-11-27 10:41:03 +08:00
lyr
882ac7d67d 优化下载按钮监听器逻辑 2020-11-27 10:00:34 +08:00
d94be8092b 修改获取推荐论坛接口 2020-11-26 21:59:33 +08:00
b9138ae810 未登录状态也可以获取推荐的论坛 2020-11-26 21:44:46 +08:00
715cecd44b 调整 Sentry 的上报内容 2020-11-26 20:22:05 +08:00
dd756fce00 Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-26 20:13:57 +08:00
56a003704d 用户搜索取消关注toast提示 2020-11-26 20:13:53 +08:00
50421e0b70 新分类事件上报增加内容 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1056 2020-11-26 18:32:40 +08:00
9f0d00f793 尝试修复后台启动前台服务的闪退 2020-11-26 18:27:35 +08:00
a56fd8ff18 用户搜索关注用户判断是否登录 2020-11-26 17:58:33 +08:00
f86fc7b0e1 【光环助手V4.5.0】论坛搜索功能及部分优化 1126测试反馈 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1049 2020-11-26 17:22:27 +08:00
e6197776ca 修改关注论坛排序问题 2020-11-26 16:30:45 +08:00
0415ae261b 光环助手V4.5.0-包名检测弹窗和应用跳转 补充3 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1058 2020-11-26 16:29:52 +08:00
d5313c7f98 Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-26 16:08:49 +08:00
360231e01f 光环助手V4.5.0-XAPK 游戏解压增加 引导设置“安装权限” 1126测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1077 2020-11-26 16:08:44 +08:00
lyr
4d86d6f96b Merge remote-tracking branch 'origin/dev-4.5.0' into dev-4.5.0 2020-11-26 15:39:00 +08:00
lyr
dd03daae84 【手机号绑定冲突】页当前用户昵称加敏处理 2020-11-26 15:38:55 +08:00
5d285fd60e 删除无用资源 2020-11-26 15:25:15 +08:00
7d4206bcd8 记录 XAPK 解压异常日志 2020-11-26 14:40:02 +08:00
a816636d9a 修复分类埋点测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1056 2020-11-26 14:39:08 +08:00
c6a5522b35 完成前端优化汇总(12,13) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1057 2020-11-26 12:00:39 +08:00
lyr
8b888f0ab4 1.修改新分类UI;2.修复新分类的二级分类详情页列表排序与专题详情页列表排序不一样问题 2020-11-26 11:43:53 +08:00
ef41a3aea5 Merge remote-tracking branch 'origin/dev-4.5.0' into dev-4.5.0 2020-11-26 10:14:31 +08:00
ba2206931f 调整隐私弹窗UI https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1064 2020-11-26 10:14:22 +08:00
ef4b7b28d8 调整论坛首页蒙层引导位置 2020-11-26 10:13:15 +08:00
lyr
4a5f12d341 光环前端优化汇总(2020年11月第1周)20201125测试问题 1 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1057#note_78154 2020-11-26 09:45:21 +08:00
ced96f5f70 调整帖子详情标签间距 2020-11-26 09:23:34 +08:00
4180d87b36 Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-26 09:10:58 +08:00
2b7f802584 光环前端优化汇总(2020年11月第1周)20201125测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1057 2020-11-26 09:10:53 +08:00
lyr
3e9a348019 分类筛选弹窗去掉弹出动画 2020-11-25 18:20:01 +08:00
9725402623 处理链接为空的图片复用问题 2020-11-25 17:17:33 +08:00
9827b04057 修复横向滑动卡片专题的曝光统计问题 2020-11-25 17:04:19 +08:00
b3052485f5 光环助手V4.5.0-XAPK 游戏解压增加 引导设置“安装权限” 1125测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1077 2020-11-25 16:52:04 +08:00
d3dc09d377 修改权限弹窗滚动条 2020-11-25 16:37:19 +08:00
58905c14a8 完成隐私弹窗1124UI调整 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1064 2020-11-25 16:24:32 +08:00
aadbbbf2ea 修改sentry上的bug (4820/4822/4952) 2020-11-25 16:17:15 +08:00
5256a9b267 Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-25 15:10:27 +08:00
0ded7b33f2 光环助手V4.5.0-包名检测弹窗和应用跳转1125测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1058 2020-11-25 15:10:17 +08:00
lyr
cdc3158f30 新分类-精选页调整游戏名显示长度 2020-11-25 14:44:15 +08:00
06de179c9e Merge remote-tracking branch 'origin/dev-4.5.0' into dev-4.5.0 2020-11-25 14:30:31 +08:00
f32dc628ef 补充更新下载头 META 的位置 2020-11-25 14:30:19 +08:00
lyr
62e371c928 【手机号绑定冲突】页用户昵称加敏处理 2020-11-25 14:22:31 +08:00
lyr
84bcc481af 光环助手V4.5.0-新分类功能(前端)20201124测试问题 3(1)(2)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1055#note_78011 2020-11-25 11:29:58 +08:00
085ddd4ea6 Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-25 11:00:42 +08:00
b3e859678e 【光环助手V4.5.0】论坛搜索功能及部分优化UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1049 2020-11-25 11:00:35 +08:00
lyr
7f586fbf13 光环前端优化汇总(2020年11月第1周)10 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1057 2020-11-25 09:49:24 +08:00
9dab3dd263 恢复广点通和头条SDK 2020-11-24 18:19:05 +08:00
lyr
3ee30f05f0 Merge remote-tracking branch 'origin/dev-4.5.0' into dev-4.5.0 2020-11-24 18:16:36 +08:00
lyr
69c8c51000 优化新分类模块代码 2020-11-24 18:16:07 +08:00
28742f54bb Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-24 18:13:13 +08:00
f62751423d 【光环助手V4.5.0】论坛搜索功能及部分优化 1124测试反馈 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1049 2020-11-24 18:13:08 +08:00
b0b699679e 添加在新页面打开 webview 的 JS 方法 2020-11-24 17:15:35 +08:00
3c55284d86 完成分类功能数据埋点 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1056 2020-11-24 17:04:25 +08:00
b6ae508cf0 Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-24 16:53:12 +08:00
lyr
c13ee31ece 光环助手V4.5.0-新分类功能(前端)20201123UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1055#note_77773 2020-11-24 16:52:56 +08:00
c87a1ba56e 光环助手V4.5.0-【APP合规】游戏详情页-游戏安装权限提示20201124UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1070 2020-11-24 16:52:55 +08:00
9f07cc7720 Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-24 16:25:16 +08:00
7bdfe7cef3 【光环助手V4.5.0】论坛搜索功能及部分优化 UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1049 2020-11-24 16:25:11 +08:00
lyr
667126f92c 光环助手V4.5.0-新分类功能(前端)20201123UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1055#note_77773 2020-11-24 16:10:47 +08:00
0409d33d5e Merge branch 'hotfix-v4.3.9-220-update' into dev-4.5.0
# Conflicts:
#	dependencies.gradle
2020-11-24 14:39:45 +08:00
lyr
14e8285c0f 光环前端优化汇总(2020年11月第1周)20201123UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1057#note_77765 2020-11-24 14:21:21 +08:00
c7d63f9df1 Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-23 18:28:17 +08:00
e2d9ad07d1 光环助手V4.5.0-XAPK 游戏解压增加 引导设置“安装权限” https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1077 2020-11-23 18:28:12 +08:00
lyr
9287b6ac4c 修改标签页顶部标签列表item背景 2020-11-23 17:51:00 +08:00
lyr
450da5e0db 修改从新分类点击跳转到游戏详情页内容缺失问题 2020-11-23 17:27:26 +08:00
0397092414 版本调整至 4.4.0 2020-11-23 15:33:19 +08:00
ddc515b490 修复更新问题 2020-11-23 15:12:18 +08:00
lyr
a6edde7853 光环前端优化汇总(2020年11月第1周)8(2)① https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1057 2020-11-23 14:55:37 +08:00
80282f7bcc 调整包名检测弹窗间距 2020-11-23 10:56:12 +08:00
lyr
664df5cb44 Merge remote-tracking branch 'origin/dev-4.5.0' into dev-4.5.0 2020-11-23 10:28:43 +08:00
lyr
8396a55ed2 新分类相关页面适配ViewBinding 2020-11-23 10:28:03 +08:00
5ee3f597bd 简单包裹游戏列表横向列表的点击闪退 (具体修复后续处理) 2020-11-23 10:26:59 +08:00
9c8bd9f85e 处理更换背景后用户详情页面闪退问题 2020-11-23 10:25:18 +08:00
4321e0a33c 光环前端优化汇总(2020年11月第1周)8(2)②-⑥ https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1057 2020-11-23 10:21:58 +08:00
6f75229209 全局处理 activity 的 configChanges 的值(新增density,fontScale,locale) 2020-11-20 17:43:31 +08:00
lyr
d6bd561e58 Merge branch 'feature-issues1055' into dev-4.5.0 2020-11-20 15:05:18 +08:00
c957d7585c 修复xapk下载完成事件被误判为解析包错误问题 2020-11-20 14:50:54 +08:00
lyr
db0e92fd68 完成光环前端优化汇总(2020年11月第1周)8(1)、9、10 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1057 2020-11-20 14:38:02 +08:00
992446cf70 去掉无用的权限注册 2020-11-20 11:01:29 +08:00
dcfa52b05a 全局处理 activity 的 configChanges 的值放弃特殊条件时的页面重建(原目的为避免分屏时的页面重建异常) 2020-11-20 10:55:15 +08:00
lyr
2a06c41dca 完成光环前端优化汇总(2020年11月第1周)1-4 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1057 2020-11-20 09:17:03 +08:00
lyr
24214c5d6b 优化"新分类"模块 2020-11-20 09:13:35 +08:00
c839eff88d 视频埋点增加[视频流刷新]事件 2020-11-19 17:47:12 +08:00
663505fdc9 整理复制内容相关代码 2020-11-19 11:17:00 +08:00
641a820ea5 删掉每次检查下载目录都生成的 timestamp.log 文件 2020-11-19 11:14:57 +08:00
lyr
bb3f888f88 完成光环助手V4.5.0-新分类功能(前端)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1055 2020-11-19 09:59:33 +08:00
75bdf6f251 视频埋点增加[提交评论]事件 2020-11-18 18:01:31 +08:00
0cacc15e7d Merge branch 'dev-4.5.0' of gitlab.ghzs.com:halo/assistant-android into dev-4.5.0 2020-11-18 17:09:59 +08:00
e4c2ac0aae 光环助手V4.5.0-包名检测弹窗和应用跳转 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1058 2020-11-18 17:09:54 +08:00
7acf4c5941 补充 Sentry 信息 2020-11-18 14:51:20 +08:00
8b22361213 接入 Sentry 2020-11-18 11:54:19 +08:00
a1dee46436 处理因捕抓查询剩余空间闪退而引起的不能下载应用的问题 2020-11-17 17:47:05 +08:00
49bf8c9e30 修改隐私弹窗文案 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1064 2020-11-17 17:42:15 +08:00
407686ca5b 处理链接为空的图片复用问题 2020-11-17 17:39:22 +08:00
89b7b45ba0 测试修改后的MTA 2020-11-17 17:37:21 +08:00
b00e7a2826 处理合并代码错误 2020-11-17 17:14:30 +08:00
383d6e7700 Merge branch 'feature-bbs-search' into dev-4.5.0
# Conflicts:
#	app/src/main/AndroidManifest.xml
2020-11-16 16:35:23 +08:00
edce98e4c6 光环助手V4.5.0-视频活动优化(第1期)(6) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1046 2020-11-16 15:30:00 +08:00
a2c3873c8d 【光环助手V4.5.0】论坛搜索功能及部分优化(帖子搜索) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1049 2020-11-16 14:15:52 +08:00
7990353d08 Merge branch 'release' into dev-4.5.0
# Conflicts:
#	app/src/main/AndroidManifest.xml
#	app/src/main/java/com/gh/common/exposure/meta/MetaUtil.kt
#	dependencies.gradle
2020-11-16 09:57:33 +08:00
a7b138b2b2 更新依赖库 id 2020-11-13 10:05:52 +08:00
951768e070 暂时屏蔽 MTA 部分代码 2020-11-13 10:04:46 +08:00
69f29fe83b 光环助手V4.5.0-视频投稿数据埋点 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1047 2020-11-12 16:42:10 +08:00
88e28b2388 优化获取经 BASE64 编码后 IMEI 的逻辑 2020-11-12 15:52:08 +08:00
538bc6f97c 调整下载 CDN 日志的请求头名称 2020-11-12 15:17:19 +08:00
b1940125f4 Merge branch 'feature-issues1070' into dev-4.5.0 2020-11-12 14:46:26 +08:00
e1f8e293c2 修改查看权限详情不显示问题 2020-11-12 14:45:30 +08:00
0a49f27ed2 去掉 MTA 事件中获取 IMEI 的代码 2020-11-12 14:19:54 +08:00
5dc7badc97 Merge branch 'hotfix-v4.3.8-218-enableMtaOnly' into 'release'
暂时屏蔽广点通和头条推广

See merge request halo/assistant-android!39
2020-11-12 11:52:26 +08:00
d185d39985 暂时屏蔽广点通和头条推广 2020-11-12 11:51:48 +08:00
d9c98d39b5 Merge branch 'feature-issues1070' into dev-4.5.0 2020-11-12 11:39:33 +08:00
6949f2b2ff 光环助手V4.5.0-【APP合规】游戏详情页-游戏安装权限提示 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1070 2020-11-12 11:37:36 +08:00
2141440ec4 Merge branch 'hotfix-v4.3.8-218-bringBackTrackingSdk' into 'release'
重新接入第三方追踪SD,手动去掉了MTA的获取IMEI、IMSI等代码

See merge request halo/assistant-android!38
2020-11-12 11:31:44 +08:00
464c212638 处理 dataBinding 和 viewBinding 的冲突 2020-11-12 11:03:48 +08:00
dbe74b2091 修复游戏搜索页自动搜索失效的问题 2020-11-11 18:18:41 +08:00
ba55a5a61c 【光环助手V4.5.0】论坛推荐规则及部分优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1051 2020-11-11 14:26:36 +08:00
452a94f4a2 Merge branch 'hotfix-v4.3.8-218-bbs' into 'release'
修改评论详情更多操作点击任何一项都会触发删除评论弹窗

See merge request halo/assistant-android!37
2020-11-10 17:42:34 +08:00
310be97fe4 修改评论详情更多操作点击任何一项都会触发删除评论弹窗 2020-11-10 17:28:23 +08:00
2fc45777e4 光环助手V4.5.0】论坛搜索功能及部分优化(用户搜索) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1049 2020-11-10 17:16:46 +08:00
da283fc1f6 帖子作者显示置顶选项 2020-11-10 16:49:49 +08:00
fee4e4635c Merge branch 'feature-issues1068' into 'dev-4.5.0'
完成实名认证文案修改 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1068

See merge request halo/assistant-android!35
2020-11-10 16:35:46 +08:00
ebcd50cdee Merge branch 'feature-issues1069' into 'dev-4.5.0'
完成IMEI权限获取限制 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1069

See merge request halo/assistant-android!34
2020-11-10 16:34:54 +08:00
cd922dd286 完成实名认证文案修改 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1068 2020-11-10 16:32:27 +08:00
97598d7330 【光环助手V4.5.0】论坛-作者增加具体跟帖数据的置顶功能https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1050 2020-11-10 15:02:35 +08:00
0db59a56d0 完成IMEI权限获取限制 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1069 2020-11-10 14:44:59 +08:00
bee3f5957e 更新 AGP 版本 2020-11-10 14:37:33 +08:00
65d4b43c9c Merge branch 'hotfix-v4.3.8-218-lgLibrary' into 'release'
更新依赖库

See merge request halo/assistant-android!33
2020-11-09 17:00:45 +08:00
41f510d333 更新依赖库 2020-11-09 16:58:15 +08:00
64d5af036c 恢复误删的 CDN 日志记录代码 2020-11-09 16:56:07 +08:00
b4c827bddf Merge branch 'feature-issues1064' into 'dev-4.5.0'
完成隐私政策弹窗优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1064

See merge request halo/assistant-android!32
2020-11-09 16:22:52 +08:00
caf3dfa9ee Merge branch 'feature-issues1053' into 'dev-4.5.0'
完成注销账号功能优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1053

See merge request halo/assistant-android!31
2020-11-09 16:17:28 +08:00
c5c10ab208 版本号升至4.5.0 2020-11-09 16:16:07 +08:00
c2251e1ad6 BASE64转码请求头的IMEI内容 2020-11-09 16:11:39 +08:00
bd6d51dab3 去掉冗余的权限注册 2020-11-09 16:10:50 +08:00
1cf9bfcca3 完成注销账号功能优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1053 2020-11-09 14:46:50 +08:00
992ec7bfe8 完成隐私政策弹窗优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1064 2020-11-09 11:52:04 +08:00
cc39bfd06c Merge branch 'hotfix-v4.3.8-218-buildError' into 'release'
处理编译错误

See merge request halo/assistant-android!30
2020-11-09 09:47:39 +08:00
15d0ad6f49 Merge branch 'hotfix-v4.3.8-218-crash' into 'release'
1.修复推送页面注册闪退 2.捕抓部分设备获取音量大小时可能的闪退

See merge request halo/assistant-android!29
2020-11-09 09:46:53 +08:00
a2e2379073 1.修复推送页面注册闪退 2.捕抓部分设备获取音量大小时可能的闪退 2020-11-09 09:34:12 +08:00
d2431ed8ff 处理编译错误 2020-11-06 18:31:29 +08:00
80818dee55 重新接入第三方追踪SD,手动去掉了MTA的获取IMEI、IMSI等代码 2020-11-06 18:30:57 +08:00
f2d0916a16 Merge branch 'hotfix-v4.3.8-218-crash' into 'release'
Hotfix v4.3.8 218 crash

See merge request halo/assistant-android!28
2020-11-05 19:17:43 +08:00
2fa84e0ce1 修复修复弹窗关闭,encoded url 跳转和视频流刷新滑动的闪退 2020-11-05 19:17:43 +08:00
c9f5cfd4aa Merge branch 'hotfix-v4.3.8-218-database-related' into 'release'
捕抓因磁盘空间不足导致的数据库插入异常

See merge request halo/assistant-android!27
2020-11-03 15:17:59 +08:00
d6c1f692be 捕抓因磁盘空间不足导致的数据库插入异常 2020-11-03 15:16:57 +08:00
12e6fb8330 补充遗漏提交的文件 :( 2020-11-03 11:30:33 +08:00
ad857d4500 Merge branch 'hotfix-v4.3.8-218-PackageManager_has_died' into 'release'
尝试处理PackageManager has died异常

See merge request halo/assistant-android!26
2020-11-03 11:02:58 +08:00
43d8d24c1c 尝试处理PackageManager has died异常 2020-11-03 10:44:19 +08:00
a34ee5a753 Merge branch 'hotfix-v4.3.8-218-generic-crash' into 'release'
简单处理常见闪退

See merge request halo/assistant-android!25
2020-11-03 09:16:21 +08:00
ca39f723e1 简单处理常见闪退 2020-11-03 09:15:20 +08:00
348 changed files with 10673 additions and 3322 deletions

View File

@ -6,6 +6,8 @@ apply plugin: 'kotlin-kapt'
// apkChannelPackage
apply plugin: 'channel'
import groovy.xml.XmlUtil
//apply from: 'tinker-support.gradle'
android {
@ -18,6 +20,10 @@ android {
enabled = true
}
viewBinding {
enabled = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@ -125,15 +131,27 @@ android {
}
}
flavorDimensions "nonsense"
flavorDimensions("env")
sourceSets {
publish {
java.srcDirs = ['src/main/java']
}
internal {
java.srcDirs = ['src/main/java']
}
tea {
java.srcDirs = ['src/main/java', 'src/tea/java']
}
gdt {
java.srcDirs = ['src/main/java', 'src/gdt/java']
}
}
/**
* 多渠道打包,渠道请参考"channel.txt"文件所有渠道值均通过java code设置
*/
productFlavors {
// publish release host
publish {
dimension "nonsense"
dimension "env"
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
@ -144,7 +162,7 @@ android {
}
// internal test dev host
internal {
dimension "nonsense"
dimension "env"
versionNameSuffix "-debug"
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
@ -155,6 +173,30 @@ android {
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEV_UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "BUGLY_APPID", "\"${DEV_BUGLY_APPID}\""
}
tea {
dimension "env"
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
}
gdt {
dimension "env"
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
}
}
}
@ -184,6 +226,7 @@ repositories {
dependencies {
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
gdtImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/gdt/libs')
testImplementation 'junit:junit:4.12'
@ -289,7 +332,7 @@ dependencies {
debugImplementation "com.github.nichbar.chucker:library:$chucker"
releaseImplementation "com.github.nichbar.chucker:library-no-op:$chucker"
// implementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog"
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog"
// implementation "com.bytedance.ies.ugc.aweme:opensdk-china-external:$bytedanceAweme"
// implementation "com.bytedance.ies.ugc.aweme:opensdk-common:$bytedanceAweme"
@ -299,6 +342,8 @@ dependencies {
implementation "net.lingala.zip4j:zip4j:${zip4j}"
implementation "io.sentry:sentry-android:$sentry"
implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
exclude group: 'com.squareup.okhttp3'
exclude group: 'androidx.swiperefreshlayout'
@ -371,3 +416,78 @@ if (propFile.exists()) {
// task.name.startsWith('merge') && task.name.endsWith('Resources')
// }.each { t -> t.dependsOn generateMetaJson }
//}
project.afterEvaluate {
def variants = null
try {
variants = android.applicationVariants
} catch (Throwable t) {
t.printStackTrace()
try {
variants = android.libraryVariants
} catch (Throwable tt) {
tt.printStackTrace()
}
}
if (variants != null) {
variants.all { variant ->
variant.outputs.each { output ->
def task = output.processManifestProvider.get()
if (task == null) {
return
}
/**
* 为 Manifest 的 Activity 的 configChanges 添加自己手动处理 configurationChanges 配置 [https://developer.android.com/guide/topics/resources/runtime-changes]
* AGP 4.1.0 从 ProcessManifest task 里拿 manifest 的 API 变更调整可以参考这里 [https://github.com/Tencent/tinker/pull/1476/commits/d71645729b13d545ca4ba6826f93fbf558751434]
* (搞半天还是不会抽离方法,有空再把 gradle 改成用 kotlin 实现吧)
*/
task.doLast {
def manifestFile = new File(multiApkManifestOutputDirectory.get().asFile, "AndroidManifest.xml")
if (manifestFile == null || !manifestFile.exists()) {
return
}
def parser = new XmlSlurper(false, true)
def manifest = parser.parse(manifestFile)
def app = manifest.'application'[0]
app.'activity'.each { act ->
String value = act.attributes()['android:configChanges']
if (value == null || value.isEmpty()) {
value = "keyboardHidden|orientation|screenSize|screenLayout|density|fontScale|locale"
act.attributes()['androidconfigChanges'] = value
} else {
String[] valueSplit = value.split("\\|")
if (!valueSplit.contains("keyboardHidden")) {
value += "|keyboardHidden"
}
if (!valueSplit.contains("orientation")) {
value += "|orientation"
}
if (!valueSplit.contains("screenSize")) {
value += "|screenSize"
}
if (!valueSplit.contains("screenLayout")) {
value += "|screenLayout"
}
if (!valueSplit.contains("density")) {
value += "|density"
}
if (!valueSplit.contains("fontScale")) {
value += "|fontScale"
}
if (!valueSplit.contains("locale")) {
value += "|locale"
}
act.attributes()['android:configChanges'] = value
}
}
def tmpManifest = XmlUtil.serialize(manifest).replaceAll("androidconfigChanges", "android:configChanges")
manifest = parser.parseText(tmpManifest)
manifestFile.setText(XmlUtil.serialize(manifest), "utf-8")
}
}
}
}
}

View File

@ -241,6 +241,13 @@
-dontwarn com.shuyu.gsyvideoplayer.utils.**
-keep class tv.danmaku.ijk.** { *; }
-dontwarn tv.danmaku.ijk.**
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#穿山甲
-keep class com.bytedance.sdk.openadsdk.** { *; }
@ -258,4 +265,7 @@
-keep class com.alibaba.sdk.android.**{*;}
-keep class com.ut.**{*;}
-keep class com.ta.**{*;}
-keep class com.ta.**{*;}
-keep class com.gh.gamecenter.GdtHelper { *; }
-keep class com.gh.gamecenter.TeaHelper { *; }

View File

@ -0,0 +1,75 @@
package com.gh.gamecenter
import android.app.Application
import android.text.TextUtils
import android.util.Log
import com.gh.common.util.ToastUtils
import com.lightgame.utils.Utils
import com.qq.gdt.action.GDTAction
import org.json.JSONObject
/**
* 广点通辅助类 [https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/403]
*
* 更换帐号 [https://gitlab.ghzs.com/pm/yunying/issues/893]
*/
object GdtHelper {
const val NETWORK_TYPE = "NETWORK_TYPE"
const val PAGE_TYPE = "PAGE_TYPE"
const val CONTENT_TYPE = "CONTENT_TYPE"
const val CONTENT_ID = "CONTENT_ID"
const val KEYWORD = "KEYWORD"
const val GAME_ID = "GAME_ID"
const val SCORE = "SCORE"
const val PLATFORM = "PLATFORM"
@JvmStatic
fun init(application: Application, channel: String) {
if (shouldUseGdtHelper()) {
if (channel == "GH_728") {
GDTAction.init(application, "1111012969", "9d3d9da5b0948a317c03d08f14d445dc")
} else if (channel == "GH_729") {
GDTAction.init(application, "1111013063", "f53dabf458a356b101d99fc4069eb7f1")
} else {
GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a")
}
}
Utils.log("init GdtHelper")
}
// fun logAction(type: String) {
// if (shouldUseGdtHelper()) {
// GDTAction.logAction(type)
// Utils.log("GDT", type)
// }
// }
@JvmStatic
fun logAction(type: String, vararg kv: String?) {
try {
val actionParam = JSONObject()
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
actionParam.put(key, value)
}
}
}
Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]")
GDTAction.logAction(type, actionParam)
} catch (e: Exception) {
e.printStackTrace()
}
}
// TODO 确认开启的渠道条件
private fun shouldUseGdtHelper(): Boolean {
return true
//
// val channel = HaloApp.getInstance().channel
// return !(TextUtils.isEmpty(channel) || channel.contains("GDT".toLowerCase(Locale.CHINA)))
}
}

Binary file not shown.

View File

@ -9,8 +9,6 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 允许应用程序读取扩展存储器 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 允许挂载和反挂载文件系统可移动存储 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 允许应用程序访问Wi-Fi网络状态信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 允许应用程序获取网络信息状态 -->
@ -25,8 +23,6 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 允许应用程序打开系统窗口,显示其他应用程序 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 修改系统设置的权限 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- 创建快捷方式的权限 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
@ -35,7 +31,7 @@
tools:ignore="ProtectedPermissions" />
<!-- bugly with tinker -->
<uses-permission android:name="android.permission.READ_LOGS" />
<!-- <uses-permission android:name="android.permission.READ_LOGS" />-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!--可选,穿山甲提供“获取地理位置权限”和“不给予地理位置权限,开发者传入地理位置参数”两种方式上报用户位置,两种方式均可不选,添加位置权限或参数将帮助投放定位广告-->
@ -79,6 +75,10 @@
tools:replace="android:allowBackup"
tools:targetApi="n">
<meta-data
android:name="io.sentry.auto-init"
android:value="false" />
<!--android:launchMode = "singleTask"-->
<activity
android:name="com.gh.gamecenter.SplashScreenActivity"
@ -462,7 +462,7 @@
<activity
android:name="com.gh.gamecenter.video.upload.view.UploadVideoActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden"/>
android:windowSoftInputMode="stateHidden" />
<activity
android:name="com.gh.gamecenter.video.game.GameVideoActivity"
@ -577,7 +577,7 @@
<activity
android:name=".personalhome.background.BackgroundClipActivity"
android:screenOrientation="portrait"
android:theme="@style/TransparentStatusBarAndNavigationBar"/>
android:theme="@style/TransparentStatusBarAndNavigationBar" />
<activity
android:name=".personalhome.excellentcomments.ExcellentCommentsActivity"
@ -591,12 +591,24 @@
android:name=".simulatorgame.SimulatorManagementActivity"
android:screenOrientation="portrait" />
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
<activity
android:name="com.gh.gamecenter.PushProxyActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Translucent" />
android:name=".catalog.CatalogActivity"
android:screenOrientation="portrait" />
<activity
android:name=".catalog.NewCatalogListActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.search.ForumOrUserSearchActivity"
android:screenOrientation="portrait" />
<!-- &lt;!&ndash; 使用小米/华为推送弹窗功能提高推送成功率&ndash;&gt;-->
<!-- <activity-->
<!-- android:name="com.gh.gamecenter.PushProxyActivity"-->
<!-- android:exported="true"-->
<!-- android:launchMode="singleTask"-->
<!-- android:theme="@android:style/Theme.Translucent" />-->
<activity
android:name="com.gh.gamecenter.SkipActivity"
@ -608,6 +620,14 @@
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<intent-filter>
<data android:scheme="market" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
<activity
@ -618,11 +638,11 @@
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity>
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
<!-- android:launchMode="singleTask"-->
<!-- android:taskAffinity="${applicationId}"-->
<!-- android:exported="true" />-->
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
<!-- android:launchMode="singleTask"-->
<!-- android:taskAffinity="${applicationId}"-->
<!-- android:exported="true" />-->
<provider
android:name="androidx.core.content.FileProvider"
@ -657,45 +677,45 @@
</intent-filter>
</receiver>
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMessageReceiver">-->
<!-- <intent-filter>-->
<!-- <action android:name="com.gh.gamecenter.UMENG" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMessageReceiver">-->
<!-- <intent-filter>-->
<!-- <action android:name="com.gh.gamecenter.UMENG" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<!-- &lt;!&ndash;魅族push应用定义消息receiver声明 &ndash;&gt;-->
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMeizuPushReceiver">-->
<!-- <intent-filter>-->
<!-- &lt;!&ndash; 接收push消息 &ndash;&gt;-->
<!-- <action android:name="com.meizu.flyme.push.intent.MESSAGE" />-->
<!-- &lt;!&ndash; 接收register消息 &ndash;&gt;-->
<!-- <action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />-->
<!-- &lt;!&ndash; 接收unregister消息&ndash;&gt;-->
<!-- <action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />-->
<!-- &lt;!&ndash; 兼容低版本Flyme3推送服务配置 &ndash;&gt;-->
<!-- <action android:name="com.meizu.c2dm.intent.REGISTRATION" />-->
<!-- <action android:name="com.meizu.c2dm.intent.RECEIVE" />-->
<!-- &lt;!&ndash;魅族push应用定义消息receiver声明 &ndash;&gt;-->
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMeizuPushReceiver">-->
<!-- <intent-filter>-->
<!-- &lt;!&ndash; 接收push消息 &ndash;&gt;-->
<!-- <action android:name="com.meizu.flyme.push.intent.MESSAGE" />-->
<!-- &lt;!&ndash; 接收register消息 &ndash;&gt;-->
<!-- <action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />-->
<!-- &lt;!&ndash; 接收unregister消息&ndash;&gt;-->
<!-- <action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />-->
<!-- &lt;!&ndash; 兼容低版本Flyme3推送服务配置 &ndash;&gt;-->
<!-- <action android:name="com.meizu.c2dm.intent.REGISTRATION" />-->
<!-- <action android:name="com.meizu.c2dm.intent.RECEIVE" />-->
<!-- <category android:name="${applicationId}" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<!-- <category android:name="${applicationId}" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<!-- <receiver-->
<!-- android:name="com.gh.common.im.ImReceiver"-->
<!-- android:enabled="true">-->
<!-- <intent-filter android:priority="2147483647">-->
<!-- <action android:name="com.gh.im" />-->
<!-- <action android:name="action_finish" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<!-- <receiver-->
<!-- android:name="com.gh.common.im.ImReceiver"-->
<!-- android:enabled="true">-->
<!-- <intent-filter android:priority="2147483647">-->
<!-- <action android:name="com.gh.im" />-->
<!-- <action android:name="action_finish" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<!-- <meta-data-->
<!-- android:name="com.huawei.hms.client.appid"-->
<!-- android:value="@string/huawei_push_appid" />-->
<!-- <meta-data-->
<!-- android:name="com.huawei.hms.client.appid"-->
<!-- android:value="@string/huawei_push_appid" />-->
<!-- <service-->
<!-- android:name="com.gh.base.GHUmengNotificationService"-->
<!-- android:permission="android.permission.BIND_JOB_SERVICE" />-->
<!-- <service-->
<!-- android:name="com.gh.base.GHUmengNotificationService"-->
<!-- android:permission="android.permission.BIND_JOB_SERVICE" />-->
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->

View File

@ -1,40 +0,0 @@
emoji_kf_1.png,:smile:
emoji_kf_2.png,:smiley:
emoji_kf_3.png,:laughing:
emoji_kf_4.png,:blush:
emoji_kf_5.png,:heart_eyes:
emoji_kf_6.png,:smirk:
emoji_kf_7.png,:flushed:
emoji_kf_8.png,:kissing_heart:
emoji_kf_9.png,:grin:
emoji_kf_10.png,:wink:
emoji_kf_11.png,:stuck_out_tongue_winking_eye:
emoji_kf_12.png,:stuck_out_tongue_closed eyes:
emoji_kf_13.png,:worried:
emoji_kf_14.png,:sleeping:
emoji_kf_15.png,:expressionless:
emoji_kf_16.png,:sweat_smile:
emoji_kf_17.png,:joy:
emoji_kf_18.png,:cold_sweat:
emoji_kf_19.png,:sob:
emoji_kf_20.png,:angry:
emoji_kf_21.png,:mask:
emoji_kf_22.png,:scream:
emoji_kf_23.png,:sunglasses:
emoji_kf_24.png,:heart:
emoji_kf_25.png,:broken_heart:
emoji_kf_26.png,:star:
emoji_kf_27.png,:anger:
emoji_kf_28.png,:exclamation:
emoji_kf_29.png,:question:
emoji_kf_30.png,:zzz:
emoji_kf_31.png,:thumbsup:
emoji_kf_32.png,:thumbsdown:
emoji_kf_33.png,:ok_hand:
emoji_kf_34.png,:punch:
emoji_kf_35.png,:yeah:
emoji_kf_36.png,:clap:
emoji_kf_37.png,:muscle:
emoji_kf_38.png,:pray:
emoji_kf_39.png,:skull:
emoji_kf_40.png,:trollface:

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,5 +0,0 @@
# This is a simple Microlog configuration file
microlog.level=DEBUG
microlog.appender=LogCatAppender;FileAppender
microlog.formatter=PatternFormatter
microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T

File diff suppressed because it is too large Load Diff

View File

@ -1,161 +1,493 @@
<html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>光环助手软件许可及服务协议</title>
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>光环助手软件许可及服务协议</title>
</head>
<style>
* {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
font-size: 16px;
}
</style>
</head>
<body>
<div class="content-area">
<p><b></b></p>
<p>
<b>光环</b>
<b>game</b>
<b>软件许可及服务协议</b>
</p>
<p><b>更新日期2020年11月20日</b></p>
<p><b>生效日期2020年11月30日</b></p>
<p><b>首部及导言</b></p>
<p>欢迎使用光环game软件许可及服务</p>
<p>
各位用户在使用光环game前请您务必审慎阅读、并充分理解本协议中的各项条款
<b>
特别是免除或者限制责任的条款,以及开通或使用某项服务的单独协议,并选择接受或不接受。
</b>
除非您已阅读并接受本协议所有条款,否则您无权下载、安装或使用本软件及相关服务。您的下载、安装、使用、登录等行为即视为您已阅读并同意上述协议的约束。
</p>
<p>如果您未满18周岁请在法定监护人的陪同下阅读本协议及其他上述协议。</p>
<p><b>一、权利声明</b></p>
<p>
“光环game”的一切知识产权以及与“光环game”相关的所有信息内容包括但不限于文字表述及其组合、图标、图饰、图像、图表、色彩、界面设计、版面框架、有关数据、附加程序、印刷材料或电子文档等均为光环game所有受著作权法和国际著作权条约以及其他知识产权法律法规的保护。
</p>
<p><b>二、软件使用规范</b></p>
<p>
2.1
本软件是基于Android安卓系统手机、平板电脑(PAD)等设备开发的一款软件,提供注册登录、观看视频、视频投稿等功能
</p>
<p>2.2 软件的下载、安装和使用</p>
<p>
本软件为免费软件用户可以非商业性、无限制数量地从光环game授权的渠道下载、安装及使用本软件。
</p>
<p>
<b>如果您从未经光环</b>
<b>game</b>
<b>授权的第三方获取本软件或与本软件名称相同的安装程序,光环</b>
<b>game</b>
<b>无法保证该软件能够正常使用,并对因此给您造成的损失不予负责。</b>
</p>
<p>2.3 软件的复制、分发和传播</p>
<p>
本产品以研究交流为目的。用户可以非商业性、无限制数量地复制、分发和传播本软件产品。但必须保证每一份复制、分发和传播都是完整和真实的,
包括所有有关本软件产品的软件、电子文档, 版权和商标,亦包括本协议。
</p>
<p>2.4 软件的更新</p>
<p>
为了改善用户体验、完善服务内容光环game将不断努力开发新的服务并为您不时提供软件更新这些更新可能会采取软件替换、修改、功能强化、版本升级等形式。为了保证本软件及服务的安全性和功能的一致性光环game有权不经向您特别通知而对软件进行更新或者对软件的部分功能效果进行改变或限制。本软件新版本发布后旧版本的软件可能无法使用。光环game不保证旧版本软件继续可用及相应的客户服务请您随时核对并下载最新版本。
</p>
<p><b>三、用户使用须知</b></p>
<p>3.1 您理解并同意:</p>
<p>
为了向您提供有效的服务,本软件会利用您移动通讯终端的处理器和带宽等资源。本软件使用过程中可能产生数据流量的费用,用户需自行向运营商了解相关资费信息,并自行承担相关费用.
</p>
<p>3.2您理解并同意:</p>
<p>
<b>
如果因您不正当使用本软件造成了不良影响,或因使用本软件造成的包括但不限于数据异常等问题,均由使用者自行承担,光环团队不对任意类型的使用结果承担责任;
</b>
</p>
<p>3.3您理解并同意:</p>
<p>
本软件不含任何破坏用户移动通讯设备数据和获取用户隐私信息的恶意代码,不会泄露用户的个人信息和隐私;
</p>
<p>3.4您理解并同意:</p>
<p>
<b>
对于包括但不限于互联网网络故障、计算机故障、手机故障或病毒、信息损坏或丢失、计算机系统问题,或其它任何基于不可抗力原因而产生的损失,光环团队不承担任何责任。
</b>
</p>
<p>3.5您理解并同意:</p>
<p>光环game发布、收录的视频均不代表光环立场。</p>
<p>3.6您理解并同意:</p>
<p>
用户应在遵守法律及本协议的前提下使用本软件。用户无权实施包括但不限于下列行为:
</p>
<p>3.6.1 不得删除或者改变本软件上的所有权利管理电子信息</p>
<p>
3.6.2
不得故意避开或者破坏著作权人为保护本软件著作权而采取的技术措施;&nbsp;
</p>
<p>3.6.3 用户不得利用本软件误导、欺骗他人;&nbsp;</p>
<p>
3.6.4
违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机信息系统不能正常运行;&nbsp;
</p>
<p>3.6.5 未经允许,进入计算机信息网络或者使用计算机信息网络资源;&nbsp;</p>
<p>3.6.6 未经允许,对计算机信息网络功能进行删除、修改或者增加;&nbsp;</p>
<p>
3.6.7
未经允许,对计算机信息网络中存储、处理或者传输的数据和应用程序进行删除、修改或者增加;&nbsp;
</p>
<p>
3.6.8
破坏本软件系统或网站的正常运行,故意传播计算机病毒等破坏性程序;&nbsp;
</p>
<p>3.6.9 其他任何危害计算机信息网络安全的行为。&nbsp;</p>
<p>3.7 您理解并同意:</p>
<p>
本软件经过详细的测试,但不能保证与所有的软硬件系统完全兼容,不能保证本软件完全没有错误。如果出现不兼容及软件错误的情况,用户可通过各反馈途径将情况告知光环团队,获得技术支持。如果无法解决兼容性问题,用户可以删除本软件。
</p>
<p><b>四、争议解决处理</b></p>
<p>
本《协议》的解释、效力及纠纷的解决适用于中华人民共和国法律。若用户和光环game之间发生任何纠纷或争议首先应友好协商解决协商不成的用户在此完全同意将纠纷或争议提交光环game所在地法院管辖
</p>
<p>
<b></b>
<b>、关于获取手机设备信息的说明</b>
</p>
<p>
1为方便区分每个用户的个人信息等本软件需获取用户的手机设备信息用于用户登录、视频评论互动交流等用户相关的行为
</p>
<p>
2为了保障软件与服务的安全运行我们会收集您的硬件型号、操作系统版本号、国际移动设备识别码、唯一设备标识符、网络设备硬件地址、IP
地址、WLAN接入点、蓝牙、基站、软件版本号、网络接入方式、类型、状态、网络质量数据、操作、使用、服务日志。
</p>
<p>
3为了预防恶意程序及安全运营所必需我们会收集安装的应用信息或正在运行的进程信息、应用程序的总体运行、使用情况与频率、应用崩溃情况、总体安装使用情况、性能数据、应用来源。
</p>
<p>
4我们可能使用您的账户信息、设备信息、服务日志信息以及我们关联公司、合作方在获得您授权或依法可以共享的信息用于判断账户安全、进行身份验证、检测及防范安全事件。
</p>
<p>5具体会发生获取手机设备信息场景如下说明</p>
<p>
&nbsp;&nbsp;1) 首次启动光环game&nbsp;2) 评论详情-发送评论功能&nbsp;3)
视频投稿-上传视频功能&nbsp;4) 视频详情-关注up主功能
</p>
<p><b>七、其他</b></p>
<p>
7.1
本协议所有条款的标题仅为阅读方便,本身并无实际涵义,不能作为本协议涵义解释的依据。
</p>
<p>
&nbsp;7.2
如果本协议中的任何条款无论因何种原因完全或部分无效或不具有执行力,或违反任何适用的法律,则该条款被视为删除,但本协议的其余条款仍应有效并且有约束力。
</p>
<p>
&nbsp;7.3
光环有权随时根据有关法律、法规的变化以及公司经营状况和经营策略的调整等修改本协议。修改后的协议会在软件设置内发布。
当发生有关争议时,以最新的协议文本为准。如果不同意改动的内容,用户可以自行删除本软件。如果用户继续使用本软件,则视为您接受本协议的变动。
</p>
<p>&nbsp;7.4 光环在法律允许的最大范围内对本协议拥有解释权与修改权。</p>
</div>
* {
margin: 0;
padding: 0;
font-size: 14px;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
}
body {
margin: 10px;
}
</body></html>
.top {
margin-left: 0;
margin-right: 0;
padding: 10px 0 10px 0;
}
.title {
font-weight: 700;
}
p {
font-size: 14px;
word-break: break-all;
}
.bold {
font-weight: 700;
}
.margintop {
margin-top: 10px;
}
.left-indent {
margin-left: 20px;
}
.red-style {
color: red;
}
.bold-font {
font-weight: bold;
}
span.bold {
font-weight: bold;
}
.link-text {
color: #005ad0;
text-decoration: underline;
}
</style>
<body>
<h3 class="top">光环助手软件许可及服务协议</h3>
<h5 class="title">首部及导言</h5>
<p>欢迎使用光环助手软件许可及服务</p>
<p>
各位用户在使用光环助手前,请您务必审慎阅读、并充分理解本协议中的各项条款,
<span class="bold">
特别是免除或者限制责任的条款,以及开通或使用某项服务的单独协议,并选择接受或不接受。
</span>
除非您已阅读并接受本协议所有条款,否则您无权下载、安装或使用本软件及相关服务。您的下载、安装、使用、登录等行为即视为您已阅读并同意上述协议的约束。
</p>
<p>如果您未满18周岁请在法定监护人的陪同下阅读本协议及其他上述协议。</p>
<h5 class="title margintop">一、权利声明</h5>
<p>
“光环助手”的一切知识产权,以及与“光环助手”相关的所有信息内容,包括但不限于:文字表述及其组合、图标、图饰、图像、图表、色彩、界面设计、版面框架、有关数据、附加程序、印刷材料或电子文档等均为光环助手所有,受著作权法和国际著作权条约以及其他知识产权法律法规的保护。
</p>
<h5 class="title margintop">二、软件使用规范</h5>
<p>
2.1
本软件是基于Android安卓系统手机、平板电脑(PAD)等设备开发的一款软件,提供注册登录、手机游戏管理、游戏推荐、文章阅读等功能
</p>
<p>2.2 软件的下载、安装和使用</p>
<p>
本软件为免费软件,用户可以非商业性、无限制数量地从光环授权的渠道下载、安装及使用本软件。
</p>
<p>
<span class="bold">
如果您从未经光环授权的第三方获取本软件或与本软件名称相同的安装程序,光环无法保证该软件能够正常使用,并对因此给您造成的损失不予负责。
</span>
</p>
<p>2.3 软件的复制、分发和传播</p>
<p>
本产品以学习、研究交流为目的。用户可以非商业性、无限制数量地复制、分发和传播本软件产品。但必须保证每一份复制、分发和传播都是完整和真实的,
包括所有有关本软件产品的软件、电子文档, 版权和商标,亦包括本协议。
</p>
<p>2.4 软件的更新</p>
<p>
为了改善用户体验、完善服务内容,光环将不断努力开发新的服务,并为您不时提供软件更新(这些更新可能会采取软件替换、修改、功能强化、版本升级等形式)。为了保证本软件及服务的安全性和功能的一致性,光环有权不经向您特别通知而对软件进行更新,或者对软件的部分功能效果进行改变或限制。本软件新版本发布后,旧版本的软件可能无法使用。光环不保证旧版本软件继续可用及相应的客户服务,请您随时核对并下载最新版本。
</p>
<h5 class="title margintop">三、用户使用须知</h5>
<p>3.1 您理解并同意:</p>
<p>
为了向您提供有效的服务,本软件会利用您移动通讯终端的处理器和带宽等资源。本软件使用过程中可能产生数据流量的费用,用户需自行向运营商了解相关资费信息,并自行承担相关费用.
</p>
<p>3.2 您理解并同意:</p>
<p>
由本软件进行收录、推荐并提供下载、升级服务的第三方软件,由第三方享有一切合法权利,光环并不能识别用户利用本软件下载、安装的第三方软件是否有合法来源。
<span class="bold">
因第三方软件引发的任何纠纷,由该第三方负责解决,光环不承担任何责任。
</span>
同时光环不对第三方软件或技术提供客服支持,若用户需要获取支持,请与该软件或技术提供商联系,若您为有关软件的权利人,不愿本软件为您的软件提供用户下载、安装、使用的服务,也可按本协议约定的联系方式联系我们,我们将会积极配合进行处理。
</p>
<p>3.3 您理解并同意:</p>
<p>
<span class="bold">
如果因您不正当使用本软件造成了不良影响,或因使用本软件造成的包括但不限于数据异常等问题,均由使用者自行承担,光环团队不对任意类型的使用结果承担责任;
</span>
</p>
<p>3.4 您理解并同意:</p>
<p>
本软件不含任何破坏用户移动通讯设备数据和获取用户隐私信息的恶意代码,不会泄露用户的个人信息和隐私;
</p>
<p>3.5 您理解并同意:</p>
<p>
<span class="bold">
对于包括但不限于互联网网络故障、计算机故障、手机故障或病毒、信息损坏或丢失、计算机系统问题,或其它任何基于不可抗力原因而产生的损失,光环团队不承担任何责任。
</span>
</p>
<p>3.6 您理解并同意:</p>
<p>光环发布、收录的文章均不代表光环立场。</p>
<p>3.7 您理解并同意:</p>
<p>
为实现软件包括但不限于集中展示、下载、安装、卸载等游戏管理功能以及文章优先推荐功能,本软件会检测用户手机中已安装游戏的包名、版本号、版本名、游戏名称信息。除征得用户明确同意和法律明确规定外,光环不会向第三方泄露任何的用户信息
</p>
<p>3.8 您理解并同意:</p>
<p>
用户应在遵守法律及本协议的前提下使用本软件。用户无权实施包括但不限于下列行为:
</p>
3.8.1 不得删除或者改变本软件上的所有权利管理电子信息
<br />
3.8.2 不得故意避开或者破坏著作权人为保护本软件著作权而采取的技术措施;
<br />
3.8.3 用户不得利用本软件误导、欺骗他人;
<br />
3.8.4
违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机信息系统不能正常运行;
<br />
3.8.5 未经允许,进入计算机信息网络或者使用计算机信息网络资源;
<br />
3.8.6 未经允许,对计算机信息网络功能进行删除、修改或者增加;
<br />
3.8.7
未经允许,对计算机信息网络中存储、处理或者传输的数据和应用程序进行删除、修改或者增加;
<br />
3.8.8 破坏本软件系统或网站的正常运行,故意传播计算机病毒等破坏性程序;
<br />
3.8.9 其他任何危害计算机信息网络安全的行为。
<br />
<p>3.9 您理解并同意:</p>
<p>
本软件经过详细的测试,但不能保证与所有的软硬件系统完全兼容,不能保证本软件完全没有错误。如果出现不兼容及软件错误的情况,用户可通过各反馈途径将情况告知光环团队,获得技术支持。如果无法解决兼容性问题,用户可以删除本软件。
</p>
<h5 class="title margintop">四、争议解决处理</h5>
<p>
本《协议》的解释、效力及纠纷的解决,适用于中华人民共和国法律。若用户和光环助手之间发生任何纠纷或争议,首先应友好协商解决,协商不成的,用户在此完全同意将纠纷或争议提交光环助手所在地法院管辖
</p>
<p class="title margintop"><b>五、第三方SDK接入说明</b></p>
<p>
为保障光环助手App相关功能的实现与应用安全稳定的运行我们会接入由第三方提供的软件开发包SDK实现相关功能。
<br />
我们会对合作方获取有关信息的软件工具开发包SDK进行严格的安全检测并与授权合作伙伴约定严格的数据保护措施令其按照我们的委托目的、服务说明、本隐私权政策以及其他任何相关的保密和安全措施来处理个人信息。
<br />
<span class="red-style">
下方为整个光环助手
<span class="bold">所有版本</span>
内接入的所有信息收集类第三方SDK的权限说明因隐私政策会因光环助手版本迭代而新接入SDK或停止合作部分SDK方便照顾
<span class="bold">所有版本</span>
的用户查看自己SDK第三方权限说明。
<br />
我们对涉及用户信息使用的SDK相关情况进行了逐项列举具体如下
</span>
</p>
<p class="margintop red-style bold-font"><b>1数据统计类</b></p>
<p>1.头条推广</p>
<p>
SDK官网
<span class="link-text">
https://ad.oceanengine.com/openapi/index.html
</span>
</p>
<p>SDK包名com.bytedance</p>
<p>企业主体:北京有竹居网络技术有限公司</p>
<p>使用目的:用于广告流量统计相关服务</p>
<p>
收集信息类型设备品牌、型号、软件系统相关信息、安卓oaid、无线网SSID名称、WiFi路由器MAC地址、设备MAC地址、IMEI、地理位置
</p>
<p>
隐私政策链接:
<span class="link-text">
https://ad.oceanengine.com/openapi/register/protocol.html?rid=vo25p8sfqde
</span>
</p>
<p>2.talkingdata统计</p>
<p>
SDK官网
<span class="link-text">http://www.talkingdata.com/</span>
</p>
<p>SDK包名com.tendcloud</p>
<p>企业主体:北京腾云天下科技有限公司</p>
<p>使用目的:用于统计数据和效果分析,以便为用户提供更好的服务</p>
<p>收集信息类型:设备信息、网络信息、位置信息、应用信息</p>
<p>
隐私政策链接:
<span class="link-text">
http://www.talkingdata.com/privacy.jsp?languagetype=zh_cn
</span>
</p>
<p>3.腾讯MTA</p>
<p>
SDK官网
<span class="link-text">https://mta.qq.com/mta/</span>
</p>
<p>SDK包名com.tencent</p>
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
<p>使用目的:用于统计数据和效果分析</p>
<p>
收集信息类型Mac地址、唯一设备识别码IMEI、android
ID、IDFA、OPENUDID、GUID/SIM卡IMSI信息、地理位置信息
</p>
<p>
隐私政策链接:
<span class="link-text">
https://mta.qq.com/mta/ctr_index/protocol_v2/
</span>
</p>
<p>4.腾讯广点通</p>
<p>
SDK官网
<span class="link-text">https://developers.e.qq.com/</span>
</p>
<p>SDK包名com.tencent</p>
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
<p>使用目的:用于广告流量统计相关服务</p>
<p>
收集信息类型:
个人常用设备信息IMEI、AndroidID、位置信息IP地址、软件版本号
</p>
<p>
隐私政策链接:
<span class="link-text">https://e.qq.com/optout.html</span>
</p>
<p class="margintop red-style bold-font"><b>2社交登录类</b></p>
<p>5.微信登录分享</p>
<p>
SDK官网
<span class="link-text">https://open.weixin.qq.com/</span>
</p>
<p>SDK包名com.tencent.mm.opensdk</p>
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
<p>使用目的:用于支持微信登录、分享</p>
<p>
收集信息类型个人常用设备信息MAC地址、IMEI、AndroidID、硬件型号、操作系统类型、软件信息软件版本号、浏览器类型、IP地址、服务日志信息、通讯日志信息
</p>
<p>
隐私政策链接:
<span class="link-text">https://privacy.tencent.com/</span>
</p>
<p>6.QQ登录分享</p>
<p>
SDK官网
<span class="link-text">https://connect.qq.com/</span>
</p>
<p>SDK包名com.tentcent</p>
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
<p>使用目的用于支持QQ登录、分享</p>
<p>
收集信息类型个人常用设备信息MAC地址、IMEI、AndroidID、IMSI、ICCID、序列号、设备型号、操作系统版本、软件信息软件版本号、浏览器类型、网络信息、IP地址、服务日志信息、通讯日志信息 
</p>
<p>
隐私政策链接:
<span class="link-text">
https://wiki.connect.qq.com/qq互联sdk隐私保护声明
</span>
</p>
<p>7.微博登录分享</p>
<p>
SDK官网
<span class="link-text">http://open.weibo.com/authentication</span>
</p>
<p>SDK包名com.sina.weibo.sdk</p>
<p>企业主体:北京微梦创科网络技术有限公司</p>
<p>使用目的:用于支持微博登录、分享</p>
<p>
收集信息类型个人常用设备信息MAC地址、IMEI、AndroidID、IMSI、ICCID、序列号、网络信息、应用列表硬件型号、操作系统类型、软件信息软件版本号、浏览器类型、IP地址、服务日志信息、通讯日志信息
</p>
<p>
隐私政策链接:
<span class="link-text">https://open.weibo.com/wiki/开发者协议</span>
</p>
<p>8.头条抖音登录</p>
<p>
SDK官网
<span class="link-text">https://open.douyin.com/platform</span>
</p>
<p>SDK包名com.bytedance.sdk</p>
<p>企业主体:北京字节跳动科技有限公司</p>
<p>使用目的:用于支持抖音登录</p>
<p>
收集信息类型个人常用设备信息MAC地址、IMEI、AndroidID、硬件型号、操作系统类型、软件信息软件版本号、浏览器类型、IP地址、服务日志信息、通讯日志信息
</p>
<p>
隐私政策链接:
<span class="link-text">
https://www.douyin.com/agreements/?id=6773901168964798477
</span>
</p>
<p class="margintop red-style bold-font"><b>3推送通知类</b></p>
<p>9.友盟推送</p>
<p>
SDK官网
<span class="link-text">https://www.umeng.com/push</span>
</p>
<p>SDK包名com.umeng</p>
<p>企业主体:北京友盟网络科技有限公司</p>
<p>使用目的:用于游戏相关信息的提醒通知</p>
<p>
收集信息类型Mac地址、唯一设备识别码IMEI、android
ID、IDFA、OPENUDID、GUID/SIM卡IMSI信息、地理位置信息
</p>
<p>
隐私政策链接:
<span class="link-text">
https://www.umeng.com/page/policy?spm=a213m0.14063960.0.0.7f626e72hx3nnv
</span>
</p>
<p class="margintop red-style bold-font"><b>4其他功能类</b></p>
<p>10.阿里云反爬虫</p>
<p>
SDK官网
<span class="link-text">https://www.aliyun.com/product/antibot</span>
</p>
<p>SDK包名com.alibaba.wireless</p>
<p>企业主体:阿里巴巴网络技术有限公司</p>
<p>使用目的为APP提供网络应用安全防护</p>
<p>
收集信息类型设备相关信息例如设备型号、操作系统版本、设备设置、唯一设备标识符等软硬件特征信息、设备所在位置相关信息例如IP地址、GPS位置以及能够提供相关信息的Wi-Fi接入点、蓝牙和基站等传感器信息
</p>
<p>
隐私政策链接:
<span class="link-text">
http://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud201902141711_54837.html?spm=a2c4g.11186623.J_9220772140.81.b7574832gmk0vr
</span>
</p>
<p>11.腾讯bugly</p>
<p>
SDK官网
<span class="link-text">https://bugly.qq.com/v2/</span>
</p>
<p>SDK包名com.tencent.bugly</p>
<p>企业主体:深圳市腾讯计算机系统有限公司</p>
<p>使用目的APP异常上报</p>
<p>
收集信息类型:设备及应用信息。如:设备名称、设备识别符、硬件型号、操作系统版本、应用程序版本
</p>
<p>
隐私政策链接:
<span class="link-text">https://bugly.qq.com/v2/contract</span>
</p>
<p>12.阿里云文件上传</p>
<p>
SDK官网
<span class="link-text">https://www.alibabacloud.com/zh</span>
</p>
<p>SDK包名com.alibaba.sdk.android</p>
<p>SDK包名com.alibaba.sdk.android</p>
<p>企业主体:阿里巴巴网络技术有限公司</p>
<p>使用目的:用于支持用户上传视频等相关内容</p>
<p>
收集信息类型设备相关信息例如设备型号、操作系统版本、设备设置、唯一设备标识符等软硬件特征信息、设备所在位置相关信息例如IP地址、GPS位置以及能够提供相关信息的Wi-Fi接入点、蓝牙和基站等传感器信息
</p>
<p>
隐私政策链接:
<span class="link-text">
http://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud201902141711_54837.html?spm=a2c4g.11186623.J_9220772140.81.b7574832gmk0vr
</span>
</p>
<p>13.阿里云日志上传</p>
<p>
SDK官网
<span class="link-text">https://www.alibabacloud.com/zh</span>
</p>
<p>SDK包名com.aliyun.sls.android.sdk</p>
<p>企业主体:阿里巴巴网络技术有限公司</p>
<p>
使用目的:通过网络日志分析这些信息以便更及时响应您的帮助请求,以及用于改进服务
</p>
<p>
收集信息类型设备相关信息例如设备型号、操作系统版本、设备设置、唯一设备标识符等软硬件特征信息、设备所在位置相关信息例如IP地址、GPS位置以及能够提供相关信息的Wi-Fi接入点、蓝牙和基站等传感器信息
</p>
<p>
隐私政策链接:
<span class="link-text">
http://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud201902141711_54837.html?spm=a2c4g.11186623.J_9220772140.81.b7574832gmk0vr
</span>
</p>
<p>14.容联七陌</p>
<p>
SDK官网
<span class="link-text">https://www.7moor.com/developer</span>
</p>
<p>SDK包名com.m7.imkfsdk</p>
<p>企业主体:北京七陌科技有限公司</p>
<p>使用目的:用于提供对应在线客服功能</p>
<p>
收集信息类型:设备相关信息(设备名称、设备型号、硬件序列号、操作系统和应用程序版本及类型、语言设置、分辨率、移动终端随机存储内存、摄像头/相册、通讯录权限等)
</p>
<p>
隐私政策链接:
<span class="link-text">http://m.7moor.com/72/57/p5077783560e807/</span>
</p>
<h5 class="title margintop">六、关于获取手机设备信息的说明</h5>
<div>
1为方便区分每个用户的个人信息等本软件需获取用户的手机设备信息用于游戏主动预约、论坛互动交流后进行推送等用户相关的行为
<br />
2为了保障软件与服务的安全运行我们会收集您的硬件型号、操作系统版本号、国际移动设备识别码、唯一设备标识符、网络设备硬件地址、IP
地址、WLAN接入点、蓝牙、基站、软件版本号、网络接入方式、类型、状态、网络质量数据、操作、使用、服务日志。
<br />
3为了预防恶意程序及安全运营所必需我们会收集安装的应用信息或正在运行的进程信息、应用程序的总体运行、使用情况与频率、应用崩溃情况、总体安装使用情况、性能数据、应用来源。
<br />
4我们可能使用您的账户信息、设备信息、服务日志信息以及我们关联公司、合作方在获得您授权或依法可以共享的信息用于判断账户安全、进行身份验证、检测及防范安全事件。
<br />
5具体会发生获取手机设备信息场景如下说明
<br />
<p class="left-indent">
1) 首次启动光环助手
<br />
2) 游戏列表/游戏详情/资讯文章详情/搜索结果页-预约功能
<br />
3) 礼包中心/礼包详情-领取功能
<br />
4) 评论详情-发送评论功能
<br />
5) 回答/问题详情-我来回答功能
<br />
6) 问答首页-提问功能
<br />
7) 个人主页-发文章功能
<br />
8) 帖子草稿/我的草稿-编辑功能
<br />
9) 游戏投稿功能
<br />
10) 视频投稿-上传视频功能
<br />
11) 游戏详情-关注游戏功能
</p>
</div>
<h5 class="title margintop">七、其他</h5>
<p>
7.1
本协议所有条款的标题仅为阅读方便,本身并无实际涵义,不能作为本协议涵义解释的依据。
<br />
7.2
如果本协议中的任何条款无论因何种原因完全或部分无效或不具有执行力,或违反任何适用的法律,则该条款被视为删除,但本协议的其余条款仍应有效并且有约束力。
<br />
7.3
光环有权随时根据有关法律、法规的变化以及公司经营状况和经营策略的调整等修改本协议。修改后的协议会在软件设置内发布。
当发生有关争议时,以最新的协议文本为准。如果不同意改动的内容,用户可以自行删除本软件。如果用户继续使用本软件,则视为您接受本协议的变动。
<br />
<span class="bold">
7.4 光环在法律允许的最大范围内对本协议拥有解释权与修改权。
</span>
</p>
</body>
</html>

View File

@ -26,6 +26,8 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import io.sentry.core.Sentry;
public class AppUncaughtHandler implements UncaughtExceptionHandler {
private Context mContext;
@ -45,7 +47,9 @@ public class AppUncaughtHandler implements UncaughtExceptionHandler {
Looper.loop();
}
});
saveLocalLog(mContext, ex);
Sentry.captureException(ex);
restart(mContext);
}

View File

@ -32,13 +32,17 @@ import com.gh.common.util.ExtensionsKt;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.RunningUtils;
import com.gh.common.util.SPUtils;
import com.gh.common.util.ShareUtils;
import com.gh.common.util.StringUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.LoginActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SplashScreenActivity;
import com.gh.gamecenter.eventbus.EBShowDialog;
import com.lightgame.BaseAppCompatActivity;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
import com.tencent.tauth.Tencent;
@ -122,6 +126,23 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
if (BuildConfig.DEBUG) {
Utils.log("ACTIVITY_ENTRANCE -> " + mEntrance);
}
if (savedInstanceState != null) {
String xapkUnzipActivity = SPUtils.getString(Constants.SP_XAPK_UNZIP_ACTIVITY);
String xapkUrl = SPUtils.getString(Constants.SP_XAPK_URL);
Utils.log("页面重建了--" + xapkUnzipActivity + "--" + xapkUrl);
if (this.getClass().getName().equals(SplashScreenActivity.class.getName())) {
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
SPUtils.setString(Constants.SP_XAPK_URL, "");
return;
}
if (this.getClass().getName().equals(xapkUnzipActivity) && !TextUtils.isEmpty(xapkUrl)) {
DownloadEntity downloadEntity = DownloadManager.getInstance(this).getDownloadEntityByUrl(xapkUrl);
PackageInstaller.install(this, downloadEntity, false);
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
SPUtils.setString(Constants.SP_XAPK_URL, "");
}
}
}
@SuppressWarnings("ConstantConditions")

View File

@ -81,8 +81,13 @@ public class WaitingDialogFragment extends BaseDialogFragment {
@Override
public void dismiss() {
dismissAllowingStateLoss();
}
@Override
public void dismissAllowingStateLoss() {
mBackListener = null;
super.dismiss();
super.dismissAllowingStateLoss();
}
public static class WaitingDialogData {

View File

@ -252,6 +252,11 @@ class DefaultJsApi(var context: Context) {
}
}
@JavascriptInterface
fun openInNewWebview(url: Any) {
runOnUiThread { DirectUtils.directToWebView(context, url.toString(), "内部网页") }
}
@Keep
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)

View File

@ -129,6 +129,11 @@ public class Constants {
public static final String SP_IS_USER_ACCEPTED_PRIVACY_STATEMENT = "has_user_accepted_privacy_statement";
public static final String SP_BRAND_NEW_USER = "brand_new_user";
//包名检测是否点击不再提示
public static final String SP_PACKAGE_CHECK = "package_check";
public static final String SP_XAPK_UNZIP_ACTIVITY = "xapk_unzip_activity";
public static final String SP_XAPK_URL = "xapk_url";
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";

View File

@ -14,10 +14,17 @@ import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.base.OnViewClickListener;
import com.gh.common.constant.Config;
import com.gh.common.dialog.CertificationDialog;
import com.gh.common.dialog.PackageCheckDialogFragment;
import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.history.HistoryHelper;
@ -38,7 +45,6 @@ import com.gh.common.util.NewsUtils;
import com.gh.common.util.NumberUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.PermissionHelper;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.ReservationHelper;
import com.gh.common.view.DownloadProgressBar;
@ -74,12 +80,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
/**
* Created by khy on 12/02/18.
*/
@ -256,6 +256,14 @@ public class BindingAdapters {
}
}
/**
* lazy 的 paddingTop
*/
@BindingAdapter("lazyPaddingLeft")
public static void lazyPaddingLeft(View view, int paddingLeftInDp) {
view.setPadding(DisplayUtils.dip2px(paddingLeftInDp), view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
}
/**
* lazy 的 paddingTop
*/
@ -448,12 +456,14 @@ public class BindingAdapters {
return;
}
}
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> {
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
PackageCheckDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> {
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
});
});
});
});
@ -509,13 +519,11 @@ public class BindingAdapters {
break;
case RESERVABLE:
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(progressBar.getContext(), () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
LogUtils.logReservation(gameEntity, traceEvent);
updateReservation(progressBar, gameEntity);
});
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
LogUtils.logReservation(gameEntity, traceEvent);
updateReservation(progressBar, gameEntity);
});
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
});
break;
case RESERVED:

File diff suppressed because it is too large Load Diff

View File

@ -118,7 +118,9 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi
//跳转登录页面
private fun gotoLoginPage() {
CheckLoginUtils.checkLogin(AppManager.getInstance().currentActivity() as AppCompatActivity,
val currentActivity = AppManager.getInstance().currentActivity() ?: return
CheckLoginUtils.checkLogin(currentActivity as AppCompatActivity,
null, true, "实名认证弹窗") {
if (UserManager.getInstance().isAuth) {
listener.onConfirm()
@ -129,7 +131,9 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi
//跳转实名认证页面
private fun gotoAuthPage() {
AvoidOnResultManager.getInstance(AppManager.getInstance().currentActivity() as AppCompatActivity)
val currentActivity = AppManager.getInstance().currentActivity() ?: return
AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity)
.startForResult(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD), object : Callback {
override fun onActivityResult(resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && data != null) {

View File

@ -48,7 +48,7 @@ class GameOffServiceDialogFragment
siteTv.setOnClickListener {
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
dismiss()
dismissAllowingStateLoss()
}
container.addView(siteTv)

View File

@ -13,16 +13,19 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentTransaction
import com.airbnb.lottie.LottieAnimationView
import com.gh.common.constant.Config
import com.gh.common.util.MtaHelper
import com.gh.common.util.PermissionHelper
import com.gh.common.util.PermissionHelper.INSTALL_PERMISS_CODE
import com.gh.common.util.goneIf
import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.common.util.PermissionHelper.INSTALL_PERMISSION_CODE
import com.gh.common.xapk.XapkInstaller
import com.gh.gamecenter.R
import com.lightgame.download.DownloadEntity
import kotlin.random.Random
class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
lateinit var mView: View
var isXapk = false
var url: String = ""
var mCallBack: (() -> Unit)? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -35,16 +38,26 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
val closeTv = mView.findViewById<TextView>(R.id.closeTv)
val closeIv = mView.findViewById<ImageView>(R.id.closeIv)
val activateTv = mView.findViewById<TextView>(R.id.activateTv)
val contentTv = mView.findViewById<TextView>(R.id.contentTv)
val switchLottie = mView.findViewById<LottieAnimationView>(R.id.switchLottie)
contentTv.text = if (isXapk) "未授权下解压XAPK可能导致解压失败" else "以保证游戏的安装和更新"
switchLottie.setAnimation("lottie/install_permission_switch.json")
switchLottie.playAnimation()
val randomNumber = Random.nextInt(2)
val randomNumber = if (isXapk) 1 else Random.nextInt(2)
closeTv.goneIf(randomNumber == 0)
closeIv.goneIf(randomNumber != 0)
if (isXapk) {
closeTv.text = "暂不,尝试解压"
closeIv.visibility = View.VISIBLE
}
closeTv.setOnClickListener {
MtaHelper.onEvent(getEvent(), getKey(), "文案样式_点击以后再说")
if (isXapk) {
mCallBack?.invoke()
}
dismiss()
}
closeIv.setOnClickListener {
@ -54,12 +67,18 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
activateTv.setOnClickListener {
MtaHelper.onEvent(getEvent(), getKey(), if (randomNumber == 0) "文案样式_点击立即开启" else "图标样式_点击立即开启")
PermissionHelper.toInstallPermissionSetting(requireActivity())
if (isXapk) {
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, requireActivity().javaClass.name)
SPUtils.setString(Constants.SP_XAPK_URL, url)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISS_CODE) {
if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISSION_CODE) {
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "")
SPUtils.setString(Constants.SP_XAPK_URL, "")
mCallBack?.invoke()
dismiss()
}
@ -71,30 +90,43 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
companion object {
@JvmStatic
fun show(activity: AppCompatActivity, callBack: (() -> Unit)?) {
fun show(activity: AppCompatActivity, downloadEntity: DownloadEntity, callBack: (() -> Unit)?) {
val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == downloadEntity.path.getExtension()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
callBack?.invoke()
return
}
if (!Config.isPermissionPopupSwitchOpen()) {
callBack?.invoke()
return
}
val haveInstallPermission = activity.packageManager.canRequestPackageInstalls();
val haveInstallPermission = activity.packageManager.canRequestPackageInstalls()
if (haveInstallPermission) {
callBack?.invoke()
return
}
if (isXapk) {
val xapkUnzipVersions = Config.getSettings()?.permissionPopupAppliedVersions?.xapkUnzip
if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
callBack?.invoke()
return
}
} else {
val installVersions = Config.getSettings()?.permissionPopupAppliedVersions?.install
if (installVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
callBack?.invoke()
return
}
}
var installPermissionDialogFragment = activity.supportFragmentManager.findFragmentByTag(InstallPermissionDialogFragment::class.java.simpleName) as? InstallPermissionDialogFragment
if (installPermissionDialogFragment != null) {
installPermissionDialogFragment.mCallBack = callBack
installPermissionDialogFragment.isXapk = isXapk
installPermissionDialogFragment.url = downloadEntity.url
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
transaction.show(installPermissionDialogFragment)
transaction.commit()
} else {
installPermissionDialogFragment = InstallPermissionDialogFragment().apply {
mCallBack = callBack
this.mCallBack = callBack
this.isXapk = isXapk
this.url = downloadEntity.url
}
installPermissionDialogFragment.show(activity.supportFragmentManager, InstallPermissionDialogFragment::class.java.simpleName)
}

View File

@ -0,0 +1,305 @@
package com.gh.common.dialog
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.common.view.CustomLinkMovementMethod
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentPackageCheckBinding
import com.gh.gamecenter.databinding.PackageCheckItemBinding
import com.gh.gamecenter.entity.DetectionObjectEntity
import com.gh.gamecenter.entity.PackageDialogEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.halo.assistant.HaloApp
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lightgame.dialog.BaseDialogFragment
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
/**
* 包名检测弹窗
*/
class PackageCheckDialogFragment : BaseDialogFragment() {
private lateinit var binding: FragmentPackageCheckBinding
private var mTotalWidth = 0f
private val mDuration = 3000
private var mDisposable: Disposable? = null
private var mAdapter: PackageCheckAdapter? = null
var packageDialogEntity: PackageDialogEntity? = null
var callBack: DialogUtils.ConfirmListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
EventBus.getDefault().register(this)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = FragmentPackageCheckBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
packageDialogEntity?.let {
changeParams(it.detectionObjects.size)
binding.packageRv.layoutManager = LinearLayoutManager(requireContext())
mAdapter = PackageCheckAdapter(requireContext(), it.detectionObjects)
binding.packageRv.adapter = mAdapter
binding.titleTv.text = it.title
binding.contentTv.text = it.content
val spanBuilder = SpanBuilder(it.linkHintText).build()
it.links.forEachIndexed { index, link ->
val linkSpan = SpanBuilder(link.title ?: "").click(0, (link.title
?: "").length, R.color.theme_font, true) {
DirectUtils.directToLinkPage(requireContext(), link, "包名检测弹窗", "")
}.build()
spanBuilder.append(linkSpan)
if (index != it.links.size - 1) {
spanBuilder.append("")
}
}
binding.linkHintTv.text = spanBuilder
binding.linkHintTv.movementMethod = CustomLinkMovementMethod.getInstance()
when (it.level) {
"HINT_SKIP" -> {
binding.cancelTv.text = "取消"
binding.noRemindAgainCb.visibility = View.GONE
}
"ALWAYS_HINT" -> {
binding.cancelTv.text = "我知道了"
binding.noRemindAgainCb.visibility = View.GONE
}
else -> {
binding.cancelTv.text = "我知道了"
binding.noRemindAgainCb.visibility = View.VISIBLE
}
}
initListener(it)
}
checkPackage()
}
private fun changeParams(size: Int) {
val params = binding.packageRv.layoutParams as LinearLayout.LayoutParams
params.height = if (size > 3) (28f.dip2px() * 3.5).toInt() else 28f.dip2px() * size
binding.packageRv.layoutParams = params
}
private fun initListener(entity: PackageDialogEntity) {
binding.downloadBtn.setOnClickListener {
if (binding.noRemindAgainCb.isChecked) {
SPUtils.setBoolean(Constants.SP_PACKAGE_CHECK, true)
}
val isAllPackageInstalled = isAllPackageInstalled(entity)
if (isAllPackageInstalled) {
callBack?.onConfirm()
dismissAllowingStateLoss()
} else {
val packageLink = entity.links.find { it.buttonLink }
if (packageLink != null) {
DirectUtils.directToLinkPage(requireContext(), packageLink, "包名检测弹窗", "")
}
}
}
binding.cancelTv.setOnClickListener {
if (entity.level != "HINT_SKIP") {
callBack?.onConfirm()
}
if (binding.noRemindAgainCb.isChecked) {
SPUtils.setBoolean(Constants.SP_PACKAGE_CHECK, true)
}
dismissAllowingStateLoss()
}
}
private fun checkPackage() {
var index = 0
mTotalWidth = (DisplayUtils.getScreenWidth() - 108f.dip2px()).toFloat()
mDisposable = rxTimer(1) {
val width = (mTotalWidth / mDuration) * it
val params = binding.progressView.layoutParams as RelativeLayout.LayoutParams
params.width = width.toInt()
binding.progressView.layoutParams = params
packageDialogEntity?.detectionObjects?.let { objects ->
if (objects.isNotEmpty()) {
val averageTime = if (objects.size == 1) {
mDuration
} else {
mDuration / objects.size
}
if (it != 0L && it % averageTime == 0L && index < objects.size) {
mAdapter?.notifyPackages()
binding.packageRv.smoothScrollToPosition(index)
index++
}
}
}
if (it >= mDuration) {
mDisposable?.dispose()
binding.downloadBtn.isEnabled = true
binding.progressText.text = "检测完成"
binding.progressView.background = ContextCompat.getDrawable(requireContext(), R.drawable.package_check_complete_bg)
}
}
}
override fun onStart() {
super.onStart()
val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
val height = ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
dialog?.setCanceledOnTouchOutside(true)
}
override fun onResume() {
super.onResume()
packageDialogEntity?.let {
if (isAllPackageInstalled(it)) {
callBack?.onConfirm()
dismissAllowingStateLoss()
}
}
}
override fun onDestroyView() {
super.onDestroyView()
EventBus.getDefault().unregister(this)
if (mDisposable?.isDisposed == false) {
mDisposable?.dispose()
}
}
//安装、卸载事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if ("安装" == busFour.type || "卸载" == busFour.type) {
mAdapter?.notifyDataSetChanged()
}
}
class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
private var index = -1
fun notifyPackages() {
index++
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return PackageCheckViewHolder(PackageCheckItemBinding.bind(LayoutInflater.from(context).inflate(R.layout.package_check_item, parent, false)))
}
override fun getItemCount(): Int = entities.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is PackageCheckViewHolder) {
val entity = entities[position]
holder.binding.entity = entity
if (position <= index) {
var isAllInstalled = false
entity.packages.forEach { packageName ->
val isInstalled = PackageUtils.getInstalledPackages(context, 0).find { it.packageName == packageName } != null
if (isInstalled) {
isAllInstalled = true
return@forEach
}
}
if (isAllInstalled) {
holder.binding.statusTv.text = "已安装"
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
} else {
holder.binding.statusTv.text = "未安装"
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.text_FF4147))
}
holder.binding.statusTv.visibility = View.VISIBLE
} else {
holder.binding.statusTv.visibility = View.GONE
}
}
}
}
class PackageCheckViewHolder(val binding: PackageCheckItemBinding) : BaseRecyclerViewHolder<DetectionObjectEntity>(binding.root)
companion object {
@JvmStatic
fun show(activity: AppCompatActivity, packageDialogEntity: PackageDialogEntity?, callBack: DialogUtils.ConfirmListener) {
if (packageDialogEntity == null) {
callBack.onConfirm()
return
}
if (isAllPackageInstalled(packageDialogEntity)) {
callBack.onConfirm()
return
}
val isChoose = SPUtils.getBoolean(Constants.SP_PACKAGE_CHECK, false)
if (packageDialogEntity.level == "OPTIONAL_HINT" && isChoose) {
callBack.onConfirm()
return
}
var dialogFragment = activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.simpleName) as? PackageCheckDialogFragment
if (dialogFragment == null) {
dialogFragment = PackageCheckDialogFragment()
dialogFragment.packageDialogEntity = packageDialogEntity
dialogFragment.callBack = callBack
dialogFragment.show(activity.supportFragmentManager, PackageCheckDialogFragment::class.java.simpleName)
} else {
dialogFragment.packageDialogEntity = packageDialogEntity
dialogFragment.callBack = callBack
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
transaction.show(dialogFragment)
transaction.commit()
}
}
fun isAllPackageInstalled(packageDialogEntity: PackageDialogEntity): Boolean {
var isAllInstalled = true
val isPackagesInstall: (ArrayList<String>) -> Boolean = { packages ->
var isPackagesInstalled = false
packages.forEach {packageName->
val isInstalled = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0).find { it.packageName == packageName } != null
if (isInstalled) {
isPackagesInstalled = true
return@forEach
}
}
isPackagesInstalled
}
packageDialogEntity.detectionObjects.forEach loop@{ obj ->
if (!isPackagesInstall(obj.packages)) {
isAllInstalled = false
return isAllInstalled
}
}
return isAllInstalled
}
}
}

View File

@ -2,23 +2,27 @@ package com.gh.common.dialog
import android.app.Dialog
import android.content.DialogInterface
import android.os.Build
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextPaint
import android.text.method.ScrollingMovementMethod
import android.text.style.ClickableSpan
import android.view.*
import android.webkit.WebSettings
import android.webkit.WebView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentTransaction
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.util.DirectUtils.directToExternalBrowser
import com.gh.common.util.dip2px
import com.gh.common.view.CustomLinkMovementMethod
import com.gh.gamecenter.R
class PrivacyDialogFragment : BaseDialogFragment() {
private val mLocalPrivacyHtml = "file:///android_asset/privacy_policies.html"
private val mLocalRegulationHtml = "file:///android_asset/user_regulation.html"
// private val mLocalPrivacyHtml = "file:///android_asset/privacy_policies.html"
// private val mLocalRegulationHtml = "file:///android_asset/user_regulation.html"
var containerView: View? = null
var mCallBack: ((isSuccess: Boolean) -> Unit)? = null
@ -30,83 +34,80 @@ class PrivacyDialogFragment : BaseDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
val mWebViewRegulation = containerView?.findViewById<WebView>(R.id.webView2)
// val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
// val mWebViewRegulation = containerView?.findViewById<WebView>(R.id.webView2)
//
// mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
// mWebViewRegulation?.isHorizontalScrollBarEnabled = false
mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
mWebViewRegulation?.isHorizontalScrollBarEnabled = false
val contentTv = containerView?.findViewById<TextView>(R.id.contentTv)
val descTv = containerView?.findViewById<TextView>(R.id.descTv)
contentTv?.movementMethod = ScrollingMovementMethod()
val mTitlePrivacyTv = containerView?.findViewById<TextView>(R.id.privacyTitleTv)
val mTitleRegulationTv = containerView?.findViewById<TextView>(R.id.userRegulationTitleTv)
val settingsArrayList = arrayListOf(mWebViewPrivacy?.settings, mWebViewRegulation?.settings)
for (settings in settingsArrayList) {
settings?.javaScriptEnabled = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
}
// 避免提示网页有害信息不能访问
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
settings?.safeBrowsingEnabled = false
val skipText = SpannableStringBuilder("查看完整版的隐私政策和用户协议")
skipText.setSpan(object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
ds.isUnderlineText = false
}
// 适配大于屏幕宽度的页面
settings?.useWideViewPort = true
settings?.loadWithOverviewMode = true
settings?.domStorageEnabled = true
// 自适应屏幕
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
settings?.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING
override fun onClick(widget: View) {
directToExternalBrowser(context!!, context!!.getString(R.string.privacy_policy_url))
}
}
}, skipText.length - 9, skipText.length - 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
// if (NetworkUtils.isNetworkConnected(requireContext())) {
// mWebViewPrivacy?.loadUrl(requireContext().getString(R.string.privacy_policy_url))
// mWebViewRegulation?.loadUrl(requireContext().getString(R.string.user_regulation_url))
// } else {
mWebViewPrivacy?.loadUrl(mLocalPrivacyHtml)
mWebViewRegulation?.loadUrl(mLocalRegulationHtml)
// }
skipText.setSpan(object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
ds.isUnderlineText = false
}
// val client = object : WebViewClient() {
// override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
// super.onReceivedError(view, request, error)
// if (view == mWebViewPrivacy) {
// view?.loadUrl(mLocalPrivacyHtml)
// } else {
// view?.loadUrl(mLocalRegulationHtml)
// }
override fun onClick(widget: View) {
directToExternalBrowser(requireContext(), requireContext().getString(R.string.disclaimer_url))
}
}, skipText.length - 4, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
descTv?.movementMethod = CustomLinkMovementMethod()
descTv?.text = skipText
// val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
//
// mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
//
// val settingsArrayList = arrayListOf(mWebViewPrivacy?.settings, mWebViewRegulation?.settings)
//
// for (settings in settingsArrayList) {
// settings?.javaScriptEnabled = true
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
// }
// // 避免提示网页有害信息不能访问
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// settings?.safeBrowsingEnabled = false
// }
//
// // 适配大于屏幕宽度的页面
// settings?.useWideViewPort = true
// settings?.loadWithOverviewMode = true
// settings?.domStorageEnabled = true
//
// // 自适应屏幕
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// settings?.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING
// }
// }
// mWebViewPrivacy?.webViewClient = client
// mWebViewRegulation?.webViewClient = client
mTitlePrivacyTv?.setOnClickListener {
mTitlePrivacyTv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
mTitleRegulationTv?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_F5F5F5))
mWebViewPrivacy?.visibility = View.VISIBLE
mWebViewRegulation?.visibility = View.GONE
}
mTitleRegulationTv?.setOnClickListener {
mTitlePrivacyTv?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_F5F5F5))
mTitleRegulationTv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
mWebViewPrivacy?.visibility = View.GONE
mWebViewRegulation?.visibility = View.VISIBLE
}
containerView?.findViewById<View>(R.id.refuseTv)?.setOnClickListener {
mCallBack?.invoke(false)
dismiss()
dismissAllowingStateLoss()
}
containerView?.findViewById<View>(R.id.agreeTv)?.setOnClickListener {
mCallBack?.invoke(true)
dismiss()
dismissAllowingStateLoss()
}
}

View File

@ -24,6 +24,7 @@ object MetaUtil {
private var m: Meta? = null
private var imei: String? = null
private var base64EncodedImei: String? = null
private var androidId: String? = null
fun refreshMeta() {
@ -104,6 +105,20 @@ object MetaUtil {
}
@JvmStatic
fun getBase64EncodedIMEI(): String {
if (TextUtils.isEmpty(base64EncodedImei) && imei != null) {
try {
base64EncodedImei = android.util.Base64.encodeToString(getIMEI().trim().toByteArray(), android.util.Base64.NO_WRAP)
} catch (e: java.lang.Exception) {
e.printStackTrace()
return ""
}
}
return base64EncodedImei ?: ""
}
fun getModel(): String? {
return Build.MODEL
}

View File

@ -4,6 +4,7 @@ import com.gh.common.runOnIoThread
import com.gh.common.util.clearHtmlFormatCompletely
import com.gh.common.util.removeInsertedContent
import com.gh.common.util.removeVideoContent
import com.gh.common.util.tryCatchInRelease
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.qa.entity.AnswerDetailEntity
import com.gh.gamecenter.qa.entity.AnswerEntity
@ -14,27 +15,28 @@ object HistoryHelper {
fun insertAnswerEntity(answerDetailEntity: AnswerDetailEntity) {
val answerEntity = convertAnswerDetailToAnswer(answerDetailEntity)
runOnIoThread { HistoryDatabase.instance.answerDao().addAnswer(answerEntity) }
// 偶尔有设备会出现磁盘满了写不进数据库的问题 database or disk is full 异常,毕竟只是插入个本地历史,这里直接捕抓
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.answerDao().addAnswer(answerEntity) } }
}
fun insertArticleEntity(articleDetailEntity: ArticleDetailEntity) {
val articleEntity = convertArticleDetailToArticle(articleDetailEntity)
runOnIoThread { HistoryDatabase.instance.articleDao().addArticle(articleEntity) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.articleDao().addArticle(articleEntity) } }
}
@JvmStatic
fun insertGameEntity(gameEntity: GameEntity) {
val historyGameEntity = convertGameEntityToHistoryGameEntity(gameEntity)
runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } }
}
@JvmStatic
fun insertGameEntity(updateEntity: GameUpdateEntity) {
val historyGameEntity = convertGameUpdateEntityToHistoryGameEntity(updateEntity)
runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } }
}
private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity{
private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity {
val historyGame = HistoryGameEntity()
historyGame.orderTag = System.currentTimeMillis()

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.database.ContentObserver
import android.media.AudioManager
import android.os.Handler
import com.gh.common.util.tryCatchInRelease
class VolumeObserver(var context: Context, handler: Handler, var callback: MuteCallback? = null)
: ContentObserver(handler) {
@ -11,14 +12,20 @@ class VolumeObserver(var context: Context, handler: Handler, var callback: MuteC
init {
val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
// 部分设备的 audioManager getStreamVolume 内部会触发空指针 :(
tryCatchInRelease { previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC) }
}
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange)
val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
var currentVolume = 0
tryCatchInRelease {
// 部分设备(Meizu 7.1.2 M6 Note)的 audioManager getStreamVolume 内部会触发空指针 :(
currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
}
val delta = previousVolume - currentVolume

View File

@ -2,6 +2,7 @@ package com.gh.common.simulator
import android.app.Dialog
import android.content.Context
import android.view.Gravity
import android.view.View
import android.view.Window
import android.widget.ProgressBar
@ -116,8 +117,8 @@ class SimulatorDownloadManager private constructor() {
key = if (shouldShowUpdate && isInstalled) "更新弹窗" else "下载弹窗",
logShowEvent = true
)
DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, {
if (shouldShowUpdate && isInstalled){
DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, Gravity.LEFT, {
if (shouldShowUpdate && isInstalled) {
cancelCallback?.invoke()
MtaHelper.onEvent(trackableEntity.event, trackableEntity.key, "点击下次再说")
}

View File

@ -33,7 +33,7 @@ object SimulatorGameManager {
@JvmStatic
fun deleteLocalGames(names: List<String>) {
val downloadEntityList = DownloadDao.getInstance(HaloApp.getInstance().application).all
val downloadEntityList = DownloadManager.getInstance(HaloApp.getInstance().application).allDownloadEntity
names.forEach { name ->
val downloadEntity = downloadEntityList.find { it.name == name }
if (downloadEntity != null) {
@ -48,7 +48,7 @@ object SimulatorGameManager {
@JvmStatic
fun deleteLocalGame(name: String) {
val downloadEntityList = DownloadDao.getInstance(HaloApp.getInstance().application).all
val downloadEntityList = DownloadManager.getInstance(HaloApp.getInstance().application).allDownloadEntity
val downloadEntity = downloadEntityList.find { it.name == name }
if (downloadEntity != null) {
val file = File(downloadEntity.path)

View File

@ -33,6 +33,7 @@ object CommentHelper {
showConversation: Boolean,
articleId: String,
communityId: String,
isShowTop: Boolean = false,
ignoreModerator: Boolean = false,
listener: OnCommentOptionClickListener?) {
showCommentOptions(view = view,
@ -40,6 +41,7 @@ object CommentHelper {
showConversation = showConversation,
articleId = articleId,
communityId = communityId,
isShowTop = isShowTop,
ignoreModerator = ignoreModerator,
listener = listener)
}
@ -79,11 +81,16 @@ object CommentHelper {
communityId: String? = null,
answerId: String? = null,
videoId: String? = null,
isShowTop: Boolean = false,
ignoreModerator: Boolean = false,
isVideoAuthor: Boolean = false,
listener: OnCommentOptionClickListener? = null) {
val context = view.context
val dialogOptions = ArrayList<String>()
if (isShowTop && articleId != null && commentEntity.me?.isArticleOrAnswerAuthor == true) {
dialogOptions.add(if (commentEntity.isTop) "取消置顶" else "置顶")
}
dialogOptions.add("复制")
if (commentEntity.user.id != UserManager.getInstance().userId) {
dialogOptions.add("投诉")

View File

@ -2,7 +2,6 @@ package com.gh.common.util;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Color;
import android.text.TextUtils;
@ -12,6 +11,9 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.gh.gamecenter.CommentDetailActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
@ -39,8 +41,6 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
@ -529,10 +529,7 @@ public class CommentUtils {
//复制文字
public static void copyText(String copyContent, Context context) {
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(copyContent);
ToastUtils.INSTANCE.showToast("复制成功");
ExtensionsKt.copyTextAndToast(copyContent, "复制成功");
}

View File

@ -3,11 +3,13 @@ package com.gh.common.util;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import com.gh.common.constant.Constants;
import com.gh.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.BuildConfig;
import com.gh.gid.GidCallback;
import com.gh.gid.GidHelper;
import com.halo.assistant.HaloApp;
@ -16,7 +18,10 @@ import com.lightgame.utils.Utils;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import io.sentry.android.core.SentryAndroid;
import io.sentry.core.Sentry;
import io.sentry.core.protocol.User;
/**
* Created by LGT on 2016/6/15.
@ -35,6 +40,40 @@ public class DataUtils {
if (CommonDebug.IS_DEBUG) {
return;
}
SentryAndroid.init(context, options -> {
// Sentry 疯狂报 ANR (很大一部分还是莫名奇妙的 ANR)严重影响到其它闪退日志的收集
// 这里将它局限到只有官网渠道的包才统计 ANR
if ("GH_206".equals(channel)) {
options.setAnrEnabled(true);
options.setAnrTimeoutIntervalMillis(6000);
} else {
options.setAnrEnabled(false);
}
options.setDebug(BuildConfig.DEBUG);
options.setEnableSessionTracking(true);
options.setEnvironment(BuildConfig.FLAVOR);
options.setDsn("https://6b1caf0d17c1408e8680f3f73ff80bd0@sentry.ghzs.com/22");
options.setBeforeSend((event, hint) -> {
if (BuildConfig.DEBUG) {
return null;
} else {
return event;
}
});
});
Sentry.configureScope(scope -> {
if (BuildConfig.BUILD_TIME != 0L) {
scope.setTag("alias", "内测版" + BuildConfig.VERSION_NAME + "_" + BuildConfig.BUILD_TIME);
} else {
scope.setTag("alias", "正式版" + BuildConfig.VERSION_NAME);
scope.setTag("channel", channel);
}
});
//TalkingData
// try {
// TCAgent.LOG_ON = false;
@ -139,8 +178,8 @@ public class DataUtils {
}
public static void onEvent(Context var0, String var1, String var2) {
Properties prop = new Properties();
prop.setProperty(var1, var2);
// Properties prop = new Properties();
// prop.setProperty(var1, var2);
// StatService.trackCustomKVEvent(var0, var1, prop);
}
@ -161,64 +200,64 @@ public class DataUtils {
}
public static void onEvent(Context var0, String var1, String var2, Map<String, Object> var3) {
Properties prop = new Properties();
prop.setProperty("label", var2);
for (String key : var3.keySet()) {
prop.setProperty(key, var3.get(key) + "");
}
// Properties prop = new Properties();
// prop.setProperty("label", var2);
// for (String key : var3.keySet()) {
// prop.setProperty(key, var3.get(key) + "");
// }
// StatService.trackCustomKVEvent(var0, var1, prop);
}
public static void trackTimeEvent(Context context, String eventId, int costTime, String... kv) {
Properties prop = new Properties();
for (int i = 0; i < kv.length; i++) {
if (i % 2 != 0 || i != 0) {
String key = kv[i - 1];
String value = kv[i];
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value);
}
}
}
if (prop.size() == 0) return;
//
// Properties prop = new Properties();
// for (int i = 0; i < kv.length; i++) {
// if (i % 2 != 0 || i != 0) {
// String key = kv[i - 1];
// String value = kv[i];
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
// prop.setProperty(key, value);
// }
// }
// }
//
// if (prop.size() == 0) return;
//
// StatService.trackCustomKVTimeIntervalEvent(context, costTime, eventId, prop);
}
// 游戏下载
public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status, String method) {
// Map<String, Object> kv = new HashMap<>();
//
// platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
//
// kv.put("版本", platform);
// kv.put("用户机型", Build.MODEL);
// kv.put("设备IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().getApplication()));
// kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
// kv.put("光环助手版本", BuildConfig.VERSION_NAME);
// kv.put("位置", entrance);
// kv.put("类型", method);
// kv.put("厂商", Build.MANUFACTURER);
// kv.put("Android版本", Build.VERSION.RELEASE);
// onEvent(context, "游戏下载", gameName, kv);
//
// Map<String, Object> kv2 = new HashMap<>();
// kv2.put("状态", status);
// kv2.put("位置", entrance);
//
// if (status.equals("开始")) {
// kv2.put("版本", entrance + "-开始");
// kv2.put("游戏分平台", gameName + "-" + platform + "-开始");
// kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
// } else {
// kv2.put("版本", platform);
// kv2.put("游戏分平台", gameName + "-" + platform);
// kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
// }
//
// onEvent(context, "游戏下载位置", gameName, kv2);
Map<String, Object> kv = new HashMap<>();
platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
kv.put("版本", platform);
kv.put("用户机型", Build.MODEL);
kv.put("设备IMEI", MetaUtil.getIMEI());
kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
kv.put("光环助手版本", BuildConfig.VERSION_NAME);
kv.put("位置", entrance);
kv.put("类型", method);
kv.put("厂商", Build.MANUFACTURER);
kv.put("Android版本", Build.VERSION.RELEASE);
onEvent(context, "游戏下载", gameName, kv);
Map<String, Object> kv2 = new HashMap<>();
kv2.put("状态", status);
kv2.put("位置", entrance);
if (status.equals("开始")) {
kv2.put("版本", entrance + "-开始");
kv2.put("游戏分平台", gameName + "-" + platform + "-开始");
kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
} else {
kv2.put("版本", platform);
kv2.put("游戏分平台", gameName + "-" + platform);
kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
}
onEvent(context, "游戏下载位置", gameName, kv2);
}
// 游戏更新

View File

@ -350,7 +350,7 @@ public class DialogUtils {
* @param cmListener 确认按钮监听
*/
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
, String negative, String positive, TrackableEntity trackableEntity, final CancelListener clListener, final ConfirmListener cmListener) {
, String negative, String positive, TrackableEntity trackableEntity, int gravity, final CancelListener clListener, final ConfirmListener cmListener) {
context = checkDialogContext(context);
final Dialog dialog;
if (trackableEntity != null) {
@ -373,6 +373,8 @@ public class DialogUtils {
TextView cancelBtn = contentView.findViewById(R.id.cancel);
TextView confirmBtn = contentView.findViewById(R.id.confirm);
View middleLine = contentView.findViewById(R.id.middle_line);
titleTv.setGravity(gravity);
contentTv.setGravity(gravity);
titleTv.setText(title);
contentTv.setText(message);
@ -411,7 +413,7 @@ public class DialogUtils {
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
, String negative, String positive, final CancelListener clListener, final ConfirmListener cmListener) {
return showNewAlertDialog(context, title, message, negative, positive, null, clListener, cmListener);
return showNewAlertDialog(context, title, message, negative, positive, null, Gravity.LEFT, clListener, cmListener);
}
/**
@ -986,13 +988,13 @@ public class DialogUtils {
WindowManager.LayoutParams params = window.getAttributes();
params.horizontalMargin = 0;
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(40);
int height = context.getResources().getDisplayMetrics().heightPixels - DisplayUtils.dip2px(120);
int maxHeight = DisplayUtils.dip2px(446);
if (height > maxHeight) {
params.height = maxHeight;
} else {
params.height = height;
}
// int height = context.getResources().getDisplayMetrics().heightPixels - DisplayUtils.dip2px(120);
// int maxHeight = DisplayUtils.dip2px(446);
// if (height > maxHeight) {
// params.height = maxHeight;
// } else {
// params.height = height;
// }
window.setAttributes(params);
}
@ -1025,8 +1027,6 @@ public class DialogUtils {
hierarchy.setPlaceholderImage(R.drawable.permission_storage);
} else if (position == 1) {
hierarchy.setPlaceholderImage(R.drawable.permission_phone_state);
} else {
hierarchy.setPlaceholderImage(R.drawable.permission_sdk);
}
}
}

View File

@ -22,6 +22,7 @@ import com.gh.common.exposure.ExposureType
import com.gh.common.util.EntranceUtils.*
import com.gh.gamecenter.*
import com.gh.gamecenter.amway.AmwayActivity
import com.gh.gamecenter.catalog.CatalogActivity
import com.gh.gamecenter.category.CategoryDirectoryActivity
import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE
import com.gh.gamecenter.entity.*
@ -57,7 +58,6 @@ import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
import com.gh.gamecenter.video.game.GameVideoActivity
import com.gh.gamecenter.video.videomanager.VideoManagerActivity
import com.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_ClipboardManager
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
@ -133,7 +133,9 @@ object DirectUtils {
"server",
"top_game_comment",
"wechat_bind",
"video")
"video",
"catalog"
)
fun directToLinkPage(context: Context,
linkEntity: LinkEntity,
@ -200,6 +202,8 @@ object DirectUtils {
"category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!)
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
"block", "版块" -> {
if (linkEntity.link.isNullOrEmpty()) return
directToBlock(context,
@ -575,7 +579,7 @@ object DirectUtils {
@JvmStatic
fun directToExternalBrowser(context: Context, url: String) {
if (url.isEmpty()) return
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(Uri.decode(url)))
if (context !is AppCompatActivity) {
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
@ -606,8 +610,7 @@ object DirectUtils {
context.startActivity(intent)
} else {
// 没有安装QQ 复制账号
Util_System_ClipboardManager.setText(context, qq)
Utils.toast(context, "已复制 QQ $qq")
qq?.copyTextAndToast("已复制 QQ $qq")
}
}
@ -889,6 +892,20 @@ object DirectUtils {
jumpActivity(context, bundle)
}
/**
* 跳转新分类
*/
@JvmStatic
fun directCatalog(context: Context, catalogId: String, catalogTitle: String, entrance: String? = null, path: String? = "") {
if (catalogId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, CatalogActivity::class.java.name)
bundle.putString(KEY_CATALOG_ID, catalogId)
bundle.putString(KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
jumpActivity(context, bundle)
}
/**
* 跳转到问题标签详情
*/

View File

@ -8,9 +8,16 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.common.constant.Config;
import com.gh.common.dialog.CertificationDialog;
import com.gh.common.dialog.DeviceRemindDialog;
import com.gh.common.dialog.PackageCheckDialogFragment;
import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.history.HistoryHelper;
@ -39,12 +46,6 @@ import com.lightgame.utils.Utils;
import java.io.File;
import java.util.concurrent.LinkedBlockingQueue;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
/**
* todo 下载判断不能以按钮文案为判断条件,否则按钮文案修改时又要修改判断逻辑
*/
@ -419,7 +420,7 @@ public class DownloadItemUtils {
}
/**
* @param clickCallback 供那些需要知道点击回调的地方使用
* @param clickCallback 供那些需要知道点击回调的地方使用,触发具体响应才会回调
*/
public static void setOnClickListener(final Context context,
final TextView downloadBtn,
@ -431,103 +432,13 @@ public class DownloadItemUtils {
final ExposureEvent traceEvent,
@Nullable final EmptyCallback clickCallback) {
if (gameEntity.isReservable()) {
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
downloadBtn.setOnClickListener(v -> {
CheckLoginUtils.checkLogin(context, entrance, () -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
gameEntity,
() -> {
LogUtils.logReservation(gameEntity, traceEvent);
adapter.notifyItemChanged(position);
}
);
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
});
});
});
} else {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
if ("download".equals(gameEntity.getReserveStatus())) {
ReservationHelper.showDeleteReservationDialog(context, () -> {
ReservationHelper.deleteReservation(gameEntity, () -> {
adapter.notifyItemChanged(position);
});
});
} else {
ReservationHelper.showCancelReservationDialog(context, () -> {
ReservationHelper.cancelReservation(gameEntity, () -> {
adapter.notifyItemChanged(position);
});
});
}
});
}
return;
}
if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) {
downloadBtn.setOnClickListener(v -> {
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
LinkEntity linkEntity = gameEntity.getH5Link();
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
if (isPlay) {
HistoryHelper.insertGameEntity(gameEntity);
}
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton());
context.startActivity(i);
});
} else if (gameEntity.getApk().size() == 1) {
downloadBtn.setOnClickListener(v -> {
EmptyCallback clickRunnable = () -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent);
};
// 启动不需要请求存储权限
if (downloadBtn.getText().toString().equals(context.getString(R.string.launch))) {
clickRunnable.onCallback();
} else {
PermissionHelper.checkStoragePermissionBeforeAction(context, clickRunnable);
}
});
} else {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
PermissionHelper.checkStoragePermissionBeforeAction(context, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location);
});
});
});
});
}
setOnClickListener(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent, clickCallback, null);
}
/**
* @param clickCallback 供那些需要知道点击回调的地方使用,只要触发点击事件就响应回调(未登录状态下点击预约也要响应回调
* @param allStateClickCallback 供那些需要知道点击回调的地方使用,只要触发点击动作就会回调
*/
public static void setOnClickListenerWithInvokeCallbackForAllState(final Context context,
public static void setOnClickListener(final Context context,
final TextView downloadBtn,
final GameEntity gameEntity,
final int position,
@ -535,29 +446,36 @@ public class DownloadItemUtils {
final String entrance,
final String location,
final ExposureEvent traceEvent,
@Nullable final EmptyCallback clickCallback) {
@Nullable final EmptyCallback clickCallback,
@Nullable final EmptyCallback allStateClickCallback) {
if (gameEntity.isReservable()) {
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
if (allStateClickCallback != null) {
allStateClickCallback.onCallback();
}
CheckLoginUtils.checkLogin(context, entrance, () -> {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
gameEntity,
() -> {
LogUtils.logReservation(gameEntity, traceEvent);
adapter.notifyItemChanged(position);
}
);
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
});
if (clickCallback != null) {
clickCallback.onCallback();
}
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
gameEntity,
() -> {
LogUtils.logReservation(gameEntity, traceEvent);
adapter.notifyItemChanged(position);
}
);
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
});
});
} else {
downloadBtn.setOnClickListener(v -> {
if (allStateClickCallback != null) {
allStateClickCallback.onCallback();
}
if (clickCallback != null) {
clickCallback.onCallback();
}
@ -581,9 +499,10 @@ public class DownloadItemUtils {
if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
if (allStateClickCallback != null) {
allStateClickCallback.onCallback();
}
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
LinkEntity linkEntity = gameEntity.getH5Link();
@ -599,6 +518,10 @@ public class DownloadItemUtils {
} else if (gameEntity.getApk().size() == 1) {
downloadBtn.setOnClickListener(v -> {
EmptyCallback clickRunnable = () -> {
if (allStateClickCallback != null) {
allStateClickCallback.onCallback();
}
if (clickCallback != null) {
clickCallback.onCallback();
}
@ -614,6 +537,10 @@ public class DownloadItemUtils {
});
} else {
downloadBtn.setOnClickListener(v -> {
if (allStateClickCallback != null) {
allStateClickCallback.onCallback();
}
if (clickCallback != null) {
clickCallback.onCallback();
}
@ -656,24 +583,27 @@ public class DownloadItemUtils {
if (str.equals(context.getString(R.string.download))) {
// 先弹下载弹窗(如果需要的话)
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
});
});
});
});
DataLogUtils.uploadGameLog(context, gameEntity.getId(), gameEntity.getName(), entrance);
} else if (str.equals(context.getString(R.string.attempt))) {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
});
});
});
});
@ -700,7 +630,7 @@ public class DownloadItemUtils {
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(context, gameEntity.getSimulator().getApk().getPackageName());
if (downloadEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity) && !isInstalled) {
SimulatorDownloadManager.getInstance().showDownloadDialog(context, gameEntity.getSimulator(),
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(),null);
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(), null);
return;
}
}

View File

@ -1,14 +1,13 @@
package com.gh.common.util
import android.content.pm.PackageManager
import android.os.Build
import android.preference.PreferenceManager
import com.gh.base.BaseActivity
import com.gh.common.constant.Constants
import com.gh.common.exposure.ExposureUtils
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.simulator.SimulatorDownloadManager
import com.gh.common.simulator.SimulatorGameManager
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.xapk.XapkInstaller
import com.gh.download.DownloadDataHelper
import com.gh.download.DownloadManager
@ -77,9 +76,10 @@ object DownloadObserver {
// MtaHelper.onEventWithBasicDeviceInfo("下载失败弹窗",
// "游戏", downloadEntity.name,
// "平台", downloadEntity.platform)
val currentActivity = AppManager.getInstance().currentActivity() ?: return
DialogUtils.showAlertDialog(AppManager.getInstance().currentActivity(), "下载失败", "下载链接已失效,建议提交反馈", "立即反馈", "取消", {
SuggestionActivity.startSuggestionActivity(AppManager.getInstance().currentActivity(),
DialogUtils.showAlertDialog(currentActivity, "下载失败", "下载链接已失效,建议提交反馈", "立即反馈", "取消", {
SuggestionActivity.startSuggestionActivity(currentActivity,
SuggestType.gameQuestion, "notfound",
StringUtils.buildString(downloadEntity.name, ",问题反馈:下载链接失效"),
SimpleGameEntity(gameId, downloadEntity.name, ""))
@ -115,7 +115,9 @@ object DownloadObserver {
// 会有 ActivityNotFoundException 异常catch 掉不管了
tryWithDefaultCatch {
if (Constants.SILENT_UPDATE != downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)) {
PackageInstaller.install(mApplication, downloadEntity)
// TODO 在 Android 11 上没有授权安装未知应用的权限前第一次调用这个方法系统会杀掉我们的进程...
// 没能找到类似的解释,最接近的是这个 https://issuetracker.google.com/issues/154157387但也只是点授权杀进程而已
PackageInstaller.install(mApplication, downloadEntity);
DataLogUtils.uploadUpgradeLog(mApplication, "install") //上传更新安装数据
}
}
@ -140,7 +142,9 @@ object DownloadObserver {
if (gameEntity?.simulator != null) {
val isInstalled = PackageUtils.isInstalledFromAllPackage(HaloApp.getInstance().application, gameEntity.simulator!!.apk!!.packageName)
if (!isInstalled) {
SimulatorDownloadManager.getInstance().showDownloadDialog(AppManager.getInstance().currentActivity(), gameEntity.simulator,
val currentActivity = AppManager.getInstance().currentActivity() ?: return
SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, gameEntity.simulator,
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.id, gameEntity.name
?: "", null)
}
@ -175,15 +179,15 @@ object DownloadObserver {
}
// 下载过程分析统计
val pm = mApplication.packageManager
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, PackageManager.GET_ACTIVITIES)
if (packageInfo == null) {
// val pm = mApplication.packageManager
// val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0)
// if (packageInfo == null) {
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析",
// "游戏名字", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
//
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误_新",
// "游戏", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
}
// }
}
if (downloadEntity.status == DownloadStatus.done) {

View File

@ -215,6 +215,12 @@ public class EntranceUtils {
public static final String KEY_BBS_ID = "bbs_id";
public static final String KEY_DIAGNOSIS = "diagnosis";
public static final String KEY_SIMULATOR = "simulator";
public static final String KEY_MARKET_DETAILS = "market_details";
public static final String KEY_CATALOG_ID = "catalogId";
public static final String KEY_PRIMARY_CATALOG_ID = "primaryCatalogId";
public static final String KEY_PRIMARY_CATALOG_NAME = "primaryCatalogName";
public static final String KEY_CATALOG_TITLE = "catalog_title";
public static final String KEY_CATALOG_INIT_TITLE = "catalog_init_title";
public static void jumpActivity(Context context, Bundle bundle) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);

View File

@ -1,6 +1,7 @@
package com.gh.common.util
import android.animation.Animator
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.graphics.drawable.GradientDrawable
@ -43,8 +44,11 @@ import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import io.reactivex.Observable
import io.reactivex.ObservableTransformer
import io.reactivex.SingleTransformer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import java.net.URI
@ -124,6 +128,20 @@ fun ViewPager.addOnScrollStateChanged(onStateChanged: ((state: Int) -> Unit)? =
addOnPageChangeListener(listener)
}
/**
* Fragment related
*/
inline fun <reified T : Fragment> Fragment.fragmentFromActivity() =
parentFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
?: parentFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T
inline fun <reified T : Fragment> Fragment.fragmentFromParentFragment() =
childFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
?: childFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T
/**
* RecyclerView Extensions
*/
@ -255,23 +273,23 @@ fun String.containHtmlTag(): Boolean {
* 用户行为相关
*/
fun Fragment.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
// if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
// DialogUtils.showRegulationTestDialog(requireContext(),
// { DirectUtils.directToRegulationTestPage(requireContext()) },
// { action.invoke() })
// } else {
if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
DialogUtils.showRegulationTestDialog(requireContext(),
{ DirectUtils.directToRegulationTestPage(requireContext()) },
{ action.invoke() })
} else {
action()
// }
}
}
fun Context.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
// if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
// DialogUtils.showRegulationTestDialog(this,
// { DirectUtils.directToRegulationTestPage(this) },
// { action.invoke() })
// } else {
if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
DialogUtils.showRegulationTestDialog(this,
{ DirectUtils.directToRegulationTestPage(this) },
{ action.invoke() })
} else {
action()
// }
}
}
/**
@ -329,6 +347,15 @@ fun throwExceptionInDebug(message: String = "", predicate: Boolean = true) {
}
}
/**
* 在自动打包的包里弹 toast
*/
fun toastInInternalRelease(content: String) {
if (BuildConfig.BUILD_TIME != 0L) {
Utils.toast(HaloApp.getInstance(), content)
}
}
/**
* 主动抛出异常
*/
@ -388,11 +415,25 @@ fun String.getFirstElementDividedByDivider(divider: String): String {
return this
}
fun String.copyText() {
this.copyTextAndToast("")
}
fun String.copyTextAndToast(toastText: String = "复制成功") {
val application = HaloApp.getInstance().application
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
cmb.text = this
ToastUtils.showToast(toastText)
try {
val application = HaloApp.getInstance().application
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(null, this)
cmb.primaryClip = clip
if (!TextUtils.isEmpty(toastText)) {
ToastUtils.showToast(toastText)
}
} catch (e: SecurityException) {
// 在一些情况下会报以下这样的错误,可能是以浮动窗口显示然后没有焦点?(https://developer.android.com/about/versions/10/privacy/changes#clipboard-data)
// java.lang.Throwable: java.lang.SecurityException: com.xunmeng.pinduoduo from uid 10317 not allowed to perform READ_CLIPBOARD
ToastUtils.showToast("复制失败,请重试")
}
}
fun Map<String, String>.createRequestBody(): RequestBody {
@ -436,6 +477,7 @@ fun Float.sp2px(): Int {
return (this * scale + 0.5f).toInt()
}
/**
* PopupWindow 自动适配方向
* 弹出与锚点右对齐
@ -559,6 +601,19 @@ fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before
})
}
/**
* ArrayList related
*/
fun <T> ArrayList<T>.safelyGetInRelease(index: Int): T? {
return if (index >= size) {
throwExceptionInDebug("这里触发了数组越界,请检查")
toastInInternalRelease("这个操作可能触发闪退,请确定复现方式并联系开发处理")
null
} else {
this[index]
}
}
/**
* 拦截 TextView 中的 Url Span用应用内页面的形式打开链接
* @param shrankText 未展开时的文字
@ -849,4 +904,18 @@ fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)?
onStopTrackingTouch?.invoke()
}
})
}
fun <T> observableToMain(): ObservableTransformer<T, T> {
return ObservableTransformer { upstream ->
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
}
fun <T> singleToMain(): SingleTransformer<T, T> {
return SingleTransformer { upstream ->
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
}

View File

@ -78,6 +78,9 @@ public class GameUtils {
int pluginCount = 0; // 可插件化数量
int updateCount = 0; // 可更新数量
int installCount = 0; // 已安装数量
boolean isRelatedEmulatorInstalled = false; // 若该游戏是模拟器游戏时其对应的模拟器是否已经安装
DownloadEntity downloadEntity;
Object gh_id;
apkFor:
@ -123,20 +126,26 @@ public class GameUtils {
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(context, gameEntity.getSimulator().getApk().getPackageName());
if (isInstalled) {
installCount++;
isRelatedEmulatorInstalled = true;
} else {
doneCount++;
}
}
}
}
if (installCount != 0) {
if (isRelatedEmulatorInstalled && doneCount != 0) {
return context.getString(R.string.launch);
}
if (doneCount != 0) {
return context.getString(R.string.install);
} else if (pluginCount != 0 && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
return context.getString(R.string.pluggable);
} else if (updateCount != 0 && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
return context.getString(R.string.update);
} else if (doneCount != 0) {
return context.getString(R.string.install);
} else if (installCount != 0) {
return context.getString(R.string.launch);
} else if (gameEntity.getVersionNumber().contains("无版号") && Config.isGameDomeSwitchOpen() && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
return context.getString(R.string.attempt);
} else {

View File

@ -1,55 +0,0 @@
package com.gh.common.util
import android.app.Application
/**
* 广点通辅助类 [https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/403]
*
* 更换帐号 [https://gitlab.ghzs.com/pm/yunying/issues/893]
*/
object GdtHelper {
const val NETWORK_TYPE = "NETWORK_TYPE"
const val PAGE_TYPE = "PAGE_TYPE"
const val CONTENT_TYPE = "CONTENT_TYPE"
const val CONTENT_ID = "CONTENT_ID"
const val KEYWORD = "KEYWORD"
const val GAME_ID = "GAME_ID"
const val SCORE = "SCORE"
const val PLATFORM = "PLATFORM"
fun init(application: Application, channel: String) {
// if (channel == "GH_728") {
// GDTAction.init(application, "1111012969", "9d3d9da5b0948a317c03d08f14d445dc")
// } else if (channel == "GH_729") {
// GDTAction.init(application, "1111013063", "f53dabf458a356b101d99fc4069eb7f1")
// } else {
// GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a")
// }
}
fun logAction(type: String) {
// GDTAction.logAction(type)
// Utils.log("GDT", type)
}
fun logAction(type: String, vararg kv: String?) {
// try {
// val actionParam = JSONObject()
// for (i in kv.indices) {
// if (i % 2 != 0) {
// val key = kv[i - 1]
// val value = kv[i]
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
// actionParam.put(key, value)
// }
// }
// }
// Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]")
// GDTAction.logAction(type, actionParam)
// } catch (e: Exception) {
// e.printStackTrace()
// }
}
}

View File

@ -15,7 +15,7 @@ object HomePluggableHelper {
if (apkList.isNotEmpty()) {
val apk = apkList.first()
val tag = if (isNever) "never" else apk.version ?: ""
mHomePluggableFilterDao.addData(HomePluggableFilterEntity(pkgName = apk.packageName, tag = tag, active = isNever))
tryCatchInRelease { mHomePluggableFilterDao.addData(HomePluggableFilterEntity(pkgName = apk.packageName, tag = tag, active = isNever)) }
}
}
@ -44,7 +44,7 @@ object HomePluggableHelper {
for (entity in filterList) {
entity.active = true
}
mHomePluggableFilterDao.addData(filterList)
tryCatchInRelease { mHomePluggableFilterDao.addData(filterList) }
}
}
}

View File

@ -67,4 +67,15 @@ public class HtmlUtils {
return htmlStr.trim(); //返回文本字符串
}
/**
* 过滤掉标签,保留标签内容
*/
public static String filterHtmlLabel(String htmlStr) {
String regEx_html = "<[^>]+>([\\s\\S]*?)<\\/[^>]+>"; //定义HTML标签的正则表达式
Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
Matcher m_html = p_html.matcher(htmlStr);
htmlStr = m_html.replaceAll("$1"); //过滤html标签
return htmlStr.trim(); //返回文本字符串
}
}

View File

@ -279,68 +279,74 @@ object ImageUtils {
})
}
@JvmStatic
fun display(view: SimpleDraweeView?, url: String?) {
display(view, url, true)
}
/**
* 规则 width>0 Wifi/4G:x2 traffic:x1
* 第一种方案:通过LayoutParams获取 可以快速(无延迟)获取宽高,但是无法获取wrap_content和match_parent的View
* 第二种方案(备用方案):有延迟,View的宽高需要在Measure过程后才能确定,能够在这里获取到正确的宽高
* @param isAutoPlayGif 是否禁止播放动图
*/
@JvmStatic
fun display(view: SimpleDraweeView?, url: String?) {
url?.let {
val width = view?.layoutParams?.width
val height = view?.layoutParams?.height
fun display(view: SimpleDraweeView?, url: String?, isAutoPlayGif: Boolean = true) {
if (url == null) return
var lowResUrl = ""
var highResUrl = ""
val width = view?.layoutParams?.width
val height = view?.layoutParams?.height
// 找同一图片地址已加载过的图片作为低质量预览图
// TODO 根据实际请求大小(w_width)来避免小图用大图作为低质量图片
for (cachedImageUrl in mImageUrlCacheSet) {
if (cachedImageUrl.contains(url)) {
lowResUrl = cachedImageUrl
break
}
var lowResUrl = ""
var highResUrl = ""
// 找同一图片地址已加载过的图片作为低质量预览图
// TODO 根据实际请求大小(w_width)来避免小图用大图作为低质量图片
for (cachedImageUrl in mImageUrlCacheSet) {
if (url.isNotEmpty() && cachedImageUrl.contains(url)) {
lowResUrl = cachedImageUrl
break
}
}
val loadImageClosure: (autoPlay: Boolean, highResUrl: String, lowResUrl: String) -> Unit = { autoPlay, hUrl, lUrl ->
view?.controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(ImageRequest.fromUri(hUrl))
.apply {
if (lUrl.isNotEmpty()
&& lUrl != hUrl
&& hUrl != view?.getTag(R.string.highResImageTag)) {
lowResImageRequest = ImageRequest.fromUri(lUrl)
}
autoPlayAnimations = autoPlay
val loadImageClosure: (autoPlay: Boolean, highResUrl: String, lowResUrl: String) -> Unit = { autoPlay, hUrl, lUrl ->
view?.controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(ImageRequest.fromUri(hUrl))
.apply {
if (lUrl.isNotEmpty()
&& lUrl != hUrl
&& hUrl != view?.getTag(R.string.highResImageTag)) {
lowResImageRequest = ImageRequest.fromUri(lUrl)
}
.build()
autoPlayAnimations = autoPlay
}
.build()
view?.setTag(R.string.highResImageTag, highResUrl)
view?.setTag(R.string.highResImageTag, highResUrl)
}
val shouldLoadAsGif = url.endsWith(".gif") && isAutoPlayGif && view?.getTag(R.id.tag_show_gif) != false
if (shouldLoadAsGif && view?.tag == url) return
if (width != null && width > 0) {
highResUrl = if (shouldLoadAsGif) {
resizeGif(url, width, height ?: 0)
} else {
getTransformLimitUrl(url, width, view.context) ?: ""
}
val shouldLoadAsGif = it.endsWith(".gif") && view?.getTag(R.id.tag_show_gif) != false
if (shouldLoadAsGif && view?.tag == url) return
if (width != null && width > 0) {
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
} else {
view?.post {
highResUrl = if (shouldLoadAsGif) {
resizeGif(url, width, height ?: 0)
resizeGif(url, view.width, height ?: 0)
} else {
getTransformLimitUrl(url, width, view.context) ?: ""
getTransformLimitUrl(url, view.width, view.context) ?: ""
}
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
} else {
view?.post {
highResUrl = if (shouldLoadAsGif) {
resizeGif(url, view.width, height ?: 0)
} else {
getTransformLimitUrl(url, view.width, view.context) ?: ""
}
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
}
}
view?.tag = url
}
view?.tag = url
}
// Wifi/4G:x2 traffic:x1

View File

@ -48,7 +48,7 @@ public class InstallUtils {
public void handleMessage(Message msg) {
if (msg.what == INSTALL_WHAT && packageManager != null) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);
List<PackageInfo> packageInfos = PackageUtils.getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
list.add(packageInfo.packageName);

View File

@ -1,7 +1,6 @@
package com.gh.common.util;
import android.app.Dialog;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.graphics.Color;
@ -11,6 +10,8 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.LibaoDetailAdapter;
@ -36,7 +37,6 @@ import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import androidx.core.content.ContextCompat;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@ -237,85 +237,160 @@ public class LibaoUtils {
// 领取限制
CheckLoginUtils.checkLogin(context, "礼包详情-[" + btnStatus + "]", () -> {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> {
if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) {
if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) {
String platform;
if (TextUtils.isEmpty(libaoEntity.getPlatform())) {
platform = "";
} else {
platform = PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform());
}
if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) {
if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) {
String platform;
if (TextUtils.isEmpty(libaoEntity.getPlatform())) {
platform = "";
} else {
platform = PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform());
}
boolean isExistPlatform = false;
ArrayList<ApkEntity> apk = adapter.getGameEntity().getApk();
for (ApkEntity apkEntity : apk) {
if (TextUtils.isEmpty(libaoEntity.getPlatform())) break;
if (libaoEntity.getPlatform().equals(apkEntity.getPlatform())) {
isExistPlatform = true;
break;
}
boolean isExistPlatform = false;
ArrayList<ApkEntity> apk = adapter.getGameEntity().getApk();
for (ApkEntity apkEntity : apk) {
if (TextUtils.isEmpty(libaoEntity.getPlatform())) break;
if (libaoEntity.getPlatform().equals(apkEntity.getPlatform())) {
isExistPlatform = true;
break;
}
}
String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform);
boolean finalIsExistPlatform = isExistPlatform;
DialogUtils.showWarningDialog(context, "条件不符",
Html.fromHtml(dialogContent), isExistPlatform ? "关闭" : null,
isExistPlatform ? "立即安装" : "关闭",
() -> {
if (finalIsExistPlatform) {
adapter.openDownload(libaoEntity.getPlatform());
}
}, null);
String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform);
boolean finalIsExistPlatform = isExistPlatform;
DialogUtils.showWarningDialog(context, "条件不符",
Html.fromHtml(dialogContent), isExistPlatform ? "关闭" : null,
isExistPlatform ? "立即安装" : "关闭",
() -> {
if (finalIsExistPlatform) {
adapter.openDownload(libaoEntity.getPlatform());
}
}, null);
return;
}
}
switch (btnStatus) {
case "未开始":
Utils.toast(context, "还没到开始领取时间");
break;
case "查看":
if (!TextUtils.isEmpty(libaoEntity.getDes())) {
DialogUtils.showAlertDialog(v.getContext(), "使用说明",
Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null);
}
break;
case "再领一个":
case "领取":
if ("repeatLing".equals(status)) {
DialogUtils.showWarningDialog(context, "礼包刷新提醒"
, "礼包每天0点刷新换新区或者换新角色需要继续领取礼包的童鞋请于明天0点之后回来即可[再领一个]"
, null, "知道了", null, null);
} else {
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
}
break;
case "再淘一个":
case "淘号":
if ("repeatTao".equals(status)) {
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
return;
}
}
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
@Override
public void postSucceed(Object response) {
switch (btnStatus) {
case "未开始":
Utils.toast(context, "还没到开始领取时间");
break;
case "查看":
if (!TextUtils.isEmpty(libaoEntity.getDes())) {
DialogUtils.showAlertDialog(v.getContext(), "使用说明",
Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null);
}
break;
case "再领一个":
case "领取":
if ("repeatLing".equals(status)) {
DialogUtils.showWarningDialog(context, "礼包刷新提醒"
, "礼包每天0点刷新换新区或者换新角色需要继续领取礼包的童鞋请于明天0点之后回来即可[再领一个]"
, null, "知道了", null, null);
} else {
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
}
break;
case "再淘一个":
case "淘号":
if ("repeatTao".equals(status)) {
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
return;
}
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
@Override
public void postSucceed(Object response) {
if (loadingDialog != null) loadingDialog.dismiss();
if (loadingDialog != null) loadingDialog.dismiss();
JSONObject responseBody = (JSONObject) response;
String libaoCode = null;
try {
libaoCode = responseBody.getString("code");
} catch (JSONException e) {
e.printStackTrace();
}
JSONObject responseBody = (JSONObject) response;
String libaoCode = null;
if (TextUtils.isEmpty(libaoCode)) {
try {
libaoCode = responseBody.getString("code");
String detail = responseBody.getString("detail");
switch (detail) {
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "淘号异常");
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
return;
}
if (TextUtils.isEmpty(libaoCode)) {
Utils.toast(context, "淘号成功");
libaoEntity.setStatus("taoed");
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(context, "淘号成功"
, Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode))
, "关闭", " 复制礼包码"
, () -> {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(() -> {
Spanned msg = Html.fromHtml(
context.getString(R.string.taoed_copy_dialog
, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}, 300);
}
}, null);
}
@Override
public void postFailed(Throwable error) {
Utils.log("---" + error.toString());
if (loadingDialog != null) loadingDialog.dismiss();
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
if (exception.code() == 403) {
try {
String detail = responseBody.getString("detail");
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
String detail = errorJson.getString("detail");
// Utils.toast(context, "返回::" + detail);
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
break;
case "finish":
Utils.toast(context, "礼包领取时间已结束");
break;
case "fetched":
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
libaoBtn.setText("已淘号");
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
libaoEntity.setStatus("taoed");
break;
case "try tao":
case "used up":
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
@ -323,101 +398,24 @@ public class LibaoUtils {
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "淘号异常");
Utils.toast(context, "操作失败");
break;
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(context, "礼包处理异常" + ex.toString());
}
return;
} else if (exception.code() == 401) {
return;
}
Utils.toast(context, "淘号成功");
libaoEntity.setStatus("taoed");
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(context, "淘号成功"
, Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode))
, "关闭", " 复制礼包码"
, () -> {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(() -> {
Spanned msg = Html.fromHtml(
context.getString(R.string.taoed_copy_dialog
, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}, 300);
}
}, null);
}
@Override
public void postFailed(Throwable error) {
Utils.log("---" + error.toString());
if (loadingDialog != null) loadingDialog.dismiss();
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
if (exception.code() == 403) {
try {
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
String detail = errorJson.getString("detail");
// Utils.toast(context, "返回::" + detail);
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
break;
case "finish":
Utils.toast(context, "礼包领取时间已结束");
break;
case "fetched":
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
libaoBtn.setText("已淘号");
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
libaoEntity.setStatus("taoed");
break;
case "try tao":
case "used up":
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "操作失败");
break;
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(context, "礼包处理异常" + ex.toString());
}
return;
} else if (exception.code() == 401) {
return;
}
}
Utils.toast(context, "发生异常");
}
});
break;
}
});
Utils.toast(context, "发生异常");
}
});
break;
}
});
});
}
@ -458,7 +456,7 @@ public class LibaoUtils {
adapter.notifyDataSetChanged();
final String finalLibaoCode = libaoCode;
NotificationHelper.showNotificationHintDialog(NotificationUgc.GIFT, isShow -> {
if (!isShow){
if (!isShow) {
DialogUtils.showWarningDialog(context, "领取成功", Html.fromHtml(context.getString(R.string.linged_dialog, finalLibaoCode))
, "关闭", " 复制礼包码"
, () -> {
@ -547,8 +545,7 @@ public class LibaoUtils {
}
public static boolean isAppInstalled(Context context, String packageName) {
final android.content.pm.PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
List<PackageInfo> pinfo = PackageUtils.getInstalledPackages(context, 0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
@ -576,10 +573,7 @@ public class LibaoUtils {
//复制文字
public static void copyLink(String copyContent, Context context) {
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(copyContent);
Utils.toast(context, copyContent + " 复制成功");
ExtensionsKt.copyTextAndToast(copyContent, copyContent + " 复制成功");
}

View File

@ -33,6 +33,7 @@ import java.util.ArrayList;
import java.util.List;
import androidx.annotation.Nullable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
@ -637,4 +638,49 @@ public class LogUtils {
}
LoghubUtils.log(object, "event", false);
}
public static void logNewCatalogAppearanceEvent(String entrance, String key) {
logCatalogEvent("access_to_classification", entrance, key, -1, -1, -1, -1);
}
public static void logSubCatalogClickEvent(String entrance, String key, int seq1) {
logCatalogEvent("click_first_classification", entrance, key, seq1, -1, -1, -1);
}
public static void logSubCatalogContentClickEvent(String entrance, String key, int seq1, int seq2) {
logCatalogEvent("click_secondary_classification", entrance, key, seq1, seq2, -1, -1);
}
public static void logSpecialCatalogContentClickEvent(String entrance, String key, int seq1, int seqContent) {
logCatalogEvent("click_content", entrance, key, seq1, -1, seqContent, -1);
}
public static void logSpecialCatalogSpecificContentClickEvent(String entrance, String key, int seq1, int seqContent, int seqContentList) {
logCatalogEvent("click_content_list", entrance, key, seq1, -1, seqContent, seqContentList);
}
private static void logCatalogEvent(String event, String entrance, String key, int seq1, int seq2, int seqContent, int seqContentList) {
JSONObject object = new JSONObject();
JSONObject payload = new JSONObject();
try {
object.put("event", event);
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
payload.put("entrance", entrance); //入口分类, 分为 首页或版块,
payload.put("key", key); //搜索类型, 有四种取值 默认搜索/历史搜索/自动搜索/主动搜索
payload.put("seq_1st", seq1); //从0开始,默认-1表示没有
payload.put("seq_2nd", seq2); //从0开始,默认-1表示没有
payload.put("seq_content", seqContent); //精选页上 图片、专题-全部按钮、专题合集-全部按钮 的排序;从0开始,默认-1表示没有
payload.put("seq_content_list", seqContentList);
object.put("payload", payload);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
}

View File

@ -9,7 +9,7 @@ object MtaHelper {
// if (kv.size == 1) {
// prop.setProperty(kv[0], kv[0])
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
// Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]")
// return
// }
//
@ -23,7 +23,7 @@ object MtaHelper {
// }
// }
//
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
// Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]")
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
}
@ -45,7 +45,7 @@ object MtaHelper {
// }
//
// if (prop.size == 0) return
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}] + last $time seconds")
// Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}] + last $time seconds")
// StatService.trackCustomKVTimeIntervalEvent(HaloApp.getInstance().application, time, eventId, prop)
}
@ -75,7 +75,7 @@ object MtaHelper {
// prop.setProperty("GID", HaloApp.getInstance().gid)
// }
//
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
// Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]")
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
}

View File

@ -154,8 +154,8 @@ object NotificationHelper {
callBack?.invoke(false)
} else {
callBack?.invoke(true)
// if (activity.supportFragmentManager.isStateSaved) return
// NotificationHintDialogFragment.getInstance(ugc).show(activity.supportFragmentManager, "notification")
if (activity.supportFragmentManager.isStateSaved) return
NotificationHintDialogFragment.getInstance(ugc).show(activity.supportFragmentManager, "notification")
}
}

View File

@ -63,7 +63,7 @@ object PackageHelper {
private fun getAllPackageName(context: Context): HashSet<String> {
val set = HashSet<String>()
return try {
val packageInfos = context.applicationContext.packageManager.getInstalledPackages(0)
val packageInfos = PackageUtils.getInstalledPackages(context, 0)
for (packageInfo in packageInfos) {
if (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0) {
if (context.packageName != packageInfo.packageName) {

View File

@ -1,5 +1,6 @@
package com.gh.common.util
import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.Intent
@ -38,13 +39,17 @@ object PackageInstaller {
*/
@JvmStatic
fun install(context: Context, downloadEntity: DownloadEntity, showUnzipToast: Boolean) {
InstallPermissionDialogFragment.show(AppManager.getInstance().currentActivity() as AppCompatActivity) {
val pkgPath = downloadEntity.path
val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()
val currentActivity = AppManager.getInstance().currentActivity() ?: return
InstallPermissionDialogFragment.show(currentActivity as AppCompatActivity, downloadEntity) {
// 取消状态栏下载完成的通知,若存在
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
val pkgPath = downloadEntity.path
if (XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()) {
if (isXapk) {
XapkInstaller.install(context, downloadEntity, showUnzipToast)
} else {
install(context, downloadEntity.path)
@ -113,6 +118,9 @@ object PackageInstaller {
val uninstallIntent = Intent()
uninstallIntent.action = Intent.ACTION_DELETE
uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT)
if (context !is Activity) {
uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
val packageName = PackageUtils.getPackageNameByPath(context, path)
uninstallIntent.data = Uri.parse("package:$packageName")
InstallUtils.getInstance(context).addUninstall(packageName)

View File

@ -30,8 +30,11 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@ -180,11 +183,13 @@ public class PackageUtils {
return null;
}
// TODO 找一个更好的办法来比较签名并且不触发 ANR
public static boolean compareSignatureBetweenInstalledAppWithApk(Context context, String packageName, String apkFilePath) {
try {
// 据 Sentry 统计,刚上架一个周末的包里对这个方法有 700+ 次调用,然后其中一部分会造成 ANR
Signature sig = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures[0];
// Fuck HUAWEI, 华为系统调用 getPackageArchiveInfo 获取魔羯 apk 的签名时会耗时超过5秒造成 ANR没有找到解决方法
// 调用 getPackageArchiveInfo 获取较大的 apk 的签名时会耗时超过5秒造成 ANR没有找到解决方法
// 如果可以的话尽量避免调用 getPackageArchiveInfo 方法
Signature releaseSig = context.getPackageManager().getPackageArchiveInfo(apkFilePath, PackageManager.GET_SIGNATURES).signatures[0];
return sig.hashCode() == releaseSig.hashCode();
@ -286,7 +291,7 @@ public class PackageUtils {
*/
public static String getPackageNameByPath(Context context, String path) {
PackageManager packageManager = context.getApplicationContext().getPackageManager();
PackageInfo info = packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
PackageInfo info = packageManager.getPackageArchiveInfo(path, 0);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
return appInfo.packageName;
@ -370,7 +375,7 @@ public class PackageUtils {
*/
public static ArrayList<String> getAllPackageName(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = context.getApplicationContext().getPackageManager().getInstalledPackages(0);
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
if (!context.getPackageName().equals(packageInfo.packageName)) {
@ -385,7 +390,7 @@ public class PackageUtils {
JSONArray jsonArray = new JSONArray();
try {
PackageManager pm = context.getPackageManager();
List<PackageInfo> packageInfos = pm.getInstalledPackages(0);
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
JSONObject jsonObject = new JSONObject();
@ -557,4 +562,42 @@ public class PackageUtils {
}
/**
* 在5.1系统手机使用PackageManager获取已安装应用容易发生Package manager has died异常
* https://stackoverflow.com/questions/13235793/transactiontoolargeeception-when-trying-to-get-a-list-of-applications-installed/30062632#30062632
*/
public static List<PackageInfo> getInstalledPackages(Context context, int flags) {
final PackageManager pm = context.getPackageManager();
try {
return pm.getInstalledPackages(flags);
} catch (Exception ignored) {
//we don't care why it didn't succeed. We'll do it using an alternative way instead
}
// use fallback:
Process process;
List<PackageInfo> result = new ArrayList<>();
BufferedReader bufferedReader = null;
try {
process = Runtime.getRuntime().exec("pm list packages");
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
final String packageName = line.substring(line.indexOf(':') + 1);
final PackageInfo packageInfo = pm.getPackageInfo(packageName, flags);
result.add(packageInfo);
}
process.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bufferedReader != null)
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}

View File

@ -13,7 +13,7 @@ import com.tbruyelle.rxpermissions2.RxPermissions
object PermissionHelper {
const val INSTALL_PERMISS_CODE = 100
const val INSTALL_PERMISSION_CODE = 100
@JvmStatic
fun requestReadPhoneStateAndStoragePermissionFromStartUp(context: Context) {
@ -232,7 +232,7 @@ object PermissionHelper {
} else {
val packageURI = Uri.fromParts("package", activity.packageName, null)
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI)
activity.startActivityForResult(intent, INSTALL_PERMISS_CODE)
activity.startActivityForResult(intent, INSTALL_PERMISSION_CODE)
}
}

View File

@ -0,0 +1,47 @@
package com.gh.common.util
import android.text.TextUtils
import com.lightgame.utils.Utils
import io.sentry.core.Sentry
import io.sentry.core.SentryEvent
import io.sentry.core.SentryLevel
import io.sentry.core.protocol.Message
object SentryHelper {
/**
* 注意 tag-key 不支持中文
*/
fun onEvent(eventId: String, vararg kv: String?) {
val sentryEvent = SentryEvent()
val message = Message()
message.message = eventId
sentryEvent.message = message
sentryEvent.level = SentryLevel.LOG
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
sentryEvent.setTag(key, value)
debugOnly {
throwExceptionInDebug("tag-key 不支持中文", isContainChinese(key))
}
}
}
}
Utils.log("Sentry", "$eventId + [${kv.joinToString(" , ")}]")
Sentry.captureEvent(sentryEvent)
}
// 判断一个字符串是否含有中文
private fun isContainChinese(str: String?): Boolean {
if (str == null) return false
for (c in str.toCharArray()) {
if (c.toInt() in 0x4E00..0x9FA5) return true
}
return false
}
}

View File

@ -1,11 +1,9 @@
package com.gh.common.util;
import android.app.Activity;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@ -24,6 +22,9 @@ import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.common.constant.Config;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WeiBoShareActivity;
@ -50,9 +51,6 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import static com.gh.common.util.LoginHelper.WEIBO_SCOPE;
/**
@ -159,8 +157,7 @@ public class ShareUtils {
//检查是否安装手机QQ
public static boolean isQQClientAvailable(Context context) {
final PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
List<PackageInfo> pinfo = PackageUtils.getInstalledPackages(context, 0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
@ -634,13 +631,11 @@ public class ShareUtils {
private void copyLink(String copyContent) {
shareType = "copy_link";
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
ClipboardManager cmb = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(copyContent);
if (mShareEntrance != ShareEntrance.shareGh) {
Utils.toast(mContext, "复制成功");
ExtensionsKt.copyTextAndToast(copyContent, "复制成功");
safelyDismiss();
} else {
Utils.toast(mContext, "复制成功,请到微信/QQ粘贴分享");
ExtensionsKt.copyTextAndToast(copyContent, "复制成功,请到微信/QQ粘贴分享");
}
}

View File

@ -13,7 +13,7 @@ import androidx.core.content.ContextCompat
import com.gh.common.view.CenterImageSpan
import com.halo.assistant.HaloApp
class SpanBuilder(content: String) {
class SpanBuilder(content: CharSequence) {
private var spannableString: SpannableStringBuilder = SpannableStringBuilder(content)
fun color(context: Context, start: Int, end: Int, colorRes: Int): SpanBuilder {
@ -70,12 +70,12 @@ class SpanBuilder(content: String) {
return this
}
fun click(start: Int, end: Int, colorRes: Int, onClick: () -> Unit): SpanBuilder {
fun click(start: Int, end: Int, colorRes: Int, isUnderlineText: Boolean = false, onClick: () -> Unit): SpanBuilder {
val clickSpan = object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(HaloApp.getInstance().application, colorRes)
ds.isUnderlineText = false
ds.isUnderlineText = isUnderlineText
}
override fun onClick(widget: View) {

View File

@ -1,32 +0,0 @@
package com.gh.common.util
import android.content.Context
/**
* 今日头条的激活统计 SDK https://gitlab.ghzs.com/pm/halo-app-issues/issues/567
*
* 更新 SDK https://gitlab.ghzs.com/pm/halo-app-issues/issues/743
*/
object TeaHelper {
@JvmStatic
fun init(context: Context, channel: String) {
// val config = InitConfig("163824", channel)
// config.setUriConfig(UriConfig.DEFAULT)
// config.appName = "guanghuan1"
// config.setEnablePlay(true)
// AppLog.setEnableLog(false)
// AppLog.init(context, config)
//
// AppLog.setOaidObserver {
// HaloApp.getInstance().oaid = it.id
// Utils.log("oaid is $it.id")
// MetaUtil.refreshMeta()
// }
//
// // gameReportHelper ?!
// GameReportHelper.onEventRegister("wechat", true)
// GameReportHelper.onEventPurchase("gift", "flower", "008", 1, "wechat", "¥", true, 1)
}
}

View File

@ -3,7 +3,6 @@ package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.view.*
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
@ -14,7 +13,6 @@ import com.gh.common.util.ImageUtils
import com.gh.common.util.rxTimer
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.SettingsEntity
import com.squareup.picasso.Picasso
import io.reactivex.disposables.Disposable
import kotlin.math.abs

View File

@ -0,0 +1,301 @@
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.core.content.ContextCompat
import com.gh.common.util.toColor
import com.gh.common.util.visibleIf
import com.gh.gamecenter.R
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
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(ContextCompat.getColor(targetTextView.context, R.color.text_757575))
}
}
private fun showSelectTypePopupWindow(containerView: View, typeTv: TextView, typeText: String) {
val drawableUp = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_up)
val drawableDown = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_down)
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
typeTv.setTextColor(R.color.theme_font.toColor())
typeTv.setCompoundDrawables(null, null, drawableUp, null)
val inflater = LayoutInflater.from(typeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT)
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (type in mTypeFilterArray) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = 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())
typeTv.setCompoundDrawables(null, null, drawableDown, null)
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun showSelectCatalogPopupWindow(containerView: View, catalogTv: TextView, catalogText: String) {
val drawableUp = ContextCompat.getDrawable(catalogTv.context, R.drawable.ic_filter_arrow_up)
val drawableDown = ContextCompat.getDrawable(catalogTv.context, R.drawable.ic_filter_arrow_down)
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
catalogTv.setTextColor(R.color.theme_font.toColor())
catalogTv.setCompoundDrawables(null, null, drawableUp, null)
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)
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())
catalogTv.setCompoundDrawables(null, null, drawableDown, null)
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun showSelectSizePopupWindow(containerView: View, sizeTv: TextView, sizeText: String) {
val drawableUp = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_up)
val drawableDown = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_down)
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
sizeTv.setTextColor(R.color.theme_font.toColor())
sizeTv.setCompoundDrawables(null, null, drawableUp, null)
val inflater = LayoutInflater.from(sizeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT)
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
sizeFilterArray = if (sizeFilterArray == null) {
getDefaultSizeFilterArray()
} else {
sizeFilterArray?.apply {
if (firstOrNull()?.text != "全部大小") {
add(0, SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
}
}
}
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (size in sizeFilterArray!!) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = 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())
sizeTv.setCompoundDrawables(null, null, drawableDown, null)
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
return arrayListOf<SubjectSettingEntity.Size>().apply {
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下"))
add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M"))
add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M"))
add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G"))
add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上"))
}
}
interface 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

@ -12,7 +12,7 @@ import android.widget.PopupWindow
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.gh.common.util.DisplayUtils
import com.gh.common.util.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.google.android.flexbox.FlexboxLayout
@ -69,16 +69,13 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
mOnConfigFilterSetupListener = onConfigFilterSetupListener
}
fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
if (highlightIt) {
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.text_blue_background)
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
targetTextView.setTextColor(Color.WHITE)
} else {
val colorDrawable = GradientDrawable()
colorDrawable.setColor(Color.WHITE)
colorDrawable.cornerRadius = DisplayUtils.dip2px(1.5f).toFloat()
targetTextView.background = colorDrawable
targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_3a3a3a))
targetTextView.background = null
targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_757575))
}
}
@ -88,8 +85,8 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
sizeTv.setTextColor(R.color.theme_font.toColor())
sizeTv.setCompoundDrawables(null, null, drawableUp, null)
sizeTv.text = "收起"
val inflater = LayoutInflater.from(sizeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
@ -146,25 +143,24 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
}
popupWindow.setOnDismissListener {
sizeTv.setTextColor(R.color.text_757575.toColor())
sizeTv.setCompoundDrawables(null, null, drawableDown, null)
if (sizeTv.text == "收起") {
sizeTv.text = sizeText
}
}
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 = 20, text = "20M以下"))
add(SubjectSettingEntity.Size(min = 20, max = 50, text = "20-50M"))
add(SubjectSettingEntity.Size(min = 50, max = 100, text = "50-100M"))
add(SubjectSettingEntity.Size(min = 100, max = 500, text = "100-500M"))
add(SubjectSettingEntity.Size(min = 500, max = -1, text = "500M以上"))
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以上"))
}
}

View File

@ -5,6 +5,7 @@ import android.text.TextUtils
import android.util.AttributeSet
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.facebook.drawee.generic.RoundingParams
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.util.DisplayUtils
@ -18,6 +19,7 @@ class GameIconView : ConstraintLayout {
private var mCornerRadius = 10
private var mBorderColor = 0
private var mGameIconOverlayColor = 0
private var mBorderWidth = 1
private var mFadeDuration = -1
@ -36,11 +38,15 @@ class GameIconView : ConstraintLayout {
val ta = context.obtainStyledAttributes(attrs, R.styleable.GameIconView)
mCornerRadius = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconCornerRadius, DisplayUtils.dip2px(10F))
mBorderColor = ta.getColor(R.styleable.GameIconView_gameIconBorderColor, 0)
mGameIconOverlayColor = ta.getColor(R.styleable.GameIconView_gameIconOverlayColor, 0)
mBorderWidth = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconBorderWidth, 1)
mFadeDuration = ta.getInt(R.styleable.GameIconView_gameIconFadeDuration, -1)
ta.recycle()
val roundingParams = RoundingParams.fromCornersRadius(mCornerRadius.toFloat())
if (mGameIconOverlayColor != 0) {
roundingParams.overlayColor = mGameIconOverlayColor
}
if (mBorderColor != 0) {
roundingParams.setBorder(mBorderColor, mBorderWidth.toFloat())

View File

@ -32,7 +32,7 @@ class ReserveDialog : BaseDialogFragment() {
binding.more.setOnClickListener {
val intent = MyGameActivity.getIntentWithConfig(requireContext(), 2)
startActivity(intent)
dismiss()
dismissAllowingStateLoss()
}
binding.recyclerView.layoutManager = if (mReserveList.size > 4) {
GridLayoutManager(context, 4)
@ -54,7 +54,7 @@ class ReserveDialog : BaseDialogFragment() {
holder.binding.game = entity
holder.itemView.setOnClickListener {
GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(预约弹窗)")
dismiss()
dismissAllowingStateLoss()
}
}
}

View File

@ -0,0 +1,70 @@
package com.gh.common.view
import android.text.Selection
import android.text.Spannable
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.text.style.URLSpan
import android.view.MotionEvent
import android.view.ViewGroup
import android.view.ViewParent
import android.widget.TextView
import com.gh.common.DefaultUrlHandler
/**
* 拦截处理以 "ghzhushou://" 起始的 URLSpan
*/
class UrlInterceptedLinkMovementMethod : LinkMovementMethod() {
override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean {
val action = event.action
var isTouchEventConsumed = false
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
var x = event.x.toInt()
var y = event.y.toInt()
x -= widget.totalPaddingLeft
y -= widget.totalPaddingTop
x += widget.scrollX
y += widget.scrollY
val layout = widget.layout
val line = layout.getLineForVertical(y)
val off = layout.getOffsetForHorizontal(line, x.toFloat())
val links = buffer.getSpans(off, off, ClickableSpan::class.java)
if (links.size != 0) {
val link = links[0]
if (action == MotionEvent.ACTION_UP) {
if (link is URLSpan && link.url.contains("ghzhushou")) {
DefaultUrlHandler.interceptUrl(widget.context, link.url, "")
} else {
link.onClick(widget)
}
} else if (action == MotionEvent.ACTION_DOWN) {
// do nothing
}
isTouchEventConsumed = true
} else {
Selection.removeSelection(buffer)
}
}
//解决点击事件冲突问题
if (!isTouchEventConsumed && event.action == MotionEvent.ACTION_UP) {
val parent: ViewParent? = iterateViewParentForClicking(widget.parent) //处理widget的父控件点击事件
if (parent is ViewGroup) {
return parent.performClick()
}
}
return false
}
private fun iterateViewParentForClicking(parent: ViewParent): ViewParent? {
return if (parent is ViewGroup) {
if (parent.hasOnClickListeners()) {
parent
} else {
iterateViewParentForClicking(parent.getParent())
}
} else null
}
}

View File

@ -86,7 +86,7 @@ class WelcomeDialog : BaseDialogFragment() {
mDismissByClickImage = true
dismiss()
dismissAllowingStateLoss()
}
binding.ivOpeningCover.loadingCallback = object : WrapContentDraweeView.LoadingCallback {
@ -102,15 +102,24 @@ class WelcomeDialog : BaseDialogFragment() {
}
binding.ivCloseBackup.setOnClickListener {
dismiss()
dismissAllowingStateLoss()
}
binding.ivClose.setOnClickListener {
dismiss()
dismissAllowingStateLoss()
}
binding.welcome = mWelcomeEntity
return binding.root
}
override fun dismissAllowingStateLoss() {
try {
mDismissByClickImage = false
super.dismissAllowingStateLoss()
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun dismiss() {
try {
mDismissByClickImage = false

View File

@ -414,7 +414,7 @@ public class DWebView extends WebView {
e.printStackTrace();
try {
super.loadUrl("javascript:" + script);
} catch (Exception ignored){
} catch (Exception ignored) {
}
}
@ -1023,4 +1023,19 @@ public class DWebView extends WebView {
mainHandler.post(runnable);
}
@Override
public void setOverScrollMode(int mode) {
try {
super.setOverScrollMode(mode);
} catch (Throwable e) {
String trace = Log.getStackTraceString(e);
if (trace.contains("android.content.pm.PackageManager$NameNotFoundException")
|| trace.contains("java.lang.RuntimeException: Cannot load WebView")
|| trace.contains("android.webkit.WebViewFactory$MissingWebViewPackageException: Failed to load WebView provider: No WebView installed")) {
e.printStackTrace();
} else {
throw e;
}
}
}
}

View File

@ -1,12 +1,9 @@
package com.gh.common.xapk
import android.content.Context
import android.os.Build
import com.gh.common.AppExecutor
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.util.*
import com.gh.download.DownloadManager
import com.gh.gamecenter.BuildConfig
import com.halo.assistant.HaloApp
import com.lightgame.download.DataChanger
import com.lightgame.download.DownloadEntity
@ -124,14 +121,9 @@ object XapkInstaller : IXapkUnzipListener {
DownloadManager.getInstance(mContext).updateDownloadEntity(downloadEntity)
}
MtaHelper.onEvent("解压失败"
, "安卓版本", Build.VERSION.RELEASE
, "IMEI", MetaUtil.getIMEI()
, "光环版本", BuildConfig.VERSION_NAME
, "厂商", Build.MANUFACTURER
, "机型", Build.MODEL
, "游戏", downloadEntity.name
, "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
SentryHelper.onEvent("XAPK_UNZIP_ERROR",
"gameName", downloadEntity.name,
"errorDigest", exception.localizedMessage)
debugOnly {
Utils.log("unzip", "onFailure->$exception")
@ -142,7 +134,14 @@ object XapkInstaller : IXapkUnzipListener {
mXapkUnzipThreadMap.remove(downloadEntity.path)
AppExecutor.uiExecutor.execute {
val pkgPath = checkNotNull(downloadEntity.meta[XAPK_PACKAGE_PATH_TAG])
val pkgPath = downloadEntity.meta[XAPK_PACKAGE_PATH_TAG]
if (pkgPath == null) {
Utils.toast(mContext, "下载出错,请重新下载!")
return@execute
}
PackageInstaller.install(mContext, pkgPath)
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"

View File

@ -4,10 +4,8 @@ import android.content.pm.PackageManager
import com.gh.common.constant.Constants
import com.gh.common.exposure.meta.MetaUtil.getMeta
import com.gh.common.loghub.LoghubUtils
import com.gh.common.util.DeviceUtils
import com.gh.common.util.getMetaExtra
import com.gh.common.util.isSimulatorDownload
import com.gh.common.util.isSimulatorGame
import com.gh.common.util.*
import com.gh.common.xapk.XapkInstaller
import com.gh.gamecenter.BuildConfig
import com.halo.assistant.HaloApp
import com.lightgame.download.DataChanger
@ -58,8 +56,8 @@ object DownloadDataHelper {
return "下载完成"
}
val pm = HaloApp.getInstance().application.applicationContext.packageManager
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, PackageManager.GET_ACTIVITIES)
if (packageInfo == null) {
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0)
if (packageInfo == null && XapkInstaller.PACKAGE_EXTENSION_NAME == downloadEntity.path.getExtension()) {
"解析包错误"
} else {
"下载完成"

View File

@ -150,6 +150,8 @@ public class DownloadManager implements DownloadStatusListener {
// 只有下载模块需要这坨东西,因此移动到这里初始化
ConnectionUtils.initHttpsUrlConnection(context);
updateMetaMap();
// DownloadNotification.showDownloadingNotification(mContext);
lastTimeMap = new ArrayMap<>();
@ -292,8 +294,6 @@ public class DownloadManager implements DownloadStatusListener {
downloadEntity.setUpdate(true);
}
updateMetaMap();
downloadEntity.setPlugin(!TextUtils.isEmpty(apkEntity.getGhVersion()));
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, gameEntity.getId());
@ -340,6 +340,8 @@ public class DownloadManager implements DownloadStatusListener {
* @param downloadEntity
*/
public void add(DownloadEntity downloadEntity) {
updateMetaMap();
if (downloadEntity != null) {
String url = downloadEntity.getUrl();
checkDownloadEntryRecordValidate(url);
@ -397,6 +399,8 @@ public class DownloadManager implements DownloadStatusListener {
* @param downloadEntity
*/
public void subscribe(DownloadEntity downloadEntity) {
updateMetaMap();
if (downloadEntity != null) {
String url = downloadEntity.getUrl();
checkDownloadEntryRecordValidate(url);
@ -539,7 +543,7 @@ public class DownloadManager implements DownloadStatusListener {
}
public List<DownloadEntity> getAllSimulatorDownloadEntity() {
List<DownloadEntity> downloadEntityList = mDownloadDao.getAll();
List<DownloadEntity> downloadEntityList = getAllDownloadEntity();
ArrayList<DownloadEntity> filteredDownloadEntityList = new ArrayList<>();
for (DownloadEntity downloadEntity : downloadEntityList) {
if (ExtensionsKt.isSimulatorGame(downloadEntity) && downloadEntity.getStatus() == DownloadStatus.done) {
@ -556,7 +560,7 @@ public class DownloadManager implements DownloadStatusListener {
if (CommonDebug.IS_DEBUG) {
CommonDebug.logMethodName(this);
}
List<DownloadEntity> all = mDownloadDao.getAll();
List<DownloadEntity> all = getAllDownloadEntity();
return filterSilentDownloadTask(all);
}
@ -992,7 +996,7 @@ public class DownloadManager implements DownloadStatusListener {
map.put(HttpDnsManager.GID, HaloApp.getInstance().getGid());
map.put(HttpDnsManager.OAID, HaloApp.getInstance().getOAID());
map.put(HttpDnsManager.USER_ID, UserManager.getInstance().getUserId());
map.put(HttpDnsManager.IMEI, MetaUtil.INSTANCE.getIMEI());
map.put(HttpDnsManager.IMEI, MetaUtil.getBase64EncodedIMEI());
HttpDnsManager.metaMap = map;
}

View File

@ -0,0 +1,203 @@
package com.gh.download
import android.annotation.SuppressLint
import android.app.NotificationManager
import android.content.Context
import android.preference.PreferenceManager
import android.text.TextUtils
import com.gh.common.constant.Constants
import com.gh.common.loghub.LoghubUtils
import com.gh.common.runOnIoThread
import com.gh.common.util.*
import com.gh.gamecenter.entity.GameDigestEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.packagehelper.PackageViewModel
import com.gh.gamecenter.retrofit.EmptyResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.SettingsFragment
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import org.json.JSONException
import org.json.JSONObject
import java.util.*
object PackageObserver {
private val mPackageViewModel: PackageViewModel
by lazy { PackageViewModel(HaloApp.getInstance().application, PackageRepository) }
@JvmStatic
fun onPackageChanged(busFour: EBPackage) {
val application = HaloApp.getInstance().application
val packageName = busFour.packageName
val versionName = busFour.versionName
var gameId = ""
var mDownloadEntity: DownloadEntity? = null
val sp = PreferenceManager.getDefaultSharedPreferences(application)
for (downloadEntity in DownloadManager.getInstance(application).allDownloadEntity) {
if (packageName == downloadEntity.packageName) {
mDownloadEntity = downloadEntity
gameId = mDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)
if (TextUtils.isEmpty(busFour.versionName)) {
// 没有版本号的事件直接选用第一个找到的 downloadEntity
break
} else {
// 有版本号的事件直接尽量找到版本一致的 downloadEntity
if (versionName == downloadEntity.versionName) {
break
}
}
}
}
if ("安装" == busFour.type) {
mPackageViewModel.addInstalledGame(packageName)
// TODO 这个取消通知栏看起来没什么用,没在其它地方看到它,暂且保留一个版本
// 删除下载完成 弹窗
val nManager = application.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
nManager.cancel(packageName.hashCode())
if (mDownloadEntity != null) {
if (mDownloadEntity.isPluggable) {
val kv6: MutableMap<String, Any> = HashMap()
kv6["安装或卸载"] = "安装完成"
DataUtils.onEvent(application, "插件化", mDownloadEntity.name, kv6)
// DataUtils.onMtaEvent(this,
// "插件化_新",
// "位置", mDownloadEntity.getEntrance(),
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "安装完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
}
// 没有光环 ID 的都记录一下游戏 ID供'我的游戏'区分同包名不同插件用
val gh_id = PackageUtils.getMetaData(application, mDownloadEntity.packageName, "gh_id")
if (gh_id == null) {
ThirdPartyPackageHelper.saveGameId(mDownloadEntity.packageName, mDownloadEntity.gameId)
}
DownloadManager.getInstance(application).cancel(
mDownloadEntity.url, false, true) // 默认不删除安装包 mSp.getBoolean("autodelete", true)
}
if (sp.getBoolean(SettingsFragment.CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注
// 安装后关注游戏
val finalDownloadEntity = mDownloadEntity
RetrofitManager.getInstance(application).sensitiveApi
.getGameDigestByPackageName(UrlFilterUtils.getFilterQuery("package", packageName))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<List<GameDigestEntity?>?>() {
override fun onResponse(response: List<GameDigestEntity?>?) {
for (gameDigestEntity in response!!) {
if (!TextUtils.isEmpty(gameDigestEntity?.id)) { // 关注游戏
if (finalDownloadEntity != null && gameDigestEntity?.id == finalDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)) {
ConcernUtils.postConcernGameId(application, gameDigestEntity?.id ?: "", null, false)
}
}
}
}
})
}
runOnIoThread { postNewlyInstalledApp(gameId, packageName) }
}
if ("卸载" == busFour.type) {
mPackageViewModel.addUninstalledGame(packageName)
if (mDownloadEntity != null && mDownloadEntity.isPluggable) {
val kv6: MutableMap<String, Any> = HashMap()
kv6["安装或卸载"] = "卸载完成"
DataUtils.onEvent(application, "插件化", mDownloadEntity.name, kv6)
// DataUtils.onMtaEvent(this,
// "插件化_新",
// "位置", mDownloadEntity.getEntrance(),
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "卸载完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
PackageInstaller.install(application, mDownloadEntity)
}
// 更新已安装游戏
deleteInstalledPackage(packageName)
}
DataCollectionUtils.uploadInorunstall(application, busFour.type, busFour.packageName)
}
@SuppressLint("CheckResult")
private fun postNewlyInstalledApp(gameId: String, packageName: String) {
// 发送应用变更前都检查一下是否需要把所有应用都上传
PackageRepository.checkAndUploadAppList()
// 更新已安装游戏
val packageObject = PackageUtils.getAppBasicInfoByPackageName(packageName)
val dataObject = JSONObject()
val wrapperObject = JSONObject()
try {
dataObject.put("type", "POST")
dataObject.put("device_id", HaloApp.getInstance().gid)
dataObject.put("app", packageObject)
dataObject.put("time", Utils.getTime(HaloApp.getInstance().application))
wrapperObject.put("content", dataObject.toString())
} catch (e: JSONException) {
e.printStackTrace()
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true)
val requestBody = RequestBody.create(MediaType.parse("application/json"),
packageObject.toString())
// 更新已安装游戏
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.postNewlyInstalledApp(HaloApp.getInstance().gid, requestBody)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(EmptyResponse())
if (!TextUtils.isEmpty(gameId) && UserManager.getInstance().isLoggedIn) {
val jsonObject = JSONObject()
try {
jsonObject.put("game_id", gameId)
jsonObject.put("package", packageName)
val rBody = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.postPlayedGame(UserManager.getInstance().userId, rBody)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(EmptyResponse())
} catch (e: JSONException) {
e.printStackTrace()
}
}
}
@SuppressLint("CheckResult")
private fun deleteInstalledPackage(packageName: String) {
// 发送应用变更前都检查一下是否需要把所有应用都上传
PackageRepository.checkAndUploadAppList()
// 删除已安装游戏
val dataObject = JSONObject()
val wrapperObject = JSONObject()
try {
dataObject.put("type", "DELETE")
dataObject.put("device_id", HaloApp.getInstance().gid)
dataObject.put("package", packageName)
dataObject.put("time", Utils.getTime(HaloApp.getInstance().application))
wrapperObject.put("content", dataObject.toString())
} catch (e: JSONException) {
e.printStackTrace()
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true)
}
}

View File

@ -140,7 +140,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
}
})
mViewModel.dismissLiveData.observe(this, Observer {
dismiss()
dismissAllowingStateLoss()
})
mElapsedHelper = TimeElapsedHelper()
@ -173,7 +173,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
postBrowseMta()
mViewModel.collectionLiveData.postValue(null)
} else {
dismiss()
dismissAllowingStateLoss()
}
}
mGestureDetector = GestureDetector(requireContext(), SingleTapConfirm())
@ -332,7 +332,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
MotionEvent.ACTION_UP,
MotionEvent.ACTION_OUTSIDE -> {
if (mBinding.root.y >= mBinding.root.height / 2) {
dismiss()
dismissAllowingStateLoss()
} else {
resetDialogPosition(300)
}

View File

@ -2,11 +2,13 @@ package com.gh.download.dialog
import android.content.Context
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.gh.base.BaseActivity
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.Config
import com.gh.common.dialog.CertificationDialog
import com.gh.common.dialog.DeviceRemindDialog
import com.gh.common.dialog.PackageCheckDialogFragment
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.*
import com.gh.common.util.DirectUtils.directToLinkPage
@ -24,6 +26,7 @@ import com.lightgame.download.DownloadStatus
import com.lightgame.download.FileUtils
import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
import io.sentry.core.protocol.App
class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
@ -278,19 +281,21 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
if (msg.isNullOrEmpty()) {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
override fun onCallback() {
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
DownloadManager.createDownload(
context,
apkEntity,
gameEntity,
downloadMethod,
entrance,
location,
isSubscribe, traceEvent)
PackageCheckDialogFragment.show(context as AppCompatActivity, gameEntity.packageDialog, DialogUtils.ConfirmListener {
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
DownloadManager.createDownload(
context,
apkEntity,
gameEntity,
downloadMethod,
entrance,
location,
isSubscribe, traceEvent)
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
}
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
}
})
})
}
})

View File

@ -28,7 +28,7 @@ class DownloadLinkDialog : BaseDialogFragment() {
mLinkEntity.content, "text/html", "utf-8", null)
binding.confirm.setOnClickListener {
dismiss()
dismissAllowingStateLoss()
}
return binding.root
}

View File

@ -9,7 +9,6 @@ import androidx.annotation.NonNull;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.fragment.LoginFragment;
import com.halo.assistant.HaloApp;
/**
* Created by khy on 14/08/17.

View File

@ -19,6 +19,7 @@ import android.util.Log;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.lifecycle.ViewModelProviders;
import com.gh.base.AppUncaughtHandler;
@ -71,6 +72,7 @@ import com.gh.gamecenter.eventbus.EBPackage;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.eventbus.EBSkip;
import com.gh.gamecenter.fragment.MainWrapperFragment;
import com.gh.gamecenter.gamedetail.GameDetailFragment;
import com.gh.gamecenter.manager.DataCollectionManager;
import com.gh.gamecenter.manager.UpdateManager;
import com.gh.gamecenter.manager.UserManager;
@ -78,12 +80,14 @@ import com.gh.gamecenter.normal.NormalFragment;
import com.gh.gamecenter.packagehelper.PackageRepository;
import com.gh.gamecenter.packagehelper.PackageViewModel;
import com.gh.gamecenter.qa.CommunityFragment;
import com.gh.gamecenter.retrofit.BiResponse;
import com.gh.gamecenter.retrofit.EmptyResponse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.suggest.SuggestSelectFragment;
import com.gh.gamecenter.suggest.SuggestType;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.halo.assistant.HaloApp;
import com.halo.assistant.fragment.SettingsFragment;
@ -96,6 +100,7 @@ import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;
@ -125,9 +130,11 @@ import static com.gh.common.util.EntranceUtils.HOST_QQ;
import static com.gh.common.util.EntranceUtils.HOST_QQ_GROUP;
import static com.gh.common.util.EntranceUtils.HOST_WEB;
import static com.gh.common.util.EntranceUtils.KEY_DATA;
import static com.gh.common.util.EntranceUtils.KEY_MARKET_DETAILS;
import static com.gh.common.util.EntranceUtils.KEY_NEXT_TO;
import static com.gh.common.util.EntranceUtils.KEY_TO;
import static com.gh.common.util.EntranceUtils.KEY_TYPE;
import static com.gh.common.util.ExtensionsKt.singleToMain;
import static com.gh.gamecenter.fragment.MainWrapperFragment.INDEX_PERSONAL;
import static com.gh.gamecenter.personal.PersonalFragment.LOGIN_TAG;
import static com.gh.gamecenter.personal.PersonalFragment.LOGOUT_TAG;
@ -164,10 +171,6 @@ public class MainActivity extends BaseActivity {
} else if (getIntent() != null) {
mMainWrapperFragment.setArguments(getIntent().getExtras());
}
Bundle arguments = mMainWrapperFragment.getArguments();
if (arguments == null) arguments = new Bundle();
arguments.putInt(BaseFragment_ViewPager.ARGS_INDEX, MainWrapperFragment.INDEX_VIDEO);
mMainWrapperFragment.setArguments(arguments);
replaceFragment(mMainWrapperFragment);
mSp = PreferenceManager.getDefaultSharedPreferences(this);
@ -403,6 +406,9 @@ public class MainActivity extends BaseActivity {
SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity);
}
break;
case KEY_MARKET_DETAILS:
redirectGameDetail(bundle.getString(KEY_DATA));
break;
}
}
}
@ -416,6 +422,28 @@ public class MainActivity extends BaseActivity {
}, 500);
}
/**
* 应用跳转
* @param packageName
*/
@SuppressLint("CheckResult")
private void redirectGameDetail(String packageName) {
RetrofitManager.getInstance(this).getApi().redirectGameDetail(packageName)
.compose(singleToMain())
.subscribe(new BiResponse<JsonObject>() {
@Override
public void onSuccess(JsonObject data) {
String gameId = data.get("game_id").getAsString();
DirectUtils.directToGameDetail(MainActivity.this, gameId, GameDetailFragment.INDEX_DESC, "应用跳转");
}
@Override
public void onFailure(@NotNull Exception exception) {
super.onFailure(exception);
}
});
}
private void checkNotificationPermission() {
// 仅登录后再启动光环时请求一次权限
if (UserManager.getInstance().isLoggedIn()) {
@ -717,184 +745,6 @@ public class MainActivity extends BaseActivity {
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBPackage busFour) {
final String packageName = busFour.getPackageName();
final String versionName = busFour.getVersionName();
String gameId = "";
DownloadEntity mDownloadEntity = null;
for (DownloadEntity downloadEntity : DownloadManager.getInstance(getApplicationContext()).getAllDownloadEntity()) {
if (packageName.equals(downloadEntity.getPackageName())) {
mDownloadEntity = downloadEntity;
gameId = mDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER);
if (TextUtils.isEmpty(busFour.getVersionName())) {
// 没有版本号的事件直接选用第一个找到的 downloadEntity
break;
} else {
// 有版本号的事件直接尽量找到版本一致的 downloadEntity
if (versionName.equals(downloadEntity.getVersionName())) {
break;
}
}
}
}
if ("安装".equals(busFour.getType())) {
mPackageViewModel.addInstalledGame(packageName);
// 删除下载完成 弹窗
NotificationManager nManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nManager.cancel(packageName.hashCode());
if (mDownloadEntity != null) {
if (mDownloadEntity.isPluggable()) {
Map<String, Object> kv6 = new HashMap<>();
kv6.put("安装或卸载", "安装完成");
DataUtils.onEvent(this, "插件化", mDownloadEntity.getName(), kv6);
// DataUtils.onMtaEvent(this,
// "插件化_新",
// "位置", mDownloadEntity.getEntrance(),
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "安装完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
}
// 没有光环 ID 的都记录一下游戏 ID供'我的游戏'区分同包名不同插件用
Object gh_id = PackageUtils.getMetaData(this, mDownloadEntity.getPackageName(), "gh_id");
if (gh_id == null) {
ThirdPartyPackageHelper.saveGameId(mDownloadEntity.getPackageName(), mDownloadEntity.getGameId());
}
DownloadManager.getInstance(getApplicationContext()).cancel(
mDownloadEntity.getUrl(), false, true); // 默认不删除安装包 mSp.getBoolean("autodelete", true)
}
if (mSp.getBoolean(SettingsFragment.CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注
// 安装后关注游戏
DownloadEntity finalDownloadEntity = mDownloadEntity;
RetrofitManager.getInstance(this).getSensitiveApi().getGameDigestByPackageName(UrlFilterUtils.getFilterQuery("package", packageName))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<List<GameDigestEntity>>() {
@Override
public void onResponse(List<GameDigestEntity> response) {
for (GameDigestEntity gameDigestEntity : response) {
if (!TextUtils.isEmpty(gameDigestEntity.getId())) { // 关注游戏
if (finalDownloadEntity != null && gameDigestEntity.getId().equals(finalDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER))) {
ConcernUtils.INSTANCE.postConcernGameId(MainActivity.this, gameDigestEntity.getId(), null, false);
}
}
}
}
});
}
postNewlyInstalledApp(gameId, packageName);
}
if ("卸载".equals(busFour.getType())) {
mPackageViewModel.addUninstalledGame(packageName);
if (mDownloadEntity != null && mDownloadEntity.isPluggable()) {
Map<String, Object> kv6 = new HashMap<>();
kv6.put("安装或卸载", "卸载完成");
DataUtils.onEvent(this, "插件化", mDownloadEntity.getName(), kv6);
// DataUtils.onMtaEvent(this,
// "插件化_新",
// "位置", mDownloadEntity.getEntrance(),
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "卸载完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
PackageInstaller.install(this, mDownloadEntity);
}
// 更新已安装游戏
deleteInstalledPackage(packageName);
}
DataCollectionUtils.uploadInorunstall(this, busFour.getType(), busFour.getPackageName());
}
@SuppressWarnings("ResultOfMethodCallIgnored")
@SuppressLint("CheckResult")
private void postNewlyInstalledApp(String gameId, String packageName) {
// 发送应用变更前都检查一下是否需要把所有应用都上传
PackageRepository.checkAndUploadAppList();
// 更新已安装游戏
JSONObject packageObject = PackageUtils.getAppBasicInfoByPackageName(packageName);
JSONObject dataObject = new JSONObject();
JSONObject wrapperObject = new JSONObject();
try {
dataObject.put("type", "POST");
dataObject.put("device_id", HaloApp.getInstance().getGid());
dataObject.put("app", packageObject);
dataObject.put("time", Utils.getTime(getApplicationContext()));
wrapperObject.put("content", dataObject.toString());
} catch (JSONException e) {
e.printStackTrace();
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true);
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"),
packageObject.toString());
// 更新已安装游戏
RetrofitManager.getInstance(MainActivity.this).getApi()
.postNewlyInstalledApp(HaloApp.getInstance().getGid(), requestBody)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new EmptyResponse<>());
if (!TextUtils.isEmpty(gameId) && UserManager.getInstance().isLoggedIn()) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("game_id", gameId);
jsonObject.put("package", packageName);
RequestBody rBody = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString());
RetrofitManager.getInstance(MainActivity.this).getApi()
.postPlayedGame(UserManager.getInstance().getUserId(), rBody)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new EmptyResponse<>());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
@SuppressLint("CheckResult")
private void deleteInstalledPackage(String packageName) {
// 发送应用变更前都检查一下是否需要把所有应用都上传
PackageRepository.checkAndUploadAppList();
// 删除已安装游戏
JSONObject dataObject = new JSONObject();
JSONObject wrapperObject = new JSONObject();
try {
dataObject.put("type", "DELETE");
dataObject.put("device_id", HaloApp.getInstance().getGid());
dataObject.put("package", packageName);
dataObject.put("time", Utils.getTime(getApplicationContext()));
wrapperObject.put("content", dataObject.toString());
} catch (JSONException e) {
e.printStackTrace();
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true);
// 删除已安装游戏
RetrofitManager.getInstance(MainActivity.this).getApi()
.deleteInstalledApp(HaloApp.getInstance().getGid(), packageName)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new EmptyResponse<>());
}
// 接收登录和登出更新事件统计的 Meta
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBReuse reuse) {

View File

@ -7,6 +7,7 @@ import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import com.gh.base.BaseActivity
@ -21,12 +22,15 @@ import com.lightgame.utils.Util_System_Keyboard
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.subjects.PublishSubject
import kotlinx.android.synthetic.main.toolbar_search.*
import kotterknife.bindView
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.concurrent.TimeUnit
open class SearchActivity : BaseActivity() {
private val searchEt by bindView<EditText>(R.id.searchEt)
private var mDao: SearchHistoryDao? = null
protected var mSearchKey: String? = null
@ -53,6 +57,7 @@ open class SearchActivity : BaseActivity() {
super.onCreate(savedInstanceState)
val hint = intent.getStringExtra(EntranceUtils.KEY_HINT)
val searchImmediately = intent.getBooleanExtra(KEY_SEARCH_IMMEDIATELY, false)
var ignoreTextChanges = savedInstanceState != null
mDao = SearchHistoryDao(this)
mPublishSubject = PublishSubject.create()
@ -62,21 +67,27 @@ open class SearchActivity : BaseActivity() {
.distinctUntilChanged()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
if (searchEt.text.isNotEmpty()) {
if (searchEt.text.isNotEmpty()
&& searchEt.text != searchEt.hint
&& !ignoreTextChanges) {
search(SearchType.AUTO, it)
}
ignoreTextChanges = false
}
initSearchBar()
if (savedInstanceState != null) {
mDisplayType = DisplayType.fromInt(savedInstanceState.getInt(KEY_DISPLAY_TYPE, 0))
mSearchKey = savedInstanceState.getString(EntranceUtils.KEY_SEARCHKEY, null)
mSearchType = SearchType.fromString(savedInstanceState.getString(KEY_SEARCH_TYPE, null))
if (mDisplayType != DisplayType.DEFAULT && !TextUtils.isEmpty(mSearchKey)) {
search(mSearchType, mSearchKey)
}
} else if (!TextUtils.isEmpty(hint)) {
// 子 Fragment 自己恢复状态
// if (savedInstanceState != null) {
// mDisplayType = DisplayType.fromInt(savedInstanceState.getInt(KEY_DISPLAY_TYPE, 0))
// mSearchKey = savedInstanceState.getString(EntranceUtils.KEY_SEARCHKEY, null)
// mSearchType = SearchType.fromString(savedInstanceState.getString(KEY_SEARCH_TYPE, null))
// if (mDisplayType != DisplayType.DEFAULT && !TextUtils.isEmpty(mSearchKey)) {
// search(mSearchType, mSearchKey)
// }
// } else
if (!TextUtils.isEmpty(hint)) {
searchEt.hint = hint
if (searchImmediately) {
mDisplayType = GAME_DETAIL
@ -87,7 +98,8 @@ open class SearchActivity : BaseActivity() {
searchEt.hint = "搜索游戏..."
}
if (mDisplayType == DisplayType.DEFAULT) {
if (savedInstanceState == null
&& mDisplayType == DisplayType.DEFAULT) {
updateDisplayType(DisplayType.DEFAULT)
}
}
@ -233,7 +245,7 @@ open class SearchActivity : BaseActivity() {
}
companion object {
private const val KEY_SEARCH_TYPE = "search_type"
const val KEY_SEARCH_TYPE = "search_type"
private const val KEY_DISPLAY_TYPE = "display_type"
private const val KEY_SEARCH_IMMEDIATELY = "search_immediately"
@ -274,11 +286,13 @@ enum class SearchType(var value: String) {
* [DEFAULT] 默认搜索页
* [GAME_DIGEST] 游戏为部分文字样式的列表
* [GAME_DETAIL] 游戏全为标准样式的列表
* [FORUM_OR_USER] 论坛内容和用户
*/
enum class DisplayType(var value: Int) {
DEFAULT(0),
GAME_DIGEST(1),
GAME_DETAIL(2);
GAME_DETAIL(2),
FORUM_OR_USER(3);
companion object {
fun fromInt(typeInt: Int) = values().find { typeInt == it.value } ?: DEFAULT

View File

@ -1,6 +1,5 @@
package com.gh.gamecenter;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@ -10,15 +9,16 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.gh.base.ToolBarActivity;
import com.gh.common.util.ExtensionsKt;
import com.gh.common.util.MessageShareUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.QRCodeUtils;
import com.gh.common.util.ShareUtils;
import com.lightgame.utils.Utils;
import com.tencent.tauth.Tencent;
import androidx.annotation.NonNull;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
@ -73,9 +73,6 @@ public class ShareGhActivity extends ToolBarActivity {
@OnClick(R.id.gh_address_tv)
public void copyAddress() {
MtaHelper.onEvent("我的光环_新", "分享光环", "复制官网");
ClipboardManager cmb = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(getString(R.string.gh_website_url_100));
Utils.toast(this, "网址复制成功,请到微信/QQ粘贴分享");
ExtensionsKt.copyTextAndToast(getString(R.string.gh_website_url_100), "网址复制成功,请到微信/QQ粘贴分享");
}
}

View File

@ -80,310 +80,325 @@ public class SkipActivity extends BaseActivity {
Uri uri = getIntent().getData();
Bundle bundle;
if (uri != null) {
if (CommonDebug.IS_DEBUG) {
Utils.log("SkipActivity:: Uri=>" + uri.toString());
}
String host = uri.getHost();
String path = uri.getPath();
if ("ghzhushou".equals(uri.getScheme())) {
if (CommonDebug.IS_DEBUG) {
Utils.log("SkipActivity:: Uri=>" + uri.toString());
}
String host = uri.getHost();
String path = uri.getPath();
String to = uri.getQueryParameter("to");
String type = uri.getQueryParameter("type");
String name = uri.getQueryParameter("name");
String referer = uri.getQueryParameter("referer");
String id = uri.getQueryParameter("id");
if (!TextUtils.isEmpty(path)) {
path = path.substring(1);
}
String to = uri.getQueryParameter("to");
String type = uri.getQueryParameter("type");
String name = uri.getQueryParameter("name");
String referer = uri.getQueryParameter("referer");
String id = uri.getQueryParameter("id");
if (!TextUtils.isEmpty(path)) {
path = path.substring(1);
}
if (host != null) {
Intent intent;
switch (host) {
case HOST_ARTICLE:
DirectUtils.directToArticle(this, path, ENTRANCE_BROWSER);
break;
case HOST_GAME:
DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, "true".equals(uri.getQueryParameter("auto_download")), to, null);
break;
case HOST_COLUMN:
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER);
break;
case HOST_SUGGESTION:
String platform = uri.getQueryParameter(KEY_PLATFORM);
String platformName = PlatformUtils.getInstance(this).getPlatformName(platform);
String gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID);
String packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5);
String content = (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) ?
String.format("%s-%s-V%s",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION)) :
String.format("%s-%s-V%s\n游戏ID%s\n游戏包MD5%s\n",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION), gameId, packageMd5);
String qaId = uri.getQueryParameter("qa_id");
String qaTitle = uri.getQueryParameter(EntranceUtils.KEY_QA_TITLE);
if (!TextUtils.isEmpty(qaId)) {
DirectUtils.directToQa(this, qaTitle, qaId);
} else {
DirectUtils.directToFeedback(this, content, ENTRANCE_BROWSER);
}
break;
case HOST_DOWNLOAD:
DirectUtils.directToDownloadManagerAndStartUpdate(this, path, uri.getQueryParameter(KEY_PACKAGENAME), ENTRANCE_BROWSER);
break;
case HOST_ANSWER:
DirectUtils.directToAnswerDetail(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_QUESTION:
DirectUtils.directToQuestionDetail(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_TOOLBOX:
DirectUtils.directToToolbox(this, uri.getQueryParameter("gameId"), uri.getQueryParameter("toolboxUrl"), ENTRANCE_BROWSER);
break;
case HOST_COMMUNITY:
UserManager.getInstance().setCommunityData(new CommunityEntity(path, name));
// 把切换放到 MainActivity 处理
if (RunningUtils.isRunning(this)
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(MainActivity.SWITCH_TO_COMMUNITY, true);
} else {
bundle = new Bundle();
bundle.putBoolean(MainActivity.SWITCH_TO_COMMUNITY, true);
intent = SplashScreenActivity.getSplashScreenIntent(this, bundle);
}
startActivity(intent);
break;
// 社区文章格式一
case "community.article":
DirectUtils.directToCommunityArticle(this, uri.getQueryParameter("articleId"), uri.getQueryParameter("communityId"), ENTRANCE_BROWSER, "浏览器");
break;
// 社区文章格式二
case "communities":
String communityId = "";
String typeId = "";
String[] split = path.split("/");
for (String text : split) {
if (TextUtils.isEmpty(communityId)) {
communityId = text;
continue;
}
if (TextUtils.isEmpty(type)) {
type = text;
continue;
}
if (TextUtils.isEmpty(typeId)) {
typeId = text;
}
}
if ("articles".equals(type)) {
DirectUtils.directToCommunityArticle(this, typeId, communityId, ENTRANCE_BROWSER, "浏览器");
if (host != null) {
Intent intent;
switch (host) {
case HOST_ARTICLE:
DirectUtils.directToArticle(this, path, ENTRANCE_BROWSER);
break;
}
break;
case HOST_VIDEO:
DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.HOTTEST_GAME_VIDEO.getValue(),
false, id, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer);
break;
case HOST_UPLOAD_VIDEO://跳转上传视频
String titleParameter = uri.getQueryParameter("title");
String title = TextUtils.isEmpty(titleParameter) ? "" : "#" + titleParameter + "#";
String categoryId = uri.getQueryParameter("category_id");
String link = uri.getQueryParameter("link");
gameId = uri.getQueryParameter("gameId");
String gameName = uri.getQueryParameter("gameName");
String tagActivityId = uri.getQueryParameter("tagActivityId");
String tagActivityName = uri.getQueryParameter("tagActivityName");
VideoLinkEntity linkEntity = new VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName);
SimpleGameEntity simpleGameEntity = new SimpleGameEntity(gameId != null ? gameId : "", gameName != null ? gameName : "", "");
Bundle nextToBundle = VideoManagerActivity.getVideoManagerBundle(linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "");
CheckLoginUtils.checkLogin(this, nextToBundle, true, EntranceUtils.ENTRANCE_BROWSER, () ->
DirectUtils.directToVideoManager(SkipActivity.this, linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "浏览器"));
break;
case HOST_VIDEO_SINGLE:
DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.getValue(),
false, "", ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer);
break;
case HOST_VIDEO_MORE:
gameId = uri.getQueryParameter("gameId");
String act = uri.getQueryParameter("act");
String fieldId = uri.getQueryParameter("fieldId");
String sectionName = uri.getQueryParameter("sectionName");
String paginationType = uri.getQueryParameter("paginationType");//活动分页方式 page filter
String location;
if (!TextUtils.isEmpty(act)) {
location = VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.getValue();
} else if (!TextUtils.isEmpty(fieldId)) {
location = VideoDetailContainerViewModel.Location.GAME_ZONE.getValue();
} else {
location = path;
}
DirectUtils.directToVideoDetail(this, path, location,
false, TextUtils.isEmpty(gameId) ? "" : gameId, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer,
TextUtils.isEmpty(type) ? "" : type, TextUtils.isEmpty(act) ? "" : act, TextUtils.isEmpty(paginationType) ? "page" : paginationType, TextUtils.isEmpty(fieldId) ? "" : fieldId,
TextUtils.isEmpty(sectionName) ? "" : sectionName);
break;
case HOST_VIDEO_STREAMING_HOME:
// 把切换放到 MainActivity 处理
if (RunningUtils.isRunning(this)
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true);
} else {
bundle = new Bundle();
bundle.putBoolean(MainActivity.SWITCH_TO_VIDEO, true);
intent = SplashScreenActivity.getSplashScreenIntent(this, bundle);
}
startActivity(intent);
break;
case HOST_VIDEO_STREAMING_DESC:
DirectUtils.directToGameDetailVideoStreaming(this, path, ENTRANCE_BROWSER);
break;
case HOST_VIDEO_COLLECTION:
DirectUtils.directToGameVideo(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_QQ:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ);
bundle.putString(KEY_DATA, path);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_QQ_GROUP:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ_GROUP);
bundle.putString(KEY_DATA, path);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_QQ_QUN:
String key = uri.getQueryParameter("key");
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ_GROUP);
bundle.putString(KEY_DATA, key);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_WEB:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_WEB);
bundle.putString(KEY_DATA, to);
bundle.putString(KEY_TYPE, type);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_LIBAO:
DirectUtils.directToGiftDetail(this, path, ENTRANCE_BROWSER);
break;
case HOST_USERHOME:
String position = uri.getQueryParameter("position");
DirectUtils.directToHomeActivity(this, path, TextUtils.isEmpty(position) ? -1 : Integer.parseInt(position), ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_COLUMN:
CommunityEntity community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
String columnId = uri.getQueryParameter("column_id");
DirectUtils.directToCommunityColumn(this, community, columnId, ENTRANCE_BROWSER, "");
break;
case HOST_CATEGORY:
title = uri.getQueryParameter("title");
DirectUtils.directCategoryDirectory(this, path, title, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COLUMN_COLLECTION:
DirectUtils.directToColumnCollection(this, path, -1, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_QUESTION_LABEL_DETAIL:
community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
String tag = uri.getQueryParameter("tag");
DirectUtils.directAskColumnLabelDetail(this, tag, community, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_COLUMN_DETAIL:
community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
columnId = uri.getQueryParameter("column_id");
DirectUtils.directAskColumnDetail(this, columnId, community, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_BLOCK:
name = uri.getQueryParameter("name");
SubjectRecommendEntity entity = new SubjectRecommendEntity();
entity.setLink(path);
entity.setName(name);
entity.setText(name);
DirectUtils.directToBlock(this, entity, mEntrance);
break;
case EntranceUtils.HOST_SERVER_BLOCK:
DirectUtils.directToGameServers(this, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_AMWAY_BLOCK:
DirectUtils.directToAmway(this, null, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_HELP:
name = uri.getQueryParameter("name");
DirectUtils.directToQa(this, name, path);
break;
case EntranceUtils.HOST_HELP_COLLECTION:
name = uri.getQueryParameter("name");
DirectUtils.directToQaCollection(this, name, path);
break;
case EntranceUtils.HOST_GAME_UPLOAD:
DirectUtils.directGameUpload(this, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_GAME_ZONE:
String zoneUrl = uri.getQueryParameter("url");
DirectUtils.directGameZone(this, path, zoneUrl, ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_LINK:
try {
String dataString = uri.getQueryParameter("data");
if (!TextUtils.isEmpty(dataString)) {
byte[] linkData = Base64.decode(dataString, Base64.DEFAULT);
String linkDataString = new String(linkData, "UTF-8");
LinkEntity le = GsonUtils.INSTANCE.getGson().fromJson(linkDataString, LinkEntity.class);
DirectUtils.directToLinkPage(this, le, ENTRANCE_BROWSER, "");
case HOST_GAME:
DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, "true".equals(uri.getQueryParameter("auto_download")), to, null);
break;
case HOST_COLUMN:
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER);
break;
case HOST_SUGGESTION:
String platform = uri.getQueryParameter(KEY_PLATFORM);
String platformName = PlatformUtils.getInstance(this).getPlatformName(platform);
String gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID);
String packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5);
String content = (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) ?
String.format("%s-%s-V%s",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION)) :
String.format("%s-%s-V%s\n游戏ID%s\n游戏包MD5%s\n",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION), gameId, packageMd5);
String qaId = uri.getQueryParameter("qa_id");
String qaTitle = uri.getQueryParameter(EntranceUtils.KEY_QA_TITLE);
if (!TextUtils.isEmpty(qaId)) {
DirectUtils.directToQa(this, qaTitle, qaId);
} else {
DirectUtils.directToFeedback(this, content, ENTRANCE_BROWSER);
}
} catch (Exception e) {
e.printStackTrace();
toast(e.getMessage());
}
break;
case EntranceUtils.HOST_GAME_NEWS:
DirectUtils.directToGameNews(
this,
uri.getQueryParameter(EntranceUtils.KEY_GAME_ID),
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
EntranceUtils.ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_GAME_CALENDAR:
DirectUtils.directToGameServerCalendar(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID));
break;
case EntranceUtils.HOST_HISTORY_APK:
DirectUtils.directToHistoryApk(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID));
break;
case EntranceUtils.HOST_FORUM_DETAIL:
DirectUtils.directForumDetail(this, id, ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_GAME_RATING_DETAIL:
DirectUtils.directToGameRatingDetail(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID), ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_FORUM:
DirectUtils.directToForum(this);
break;
case EntranceUtils.HOST_HELP_AND_FEEDBACK:
position = uri.getQueryParameter("position");
DirectUtils.directToHelpAndFeedback(this, TextUtils.isEmpty(position) ? 0 : Integer.parseInt(position));
break;
default:
break;
case HOST_DOWNLOAD:
DirectUtils.directToDownloadManagerAndStartUpdate(this, path, uri.getQueryParameter(KEY_PACKAGENAME), ENTRANCE_BROWSER);
break;
case HOST_ANSWER:
DirectUtils.directToAnswerDetail(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_QUESTION:
DirectUtils.directToQuestionDetail(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_TOOLBOX:
DirectUtils.directToToolbox(this, uri.getQueryParameter("gameId"), uri.getQueryParameter("toolboxUrl"), ENTRANCE_BROWSER);
break;
case HOST_COMMUNITY:
UserManager.getInstance().setCommunityData(new CommunityEntity(path, name));
// 把切换放到 MainActivity 处理
if (RunningUtils.isRunning(this)
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(MainActivity.SWITCH_TO_COMMUNITY, true);
} else {
bundle = new Bundle();
bundle.putBoolean(MainActivity.SWITCH_TO_COMMUNITY, true);
intent = SplashScreenActivity.getSplashScreenIntent(this, bundle);
}
startActivity(intent);
break;
// 社区文章格式一
case "community.article":
DirectUtils.directToCommunityArticle(this, uri.getQueryParameter("articleId"), uri.getQueryParameter("communityId"), ENTRANCE_BROWSER, "浏览器");
break;
// 社区文章格式二
case "communities":
String communityId = "";
String typeId = "";
String[] split = path.split("/");
for (String text : split) {
if (TextUtils.isEmpty(communityId)) {
communityId = text;
continue;
}
if (TextUtils.isEmpty(type)) {
type = text;
continue;
}
if (TextUtils.isEmpty(typeId)) {
typeId = text;
}
}
if ("articles".equals(type)) {
DirectUtils.directToCommunityArticle(this, typeId, communityId, ENTRANCE_BROWSER, "浏览器");
break;
}
break;
case HOST_VIDEO:
DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.HOTTEST_GAME_VIDEO.getValue(),
false, id, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer);
break;
case HOST_UPLOAD_VIDEO://跳转上传视频
String titleParameter = uri.getQueryParameter("title");
String title = TextUtils.isEmpty(titleParameter) ? "" : "#" + titleParameter + "#";
String categoryId = uri.getQueryParameter("category_id");
String link = uri.getQueryParameter("link");
gameId = uri.getQueryParameter("gameId");
String gameName = uri.getQueryParameter("gameName");
String tagActivityId = uri.getQueryParameter("tagActivityId");
String tagActivityName = uri.getQueryParameter("tagActivityName");
VideoLinkEntity linkEntity = new VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName);
SimpleGameEntity simpleGameEntity = new SimpleGameEntity(gameId != null ? gameId : "", gameName != null ? gameName : "", "");
Bundle nextToBundle = VideoManagerActivity.getVideoManagerBundle(linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "");
CheckLoginUtils.checkLogin(this, nextToBundle, true, EntranceUtils.ENTRANCE_BROWSER, () ->
DirectUtils.directToVideoManager(SkipActivity.this, linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "浏览器"));
break;
case HOST_VIDEO_SINGLE:
DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.getValue(),
false, "", ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer);
break;
case HOST_VIDEO_MORE:
gameId = uri.getQueryParameter("gameId");
String act = uri.getQueryParameter("act");
String fieldId = uri.getQueryParameter("fieldId");
String sectionName = uri.getQueryParameter("sectionName");
String paginationType = uri.getQueryParameter("paginationType");//活动分页方式 page filter
String location;
if (!TextUtils.isEmpty(act)) {
location = VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.getValue();
} else if (!TextUtils.isEmpty(fieldId)) {
location = VideoDetailContainerViewModel.Location.GAME_ZONE.getValue();
} else {
location = path;
}
DirectUtils.directToVideoDetail(this, path, location,
false, TextUtils.isEmpty(gameId) ? "" : gameId, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer,
TextUtils.isEmpty(type) ? "" : type, TextUtils.isEmpty(act) ? "" : act, TextUtils.isEmpty(paginationType) ? "page" : paginationType, TextUtils.isEmpty(fieldId) ? "" : fieldId,
TextUtils.isEmpty(sectionName) ? "" : sectionName);
break;
case HOST_VIDEO_STREAMING_HOME:
// 把切换放到 MainActivity 处理
if (RunningUtils.isRunning(this)
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true);
} else {
bundle = new Bundle();
bundle.putBoolean(MainActivity.SWITCH_TO_VIDEO, true);
intent = SplashScreenActivity.getSplashScreenIntent(this, bundle);
}
startActivity(intent);
break;
case HOST_VIDEO_STREAMING_DESC:
DirectUtils.directToGameDetailVideoStreaming(this, path, ENTRANCE_BROWSER);
break;
case HOST_VIDEO_COLLECTION:
DirectUtils.directToGameVideo(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_QQ:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ);
bundle.putString(KEY_DATA, path);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_QQ_GROUP:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ_GROUP);
bundle.putString(KEY_DATA, path);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_QQ_QUN:
String key = uri.getQueryParameter("key");
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ_GROUP);
bundle.putString(KEY_DATA, key);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_WEB:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_WEB);
bundle.putString(KEY_DATA, to);
bundle.putString(KEY_TYPE, type);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_LIBAO:
DirectUtils.directToGiftDetail(this, path, ENTRANCE_BROWSER);
break;
case HOST_USERHOME:
String position = uri.getQueryParameter("position");
DirectUtils.directToHomeActivity(this, path, TextUtils.isEmpty(position) ? -1 : Integer.parseInt(position), ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_COLUMN:
CommunityEntity community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
String columnId = uri.getQueryParameter("column_id");
DirectUtils.directToCommunityColumn(this, community, columnId, ENTRANCE_BROWSER, "");
break;
case HOST_CATEGORY:
title = uri.getQueryParameter("title");
DirectUtils.directCategoryDirectory(this, path, title, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COLUMN_COLLECTION:
DirectUtils.directToColumnCollection(this, path, -1, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_QUESTION_LABEL_DETAIL:
community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
String tag = uri.getQueryParameter("tag");
DirectUtils.directAskColumnLabelDetail(this, tag, community, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_COLUMN_DETAIL:
community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
columnId = uri.getQueryParameter("column_id");
DirectUtils.directAskColumnDetail(this, columnId, community, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_BLOCK:
name = uri.getQueryParameter("name");
SubjectRecommendEntity entity = new SubjectRecommendEntity();
entity.setLink(path);
entity.setName(name);
entity.setText(name);
DirectUtils.directToBlock(this, entity, mEntrance);
break;
case EntranceUtils.HOST_SERVER_BLOCK:
DirectUtils.directToGameServers(this, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_AMWAY_BLOCK:
DirectUtils.directToAmway(this, null, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_HELP:
name = uri.getQueryParameter("name");
DirectUtils.directToQa(this, name, path);
break;
case EntranceUtils.HOST_HELP_COLLECTION:
name = uri.getQueryParameter("name");
DirectUtils.directToQaCollection(this, name, path);
break;
case EntranceUtils.HOST_GAME_UPLOAD:
DirectUtils.directGameUpload(this, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_GAME_ZONE:
String zoneUrl = uri.getQueryParameter("url");
DirectUtils.directGameZone(this, path, zoneUrl, ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_LINK:
try {
String dataString = uri.getQueryParameter("data");
if (!TextUtils.isEmpty(dataString)) {
byte[] linkData = Base64.decode(dataString, Base64.DEFAULT);
String linkDataString = new String(linkData, "UTF-8");
LinkEntity le = GsonUtils.INSTANCE.getGson().fromJson(linkDataString, LinkEntity.class);
DirectUtils.directToLinkPage(this, le, ENTRANCE_BROWSER, "");
}
} catch (Exception e) {
e.printStackTrace();
toast(e.getMessage());
}
break;
case EntranceUtils.HOST_GAME_NEWS:
DirectUtils.directToGameNews(
this,
uri.getQueryParameter(EntranceUtils.KEY_GAME_ID),
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
EntranceUtils.ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_GAME_CALENDAR:
DirectUtils.directToGameServerCalendar(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID));
break;
case EntranceUtils.HOST_HISTORY_APK:
DirectUtils.directToHistoryApk(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID));
break;
case EntranceUtils.HOST_FORUM_DETAIL:
DirectUtils.directForumDetail(this, id, ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_GAME_RATING_DETAIL:
DirectUtils.directToGameRatingDetail(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID), ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_FORUM:
DirectUtils.directToForum(this);
break;
case EntranceUtils.HOST_HELP_AND_FEEDBACK:
position = uri.getQueryParameter("position");
DirectUtils.directToHelpAndFeedback(this, TextUtils.isEmpty(position) ? 0 : Integer.parseInt(position));
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;
}
}
} else if ("market".equals(uri.getScheme())) {
String host = uri.getHost();
String id = uri.getQueryParameter("id");
if (host != null) {
if ("details".equals(host)) {
bundle = new Bundle();
bundle.putString(KEY_TO, EntranceUtils.KEY_MARKET_DETAILS);
bundle.putString(KEY_DATA, id);
EntranceUtils.jumpActivity(this, bundle);
} else {
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;
}
}
}
}

View File

@ -2,6 +2,7 @@ package com.gh.gamecenter;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -15,6 +16,12 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.g00fy2.versioncompare.Version;
import com.gh.base.BaseActivity;
import com.gh.common.AppExecutor;
@ -23,6 +30,7 @@ import com.gh.common.constant.Constants;
import com.gh.common.dialog.PrivacyDialogFragment;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DeviceTokenUtils;
import com.gh.common.util.DeviceUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.EmptyCallback;
import com.gh.common.util.GameSubstituteRepositoryHelper;
@ -32,7 +40,6 @@ import com.gh.common.util.PackageUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.SPUtils;
import com.gh.common.util.TagUtils;
import com.gh.common.util.TeaHelper;
import com.gh.common.util.UsageStatsHelper;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.entity.AuthDialogEntity;
@ -50,17 +57,14 @@ import org.jetbrains.annotations.NotNull;
import org.json.JSONObject;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
@ -74,7 +78,8 @@ public class SplashScreenActivity extends BaseActivity {
private SharedPreferences mSharedPreferences;
private boolean isNewFirstLaunch;
private boolean mIsNewForThisVersion;
private boolean mStartMainActivityDirectly = false; // 是否不需要用户点击立即体验就直接跳转首页
private static final int REQUEST_PERMISSION_TAG = 30001;
private String[] mPermissions = {
@ -94,7 +99,7 @@ public class SplashScreenActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
isNewFirstLaunch = mSharedPreferences.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true);
mIsNewForThisVersion = mSharedPreferences.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true);
super.onCreate(savedInstanceState);
@ -105,13 +110,14 @@ public class SplashScreenActivity extends BaseActivity {
}
// 判断是不是这个版本的新用户
if (isNewFirstLaunch) {
if (mIsNewForThisVersion) {
mContentView.setPadding(0, 0, 0, 0);
ViewPager guideLayout = findViewById(R.id.splash_intro_vp_guide);
guideLayout.setAdapter(new GuidePagerAdapter());
// 判断是不是光环的新用户
if (SPUtils.getBoolean(Constants.SP_BRAND_NEW_USER, true)) {
mStartMainActivityDirectly = true;
SPUtils.setLong(Constants.SP_INITIAL_USAGE_TIME, System.currentTimeMillis());
HaloApp.getInstance().isBrandNewInstall = true;
showPrivacyDialog(guideLayout);
@ -124,6 +130,9 @@ public class SplashScreenActivity extends BaseActivity {
} else {
launchMainActivity();
}
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
SPUtils.setString(Constants.SP_XAPK_URL, "");
}
private void showPrivacyDialog(ViewPager guideLayout) {
@ -131,13 +140,12 @@ public class SplashScreenActivity extends BaseActivity {
if (isSuccess) {
showPrivacyPolicy(() -> {
// Dialog dismiss 后的回调
// guideLayout.setVisibility(View.VISIBLE);
guideLayout.setVisibility(View.VISIBLE);
SPUtils.setBoolean(Constants.SP_BRAND_NEW_USER, false);
// requestPermission();
launchMainActivity();
requestPermission();
});
} else {
DialogUtils.showPrivacyPolicyDisallowDialog(this, PrivacyPolicyEntity.createDefaultData(),()->{
DialogUtils.showPrivacyPolicyDisallowDialog(this, PrivacyPolicyEntity.createDefaultData(), () -> {
showPrivacyDialog(guideLayout);
});
}
@ -231,7 +239,7 @@ public class SplashScreenActivity extends BaseActivity {
public void onSuccess(PrivacyPolicyEntity data) {
DialogUtils.showPrivacyPolicyDialog(
SplashScreenActivity.this,
PrivacyPolicyEntity.createDefaultData(), callback);
data, callback);
}
@Override
@ -246,7 +254,7 @@ public class SplashScreenActivity extends BaseActivity {
@Override
protected int getLayoutId() {
if (isNewFirstLaunch) {
if (mIsNewForThisVersion) {
return R.layout.activity_splash_intro;
} else {
return 0;
@ -256,7 +264,7 @@ public class SplashScreenActivity extends BaseActivity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
if (isNewFirstLaunch && EasyPermissions.hasPermissions(this, mPermissions)) {
if (mIsNewForThisVersion && EasyPermissions.hasPermissions(this, mPermissions)) {
launchMainActivity();
} else {
return true;
@ -283,9 +291,7 @@ public class SplashScreenActivity extends BaseActivity {
prefetchData();
// 在可能获取了相关权限后才初始化SDK/发送激活数据
TeaHelper.init(getApplication(), HaloApp.getInstance().getChannel());
// GdtHelper.INSTANCE.logAction(ActionType.START_APP, GdtHelper.NETWORK_TYPE, DeviceUtils.getNetwork(this));
uploadTeaAndGdtData();
Bundle bundle = getIntent().getExtras();
Intent intent = new Intent(SplashScreenActivity.this, MainActivity.class);
@ -294,6 +300,33 @@ public class SplashScreenActivity extends BaseActivity {
finish();
}
private void uploadTeaAndGdtData() {
// 在可能获取了相关权限后才初始化SDK/发送激活数据
// TeaHelper.init(getApplication(), HaloApp.getInstance().getChannel());
try {
Class<?> clazz = Class.forName("com.gh.gamecenter.TeaHelper");
Method method = clazz.getMethod("init", Context.class, String.class);
method.invoke(null, getApplication(), HaloApp.getInstance().getChannel());
} catch (Exception e) {
e.printStackTrace();
}
// GdtHelper.INSTANCE.logAction(ActionType.START_APP, GdtHelper.NETWORK_TYPE, DeviceUtils.getNetwork(this));
try {
Class<?> clazz = Class.forName("com.gh.gamecenter.GdtHelper");
Field field = clazz.getDeclaredField("NETWORK_TYPE");
String type = (String) field.get(null);
Method method = clazz.getMethod("logAction", String.class, String[].class);
Class<?> actionTypeClazz = Class.forName("com.qq.gdt.action.ActionType");
Field typeField = actionTypeClazz.getDeclaredField("START_APP");
String actionType = (String) typeField.get(null);
method.invoke(null, actionType, new String[]{type, DeviceUtils.getNetwork(this)});
} catch (Exception e) {
e.printStackTrace();
}
}
private void getUniqueId() {
DataUtils.getGid();
}
@ -337,6 +370,9 @@ public class SplashScreenActivity extends BaseActivity {
MtaHelper.onEvent("授权情况", "启动授权", "都授权");
// 检查是否有旧版本光环,有就删掉
AppExecutor.getIoExecutor().execute(this::deleteOutdatedUpdatePackage);
if (mStartMainActivityDirectly) {
launchMainActivity();
}
} else {
ActivityCompat.requestPermissions(this, mPermissions, REQUEST_PERMISSION_TAG);
}
@ -351,12 +387,22 @@ public class SplashScreenActivity extends BaseActivity {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}, () -> logGrantedPermission(perms));
}, () -> {
logGrantedPermission(perms);
if (mStartMainActivityDirectly) {
launchMainActivity();
}
});
} else {
DialogUtils.showPermissionDialog(this, "权限申请",
"在设置-应用-光环助手-权限中开启存储和手机信息权限,以保证能正常使用相关功能", "重试", "放弃",
this::checkAndRequestPermission,
() -> logGrantedPermission(perms));
() -> {
logGrantedPermission(perms);
if (mStartMainActivityDirectly) {
launchMainActivity();
}
});
}
}
@ -376,25 +422,25 @@ public class SplashScreenActivity extends BaseActivity {
// 检查下载文件夹下是否有旧版本的光环助手的包,有则删除
@SuppressWarnings("ResultOfMethodCallIgnored")
private void deleteOutdatedUpdatePackage() {
File folder = new File(FileUtils.getDownloadDir(this) + File.separator);
if (folder.isDirectory()) {
for (File file : folder.listFiles()) {
if (!file.isDirectory() && file.getName().startsWith("光环助手V")) {
String name = file.getName();
int index = name.indexOf("_");
if (index != -1) {
try {
try {
File folder = new File(FileUtils.getDownloadDir(this) + File.separator);
if (folder.isDirectory()) {
for (File file : folder.listFiles()) {
if (!file.isDirectory() && file.getName().startsWith("光环助手V")) {
String name = file.getName();
int index = name.indexOf("_");
if (index != -1) {
String versionString = name.substring(name.indexOf("V") + 1, index);
Version currentVersion = new Version(PackageUtils.getVersionName());
if (currentVersion.isHigherThan(versionString) || currentVersion.isEqual(versionString)) {
file.delete();
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

View File

@ -17,6 +17,7 @@ import androidx.core.content.ContextCompat;
import com.gh.common.util.BitmapUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.KcSelectGameViewHolder;
import com.gh.gamecenter.entity.InstallGameEntity;
@ -106,7 +107,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
for (String apk_path : mApkPath) {
InstallGameEntity apkEntity = new InstallGameEntity();
PackageManager pm = mContext.getApplicationContext().getPackageManager();
PackageInfo packageInfo = pm.getPackageArchiveInfo(apk_path, PackageManager.GET_ACTIVITIES);
PackageInfo packageInfo = pm.getPackageArchiveInfo(apk_path, 0);
if (packageInfo == null) continue;
ApplicationInfo appInfo = packageInfo.applicationInfo;
@ -132,7 +133,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
/**安装处理类型*/
/** 得到包名 */
String packageName = packageInfo.packageName;
int type = doType(pm, packageName);
int type = doType(packageName);
apkEntity.setInstallStatus(type);
mApkList.add(apkEntity);
@ -176,8 +177,8 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
}
}
private int doType(PackageManager pm, String packageName) {
List<PackageInfo> pakageinfos = pm.getInstalledPackages(0);
private int doType(String packageName) {
List<PackageInfo> pakageinfos = PackageUtils.getInstalledPackages(mContext, 0);
for (PackageInfo pi : pakageinfos) {
if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
String pi_packageName = pi.packageName;

View File

@ -5,9 +5,14 @@ import android.content.Intent;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentActivity;
import com.gh.common.dialog.CertificationDialog;
import com.gh.common.dialog.DeviceRemindDialog;
import com.gh.common.dialog.GameOffServiceDialogFragment;
import com.gh.common.dialog.PackageCheckDialogFragment;
import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.history.HistoryHelper;
@ -39,16 +44,13 @@ import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.gamedetail.GameDetailFragment;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.AppManager;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentActivity;
/**
* Created by khy on 27/06/17.
* 详情页面下载ViewHolder
@ -165,16 +167,18 @@ public class DetailViewHolder {
PermissionHelper.checkStoragePermissionBeforeAction(mViewHolder.context, () -> {
if (mGameEntity.getApk().size() == 1) {
ApkEntity apk = mGameEntity.getApk().get(0);
DownloadDialogHelper.findAvailableDialogAndShow(mViewHolder.context, mGameEntity, apk,
() -> {
CertificationDialog.showCertificationDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.showVersionNumberDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.checkDownload(mViewHolder.context, apk.getSize(), this::download);
});
PackageCheckDialogFragment.show((AppCompatActivity) mViewHolder.context, mGameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(mViewHolder.context, mGameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.showVersionNumberDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.checkDownload(mViewHolder.context, apk.getSize(), this::download);
});
});
});
});
});
} else {
CertificationDialog.showCertificationDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.showVersionNumberDialog(mViewHolder.context, mGameEntity, () -> {
@ -248,15 +252,13 @@ public class DetailViewHolder {
break;
case RESERVABLE:
CheckLoginUtils.checkLogin(mViewHolder.context, mEntrance, () -> {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(mViewHolder.context, () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
mGameEntity,
() -> {
LogUtils.logReservation(mGameEntity, mTraceEvent);
DetailDownloadUtils.detailInitDownload(mViewHolder, false);
});
dialogFragment.show(((AppCompatActivity) mViewHolder.context).getSupportFragmentManager(), "reserve");
});
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
mGameEntity,
() -> {
LogUtils.logReservation(mGameEntity, mTraceEvent);
DetailDownloadUtils.detailInitDownload(mViewHolder, false);
});
dialogFragment.show(((AppCompatActivity) mViewHolder.context).getSupportFragmentManager(), "reserve");
});
break;
case RESERVED:

View File

@ -63,7 +63,7 @@ class AmwaySearchActivity : SearchActivity() {
val transaction = supportFragmentManager.beginTransaction()
when (type) {
DisplayType.DEFAULT -> {
val fragment = supportFragmentManager.findFragmentByTag(AmwaySearchDefaultFragment::class.java.simpleName)
val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.simpleName)
?: AmwaySearchDefaultFragment()
transaction.replace(R.id.search_result, fragment, SearchDefaultFragment::class.java.simpleName)
}

View File

@ -44,14 +44,10 @@ class AmwaySearchViewHolder(var binding: AmwaySearchItemBinding, val mViewModel:
it.context.showRegulationTestDialogIfNeeded {
val installPackageName = mViewModel.canUserCommentThisGame(gameEntity)
if (gameEntity.directComment || !installPackageName.isNullOrEmpty()) {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(activity, object : EmptyCallback {
override fun onCallback() {
MtaHelper.onEvent("发表评论", "进入", "选中游戏_${gameEntity.name}")
val intent = RatingEditActivity.getIntent(binding.root.context, gameEntity, 0.0F, installPackageName, true)
activity.startActivity(intent)
activity.finish()
}
})
MtaHelper.onEvent("发表评论", "进入", "选中游戏_${gameEntity.name}")
val intent = RatingEditActivity.getIntent(binding.root.context, gameEntity, 0.0F, installPackageName, true)
activity.startActivity(intent)
activity.finish()
} else {
Utils.toast(activity, "安装游戏后才能评论哦")
}

View File

@ -20,6 +20,7 @@ public abstract class ListAdapter<DataType> extends BaseRecyclerAdapter {
public static final int FOOTER_ITEM_COUNT = 1;
public static final int TOP_ITEM_COUNT = 1;
// TODO mEntityList 适配多线程读写
protected List<DataType> mEntityList = new ArrayList<>();
protected boolean mIsOver;

View File

@ -0,0 +1,34 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.NormalActivity
import com.gh.gamecenter.R
class CatalogActivity : NormalActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
}
override fun showDownloadMenu(): Boolean {
return true
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(this, CatalogActivity::class.java, CatalogFragment::class.java)
}
companion object {
fun getIntent(context: Context, catalogId: String, catalogTitle: String, entrance: String): Intent {
val bundle = Bundle()
bundle.putString(EntranceUtils.KEY_CATALOG_ID, catalogId)
bundle.putString(EntranceUtils.KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance)
return getTargetIntent(context, CatalogActivity::class.java, CatalogFragment::class.java, bundle)
}
}
}

View File

@ -0,0 +1,51 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.CatalogItemBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class CatalogAdapter(context: Context,
private val mFragment: CatalogFragment,
private val mViewModel: CatalogViewModel,
private val mList: List<CatalogEntity.SubCatalogEntity>)
: BaseRecyclerAdapter<CatalogAdapter.CatalogItemViewHolder>(context) {
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
CatalogItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_item,parent, false))
override fun onBindViewHolder(holder: CatalogItemViewHolder, position: Int) {
holder.binding.run {
val catalogEntity = mList[position]
entity = catalogEntity
executePendingBindings()
if (catalogEntity.name == mViewModel.selectedCatalogName) {
selectedTag.visibility = View.VISIBLE
catalogName.setTextColor(R.color.theme_font.toColor())
root.setBackgroundColor(R.color.white.toColor())
} else {
selectedTag.visibility = View.GONE
catalogName.setTextColor(R.color.text_333333.toColor())
root.setBackgroundColor(R.color.text_F5F5F5.toColor())
}
root.setOnClickListener {
if (catalogEntity.name != mViewModel.selectedCatalogName) {
mViewModel.selectedCatalogName = catalogEntity.name
mViewModel.logSubCatalogClick(position)
mFragment.changeCatalog(position)
notifyDataSetChanged()
}
}
}
}
class CatalogItemViewHolder(val binding: CatalogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,116 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import com.gh.common.util.EntranceUtils
import com.gh.common.util.viewModelProviderFromParent
import com.gh.common.view.FixLinearLayoutManager
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentCatalogBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.normal.NormalFragment
class CatalogFragment : NormalFragment() {
private lateinit var mBinding: FragmentCatalogBinding
private lateinit var mViewModel: CatalogViewModel
private lateinit var mEntity: CatalogEntity
private lateinit var mSpecialCatalogFragment: SpecialCatalogFragment
private lateinit var mSubCatalogFragment: SubCatalogFragment
private var mCatalogId: String = ""
private var mCatalogTitle: String = ""
override fun getLayoutId() = 0
override fun getInflatedLayout() = FragmentCatalogBinding.inflate(layoutInflater).apply { mBinding = this }.root
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: ""
mCatalogTitle = arguments?.getString(EntranceUtils.KEY_CATALOG_TITLE) ?: ""
mViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, mCatalogTitle))
mViewModel.validEntranceName = if (mEntrance.contains("首页")) "首页" else "板块"
mViewModel.logAppearance()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setNavigationTitle(mCatalogTitle)
mViewModel.catalogs.observe(viewLifecycleOwner, Observer {
mBinding.run {
reuseLoading.root.visibility = View.GONE
if (it != null) {
reuseNoConnection.root.visibility = View.GONE
if (it.subCatalog.isNotEmpty()) {
containerCatalog.visibility = View.VISIBLE
reuseNoneData.root.visibility = View.GONE
mEntity = it
if (mEntity.hasSpecial) {
val specialEntity = CatalogEntity.SubCatalogEntity(name = "精选")
(mEntity.subCatalog as ArrayList).add(0, specialEntity)
}
initView()
} else {
containerCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.VISIBLE
}
} else {
containerCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.VISIBLE
reuseNoConnection.root.setOnClickListener {
reuseLoading.root.visibility = View.VISIBLE
mViewModel.getCatalogs()
}
}
}
})
}
private fun initView() {
mEntity.run {
if (subCatalog.isNotEmpty()) {
mViewModel.selectedCatalogName = subCatalog[0].name
mBinding.rvCatalog.layoutManager = FixLinearLayoutManager(requireContext())
mBinding.rvCatalog.adapter = CatalogAdapter(requireContext(), this@CatalogFragment, mViewModel, subCatalog)
if (hasSpecial) {
mSpecialCatalogFragment = childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.simpleName) as? SpecialCatalogFragment ?: SpecialCatalogFragment()
mSpecialCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id)
childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSpecialCatalogFragment, SpecialCatalogFragment::class.java.simpleName).commitAllowingStateLoss()
} else {
mSubCatalogFragment = childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.simpleName) as? SubCatalogFragment ?: SubCatalogFragment()
mSubCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id, EntranceUtils.KEY_PRIMARY_CATALOG_ID to subCatalog[0].id)
childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSubCatalogFragment, SubCatalogFragment::class.java.simpleName).commitAllowingStateLoss()
}
}
}
}
fun changeCatalog(position: Int) {
mEntity.run {
if (hasSpecial) {
if (mViewModel.selectedCatalogPosition == 0) {
mSubCatalogFragment = childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.simpleName) as? SubCatalogFragment ?: SubCatalogFragment()
mSubCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id, EntranceUtils.KEY_PRIMARY_CATALOG_ID to subCatalog[position].id)
childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSubCatalogFragment, SubCatalogFragment::class.java.simpleName).commitAllowingStateLoss()
} else {
if (position == 0) {
mSpecialCatalogFragment = childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.simpleName) as? SpecialCatalogFragment ?: SpecialCatalogFragment()
mSpecialCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id)
childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSpecialCatalogFragment, SpecialCatalogFragment::class.java.simpleName).commitAllowingStateLoss()
} else {
mSubCatalogFragment.changeSubCatalog(subCatalog[position].id)
}
}
} else {
mSubCatalogFragment.changeSubCatalog(subCatalog[position].id)
}
mViewModel.selectedCatalogPosition = position
}
}
}

View File

@ -0,0 +1,77 @@
package com.gh.gamecenter.catalog
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.exposure.ExposureSource
import com.gh.common.util.LogUtils
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class CatalogViewModel(application: Application, private val catalogId: String, val catalogTitle: String)
: AndroidViewModel(application) {
private val api = RetrofitManager.getInstance(getApplication()).api
var catalogs = MutableLiveData<CatalogEntity>()
var selectedCatalogName: String = ""
var selectedCatalogPosition: Int = 0
var validEntranceName: String = ""
val basicExposureSource by lazy { ExposureSource("分类", catalogTitle) }
init {
getCatalogs()
}
@SuppressLint("CheckResult")
fun getCatalogs() {
api.getCatalogs(catalogId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<CatalogEntity>() {
override fun onSuccess(data: CatalogEntity) {
catalogs.postValue(data)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
catalogs.postValue(null)
}
})
}
fun logAppearance() {
LogUtils.logNewCatalogAppearanceEvent(validEntranceName, catalogTitle)
}
fun logSubCatalogClick(position: Int) {
LogUtils.logSubCatalogClickEvent(validEntranceName, "${catalogTitle}_${selectedCatalogName}", position)
}
fun logSubCatalogContentClick(itemName: String, listPosition: Int) {
LogUtils.logSubCatalogContentClickEvent(validEntranceName, "${catalogTitle}_${selectedCatalogName}_${itemName}", selectedCatalogPosition, listPosition)
}
fun logSpecialCatalogContentClick(contentType: String, contentName: String, listPosition: Int) {
LogUtils.logSpecialCatalogContentClickEvent(validEntranceName, "${catalogTitle}_${contentType}_${contentName}", selectedCatalogPosition, listPosition)
}
fun logSpecialCatalogSpecificContentClick(contentType: String, contentName: String, targetName: String, listPosition: Int, specificListPosition: Int) {
LogUtils.logSpecialCatalogSpecificContentClickEvent(validEntranceName, "${catalogTitle}_${contentType}_${contentName}_${targetName}", selectedCatalogPosition, listPosition, specificListPosition)
}
class Factory(private val catalogId: String, private val catalogTitle: String) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return CatalogViewModel(HaloApp.getInstance().application, catalogId, catalogTitle) as T
}
}
}

View File

@ -0,0 +1,38 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.NormalActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.CatalogEntity
class NewCatalogListActivity : NormalActivity() {
companion object {
fun getIntent(context: Context,
primaryCatalogName: String, // 一级分类名
catalogTitle: String,
catalog: CatalogEntity,
initTitle: String): Intent {
val bundle = Bundle()
bundle.putParcelable(EntranceUtils.KEY_DATA, catalog)
bundle.putString(EntranceUtils.KEY_PRIMARY_CATALOG_NAME, primaryCatalogName)
bundle.putString(EntranceUtils.KEY_NAME, catalog.name)
bundle.putString(EntranceUtils.KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(EntranceUtils.KEY_CATALOG_INIT_TITLE, initTitle)
return getTargetIntent(context, NewCatalogListActivity::class.java, NewCatalogListFragment::class.java, bundle)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
}
override fun showDownloadMenu(): Boolean {
return true
}
}

View File

@ -0,0 +1,173 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.util.SparseArray
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.constant.ItemViewType
import com.gh.common.exposure.ExposureEvent
import com.gh.common.exposure.ExposureSource
import com.gh.common.exposure.ExposureType
import com.gh.common.exposure.IExposable
import com.gh.common.util.DownloadItemUtils
import com.gh.common.util.GameViewUtils
import com.gh.common.util.StringUtils
import com.gh.common.util.dip2px
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.baselist.LoadType
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.game.GameItemViewHolder
import com.lightgame.download.DownloadEntity
import java.util.*
class NewCatalogListAdapter(context: Context,
private val mBaseExposureSource: ExposureSource,
private val mViewModel: NewCatalogListViewModel,
private val mEntrance: String?) : ListAdapter<GameEntity>(context), IExposable {
private val mExposureEventSparseArray: SparseArray<ExposureEvent> = SparseArray()
val positionAndPackageMap = HashMap<String, Int>()
override fun setListData(updateData: MutableList<GameEntity>?) {
// 记录游戏位置
if (updateData != null) {
for (i in 0 until updateData.size) {
val gameEntity = updateData[i]
var packages = gameEntity.id
for (apkEntity in gameEntity.getApk()) {
packages += apkEntity.packageName
}
positionAndPackageMap[packages + i] = i
}
}
super.setListData(updateData)
}
fun clearPositionAndPackageMap() {
positionAndPackageMap.clear()
}
override fun areItemsTheSame(oldItem: GameEntity?, newItem: GameEntity?): Boolean {
return oldItem?.id == newItem?.id
}
override fun getItemViewType(position: Int): Int {
if (position == itemCount - 1) {
return ItemViewType.ITEM_FOOTER
}
return ItemViewType.GAME_NORMAL
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ItemViewType.GAME_NORMAL -> {
GameItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.game_item, parent, false))
}
else -> {
FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
}
}
}
override fun getItemCount(): Int {
return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameItemViewHolder) {
val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px()
holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px())
val gameEntity = mEntityList[position]
holder.binding.game = gameEntity
holder.initServerType(gameEntity)
holder.binding.hideSize = true
holder.binding.executePendingBindings()
GameViewUtils.setLabelList(mContext, holder.binding.labelList, gameEntity.tagStyle)
gameEntity.sequence = position + 1
val sortType = mViewModel.sortType.value
val sortSize = mViewModel.sortSize.text
val toolbarTitle = mViewModel.title
val selectedCatalogName = mViewModel.selectedCatalog.name
val exposureSources = ArrayList<ExposureSource>()
exposureSources.add(mBaseExposureSource)
exposureSources.add(ExposureSource(toolbarTitle))
exposureSources.add(ExposureSource("二级分类详情", "$selectedCatalogName+$sortType+$sortSize"))
gameEntity.sequence = position + 1
val event = ExposureEvent.createEvent(gameEntity, exposureSources, null, ExposureType.EXPOSURE)
mExposureEventSparseArray.put(position, event)
holder.itemView.setOnClickListener {
GameDetailActivity.startGameDetailActivity(
mContext,
gameEntity,
StringUtils.buildString(mEntrance, "+(", toolbarTitle, ":列表[", selectedCatalogName, "=", sortType, "=", (position + 1).toString(), "])"),
event)
}
DownloadItemUtils.setOnClickListener(mContext,
holder.binding.downloadBtn,
gameEntity,
position,
this,
StringUtils.buildString(StringUtils.buildString(mEntrance, "+(", toolbarTitle, ":列表[", selectedCatalogName, "=", sortType, "=", (position + 1).toString(), "])")),
StringUtils.buildString(selectedCatalogName, ":", gameEntity.name),
event)
DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(holder.binding), true, "star&brief")
} else if (holder is FooterViewHolder) {
holder.initItemPadding()
holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint)
holder.itemView.setOnClickListener {
if (mIsNetworkError) {
mViewModel.load(LoadType.RETRY)
}
}
}
}
fun notifyItemByDownload(download: DownloadEntity) {
for (key in positionAndPackageMap.keys) {
if (key.contains(download.packageName) && key.contains(download.gameId)) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size) {
mEntityList[position].getEntryMap()[download.platform] = download
notifyItemChanged(position)
}
}
}
}
fun notifyItemAndRemoveDownload(status: EBDownloadStatus) {
for (key in positionAndPackageMap.keys) {
if (key.contains(status.packageName) && key.contains(status.gameId)) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size) {
mEntityList[position].getEntryMap().remove(status.platform)
notifyItemChanged(position)
}
}
}
}
override fun getEventByPosition(pos: Int): ExposureEvent? {
return mExposureEventSparseArray.get(pos)
}
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? {
return null
}
}

View File

@ -0,0 +1,182 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import com.ethanhua.skeleton.Skeleton
import com.gh.common.constant.Constants
import com.gh.common.exposure.ExposureListener
import com.gh.common.exposure.ExposureSource
import com.gh.common.util.DialogUtils
import com.gh.common.util.EntranceUtils
import com.gh.common.util.observeNonNull
import com.gh.common.util.viewModelProvider
import com.gh.common.view.CatalogFilterView
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListFragment
import com.gh.gamecenter.databinding.FragmentCatalogListBinding
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class NewCatalogListFragment : ListFragment<GameEntity, NewCatalogListViewModel>() {
private var mPrimaryCatalogName: String = "" // 一级分类名
private var mPrimeCatalog: CatalogEntity? = null
private var mSubCatalogList = arrayListOf<CatalogEntity.SubCatalogEntity>()
private var mInitCatalogName = ""
private var mAdapter: NewCatalogListAdapter? = null
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
mAdapter?.notifyItemByDownload(downloadEntity)
if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) {
showUnzipFailureDialog(downloadEntity)
}
}
}
private lateinit var mBinding: FragmentCatalogListBinding
private lateinit var mExposureListener: ExposureListener
private lateinit var mViewModel: NewCatalogListViewModel
override fun getLayoutId() = 0
override fun getInflatedLayout() = FragmentCatalogListBinding.inflate(layoutInflater).apply { mBinding = this }.root
override fun provideListViewModel() = viewModelProvider<NewCatalogListViewModel>()
override fun provideListAdapter() = mAdapter
?: NewCatalogListAdapter(
requireContext(),
ExposureSource(mPrimaryCatalogName),
mViewModel,
mEntrance).apply { mAdapter = this }
override fun getItemDecoration() = null
override fun onCreate(savedInstanceState: Bundle?) {
mViewModel = provideListViewModel()
mViewModel.title = arguments?.getString(EntranceUtils.KEY_NAME) ?: ""
mViewModel.categoryTitle = arguments?.getString(EntranceUtils.KEY_CATALOG_TITLE) ?: ""
mEntrance = arguments?.getString(EntranceUtils.KEY_ENTRANCE) ?: Constants.ENTRANCE_UNKNOWN
mPrimeCatalog = arguments?.getParcelable(EntranceUtils.KEY_DATA)
mSubCatalogList = mPrimeCatalog?.subCatalog as ArrayList<CatalogEntity.SubCatalogEntity>
mInitCatalogName = arguments?.getString(EntranceUtils.KEY_CATALOG_INIT_TITLE) ?: ""
mPrimaryCatalogName = arguments?.getString(EntranceUtils.KEY_PRIMARY_CATALOG_NAME) ?: ""
mViewModel.selectedCatalog = mSubCatalogList.find { entity -> entity.name == mInitCatalogName }
?: CatalogEntity.SubCatalogEntity()
initSortType()
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setNavigationTitle(mViewModel.title)
initFilterView()
mViewModel.refresh.observeNonNull(this) { onRefresh() }
mExposureListener = ExposureListener(this, mAdapter!!)
mListRv.addOnScrollListener(mExposureListener)
mSkeletonScreen = Skeleton.bind(mBinding.listSkeleton).shimmer(false).load(R.layout.fragment_subject_skeleton).show()
}
private fun initSortType() {
mPrimeCatalog?.switch?.run {
if (hotSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.RECOMMENDED
return@run
}
if (newSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.NEWEST
return@run
}
if (starSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.RATING
return@run
}
}
}
private fun initFilterView() {
mBinding.filterContainer.run {
visibility = View.VISIBLE
setTypeList(mPrimeCatalog?.switch ?: CatalogEntity.CatalogSwitch())
setCatalogList(mSubCatalogList, mInitCatalogName)
setOnConfigSetupListener(object : CatalogFilterView.OnCatalogFilterSetupListener {
override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) {
mViewModel.updateSortConfig(sortSize = sortSize)
}
override fun onSetupSortType(sortType: CatalogFilterView.SortType) {
mViewModel.updateSortConfig(sortType = sortType)
}
override fun onSetupSortCatalog(sortCatalog: CatalogEntity.SubCatalogEntity) {
mViewModel.updateSortConfig(sortCatalog = sortCatalog)
}
})
}
}
override fun onResume() {
if (isEverPause && mAdapter != null) mAdapter?.notifyDataSetChanged()
super.onResume()
DownloadManager.getInstance(context).addObserver(mDataWatcher)
}
override fun onPause() {
super.onPause()
DownloadManager.getInstance(context).removeObserver(mDataWatcher)
}
override fun onRefresh() {
mAdapter?.clearPositionAndPackageMap()
super.onRefresh()
}
// 下载被删除事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(status: EBDownloadStatus) {
if ("delete" == status.status) {
mAdapter?.notifyItemAndRemoveDownload(status)
}
}
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if ("安装" == busFour.type || "卸载" == busFour.type) {
mAdapter?.notifyDataSetChanged()
}
}
fun showUnzipFailureDialog(downloadEntity: DownloadEntity) {
val data = mAdapter?.positionAndPackageMap ?: return
for (gameAndPosition in data) {
if (gameAndPosition.key.contains(downloadEntity.packageName)) {
val targetView = mLayoutManager.findViewByPosition(gameAndPosition.value)
if (targetView != null) {
DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
return
}
}
}
}
}

View File

@ -0,0 +1,82 @@
package com.gh.gamecenter.catalog
import android.app.Application
import androidx.lifecycle.MutableLiveData
import com.gh.common.util.UrlFilterUtils
import com.gh.common.view.CatalogFilterView
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.Single
class NewCatalogListViewModel(application: Application) : ListViewModel<GameEntity, GameEntity>(application) {
var title = "" // 显示在 Toolbar 的标题
var categoryTitle = "" // 跳转进来的分类的标题
val refresh = MutableLiveData<Boolean>()
var selectedCatalog = CatalogEntity.SubCatalogEntity()
var sortType = CatalogFilterView.SortType.RECOMMENDED
var sortSize = SubjectSettingEntity.Size()
private val sensitiveApi = RetrofitManager.getInstance(getApplication()).sensitiveApi
override fun provideDataObservable(page: Int): Observable<List<GameEntity>>? = null
override fun provideDataSingle(page: Int): Single<List<GameEntity>> {
return if (selectedCatalog.link.type == "column") { // column(专题)/tag(标签)
sensitiveApi.getColumn(selectedCatalog.link.link, getSortType(), getSortSize(), page) // 专题
} else {
sensitiveApi.getGamesWithSpecificTag(getSortSize(), getSortType(), page) // 标签
}
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) }
}
fun updateSortConfig(sortSize: SubjectSettingEntity.Size? = null,
sortType: CatalogFilterView.SortType? = null,
sortCatalog: CatalogEntity.SubCatalogEntity? = null) {
when {
sortSize != null && sortSize != this.sortSize -> {
this.sortSize = sortSize
refresh.postValue(true)
}
sortType != null && sortType != this.sortType -> {
this.sortType = sortType
refresh.postValue(true)
}
sortCatalog != null && sortCatalog != selectedCatalog -> {
selectedCatalog = sortCatalog
refresh.postValue(true)
}
}
}
private fun getSortSize(): String? {
return if (selectedCatalog.link.type == "column") {
UrlFilterUtils.getFilterQuery(
"min_size", sortSize.min.toString(),
"max_size", sortSize.max.toString())
} else {
UrlFilterUtils.getFilterQuery(
"tag_id", selectedCatalog.link.link,
"min_size", sortSize.min.toString(),
"max_size", sortSize.max.toString())
}
}
private fun getSortType(): String? {
return when (sortType) {
CatalogFilterView.SortType.RECOMMENDED -> if (selectedCatalog.link.type == "column") "position:1" else "download:-1"
CatalogFilterView.SortType.NEWEST -> "publish:-1"
CatalogFilterView.SortType.RATING -> "star:-1"
}
}
}

View File

@ -0,0 +1,245 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.ItemViewType
import com.gh.common.exposure.ExposureEvent
import com.gh.common.exposure.ExposureSource
import com.gh.common.exposure.IExposable
import com.gh.common.util.DirectUtils
import com.gh.common.util.dip2px
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.databinding.CatalogHeaderItemBinding
import com.gh.gamecenter.databinding.CatalogImageItemBinding
import com.gh.gamecenter.databinding.CatalogSubjectCollectionItemBinding
import com.gh.gamecenter.databinding.CatalogSubjectItemBinding
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.subject.SubjectActivity.Companion.startSubjectActivity
class SpecialCatalogAdapter(context: Context, private val mCatalogViewModel: CatalogViewModel)
: ListAdapter<SpecialCatalogItemData>(context), IExposable {
private val mExposureEventSparseArray: SparseArray<ExposureEvent> = SparseArray()
override fun getItemCount() = if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size + FOOTER_ITEM_COUNT
override fun areItemsTheSame(oldItem: SpecialCatalogItemData?, newItem: SpecialCatalogItemData?): Boolean {
return when {
oldItem?.header != null && newItem?.header != null -> {
oldItem.header.id == newItem.header.id
}
oldItem?.bigImage != null && newItem?.bigImage != null -> {
oldItem.bigImage.id == newItem.bigImage.id
}
oldItem?.subject != null && newItem?.subject != null -> {
oldItem.subject.id == newItem.subject.id
}
oldItem?.subjectCollection != null && newItem?.subjectCollection != null -> {
oldItem.subjectCollection.id == newItem.subjectCollection.id
}
else -> super.areItemsTheSame(oldItem, newItem)
}
}
override fun areContentsTheSame(oldItem: SpecialCatalogItemData?, newItem: SpecialCatalogItemData?): Boolean {
return when {
oldItem?.header != null && newItem?.header != null -> {
oldItem.header.id == newItem.header.id
}
oldItem?.bigImage != null && newItem?.bigImage != null -> {
oldItem.bigImage.id == newItem.bigImage.id
}
oldItem?.subject != null && newItem?.subject != null -> {
oldItem.subject.id == newItem.subject.id
}
oldItem?.subjectCollection != null && newItem?.subjectCollection != null -> {
oldItem.subjectCollection.id == newItem.subjectCollection.id
}
else -> super.areItemsTheSame(oldItem, newItem)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view: View
return when (viewType) {
ItemViewType.ITEM_FOOTER -> {
view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)
FooterViewHolder(view)
}
TYPE_HEADER -> CatalogHeaderItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_header_item, parent, false))
TYPE_BIG_IMAGE -> CatalogImageItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_image_item, parent, false))
TYPE_SUBJECT -> CatalogSubjectItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_item, parent, false))
TYPE_SUBJECT_COLLECTION -> CatalogSubjectCollectionItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_collection_item, parent, false))
else -> throw NullPointerException()
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is CatalogImageItemHolder -> {
val imageEntity = mEntityList[position].bigImage!!
holder.binding.run {
image.layoutParams = image.layoutParams.apply {
val imageWidth = mContext.resources.displayMetrics.widthPixels - (80F + 16F + 16F).dip2px()
height = imageWidth * 9 / 16
}
entity = imageEntity.image
var exposureEvent: ExposureEvent? = null
if (imageEntity.link.type == "game") {
exposureEvent = ExposureEvent.createEvent(
GameEntity(id = imageEntity.link.link),
listOf(mCatalogViewModel.basicExposureSource, ExposureSource("精选页图片", "")))
mExposureEventSparseArray.append(position, exposureEvent)
}
root.setOnClickListener {
DirectUtils.directToLinkPage(mContext, imageEntity.link, "新分类-精选分类", "图片", exposureEvent)
mCatalogViewModel.logSpecialCatalogContentClick("图片", imageEntity.image.title, mEntityList[position].position)
}
}
}
is CatalogHeaderItemHolder -> {
val entity = mEntityList[position].header!!
val specialLink = entity.link
holder.binding.run {
link = specialLink
headMore.setOnClickListener {
if (entity.type == "专题合集") {
DirectUtils.directToColumnCollection(mContext, specialLink.link
?: "", -1, "(游戏-专题:" + specialLink.text + "-全部)")
} else {
startSubjectActivity(mContext, specialLink.link, specialLink.text, false, "(游戏-专题:" + specialLink.text + "-全部)")
}
mCatalogViewModel.logSpecialCatalogContentClick(entity.type, specialLink.text
?: "", mEntityList[position].position)
}
}
}
is CatalogSubjectItemHolder -> {
val subject = mEntityList[position].subject!!
val exposureList = arrayListOf<ExposureEvent>()
for (game in subject.link.data) {
val exposureEvent = ExposureEvent.createEvent(game,
listOf(mCatalogViewModel.basicExposureSource, ExposureSource("精选页专题", subject.link.text ?: "")))
exposureList.add(exposureEvent)
game.exposureEvent = exposureEvent
game.subjectName = subject.link.text
}
mEntityList[position].exposureEventList = exposureList
holder.bindSubject(subject.link.data, mEntityList[position].position)
}
is CatalogSubjectCollectionItemHolder -> {
val subjectCollection = mEntityList[position].subjectCollection!!
for (subject in subjectCollection.link.data) {
subject.subjectName = subjectCollection.link.text
}
holder.bindSubjectCollection(subjectCollection.link.data, mEntityList[position].position)
}
is FooterViewHolder -> {
holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint)
}
}
}
override fun getItemViewType(position: Int): Int {
return if (position == itemCount - 1) {
ItemViewType.ITEM_FOOTER
} else {
val item = mEntityList[position]
when {
item.header != null -> TYPE_HEADER
item.bigImage != null -> TYPE_BIG_IMAGE
item.subject != null -> TYPE_SUBJECT
item.subjectCollection != null -> TYPE_SUBJECT_COLLECTION
else -> TYPE_SUBJECT_COLLECTION
}
}
}
override fun getEventByPosition(pos: Int): ExposureEvent? = mExposureEventSparseArray.get(pos)
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? = mEntityList[pos].exposureEventList
class CatalogImageItemHolder(val binding: CatalogImageItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
class CatalogHeaderItemHolder(val binding: CatalogHeaderItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
inner class CatalogSubjectItemHolder(val binding: CatalogSubjectItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bindSubject(gameList: List<GameEntity>, position: Int) {
binding.gameList.run {
var subjectAdapter = adapter
if (subjectAdapter is SpecialCatalogSubjectAdapter) {
subjectAdapter.checkResetData(gameList)
subjectAdapter.updatePosition(position)
return
}
subjectAdapter = SpecialCatalogSubjectAdapter(context, mCatalogViewModel, gameList).apply {
updatePosition(position)
}
layoutManager = GridLayoutManager(context, 3)
adapter = subjectAdapter
}
}
}
inner class CatalogSubjectCollectionItemHolder(val binding: CatalogSubjectCollectionItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bindSubjectCollection(subjectCollection: List<GameEntity>, position: Int) {
binding.subjectCollectionList.run {
var collectionAdapter = adapter
if (collectionAdapter is SpecialCatalogSubjectCollectionAdapter) {
collectionAdapter.checkResetData(subjectCollection)
collectionAdapter.updatePosition(position)
return
}
collectionAdapter = SpecialCatalogSubjectCollectionAdapter(context, mCatalogViewModel, subjectCollection).apply {
updatePosition(position)
}
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
adapter = collectionAdapter
}
}
}
companion object {
private const val TYPE_HEADER = 900
private const val TYPE_BIG_IMAGE = 901
private const val TYPE_SUBJECT = 902
private const val TYPE_SUBJECT_COLLECTION = 903
}
}

View File

@ -0,0 +1,45 @@
package com.gh.gamecenter.catalog
import android.graphics.Color
import android.os.Bundle
import android.view.View
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.EntranceUtils
import com.gh.common.util.viewModelProvider
import com.gh.common.util.viewModelProviderFromParent
import com.gh.gamecenter.baselist.ListFragment
class SpecialCatalogFragment : ListFragment<SpecialCatalogItemData, SpecialCatalogViewModel>() {
private var mCatalogId = ""
private var mAdapter: SpecialCatalogAdapter? = null
private lateinit var mCatalogViewModel: CatalogViewModel
private lateinit var mExposureListener: ExposureListener
override fun provideListViewModel() = viewModelProvider<SpecialCatalogViewModel>(SpecialCatalogViewModel.Factory(mCatalogId))
override fun provideListAdapter() = mAdapter ?: SpecialCatalogAdapter(requireContext(), mCatalogViewModel).apply {
mAdapter = this
mExposureListener = ExposureListener(this@SpecialCatalogFragment, this)
}
override fun getItemDecoration() = null
override fun onCreate(savedInstanceState: Bundle?) {
mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: ""
// 按理来说在这里获取不需要再传值给构造函数,但保守起见还是传了
mCatalogViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, ""))
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mListRv.setBackgroundColor(Color.WHITE)
mListRv.addOnScrollListener(mExposureListener)
}
}

View File

@ -0,0 +1,14 @@
package com.gh.gamecenter.catalog
import com.gh.common.exposure.ExposureEvent
import com.gh.gamecenter.entity.SpecialCatalogEntity
data class SpecialCatalogItemData(
val header: SpecialCatalogEntity? = null,
val bigImage: SpecialCatalogEntity? = null,
val subject: SpecialCatalogEntity? = null,
val subjectCollection: SpecialCatalogEntity? = null,
var position: Int = 0,
var exposureEventList: ArrayList<ExposureEvent>? = null
)

View File

@ -0,0 +1,82 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.dip2px
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.CatalogSubjectGameItemBinding
import com.gh.gamecenter.entity.GameEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class SpecialCatalogSubjectAdapter(context: Context,
private val mCatalogViewModel: CatalogViewModel,
private var mList: List<GameEntity>)
: BaseRecyclerAdapter<SpecialCatalogSubjectAdapter.CatalogSubjectGameItemViewHolder>(context) {
private val mEntrance = "精选分类"
private var countAndKey: Pair<Int, String>? = null
private var mPosition: Int = -1
init {
var dataIds = ""
mList.forEach {
dataIds += it.id
}
if (dataIds.isNotEmpty()) countAndKey = Pair(mList.size, dataIds)
}
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
= CatalogSubjectGameItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_game_item, parent, false))
override fun onBindViewHolder(holder: CatalogSubjectGameItemViewHolder, position: Int) {
holder.binding.run {
root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
topMargin = if (position > 2) 24F.dip2px() else 16F.dip2px()
}
val entity = mList[position]
game = entity
executePendingBindings()
if (!gameName.isSelected) {
gameName.postDelayed({ gameName.isSelected = true }, 500)
}
root.setOnClickListener {
GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(${mEntrance})", entity.exposureEvent)
mCatalogViewModel.logSpecialCatalogSpecificContentClick(
"专题",
game?.subjectName ?: "",
game?.name ?: "",
mPosition,
position)
}
}
}
fun checkResetData(update: List<GameEntity>) {
var dataIds = ""
mList.forEach { dataIds += it.id }
mList = update
if (countAndKey?.first == update.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变
notifyItemRangeChanged(0, itemCount)
} else if (countAndKey?.first != update.size) { // 数量发生改变
notifyDataSetChanged()
}
// 重新刷新数据标识
countAndKey = Pair(update.size, dataIds)
}
fun updatePosition(position: Int) {
mPosition = position
}
class CatalogSubjectGameItemViewHolder(val binding: CatalogSubjectGameItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,77 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.DirectUtils
import com.gh.common.util.ImageUtils
import com.gh.common.util.dip2px
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.CatalogSubjectCollectionListItemBinding
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.LinkEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class SpecialCatalogSubjectCollectionAdapter(context: Context,
private val mCatalogViewModel: CatalogViewModel,
private var mList: List<GameEntity>)
: BaseRecyclerAdapter<SpecialCatalogSubjectCollectionAdapter.CatalogSubjectCollectionListItemViewHolder>(context) {
private var countAndKey: Pair<Int, String>? = null
private var mPosition: Int = -1
init {
var dataIds = ""
mList.forEach {
dataIds += it.id
}
if (dataIds.isNotEmpty()) countAndKey = Pair(mList.size, dataIds)
}
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
= CatalogSubjectCollectionListItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_collection_list_item, parent, false))
override fun onBindViewHolder(holder: CatalogSubjectCollectionListItemViewHolder, position: Int) {
holder.binding.run {
root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
leftMargin = if (position == 0) 16F.dip2px() else 0
}
val entity = mList[position]
ImageUtils.display(subjectCollectionImage, entity.image)
root.setOnClickListener {
DirectUtils.directToLinkPage(mContext, LinkEntity(link = entity.link, type = entity.type), "精选分类", "专题合集")
mCatalogViewModel.logSpecialCatalogSpecificContentClick(
"专题合集",
entity.subjectName ?: "",
entity.name ?: "",
mPosition,
position)
}
}
}
fun checkResetData(update: List<GameEntity>) {
var dataIds = ""
mList.forEach { dataIds += it.id }
mList = update
if (countAndKey?.first == update.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变
notifyItemRangeChanged(0, itemCount)
} else if (countAndKey?.first != update.size) { // 数量发生改变
notifyDataSetChanged()
}
// 重新刷新数据标识
countAndKey = Pair(update.size, dataIds)
}
fun updatePosition(position: Int) {
mPosition = position
}
class CatalogSubjectCollectionListItemViewHolder(val binding: CatalogSubjectCollectionListItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,50 @@
package com.gh.gamecenter.catalog
import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.entity.SpecialCatalogEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.Observable
import io.reactivex.Single
class SpecialCatalogViewModel(application: Application, private val catalogId: String) : ListViewModel<SpecialCatalogEntity, SpecialCatalogItemData>(application) {
override fun provideDataObservable(page: Int): Observable<List<SpecialCatalogEntity>>? = null
override fun provideDataSingle(page: Int): Single<List<SpecialCatalogEntity>> {
return RetrofitManager.getInstance(getApplication())
.api
.getSpecialCatalogs(catalogId, page)
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { list ->
val itemDataList = arrayListOf<SpecialCatalogItemData>()
list.forEachIndexed { index, it ->
when (it.type) {
"图片" -> itemDataList.add(SpecialCatalogItemData(bigImage = it).apply { position = index })
"专题" -> {
itemDataList.add(SpecialCatalogItemData(header = it).apply { position = index })
itemDataList.add(SpecialCatalogItemData(subject = it).apply { position = index })
}
"专题合集" -> {
itemDataList.add(SpecialCatalogItemData(header = it).apply { position = index })
itemDataList.add(SpecialCatalogItemData(subjectCollection = it).apply { position = index })
}
}
}
mResultLiveData.postValue(itemDataList)
}
}
class Factory(private val catalogId: String) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return SpecialCatalogViewModel(HaloApp.getInstance().application, catalogId) as T
}
}
}

View File

@ -0,0 +1,43 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.DialogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.SubCatalogItemBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class SubCatalogAdapter(context: Context,
private val mCatalogViewModel: CatalogViewModel,
private val mPrimaryCatalog: CatalogEntity,
private var mList: List<CatalogEntity.SubCatalogEntity>)
: BaseRecyclerAdapter<SubCatalogAdapter.SubCatalogItemViewHolder>(context) {
private val mTypes = listOf("专题", "标签")
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
SubCatalogItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.sub_catalog_item, parent, false))
override fun onBindViewHolder(holder: SubCatalogItemViewHolder, position: Int) {
holder.binding.run {
val catalogEntity = mList[position]
entity = catalogEntity
executePendingBindings()
root.setOnClickListener {
mCatalogViewModel.logSubCatalogContentClick(catalogEntity.name, position)
if (mTypes.contains(catalogEntity.type)) {
root.context.startActivity(NewCatalogListActivity.getIntent(mContext, mCatalogViewModel.catalogTitle, catalogEntity.name, mPrimaryCatalog, catalogEntity.name))
} else {
DialogUtils.showLowVersionDialog(mContext)
}
}
}
}
class SubCatalogItemViewHolder(val binding: SubCatalogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,84 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.GridLayoutManager
import com.gh.common.util.EntranceUtils
import com.gh.common.util.viewModelProvider
import com.gh.common.util.viewModelProviderFromParent
import com.gh.gamecenter.databinding.FragmentSubCatalogBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.normal.NormalFragment
class SubCatalogFragment : NormalFragment() {
private lateinit var mBinding: FragmentSubCatalogBinding
private lateinit var mViewModel: SubCatalogViewModel
private lateinit var mCatalogViewModel: CatalogViewModel
private lateinit var mEntity: CatalogEntity
private var mCatalogId: String = ""
private var mPrimaryCatalogId: String = ""
override fun getLayoutId() = 0
override fun getInflatedLayout() = FragmentSubCatalogBinding.inflate(layoutInflater).apply { mBinding = this }.root
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: ""
mPrimaryCatalogId = arguments?.getString(EntranceUtils.KEY_PRIMARY_CATALOG_ID) ?: ""
mViewModel = viewModelProvider(SubCatalogViewModel.Factory(mCatalogId))
mCatalogViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, ""))
mViewModel.getSubCatalogs(mPrimaryCatalogId)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewModel.catalogs.observe(viewLifecycleOwner, Observer {
mBinding.run {
reuseLoading.root.visibility = View.GONE
if (it != null) {
reuseNoConnection.root.visibility = View.GONE
if (it.subCatalog.isNotEmpty()) {
rvSubCatalog.visibility = View.VISIBLE
reuseNoneData.root.visibility = View.GONE
mEntity = it
initView()
} else {
rvSubCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.VISIBLE
}
} else {
rvSubCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.VISIBLE
reuseNoConnection.root.setOnClickListener {
reuseLoading.root.visibility = View.VISIBLE
mViewModel.getSubCatalogs(mPrimaryCatalogId)
}
}
}
})
}
private fun initView() {
mEntity.run {
mBinding.rvSubCatalog.layoutManager = GridLayoutManager(requireContext(), 3)
mBinding.rvSubCatalog.adapter = SubCatalogAdapter(requireContext(), mCatalogViewModel, mEntity, subCatalog)
}
}
fun changeSubCatalog(primaryCatalogId: String) {
mBinding.run {
mPrimaryCatalogId = primaryCatalogId
rvSubCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.GONE
reuseLoading.root.visibility = View.VISIBLE
mViewModel.getSubCatalogs(mPrimaryCatalogId)
}
}
}

View File

@ -0,0 +1,44 @@
package com.gh.gamecenter.catalog
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class SubCatalogViewModel(application: Application, private val catalogId: String): AndroidViewModel(application) {
private val api = RetrofitManager.getInstance(getApplication()).api
var catalogs = MutableLiveData<CatalogEntity>()
@SuppressLint("CheckResult")
fun getSubCatalogs(primaryCatalogId: String) {
api.getSubCatalogs(catalogId, primaryCatalogId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<CatalogEntity>() {
override fun onSuccess(data: CatalogEntity) {
catalogs.postValue(data)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
catalogs.postValue(null)
}
})
}
class Factory(private val catalogId: String) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return SubCatalogViewModel(HaloApp.getInstance().application, catalogId) as T
}
}
}

View File

@ -4,7 +4,6 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.common.util.EntranceUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.NormalActivity
import com.gh.gamecenter.R

View File

@ -27,21 +27,16 @@ class NewCategoryHorizontalAdapter(context: Context,
override fun onBindViewHolder(holder: TagsViewHolder, position: Int) {
val categoryEntity = mCategoryList[position]
val gradientDrawable = GradientDrawable()
gradientDrawable.shape = GradientDrawable.RECTANGLE
if (mViewModel.selectedCategory.name == categoryEntity.name) {
gradientDrawable.setColor(ContextCompat.getColor(mContext, R.color.theme))
gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat()
holder.tagTv.background = ContextCompat.getDrawable(mContext, R.drawable.bg_tag_text)
holder.tagTv.setTextColor(Color.WHITE)
} else {
gradientDrawable.setColor(Color.WHITE)
gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat()
holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_3a3a3a))
holder.tagTv.background = null
holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_757575))
}
holder.tagTv.text = categoryEntity.name
holder.tagTv.background = gradientDrawable
holder.tagTv.setOnClickListener {
mViewModel.changeSelectedCategory(categoryEntity)
notifyDataSetChanged()

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