Compare commits

...

427 Commits

Author SHA1 Message Date
f826dc07c6 版本更新至 4.9.6 2021-06-08 10:23:08 +08:00
34670d08c0 Merge branch 'hotfix-v4.9.5-335-crash' into 'release'
Hotfix v4.9.5 335 crash

See merge request halo/android/assistant-android!113
2021-06-08 10:22:04 +08:00
5e5646468e 1. 捕抓分类2.0页面延迟操作造成的闪退异常
2. 修复首页滑动 tab 时偶发的闪退
3. 捕抓模拟器游戏延迟操作造成的闪退异常
4. 捕抓礼包详情页延迟操作造成的闪退异常
2021-06-08 10:22:04 +08:00
039203408a 版本更新至 4.9.5 2021-05-31 10:32:07 +08:00
60b325812e Merge branch 'hotfix-v4.9.4-334-crash' into 'release'
Hotfix v4.9.4 334 crash

See merge request halo/android/assistant-android!112
2021-05-31 10:29:00 +08:00
06a43f617b 处理闪退
1. 处理首页 tab 触摸时某些设备可能会闪退的问题
2. 修复游戏库刷新按钮被遮盖的问题
3. 尝试修复游戏库横向列表因恢复滚动状态而出现的闪退
4. 修复偶发的因为获取不到渠道号而触发的闪退
5. 尝试修复启动时偶发的初始化图片加载库触发的闪退
6. 修复 Android 11 首次安装 XAPK 获取权限回到页面时的闪退问题
2021-05-31 10:29:00 +08:00
85d3412fd8 版本更新到 4.9.4 2021-05-28 10:28:06 +08:00
71b8cbbef3 Merge branch 'hotfix-v4.9.3-333-crash' into 'release'
Hotfix v4.9.3 333 crash

See merge request halo/android/assistant-android!111
2021-05-28 10:26:50 +08:00
dfc0183a14 1. 处理包名检测弹窗上报日志的空指针闪退问题
2. 捕抓评论列表一键登录可能触发的闪退问题
3. 修复礼包详情页重建时的闪退问题
4. 修复视频流评论页页面重建时的闪退问题
2021-05-28 10:26:50 +08:00
156e52f619 版本升级到 4.9.3 2021-05-26 14:26:49 +08:00
252cb3825b Merge branch 'hotfix-v4.9.2-332-crash' into 'release'
Hotfix v4.9.2 332 crash

See merge request halo/android/assistant-android!110
2021-05-26 14:26:14 +08:00
075a7e4e77 处理专题详情滚到顶部空指针异常 2021-05-26 09:55:30 +08:00
0c95f911d1 捕抓插件化数据库读写异常 2021-05-26 09:43:40 +08:00
49b74c9a37 修复包名检测弹窗的重建闪退问题 2021-05-25 14:37:31 +08:00
c4240440d1 版本更新到 4.9.2 2021-05-25 10:56:09 +08:00
e0205ec060 Merge branch 'hotfix-v4.9.1-331-crash' into 'release'
修复闪退

See merge request halo/android/assistant-android!109
2021-05-25 10:55:35 +08:00
895024aa09 1. 修复启动时初始化图片加载库可能的闪退问题
2. 修复游戏详情最新开服可能的闪退问题
3. 修复在越南/法语设备上启动会闪退的问题
2021-05-25 10:53:47 +08:00
fd946703a9 版本更新至 4.9.1 2021-05-24 15:01:38 +08:00
806935a81e Merge branch 'hotfix-v4.9.0-330-privacy' into 'release'
4.9.0 隐私变更更改

See merge request halo/android/assistant-android!108
2021-05-24 14:59:14 +08:00
feb30ff3a4 1. 去掉 SYSTEM_ALERT_WINDOW 权限声明
2. 完成 https://git.ghzs.com/pm/halo-app-issues/-/issues/1262 的第32点
3. 取消 WorkManager 自动初始化,关闭 Sentry 读取系统事件能力
2021-05-24 14:59:14 +08:00
4b851732c9 正式包暂不启用 AndResGuard (旧版本在新AGP上默认启用 V3 签名,新版本在蓝叠模拟器上无法运行) 2021-05-19 16:53:51 +08:00
lyr
3abf29fa75 微调登录页UI 2021-05-19 15:57:21 +08:00
lyr
4bb7d2a043 光环助手V4.7.0-积分体系(第2期)--光能中心(0519 运营反馈 去掉签到提醒)https://git.ghzs.com/pm/halo-app-issues/-/issues/1110#note_101733 2021-05-19 15:34:23 +08:00
lyr
e3d830235e 微调登录页UI 2021-05-19 14:59:00 +08:00
lyr
6425f3d50c 光环助手V4.9.0-优化登录功能(第3期)(0518 运营反馈) https://git.ghzs.com/pm/halo-app-issues/-/issues/1206#note_101568 2021-05-19 11:11:47 +08:00
e9d2c6573f 完成同步正式环境后测试问题汇总(22) https://git.ghzs.com/pm/halo-app-issues/-/issues/1262 2021-05-18 15:02:26 +08:00
05e36f11cf 处理视频流闪退问题 2021-05-18 14:57:36 +08:00
lyr
bc76e6eddb 光环助手V4.9.0-同步正式环境后测试问题汇总(14、16) https://git.ghzs.com/pm/halo-app-issues/-/issues/1262#note_101438 2021-05-18 11:59:50 +08:00
lyr
6de543261b 修改"邀请好友"正式环境地址 2021-05-18 09:15:19 +08:00
lyr
d9a8fa0a2d 光环助手V4.9.0-个人主页优化(第2期)(0517 运营测试反馈) https://git.ghzs.com/pm/halo-app-issues/-/issues/1203#note_101240 2021-05-17 18:08:40 +08:00
lyr
51c88e8586 光环助手V4.9.0-优化登录功能(第3期)(0517 运营测试问题 1) 2021-05-17 17:10:12 +08:00
9e930f1b35 去掉游戏详情顶部区域自动隐藏时的动画 2021-05-17 15:34:15 +08:00
eb8fb191bb 修改视频流全屏后的显示错误问题 2021-05-17 14:27:37 +08:00
6653467259 完成首页顶部 tab 栏功能(20210517运营测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1215 2021-05-17 11:39:27 +08:00
9ec29ad367 修复因优化首页 tab 性能造成开服表页面的开测 tab 不显示的问题 2021-05-17 10:13:15 +08:00
406ac98616 激活数据上报里补充 oaid (若存在) 2021-05-15 15:12:52 +08:00
5832c75909 修复同步正式环境后测试问题汇总(5) https://git.ghzs.com/pm/halo-app-issues/-/issues/1262 2021-05-14 11:36:59 +08:00
9d8681c50f 光环助手V4.8.0-视频优化(第1期)(0514 运营测试问题3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1107 2021-05-14 10:47:47 +08:00
lyr
9c28bf162e 新分类2.0页-侧边栏关闭手势滑动 2021-05-14 09:37:54 +08:00
061d5c19ed 微调首页轮播图上边距 2021-05-13 17:38:50 +08:00
1241207dd2 处理首页 tab 无数据时的回落问题 2021-05-13 15:59:30 +08:00
lyr
702da08bc4 修复问题:在验证码登录页点击一键登录,然后授权电话权限后,无法弹起一键登录页 2021-05-12 18:58:18 +08:00
8c885e38a1 完成4月光环前端优化汇总(6) https://git.ghzs.com/pm/halo-app-issues/-/issues/1236 2021-05-12 11:50:34 +08:00
acc6935608 正式环境 API 切换到 4.9.0 2021-05-12 11:47:56 +08:00
lyr
62a87d1c71 完善是否能进行一键登录的判断 2021-05-10 09:34:15 +08:00
lyr
2ba479d3ca 光环助手V4.9.0-优化登录功能(第3期)(0507 补充运营意见--增加一键登录说明弹窗 遗漏部分) https://git.ghzs.com/pm/halo-app-issues/-/issues/1206#note_100061 2021-05-08 17:29:56 +08:00
lyr
3f5f3bf57c 光环助手V4.9.0-优化登录功能(第3期)(0507 补充运营意见--增加一键登录说明弹窗) https://git.ghzs.com/pm/halo-app-issues/-/issues/1206#note_100061 2021-05-08 15:55:42 +08:00
4d10ca0c6c Merge branch 'dev-4.9.0' into dev 2021-05-08 15:41:28 +08:00
c816fd87f4 Merge branch 'dev-4.9.0' into dev
# Conflicts:
#	app/src/main/res/layout/fragment_login.xml
2021-05-08 10:41:39 +08:00
lyr
547bfd98ac 个人主页-根据个人信息内容设置背景的高度 2021-05-07 11:02:37 +08:00
34ba85f099 修改网页链接全局添加from=ghzs参数 2021-05-06 15:17:00 +08:00
lyr
2d251ef453 调整"我的光环"和"个人主页"徽章标签的红点提示位置 2021-04-29 14:57:29 +08:00
lyr
d7c7fe8740 优化个人主页背景UI 2021-04-29 01:10:53 +08:00
295e783d4b Merge remote-tracking branch 'origin/dev-4.9.0' into dev-4.9.0 2021-04-28 23:56:57 +08:00
58dfad4123 调整实名认证解析 2021-04-28 23:56:47 +08:00
f31d8b51fa 修改礼包中心-关注tab游戏icon显示异常 2021-04-28 23:52:41 +08:00
lyr
01ea8b9834 光环助手V4.9.0-个人主页优化(第2期)(0427 产品测试问题 个人主页没有显示圆角问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1203 2021-04-28 22:51:31 +08:00
5152060515 调整实名认证结束时间判断 2021-04-28 22:32:42 +08:00
0a0d805e9d 完成防沉迷下载流程 https://git.ghzs.com/pm/halo-app-issues/-/issues/1218 2021-04-28 22:24:08 +08:00
51511c8be8 更换礼包是否被隐藏字段 2021-04-28 21:53:22 +08:00
4bbfa3e16e 修改推荐弹窗按钮点击范围 2021-04-28 21:50:30 +08:00
lyr
81c0c6ee09 Merge remote-tracking branch 'origin/dev-4.9.0' into dev-4.9.0 2021-04-28 20:48:38 +08:00
lyr
50b449ca64 光环助手V4.9.0-优化登录功能(第3期)(0428 产品测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1206#note_99487 2021-04-28 20:48:28 +08:00
8764412492 优化首页 tab 滑动性能 2021-04-28 20:30:31 +08:00
c1e011cae8 优化首页 tab 滑动性能 2021-04-28 20:29:36 +08:00
018f814a6b 更新渠道JAR 2021-04-28 20:01:54 +08:00
lyr
ef9cb24b61 个人主页的背景裁剪比例调整为1:1 2021-04-28 17:27:59 +08:00
245a4273de 完成光环前端优化汇总4月(1) https://git.ghzs.com/pm/halo-app-issues/-/issues/1236 2021-04-28 16:58:23 +08:00
lyr
94c1651510 一键登录增加错误码log 2021-04-28 16:38:07 +08:00
lyr
07f55acb3a 光环助手V4.9.0-积分体系(第4期)(0428 产品测试问题 2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1204#note_99369 2021-04-28 16:34:17 +08:00
lyr
43ee3b3488 一键登录未弹出授权页增加等待弹窗,以及防止多次点击 2021-04-28 16:33:00 +08:00
32625f59e0 Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-28 16:04:05 +08:00
e1e3aa5598 光环助手V4.9.0-游戏礼包功能优化汇总(0428测试1,3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1209 2021-04-28 16:03:58 +08:00
c5ff2cb5bd Merge remote-tracking branch 'origin/dev-4.9.0' into dev-4.9.0 2021-04-28 16:02:23 +08:00
acf02c99e7 完成首页顶部Tab栏功能(20210428测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1215 2021-04-28 16:02:14 +08:00
9a00999d9e 回退test_build.sh脚本 2021-04-28 15:41:42 +08:00
lyr
4c5b602a3b 光环助手V4.9.0-个人主页优化(第2期)(0427 产品测试问题) (0428 产品测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1203 2021-04-28 15:39:24 +08:00
cbde36f3bd 完成0420测试反馈 https://git.ghzs.com/pm/halo-app-issues/-/issues/1231 2021-04-28 15:01:39 +08:00
f4b6193a6b 处理潜在的 toast 内存泄漏问题 2021-04-28 14:32:04 +08:00
85a596766d Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-28 12:03:54 +08:00
785cfecf81 光环助手V4.9.0-游戏相关优化汇总(0428测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1211 2021-04-28 12:03:41 +08:00
0c8b98084a Merge remote-tracking branch 'origin/dev-4.9.0' into dev-4.9.0 2021-04-28 12:00:05 +08:00
87a6a3a539 游戏库接口添加版本号 2021-04-28 11:59:56 +08:00
lyr
6c50082de5 光环助手V4.9.0-个人主页优化(第2期)(20210427UI测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1203#note_99322 2021-04-28 11:57:43 +08:00
41195ec9d4 游戏库和搜索接口添加版本号 2021-04-28 11:49:28 +08:00
223646cf3d 更改专题的筛选字段为 tags 2021-04-28 11:06:47 +08:00
ab4bb79a32 首页接口补充版本信息 2021-04-28 10:16:28 +08:00
lyr
50b51e2f3c 光环助手V4.9.0-个人主页优化(第2期)(20210427UI测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1203#note_99322 2021-04-28 09:23:03 +08:00
lyr
1fef7d51d6 修复光能中心-兑换区-分类面板展开后缺失关闭图标问题 2021-04-28 09:15:44 +08:00
lyr
6546961f81 更新一键登录错误码提示 2021-04-27 19:10:36 +08:00
lyr
75e4f32840 光环助手V4.9.0-积分体系(第4期)(分类面板问题)https://git.ghzs.com/pm/halo-app-issues/-/issues/1204#note_99323 2021-04-27 19:01:33 +08:00
lyr
a3f3c95e19 优化:一键登录页跳转验证码登录页后,再登录成功后,增加销毁一键登录页的逻辑 2021-04-27 17:43:34 +08:00
lyr
508231d547 光环助手V4.9.0-注销功能优化(第2期)(0427 产品测试问题 1) https://git.ghzs.com/pm/halo-app-issues/-/issues/1207#note_99285 2021-04-27 17:40:44 +08:00
8649b98032 处理分类2.0在首页的显示问题 2021-04-27 17:25:57 +08:00
d35211262f 回退 AndResGuard 2021-04-27 16:37:10 +08:00
lyr
96a5838155 光环助手V4.9.0-积分体系(第4期)(ui反馈 图1)(0427 产品测试问题 1-4)https://git.ghzs.com/pm/halo-app-issues/-/issues/1204 2021-04-27 16:35:57 +08:00
fc21799288 完成首页顶部Tab栏功能(20210426测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1215 2021-04-27 16:17:25 +08:00
lyr
3e04d77d50 优化一键登录关闭授权页的逻辑 2021-04-27 15:35:15 +08:00
lyr
35f47e363a 光环助手V4.9.0-个人主页优化(第2期)(0426 产品测试问题) (0427 产品测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1203 2021-04-27 15:27:30 +08:00
lyr
019724e9c6 光环助手V4.9.0-优化登录功能(第3期)(0426 产品测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1206#note_99181 2021-04-27 14:56:57 +08:00
70f059b4de 微调礼包中心按钮UI 2021-04-27 11:59:53 +08:00
34cd63d36d Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-27 10:43:47 +08:00
033cf6b566 光环助手V4.9.0-游戏礼包功能优化汇总(0427补充1) https://git.ghzs.com/pm/halo-app-issues/-/issues/1209 2021-04-27 10:43:38 +08:00
513fc3be1c V4.9.0推荐弹窗功能:后台通知频率设置累计次数无效 https://jira.ghzs.com/browse/HALO-68 2021-04-27 10:43:00 +08:00
fd1273a092 更新 AndResGuard 修复在高版本 AGP 默认启用 V3 签名的问题 2021-04-27 10:25:55 +08:00
lyr
27a6f14d18 修复Jira问题63( V4.9.0 光能中心后台优化:APP端,抽奖乐园和兑换商品点击进入的页面搞反了) 2021-04-26 18:01:09 +08:00
000c7978fd 完成推荐入口优化及数据埋点(20210426测试问题2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1214 2021-04-26 17:41:35 +08:00
486c8f691c 修复自定义 tab 指示器在 tab 内容变小时会变形的问题 2021-04-26 17:39:30 +08:00
16450a7f8d 完成光环前端优化汇总(4,8) https://git.ghzs.com/pm/halo-app-issues/-/issues/1236 2021-04-26 17:30:50 +08:00
438e660449 Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-26 17:15:16 +08:00
b9bf4311cf 礼包中心-最新tab接口判断分页完毕条件改为10 2021-04-26 17:14:56 +08:00
lyr
75a324747c 光环助手V4.9.0-优化登录功能(第3期)(20210425UI测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1206#note_99017 2021-04-26 17:10:33 +08:00
04b579cda7 完成首页顶部Tab栏功能(20210426UI测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1215 2021-04-26 17:04:03 +08:00
5962a8cf08 光环助手V4.9.0-游戏礼包功能优化汇总(0425测试2,3,4,5,6,10,11,12,19) https://git.ghzs.com/pm/halo-app-issues/-/issues/1209 2021-04-26 16:53:52 +08:00
ea388a8e1b Merge remote-tracking branch 'origin/dev-4.9.0' into dev-4.9.0 2021-04-26 16:20:37 +08:00
8a98d6323a 完成合规问题前端优化汇总(5) https://git.ghzs.com/pm/halo-app-issues/-/issues/1219 2021-04-26 16:20:28 +08:00
lyr
1b67ff5d12 光环助手V4.9.0-个人主页优化(第2期)(20210426UI测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1203#note_99085 2021-04-26 16:13:54 +08:00
9ee0f65e02 完成推荐入口优化和数据埋点(20210426测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1214 2021-04-26 15:56:30 +08:00
557b6fee21 完成合规问题前端优化汇总(1~4) https://git.ghzs.com/pm/halo-app-issues/-/issues/1219 2021-04-26 15:52:34 +08:00
c90d6ec0dc 完成首页顶部Tab栏功能遗漏的曝光位置命名 https://git.ghzs.com/pm/halo-app-issues/-/issues/1215 2021-04-26 11:56:54 +08:00
lyr
8109aa58c9 光环助手V4.9.0-积分体系(第4期)UI反馈 https://git.ghzs.com/pm/halo-app-issues/-/issues/1204#note_98963 2021-04-26 09:50:38 +08:00
213e079e9d 修复首页排行榜切换 tab 时标题的闪烁问题 2021-04-26 09:20:49 +08:00
40e38e50b9 修复自滚动栏目的图标变形问题 2021-04-26 09:20:38 +08:00
b70e18af96 Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-25 19:13:11 +08:00
4c91f06d94 光环助手V4.9.0-游戏礼包功能优化汇总(20210425UI测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1209 2021-04-25 19:13:00 +08:00
199067cf8a 完成游戏相关优化汇总(0423测试 1,2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1211 2021-04-25 18:07:41 +08:00
fa01260f0b Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-25 17:40:57 +08:00
f8dac32bd6 光环助手V4.9.0-游戏相关优化汇总(20210425UI测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1211 2021-04-25 17:40:40 +08:00
d5641d437c 微调首页 tab 切换样式 2021-04-25 15:09:14 +08:00
lyr
c27f62e726 优化一键登录页逻辑 2021-04-25 14:33:04 +08:00
b98d4e6ec6 完成首页顶部Tab栏功能(20200423UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1215 2021-04-25 14:14:37 +08:00
a4e67cda91 光环助手V4.9.0-游戏相关优化汇总(0423测试5) https://git.ghzs.com/pm/halo-app-issues/-/issues/1211 2021-04-25 10:21:21 +08:00
ab3616f237 Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-23 17:34:59 +08:00
bd9032c659 光环助手V4.9.0-新增[推荐弹窗]功能(0423测试,回退代码) https://git.ghzs.com/pm/halo-app-issues/-/issues/1212 2021-04-23 17:34:50 +08:00
lyr
4ded8cbfc8 微调个人主页UI 2021-04-23 16:47:00 +08:00
5a14afa71e Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-23 16:02:42 +08:00
7736ef37e5 光环助手V4.9.0-新增[推荐弹窗]功能(0423测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1212 2021-04-23 16:02:35 +08:00
lyr
40adf1938e 提交漏传文件 2021-04-23 16:00:02 +08:00
lyr
7e1f821d7a 光环助手V4.9.0-个人主页优化(第2期)https://git.ghzs.com/pm/halo-app-issues/-/issues/1203 2021-04-23 15:42:31 +08:00
4f81996857 首页放弃 fragment 自动重建 2021-04-23 14:49:27 +08:00
328a559ef0 1.修改推荐弹窗显示规则 2.提前加载推荐弹窗数据 2021-04-23 11:42:51 +08:00
lyr
ee01512f84 光环助手V4.9.0-积分体系(第4期)(我的光环-二、收货信息) https://git.ghzs.com/pm/halo-app-issues/-/issues/1204 2021-04-22 18:41:16 +08:00
a366a87324 修复首页页面重建时选中 TAB 与重建前不一致的问题 2021-04-22 18:34:41 +08:00
3c7a1e2ae3 修复专题详情页面进入显示空白的问题 2021-04-22 18:23:08 +08:00
87c71882f5 完成光环前端优化汇总(3,5) https://git.ghzs.com/pm/halo-app-issues/-/issues/1236 2021-04-22 18:22:44 +08:00
7fa912bc0c 首页页面重建时复用 fm 重建的底部五个 tab,避免内存泄漏 2021-04-22 17:49:50 +08:00
lyr
27dc3f73ae 一键登录页适配底部导航栏 2021-04-22 17:44:48 +08:00
be630e39cd 光环助手V4.9.0-新增[推荐弹窗]功能(UI反馈) https://git.ghzs.com/pm/halo-app-issues/-/issues/1212 2021-04-22 17:06:21 +08:00
cded31298c Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-22 16:43:02 +08:00
54030fd1df 光环助手V4.9.0-包名检测弹窗优化汇总(ui反馈) https://git.ghzs.com/pm/halo-app-issues/-/issues/1210 2021-04-22 16:42:51 +08:00
lyr
98c1565dfb 首页和游戏库的"猜你喜欢"专题拆分成两个接口分别获取 2021-04-22 16:42:13 +08:00
d89c2d4a70 Merge branch 'feature-issues1209' into dev-4.9.0 2021-04-22 15:28:03 +08:00
0f11f6344f 光环助手V4.9.0-游戏礼包功能优化汇总(数据埋点) https://git.ghzs.com/pm/halo-app-issues/-/issues/1209 2021-04-22 15:27:11 +08:00
a25f265bd3 光环助手V4.9.0-游戏礼包功能优化汇总 https://git.ghzs.com/pm/halo-app-issues/-/issues/1209 2021-04-22 14:15:12 +08:00
68adc0ff23 首页页面重建时复用旧 fragment 2021-04-22 11:58:35 +08:00
ab5aa01ec5 避免首页第一个 tab 被默认选中 2021-04-22 11:58:07 +08:00
lyr
71e5f798d9 1.恢复首页的猜你喜欢专题
2.板块展示猜你喜欢专题增加是否为游戏库判断
2021-04-22 10:29:06 +08:00
2572c53305 修复首页 tab 快速滚动文字可能出现大小不一的问题 2021-04-21 18:29:19 +08:00
lyr
64b5ca8efa 首页去掉智能推荐专题(只在游戏库页展示) 2021-04-21 18:09:50 +08:00
b5ef73517f 完成游戏相关优化(3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1211 2021-04-21 17:53:24 +08:00
lyr
feb2f68778 完成 "推荐算法优化——猜你喜欢专题 第4(1)点" https://git.ghzs.com/pm/halo-app-issues/-/issues/1224 2021-04-21 16:45:57 +08:00
lyr
f0a6e79418 调整光能中心和光能屋UI 2021-04-21 16:43:36 +08:00
lyr
78699cc0e8 修复Jira问题48(V4.9.0-优化登录功能(第3期):无法打开登录界面) 2021-04-21 16:39:59 +08:00
96805537f4 基本完成首页顶部Tab栏功能 https://git.ghzs.com/pm/halo-app-issues/-/issues/1215 2021-04-21 10:19:50 +08:00
13c4be2ab0 处理 proguard 语法问题 2021-04-21 10:09:27 +08:00
lyr
c2e5e8adbc 光环助手V4.9.0-积分体系(第4期)(光能中心和光能屋UI改动) 2021-04-20 18:56:05 +08:00
c5c9a3f4d2 放弃所有 activity 重建的 config 2021-04-20 17:34:28 +08:00
8bd2fa9b3a 避免 MIUI 夜间模式切换时重建页面 2021-04-20 17:07:53 +08:00
lyr
4bd8fc4e51 1.优化光能任务悬浮图标显示逻辑
2.修复未登录状态下在光能中心登录后,刷新任务列表后列表可以无限加载问题
2021-04-19 19:02:23 +08:00
lyr
5b26165aaa 微调默认Toast样式 2021-04-19 18:55:45 +08:00
lyr
1bb4c1cc2c 光环助手V4.9.0-优化登录功能(第3期)https://git.ghzs.com/pm/halo-app-issues/-/issues/1206 2021-04-19 18:53:21 +08:00
d38b347eb8 Merge branch 'feature-issues1215' into 'dev-4.9.0'
Feature issues1215

See merge request halo/android/assistant-android!107
2021-04-19 18:15:13 +08:00
feaf2d0bfc 完成粗糙的首页顶部Tab栏功能(细节带完善) https://git.ghzs.com/pm/halo-app-issues/-/issues/1225 2021-04-19 18:15:13 +08:00
210dcdc698 设置app支持x86架构 2021-04-19 15:31:00 +08:00
fec291156a 【光环助手】论坛相关bug汇总(0413bug反馈) https://git.ghzs.com/pm/halo-app-issues/-/issues/1223 2021-04-19 11:43:03 +08:00
62bb23abc9 光环后台需求汇总(2021年4月第1周)(25) https://git.ghzs.com/pm/halo-app-issues/-/issues/1193 2021-04-19 11:41:22 +08:00
19be9e1842 支持获取上一个页面的名称 2021-04-16 17:00:31 +08:00
lyr
a5cfd147b4 微调登录页和光能中心UI 2021-04-16 16:53:37 +08:00
lyr
f15d572785 微调登录页和光能中心UI 2021-04-16 16:53:13 +08:00
5e99e8b032 光环助手V4.9.0-新增[推荐弹窗]功能(数据埋点) https://git.ghzs.com/pm/halo-app-issues/-/issues/1212 2021-04-16 15:26:53 +08:00
af39b82da1 Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-16 11:22:19 +08:00
ba3a4ede11 光环后台需求汇总(2021年4月第1周)(17) https://git.ghzs.com/pm/halo-app-issues/-/issues/1193 2021-04-16 11:20:40 +08:00
db591d0249 完成推荐入口优化及数据埋点 https://git.ghzs.com/pm/halo-app-issues/-/issues/1214 2021-04-16 10:25:01 +08:00
lyr
1370261b87 Merge remote-tracking branch 'origin/dev-4.9.0' into dev-4.9.0 2021-04-15 15:34:36 +08:00
lyr
3824de4719 微调登录页UI 2021-04-15 15:34:09 +08:00
lyr
6ee26fb401 微调登录页UI 2021-04-15 15:33:45 +08:00
865fe2729f Merge branch 'feature-issues1212' into dev-4.9.0 2021-04-15 15:28:20 +08:00
85c556c593 光环助手V4.9.0-新增[推荐弹窗]功能 https://git.ghzs.com/pm/halo-app-issues/-/issues/1212 2021-04-15 15:27:02 +08:00
86681b8ab1 修改包名检测弹窗进度条兼容性问题 2021-04-14 20:38:41 +08:00
5f2ce22506 完成游戏相关优化汇总(1) https://git.ghzs.com/pm/halo-app-issues/-/issues/1211 2021-04-14 16:41:53 +08:00
dafa85a791 光环助手V4.9.0-包名检测弹窗优化汇总 https://git.ghzs.com/pm/halo-app-issues/-/issues/1210 2021-04-14 11:18:21 +08:00
lyr
9cc3a29b5a 处理登录页面底部适配问题(有些手机在有导航栏情况下位置不够) 2021-04-13 18:35:34 +08:00
lyr
d2e8a67971 处理登录页面底部适配问题(有些手机在有导航栏情况下位置不够) 2021-04-13 18:30:56 +08:00
1bd3168add 1.修改关注视频流内容重叠问题
2.修改关注视频流刷新时上传缓存视频id
2021-04-13 15:58:43 +08:00
81d81882e0 Merge branch 'dev-4.9.0' of git.ghzs.com:halo/android/assistant-android into dev-4.9.0 2021-04-13 12:01:14 +08:00
3f4e4f1a52 光环助手V4.9.0-包名检测弹窗优化汇总(自定义进度条) https://git.ghzs.com/pm/halo-app-issues/-/issues/1210 2021-04-13 12:00:50 +08:00
3845e1f3ee 完成预约事件曝光位置上报优化 https://git.ghzs.com/pm/halo-app-issues/-/issues/1221 2021-04-12 18:09:06 +08:00
6d2ae4dca5 版本号更新至 4.9.0 2021-04-12 17:31:08 +08:00
e2efa26ac0 Merge branch 'dev' into dev-4.9.0 2021-04-12 17:24:57 +08:00
70e12ebd08 光环助手V4.9.0-游戏相关优化汇总(4) https://git.ghzs.com/pm/halo-app-issues/-/issues/1211 2021-04-12 11:13:33 +08:00
91fc511fe6 光环助手V4.9.0-新增[推荐弹窗]功能(UI部分) https://git.ghzs.com/pm/halo-app-issues/-/issues/1212 2021-04-12 09:11:36 +08:00
lyr
c5530ba307 完成组件库(第1期)测试问题(2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1162#note_96797 2021-04-09 10:38:03 +08:00
67cbd9b641 完成组件库(第1期)测试问题(3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1162 2021-04-09 09:45:31 +08:00
6735047e67 完成组件库(第1期)测试问题(1,4) https://git.ghzs.com/pm/halo-app-issues/-/issues/1162 2021-04-08 17:50:18 +08:00
9993bca582 处理UI组件库遗漏的细节部分(2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1162 2021-04-08 15:06:16 +08:00
07258b08af 临时处理 mapping_id 写入包文件失败的问题 https://github.com/getsentry/sentry-android-gradle-plugin/issues/37 2021-04-08 10:14:34 +08:00
lyr
f8bd7787f6 更新 Loghub SDK (https://git.ghzs.com/halo/assistant-android/-/issues/28) 2021-04-07 18:05:55 +08:00
b6a3ef5faa [ 光环助手 V4.9 - 游戏顶部视频 ] 光环助手APP,游戏详情页顶部视频全屏播放优化(https://git.ghzs.com/pm/halo-app-issues/-/issues/1213) 2021-04-07 15:28:08 +08:00
lyr
730151f6ba 补全新分类2.0列表曝光遗漏步骤 2021-04-06 17:51:56 +08:00
532b98e002 修复进入游戏详情页时快速点击 tab 栏可能触发闪退的问题 2021-04-06 10:51:37 +08:00
lyr
202a26b09c 光环助手V4.8.0-光环助手UI组件库(第1期)(9) https://git.ghzs.com/pm/halo-app-issues/-/issues/1162 2021-04-01 14:17:28 +08:00
lyr
fe1821884a 光环助手V4.8.0-光环助手UI组件库(第1期)(6,8) https://git.ghzs.com/pm/halo-app-issues/-/issues/1162 2021-04-01 11:52:00 +08:00
eb1605cc0a 调整搜索热门标签/历史搜索区域的高度,避免在 mumu 模拟器上被裁切 2021-03-31 17:34:11 +08:00
08ad5c3455 模拟器支持 FBN 类型 2021-03-31 17:13:21 +08:00
0774525de6 修复游戏详情预览图过于模糊的问题 2021-03-31 16:01:03 +08:00
b69ebc8122 完成游戏搜索功能优化(20210331测试问题 2,3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1173 2021-03-31 15:20:42 +08:00
lyr
49f31da303 光环助手V4.8.0-新分类功能2.0(前端)(20210330测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1171#note_95153 2021-03-31 14:50:55 +08:00
66568b09d5 完成开测表功能0331补充 https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-31 14:13:01 +08:00
57a944f954 取消限制历史搜索/热门标签文字长度限制 https://git.ghzs.com/pm/halo-app-issues/-/issues/1173 2021-03-31 12:00:31 +08:00
1fb8a60b2b 正式环境切换到 4.8.0 2021-03-31 09:34:46 +08:00
489a57a379 完成游戏功能搜索优化(20210330需求补充) https://git.ghzs.com/pm/halo-app-issues/-/issues/1173 2021-03-31 09:17:16 +08:00
0aa02c186c 恢复因为压缩影响质量的新版本提示图标 2021-03-30 14:59:25 +08:00
lyr
fd463ec1e3 光环助手V4.8.0-新分类功能2.0(前端)(20210330修改) https://git.ghzs.com/pm/halo-app-issues/-/issues/1171#note_95001 2021-03-30 14:54:43 +08:00
lyr
0c16ae5f3f 解决邀请好友过程中无法保存海报的问题 2021-03-30 14:40:37 +08:00
76cca46015 修复开测表测试问题 https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-29 22:55:39 +08:00
748cacce3f Merge branch 'dev' of git.ghzs.com:halo/assistant-android into dev 2021-03-29 22:47:23 +08:00
b47985d4ff 修改游戏搜索热门搜索图标 2021-03-29 22:47:20 +08:00
lyr
9e41bd2846 光环助手V4.8.0-新分类功能2.0(前端)(20210329测试问题 5) 2021-03-29 22:32:11 +08:00
0e4b18fc5d 修复开测表手动选择日期时与自动滚动时的冲突问题 2021-03-29 22:05:50 +08:00
lyr
5594a03cee 1.修复Jira HALO-46 问题;
2.光环助手V4.8.0-新分类功能2.0(前端)(20210329测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1171#note_94892
2021-03-29 21:59:01 +08:00
lyr
59ece3be49 光环助手V4.7.0-积分体系(第2期)--个人主页(头像挂件页面相关优化-UI测试内容2)https://git.ghzs.com/pm/halo-app-issues/-/issues/1112#note_94854 2021-03-29 21:22:16 +08:00
a7f77076a5 Merge remote-tracking branch 'origin/dev' into dev 2021-03-29 21:04:14 +08:00
6526d5b3ce 完成开测表功能(0329测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-29 21:04:07 +08:00
3a2f877d0c Merge branch 'dev' of git.ghzs.com:halo/assistant-android into dev 2021-03-29 21:00:51 +08:00
0d344e66a1 光环助手V4.8.0-游戏弹窗功能优化(0329测试) https://jira.ghzs.com/browse/HALO-1 2021-03-29 21:00:47 +08:00
d3de323c06 完成开测表功能(0329测试2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-29 20:54:34 +08:00
721d5acc1d 完成开测表功能0329测试 https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-29 18:33:15 +08:00
7069744191 完成隐私权限相关问题 https://git.ghzs.com/pm/halo-app-issues/-/issues/1192 2021-03-29 17:59:55 +08:00
lyr
b1f56d5dcd 提交遗漏资源文件 2021-03-29 17:42:07 +08:00
lyr
5aaa5bd076 光环助手V4.8.0-新分类功能2.0(前端)(20210329测试问题 1)、 (20210329UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1171#note_94764 2021-03-29 17:41:41 +08:00
lyr
7e74dee0eb 1.光环助手V4.7.0-积分体系(第2期)--光能中心(0329 产品验收问题)https://git.ghzs.com/pm/halo-app-issues/-/issues/1110#note_94783
2.光环助手V4.7.0-积分体系(第2期)--邀请好友(0329 产品验收回归)https://git.ghzs.com/pm/halo-app-issues/-/issues/1114#note_94794
2021-03-29 15:59:05 +08:00
45b8f7f82f 修复使用浏览器安装判断不准确的问题 2021-03-29 15:55:42 +08:00
7c9b8732e2 光环助手V4.8.0-游戏搜索功能优化(第7期)(0329UI补充调整) https://git.ghzs.com/pm/halo-app-issues/-/issues/1173 2021-03-29 15:24:08 +08:00
86ae96253b 去掉视频流引导动画 2021-03-29 15:11:39 +08:00
9dcc0b5587 Merge branch 'dev' of git.ghzs.com:halo/assistant-android into dev 2021-03-29 15:05:16 +08:00
9ceba793e8 修改搜索框背景 2021-03-29 15:05:13 +08:00
175cc55b75 修复开测表的备注信息上报问题 https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-29 15:03:37 +08:00
5486d1803f Merge branch 'dev' of git.ghzs.com:halo/assistant-android into dev 2021-03-29 14:51:32 +08:00
cb885f8b66 光环助手V4.8.0-游戏弹窗功能优化(0323测试2,3,4) https://jira.ghzs.com/browse/HALO-1 2021-03-29 14:51:27 +08:00
ab9f5cf7d8 完成光环助手UI组件库的2 https://git.ghzs.com/pm/halo-app-issues/-/issues/1162 2021-03-29 14:40:22 +08:00
7f4fafc637 Merge remote-tracking branch 'origin/dev' into dev 2021-03-29 12:01:17 +08:00
acccd2330d 修复游戏预览图过于模糊的问题 2021-03-29 12:01:00 +08:00
lyr
2745147e73 光环助手V4.7.0-积分体系(第2期)--邀请好友(0329 产品验收问题 1)https://git.ghzs.com/pm/halo-app-issues/-/issues/1114#note_94755 2021-03-29 12:00:56 +08:00
8fb0e3feaf 曝光数据添加区分浏览器安装字段,修复开测日志上报异常 2021-03-29 12:00:38 +08:00
lyr
335fa8ba39 1.调整新分类2.0UI;
2.修复新分类2.0若干显示bug
2021-03-29 11:47:52 +08:00
c739074057 修复通用列表分页刷新时偶发的闪退问题,捕抓首页游戏视频偶发的数组越界异常 2021-03-29 11:05:24 +08:00
a2569cf876 处理部分 4.7.4 遗留的空指针异常和数组越界异常 2021-03-29 10:39:11 +08:00
a81b0a1603 修复开测表游戏下载任务被删除缺没有及时更新的问题 2021-03-29 09:33:37 +08:00
lyr
76c20e4b82 修复新分类页面对象未初始化问题 2021-03-26 18:40:18 +08:00
lyr
4144cc2c4f 光环助手V4.7.0-积分体系(第2期)--光能中心(调整UI间距)https://git.ghzs.com/pm/halo-app-issues/-/issues/1110#note_94623 2021-03-26 18:24:23 +08:00
5465ff7731 Merge remote-tracking branch 'origin/dev' into dev 2021-03-26 18:05:32 +08:00
fc6dedb320 修复开测表游戏显示游戏标签时无法进行筛选的问题 2021-03-26 18:05:26 +08:00
lyr
a76b98f20c 1.光环助手V4.8.0-积分体系(第3期)--光能中心(0326 产品测试问题)https://git.ghzs.com/pm/halo-app-issues/-/issues/1146#note_94597
2.光环助手V4.7.0-积分体系(第2期)--邀请好友(0326 产品验收问题)https://git.ghzs.com/pm/halo-app-issues/-/issues/1114#note_94513
2021-03-26 17:59:07 +08:00
lyr
f05c0324fa 光环助手V4.8.0-新分类功能2.0(前端)(20210325UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1171#note_94296 2021-03-26 17:44:06 +08:00
606eb30d9f 修改图片上传超时时间20s,重试次数2次 2021-03-26 16:59:30 +08:00
aa41da022d 光环助手V4.8.0-多版本下载面板优化(第二期)(UI测试问题-5) https://git.ghzs.com/pm/halo-app-issues/-/issues/1157 2021-03-26 15:33:21 +08:00
b62d2c1b9e Merge branch 'dev' of git.ghzs.com:halo/assistant-android into dev 2021-03-26 15:24:26 +08:00
ba21543800 修改qa搜索icon 2021-03-26 15:24:21 +08:00
6f5b832a68 调整 R8 配置 2021-03-26 15:20:30 +08:00
eb4bbb9efa Merge remote-tracking branch 'origin/dev' into dev 2021-03-26 15:16:40 +08:00
233f91d2b9 修改热门搜索标签图片 2021-03-26 15:14:26 +08:00
1c51b2fe41 Merge branch 'release' into dev
# Conflicts:
#	dependencies.gradle
2021-03-26 15:09:26 +08:00
5123d7ff11 Merge branch 'dev-4.8.0' into dev
# Conflicts:
#	app/build.gradle
#	app/src/main/java/com/gh/common/util/PackageUtils.java
#	app/src/main/java/com/gh/gamecenter/catalog/CatalogFragment.kt
2021-03-26 15:01:57 +08:00
c20e06f2eb Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-26 14:55:51 +08:00
df55caa1f8 光环助手V4.8.0-游戏搜索功能优化(第7期)(20210326UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1173 2021-03-26 14:55:48 +08:00
lyr
61bdac3aa2 光环前端优化汇总(2021年2月)(UI测试问题)https://git.ghzs.com/pm/halo-app-issues/-/issues/1154#note_94518 2021-03-26 14:47:15 +08:00
d56dc53b06 完成开测表功能(0326AM UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-26 14:38:44 +08:00
18c02ad9c3 Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-26 14:25:17 +08:00
8a262532e1 光环助手V4.8.0-多版本下载面板优化(第二期)(0326AM) https://git.ghzs.com/pm/halo-app-issues/-/issues/1157 2021-03-26 14:25:13 +08:00
lyr
876d920251 光环助手V4.7.0-积分体系(第2期)--个人主页(头像挂件页面相关优化-UI内容 4)https://git.ghzs.com/pm/halo-app-issues/-/issues/1112#note_94511 2021-03-26 11:42:38 +08:00
1bad70a83f Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-26 10:44:46 +08:00
c04a1a5802 光环助手V4.8.0-Q&A管理优化需求(第二期)(0322测试3,6) https://jira.ghzs.com/browse/HALO-2 2021-03-26 10:44:41 +08:00
lyr
ea8c47a6d6 光环助手V4.8.0-积分体系(第3期)--光能中心(0325 产品测试问题)https://git.ghzs.com/pm/halo-app-issues/-/issues/1146#note_94377 2021-03-26 09:16:33 +08:00
53f3f48c4d 修复开测表(0325测试 4~7) https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-25 20:56:10 +08:00
lyr
706df0c22f 光环助手V4.8.0-新分类功能2.0(前端)20210325测试问题 第2点 2021-03-25 18:41:44 +08:00
lyr
74cee421f9 光环助手V4.8.0-新分类功能2.0(前端)20210325测试问题 https://git.ghzs.com/pm/halo-app-issues/-/issues/1171#note_94292 2021-03-25 18:05:48 +08:00
lyr
4b08fa56da 光环助手V4.7.0-积分体系(第2期)--消息文案梳理(新增 win_order_detail 中奖订单详情 (中奖订单详情)) https://git.ghzs.com/pm/halo-app-issues/-/issues/1113#note_94198 2021-03-25 15:50:53 +08:00
522f664f30 光环前端优化汇总(2021年2月)(0325补充1) https://git.ghzs.com/pm/halo-app-issues/-/issues/1154 2021-03-25 15:18:00 +08:00
87a92055a7 光环助手V4.8.0-模拟器游戏优化汇总(0325测试2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1159 2021-03-25 14:29:38 +08:00
f23aa496ae 关闭 testOnly,避免部分 vivo 设备装不了 debug 包 2021-03-25 11:33:07 +08:00
65d7322546 修复部分 vivo 设备上无法显示游戏图标圆角的问题 2021-03-25 11:32:24 +08:00
d9178f8538 调整浏览器安装提示文案 https://git.ghzs.com/pm/halo-app-issues/-/issues/1132 2021-03-25 11:18:31 +08:00
lyr
5de471d89a Merge remote-tracking branch 'origin/dev-4.8.0' into dev-4.8.0 2021-03-25 11:14:28 +08:00
lyr
63cc104e9f 光环助手V4.7.0-积分体系(第2期)--个人主页(头像挂件页面相关优化-UI内容)https://git.ghzs.com/pm/halo-app-issues/-/issues/1112#note_92945 2021-03-25 11:14:14 +08:00
f06ba9bf45 修复 XAPK 原文件后缀为 .apk.apk 时无法使用浏览器下载的问题 2021-03-25 11:11:31 +08:00
lyr
682d5a2cd4 增加判断网络状态的JS调用方法 2021-03-25 11:06:14 +08:00
76ce4e2f04 Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-25 10:15:25 +08:00
54221cc976 编辑帖子插入图片成功后取消滚动到底部位置 2021-03-25 10:15:22 +08:00
79ae36c51f 修复浏览器安装端口在部分 vivo 手机被占用的问题 2021-03-24 18:33:45 +08:00
lyr
335d6787a7 意见反馈页的反馈提交都需要先登录 2021-03-24 17:21:12 +08:00
lyr
2bf9c1e4d7 提交闪退类型反馈不需要登录 2021-03-24 16:21:33 +08:00
lyr
133635c495 光环助手V4.7.0-积分体系(第2期)--光能中心(0324 ui反馈)https://git.ghzs.com/pm/halo-app-issues/-/issues/1110#note_94065 2021-03-24 15:40:00 +08:00
2aaf6d8a9c 修复开测表测试问题(0324测试 3,4,5) https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-24 15:26:20 +08:00
f119f6751a Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-24 15:05:11 +08:00
18f964c167 光环助手V4.8.0-视频优化(第1期)(0324 产品验收问题1,2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1107 2021-03-24 15:05:07 +08:00
lyr
369275225e 光环助手V4.8.0-新分类功能2.0(前端)https://git.ghzs.com/pm/halo-app-issues/-/issues/1171 2021-03-24 14:23:22 +08:00
d80daf104f Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-24 10:08:16 +08:00
71c697d596 1.修改专区热门回答图片被裁剪的问题
2.修改游戏搜索求功能标签显示问题
2021-03-24 10:08:07 +08:00
lyr
169814d6a9 光环助手V4.7.0-积分体系(第2期)--邀请好友(V4.7.0-积分体系(第2期)--邀请好友-UI测试问题-4、0319 产品验收问题 第1点) 2021-03-23 18:36:20 +08:00
lyr
52cffde739 正式发布环境隐藏个人等级入口 2021-03-23 18:11:23 +08:00
lyr
11f84b69ac 正式发布环境隐藏光能签到入口、邀请码输入框、上报光能任务 2021-03-23 18:10:36 +08:00
2c3e03bd0f 完成2月光环前端优化(12) https://git.ghzs.com/pm/halo-app-issues/-/issues/1154 2021-03-23 16:57:31 +08:00
264e103395 修复预约列表曝光下载数据没有上报的问题 2021-03-23 16:48:54 +08:00
7f4d3ffe3e 完成开测表的数据埋点 https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-23 16:36:19 +08:00
79b7a15f7d 增加获取 activity 栈中顶部倒数第二个元素的方法 2021-03-23 16:27:00 +08:00
638dd4ad1d 对接上传图片新错误码 https://git.ghzs.com/pm/halo-app-issues/-/issues/1154 2021-03-23 14:48:51 +08:00
lyr
04f58e036b 光环助手V4.7.0-积分体系(第2期)--光能中心(0322 产品验收问题)https://git.ghzs.com/pm/halo-app-issues/-/issues/1110 2021-03-23 14:31:07 +08:00
6624868bfe Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-23 11:43:30 +08:00
2ff83b8cc5 光环助手V4.8.0-多版本下载面板优化(第二期)(UI测试问题-4) https://git.ghzs.com/pm/halo-app-issues/-/issues/1157 2021-03-23 11:43:26 +08:00
lyr
cab412ab70 优化插入日程和删除日程流程 2021-03-23 11:32:11 +08:00
1a83e64f3a 完成插件跳转意见反馈的相关需求 https://git.ghzs.com/pm/halo-app-issues/-/issues/1160 2021-03-23 10:40:47 +08:00
lyr
be76fb0526 消息推送新增"兑换商品"链接类型 2021-03-23 10:28:21 +08:00
lyr
5cc25482a9 1.消息推送新增链接类型;
2.积分体系埋点补充邀请好友结果埋点
2021-03-23 10:21:53 +08:00
c683e6786c Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-22 17:01:04 +08:00
5f182eeddb 光环前端优化汇总(2021年2月)(0322补充13) https://git.ghzs.com/pm/halo-app-issues/-/issues/1154 2021-03-22 17:01:01 +08:00
3e0979fabb 完成2月光环前端优化(3,8) https://git.ghzs.com/pm/halo-app-issues/-/issues/1154 2021-03-22 16:20:51 +08:00
lyr
13685ec605 光能助手V4.8.0-积分体系(第3期)--光能屋(0317 产品验收测试 第1点)https://git.ghzs.com/pm/halo-app-issues/-/issues/1147 2021-03-22 16:04:20 +08:00
4eac5ff61c Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-22 15:36:28 +08:00
98f0cf5fc0 光环助手V4.8.0-Q&A管理优化需求(第二期)(20210319UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1156 2021-03-22 15:36:24 +08:00
lyr
cb345f49eb 光环前端优化汇总(2021年2月)第5、11点 https://git.ghzs.com/pm/halo-app-issues/-/issues/1154 2021-03-22 15:26:20 +08:00
ef95be60f1 修改多版本下载错位问题 2021-03-22 14:46:33 +08:00
a85cfa47e2 光环前端优化汇总(2021年2月)(0320补充1) https://git.ghzs.com/pm/halo-app-issues/-/issues/1154 2021-03-22 14:42:47 +08:00
66123b0ae8 为 Application 异步初始化 Fresco 超时兜底 2021-03-22 10:37:07 +08:00
cdb660b884 Gradle Transform 切换到 Kotlin 实现 2021-03-19 16:27:24 +08:00
026e4f71de Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-19 16:20:56 +08:00
01ecde0425 光环助手V4.8.0-模拟器游戏优化汇总(0319测试1-5) https://git.ghzs.com/pm/halo-app-issues/-/issues/1159 2021-03-19 16:20:52 +08:00
lyr
f748fcbd48 光环助手V4.7.0-积分体系(第2期)--邀请好友 (0318 产品验收问题 第3点) https://git.ghzs.com/pm/halo-app-issues/-/issues/1114 2021-03-19 15:11:25 +08:00
65464eed3d 修复使用浏览器安装询问弹窗总是弹起的问题 2021-03-19 11:42:07 +08:00
6a5d8e915c 完成数据统计需求(曝光位置补充) https://git.ghzs.com/pm/halo-app-issues/-/issues/1174 2021-03-19 09:33:22 +08:00
5fde455bcd Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-19 09:18:25 +08:00
e1e257b1d8 光环助手V4.8.0-模拟器游戏优化汇总(ui测试反馈) https://git.ghzs.com/pm/halo-app-issues/-/issues/1159 2021-03-19 09:18:21 +08:00
7a87f8dc14 Merge branch 'feature-issues1134' into 'dev-4.8.0'
Feature issues1134

See merge request halo/assistant-android!106
2021-03-18 18:15:25 +08:00
3fe2b8ffcd 基本完成开测表功能 https://git.ghzs.com/pm/halo-app-issues/-/issues/1134 2021-03-18 18:15:25 +08:00
565b7b2c38 修改编辑帖子删除图片后无法点击发布按钮 2021-03-18 14:50:32 +08:00
b3bf9d862f 光环助手V4.8.0-多版本下载面板优化(第二期)(UI测试问题-3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1157 2021-03-18 11:18:52 +08:00
c6f5ef64d5 光环助手V4.8.0-视频优化(第1期)(UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1107 2021-03-18 10:13:24 +08:00
95b21b5bb5 光环助手V4.8.0-多版本下载面板优化(第二期)(UI测试问题-2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1157 2021-03-17 18:21:27 +08:00
0da331d109 Merge branches 'dev-4.8.0' and 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-17 16:08:18 +08:00
8c1f8833b1 光环前端优化汇总(2021年2月)(9) https://git.ghzs.com/pm/halo-app-issues/-/issues/1154 2021-03-17 16:08:11 +08:00
e53cd6dede 处理 R8 混淆造成的微信分享问题 2021-03-17 15:27:42 +08:00
fa27e172e4 Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-17 15:22:33 +08:00
544f5102ea 光环助手V4.8.0-游戏搜索功能优化(第7期)(4,5,6) https://git.ghzs.com/pm/halo-app-issues/-/issues/1173 2021-03-17 15:22:28 +08:00
lyr
5d6134f0dd 光环助手V4.8.0-积分体系(第3期https://git.ghzs.com/pm/halo-app-issues/-/issues/1146)--光能中心(0315 产品测试问题) 2021-03-17 14:12:09 +08:00
e0b951e043 Merge remote-tracking branch 'origin/dev-4.8.0' into dev-4.8.0 2021-03-17 11:18:59 +08:00
f2476c84c4 完成浏览器安装(0317补充) https://git.ghzs.com/pm/halo-app-issues/-/issues/1132 2021-03-17 11:18:51 +08:00
c186c32d47 包名检测弹窗进度条降低更新频率,防止卡顿 2021-03-17 09:45:46 +08:00
lyr
194f30650e 修改兑换商品地址错误导致web无法正常返回问题 2021-03-16 16:49:06 +08:00
a475b176b4 光环助手V4.8.0-模拟器游戏优化汇总(ui测试反馈) https://git.ghzs.com/pm/halo-app-issues/-/issues/1159 2021-03-16 15:27:26 +08:00
73cac4d39d 修改视频关注tab下拉刷新一直加载问题 2021-03-16 14:42:44 +08:00
93d0f30352 光环助手V4.8.0-多版本下载面板优化(第二期)(UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1157 2021-03-16 10:41:25 +08:00
98d30d1183 Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0
# Conflicts:
#	app/src/main/java/com/gh/common/util/EntranceUtils.java
2021-03-16 09:12:42 +08:00
b1d178f8df 光环前端优化汇总(2021年2月)(4) https://git.ghzs.com/pm/halo-app-issues/-/issues/1154 2021-03-16 09:11:45 +08:00
lyr
0550df7039 光环助手V4.8.0-积分体系(第3期)--我的光环(0315 产品测试问题)https://git.ghzs.com/pm/halo-app-issues/-/issues/1145 2021-03-15 16:37:57 +08:00
lyr
13c7b8ff1d 1.补充积分体系web入口地址;
2.增加客服跳转类型
2021-03-12 18:29:59 +08:00
d7b7633ffe 调整游戏详情提示文案 2021-03-12 12:00:19 +08:00
5e536db94e 修复使用浏览器下载功能在山寨机上的适配问题 2021-03-12 11:50:33 +08:00
55d8b6a866 Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-11 17:54:57 +08:00
a2a8610083 光环助手V4.8.0-光环助手UI组件库(第1期)(7) https://git.ghzs.com/pm/halo-app-issues/-/issues/1162 2021-03-11 17:54:53 +08:00
lyr
8d9f0adebe 修改web跳转头像挂件页方法,使用分类id来定位tab 2021-03-11 15:02:50 +08:00
lyr
e386994e4d 完成积分体系第3期:
1.光环助手V4.8.0-积分体系(第3期)--光能中心 pm/halo-app-issues#1146
2.光环助手V4.8.0-积分体系(第3期)--我的光环 一、光能明细 1、文案修改 pm/halo-app-issues#1145
3.光能助手V4.8.0-积分体系(第3期)--光能屋 四、光能明细,以及增加兑换商品、抽奖乐园入口
4.光能助手V4.8.0-积分体系埋点(第1期)- 安卓端埋点 pm/halo-app-issues#1149
5.增加web上报埋点、跳转头像挂件页的JS调用方法
2021-03-11 10:45:45 +08:00
fc5f1e9830 Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-11 10:25:45 +08:00
fd17eaea00 光环助手V4.8.0-光环助手UI组件库(第1期)(4,5) https://git.ghzs.com/pm/halo-app-issues/-/issues/1162 2021-03-11 10:25:11 +08:00
8a65d6dd85 关闭测试 mapping 上传 2021-03-11 09:09:41 +08:00
8d3c609ad0 getIndentifier 调用的资源添加到 AndResGuard 白名单 2021-03-11 09:08:54 +08:00
2e71e11a09 删除无用依赖 2021-03-11 09:07:18 +08:00
lyr
b9c17bcdb8 正式发布环境隐藏个人等级入口 2021-03-10 18:53:59 +08:00
55bb1a1873 Merge branch 'feature-issues1156' into dev-4.8.0 2021-03-10 14:47:21 +08:00
54601bc083 光环助手V4.8.0-Q&A管理优化需求(第二期)https://git.ghzs.com/pm/halo-app-issues/-/issues/1156 2021-03-10 14:45:36 +08:00
df2bb9c020 完成浏览器安装(数据埋点) https://git.ghzs.com/pm/halo-app-issues/-/issues/1132 2021-03-09 17:54:06 +08:00
0bf297d094 Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-09 15:03:27 +08:00
db8a2a06aa 光环助手V4.8.0-多版本下载面板优化(第二期)(UI相关补充0309AM) https://git.ghzs.com/pm/halo-app-issues/-/issues/1157 2021-03-09 15:03:23 +08:00
44a9db7294 使用滴滴的SP优化和系统异常捕抓等插件,将插件整体搬迁至 gradle init 文件中提高开发编译速度 2021-03-09 14:45:25 +08:00
7db48b6923 Merge branch 'feature-issues1158' into dev-4.8.0 2021-03-09 11:08:12 +08:00
0a8f2d51db 光环助手V4.8.0-游戏弹窗功能优化 https://git.ghzs.com/pm/halo-app-issues/-/issues/1158 2021-03-09 11:06:20 +08:00
b06d2a479a 版本更新至 4.7.4 2021-03-09 10:56:25 +08:00
d56bd0078e Merge branch 'hotfix-4.7.3-293_crash' into 'release'
修复闪退

See merge request halo/assistant-android!105
2021-03-09 10:55:22 +08:00
7b87aadd86 修复首页列表对比差异时偶发的数组越界闪退 2021-03-08 17:26:02 +08:00
8f2da187f2 Revert "主 SP 迁移到 MMKV",原因是存储空间不足时有各种奇怪的问题 2021-03-08 15:50:44 +08:00
8291caa5e3 主 SP 迁移到 MMKV 2021-03-08 15:15:04 +08:00
e30ec540bd Merge branch 'feature-issues1157' into dev-4.8.0 2021-03-08 10:02:51 +08:00
3c4da21bf6 光环助手V4.8.0-多版本下载面板优化(第二期)(埋点) https://git.ghzs.com/pm/halo-app-issues/-/issues/1157 2021-03-08 10:02:00 +08:00
lyr
800260b6a4 光环前端优化汇总(2021年2月)第1、2、6、7点 https://git.ghzs.com/pm/halo-app-issues/-/issues/1154 2021-03-05 18:23:51 +08:00
lyr
ddea202f85 Merge remote-tracking branch 'origin/dev-4.8.0' into dev-4.8.0 2021-03-05 18:17:40 +08:00
lyr
b3a786ee22 光环助手V4.8.0-xapk解压过程助手卡顿问题 https://git.ghzs.com/pm/halo-app-issues/-/issues/1155 2021-03-05 18:17:21 +08:00
332e24b874 jenkins 打包测试 mapping 上传 2021-03-05 18:16:12 +08:00
5413ebfba4 更改活跃统计的上报的 logstore https://git.ghzs.com/pm/halo-app-issues/-/issues/1115 2021-03-05 18:08:44 +08:00
7ead1c89f3 Merge branch 'dev-4.8.0' of git.ghzs.com:halo/assistant-android into dev-4.8.0 2021-03-05 17:34:13 +08:00
03300a41f7 缺省渠道改为 GH_TEST2 2021-03-05 17:33:35 +08:00
2d8698e070 缺省渠道改为 GH_TEST2 2021-03-05 17:32:48 +08:00
078b1a18a0 Merge branch 'feature-issues1159' into dev-4.8.0
# Conflicts:
#	app/src/main/java/com/gh/common/constant/Constants.java
#	app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt
2021-03-05 16:57:42 +08:00
de1e3ba7a7 Merge branch 'feature-issues1107' into dev-4.8.0
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/MainActivity.java
2021-03-05 16:54:39 +08:00
a9275c83d2 光环助手V4.8.0-视频优化(第1期)https://git.ghzs.com/pm/halo-app-issues/-/issues/1107 2021-03-05 16:52:21 +08:00
1a5a4ba149 完成UI组件化-常规弹窗 https://git.ghzs.com/pm/halo-app-issues/-/issues/1162 2021-03-04 14:56:23 +08:00
9bdae33655 更新大图查看库 2021-03-04 09:59:34 +08:00
be1184583b Merge branch 'feature-browser_install' into dev-4.8.0
# Conflicts:
#	app/src/main/java/com/gh/common/constant/Constants.java
2021-03-03 18:32:05 +08:00
68ee926897 基本完成使用浏览器下载功能,埋点细节待补充 https://git.ghzs.com/pm/halo-app-issues/-/issues/1132 2021-03-03 18:30:14 +08:00
4d0db8cbcc Merge branch 'dev-4.8.0' into feature-issues1159 2021-03-03 14:42:57 +08:00
59e4b6e063 光环助手V4.8.0-多版本下载面板优化(第二期)https://git.ghzs.com/pm/halo-app-issues/-/issues/1157 2021-03-03 14:35:36 +08:00
811b1bbfce 修复下载完成时可能出现多个完成事件的问题 2021-03-03 10:41:02 +08:00
00c25d0d47 缺省渠道改为 test2 2021-03-03 10:39:52 +08:00
795af0528f 调整 jenkins 打包脚本 2021-03-02 10:56:20 +08:00
d0b4ea8ec2 修复 base64 图片保存被覆盖问题 https://git.ghzs.com/pm/web-issues/-/issues/123 2021-03-02 10:02:08 +08:00
45861dff61 光环助手V4.8.0-模拟器游戏优化汇总 https://git.ghzs.com/pm/halo-app-issues/-/issues/1159 2021-03-02 09:21:33 +08:00
5f41463fc3 启用插件内联 access 2021-03-01 16:04:23 +08:00
89cca6dbfd 更新编译脚本 2021-03-01 15:35:06 +08:00
e43c0efdcb 版本号更改为 4.8.0 2021-03-01 15:34:40 +08:00
2dbd635b8e Merge branch 'feature-shrink_size' into 'dev-4.8.0'
引入微信的资源优化和头条的 dex 优化插件

See merge request halo/assistant-android!100
2021-03-01 15:20:07 +08:00
728d4fd8e1 引入微信的资源优化和头条的 dex 优化插件 2021-03-01 15:19:17 +08:00
48b5c7efc1 光环助手V4.8.0-多版本下载面板优化(第二期)https://git.ghzs.com/pm/halo-app-issues/-/issues/1157 2021-03-01 10:05:35 +08:00
4f6969a70a 完成粗糙的使用浏览器下载功能,接口与UI细节待补充 https://git.ghzs.com/pm/halo-app-issues/-/issues/1132 2021-02-26 16:48:16 +08:00
lyr
29140b6c0b 添加日程前增加是否已经添加判断 2021-02-26 16:34:53 +08:00
lyr
11bd9bed95 任务管理 - 【前端】任务列表,新增常驻任务类型,UI沿用日常任务 https://git.ghzs.com/pm/halo-app-issues/-/issues/1121#note_87359 2021-02-26 11:45:01 +08:00
997b5676dc 修改数据库升级错误 2021-02-26 09:46:22 +08:00
lyr
9b8755e035 光环助手V4.7.0-积分体系(第2期)--个人主页 - 0224产品测试问题-2(1) 2021-02-26 09:22:24 +08:00
0ea7c81ce9 光环助手V4.8.0-模拟器游戏优化汇总 https://git.ghzs.com/pm/halo-app-issues/-/issues/1159 2021-02-25 15:27:09 +08:00
a550305947 Merge branch 'feature-tracker' into 'dev-4.8.0'
Merge feature tracker

See merge request halo/assistant-android!97
2021-02-24 11:49:45 +08:00
3af4dd5494 完成页面/应用可见上报功能 https://git.ghzs.com/pm/halo-app-issues/-/issues/1115 2021-02-24 11:49:45 +08:00
1120 changed files with 20635 additions and 23538 deletions

View File

@ -2,24 +2,20 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' // kotlin
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: "com.gh.gamecenter.plugin"
//apply plugin: 'io.sentry.android.gradle'
apply plugin: 'AndResGuard'
import groovy.xml.XmlUtil
//apply from: 'tinker-support.gradle'
android {
androidExtensions {
experimental = true
}
dataBinding {
enabled = true
}
viewBinding {
enabled = true
buildFeatures {
viewBinding = true
dataBinding = true
}
compileOptions {
@ -50,7 +46,7 @@ android {
}
ndk {
abiFilters "armeabi-v7a"
abiFilters "armeabi-v7a", "x86"
}
renderscriptTargetApi 18
@ -65,7 +61,7 @@ android {
versionName rootProject.ext.versionName
applicationId rootProject.ext.applicationId
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-legacy.txt', 'proguard-fresco.txt'
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
/**
* All third-party appid/appkey
@ -80,6 +76,8 @@ android {
buildConfigField "String", "TTAD_APPID", "\"${TTAD_APPID}\""
buildConfigField "String", "DOUYIN_CLIENTKEY", "\"${DOUYIN_CLIENTKEY}\""
buildConfigField "String", "DOUYIN_CLIENTSECRET", "\"${DOUYIN_CLIENTSECRET}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
@ -187,7 +185,7 @@ android {
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
manifestPlaceholders.put("APPLOG_SCHEME","rangersapplog.byAx6uYt".toLowerCase())
manifestPlaceholders.put("APPLOG_SCHEME", "rangersapplog.byAx6uYt".toLowerCase())
}
gdt {
@ -334,18 +332,18 @@ dependencies {
// plugin 需要字符串,故不能用值
implementation "io.sentry:sentry-android:3.2.0"
// implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
implementation("com.github.nichbar.BigImageViewer:BigImageViewer:$bigImageViewer", {
implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
exclude group: 'com.squareup.okhttp3'
exclude group: 'androidx.swiperefreshlayout'
exclude group: 'com.github.bumptech.glide'
exclude group: 'com.facebook.fresco'
})
implementation "com.github.nichbar.BigImageViewer:FrescoImageLoader:$bigImageViewer"
implementation "com.github.nichbar.BigImageViewer:FrescoImageViewFactory:$bigImageViewer"
implementation "com.github.PhilJay:MPAndroidChart:${chart}"
implementation "com.github.hsiafan:apk-parser:$apkParser"
implementation "org.nanohttpd:nanohttpd:$nanohttpd"
implementation "com.aliyun.openservices:aliyun-log-android-sdk:$aliyunLog"
implementation project(':libraries:LGLibrary')
// implementation project(':libraries:MTA')
@ -413,6 +411,72 @@ if (propFile.exists()) {
// }.each { t -> t.dependsOn generateMetaJson }
//}
andResGuard {
mappingFile = null
use7zip = true
useSign = true
// 打开这个开关会keep住所有资源的原始路径只混淆资源的名字
keepRoot = false
// 设置这个值会把arsc name列混淆成相同的名字减少string常量池的大小
fixedResName = "arg"
// 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源
mergeDuplicatedRes = true
whiteList = [
"R.drawable.icon",
"R.drawable.bg_notification_answer_style_1",
"R.drawable.bg_notification_answer_style_2",
"R.drawable.bg_notification_article_style_1",
"R.drawable.bg_notification_article_style_2",
"R.drawable.bg_notification_feedback_style_1",
"R.drawable.bg_notification_feedback_style_2",
"R.drawable.bg_notification_gift_style_1",
"R.drawable.bg_notification_gift_style_2",
"R.drawable.bg_notification_login_style_1",
"R.drawable.bg_notification_login_style_2",
"R.drawable.bg_notification_question_style_1",
"R.drawable.bg_notification_question_style_2",
"R.drawable.bg_notification_rating_style_1",
"R.drawable.bg_notification_rating_style_2",
"R.drawable.bg_notification_reserve_game_style_1",
"R.drawable.bg_notification_reserve_game_style_2",
"R.drawable.bg_notification_video_style_1",
"R.drawable.bg_notification_video_style_2",
"R.drawable.ic_search_no_1",
"R.drawable.ic_search_no_2",
"R.drawable.ic_search_no_3",
"R.drawable.ic_search_no_4",
"R.drawable.ic_search_no_5",
"R.drawable.ic_search_no_6",
"R.drawable.ic_search_no_7",
"R.drawable.ic_search_no_8",
"R.drawable.ic_search_no_9",
"R.drawable.ic_search_no_10",
"R.drawable.ic_search_no_11",
"R.drawable.ic_search_no_12",
"R.drawable.ic_search_no_13",
"R.drawable.ic_search_no_14",
"R.drawable.ic_search_no_15",
"R.drawable.ic_search_no_16",
"R.drawable.ic_search_no_17",
"R.drawable.ic_search_no_18",
"R.drawable.ic_search_no_19",
"R.drawable.ic_search_no_20",
"R.drawable.login_btn_bg",
"R.drawable.ic_quick_login_check",
"R.drawable.ic_quick_login_uncheck",
"R.anim.anim_auth_in",
"R.anim.anim_auth_out",
]
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
]
sevenzip {
artifact = 'com.tencent.mm:SevenZip:1.2.20'
}
}
project.afterEvaluate {
def variants = null
@ -444,36 +508,46 @@ project.afterEvaluate {
if (manifestFile == null || !manifestFile.exists()) {
return
}
String[] configChanges = [
"density",
"fontScale",
"keyboard",
"keyboardHidden",
"layoutDirection",
"locale",
"mcc",
"mnc",
"navigation",
"orientation",
"screenLayout",
"screenSize",
"smallestScreenSize",
"touchscreen",
"uiMode"]
def parser = new XmlSlurper(false, true)
def manifest = parser.parse(manifestFile)
def app = manifest.'application'[0]
app.'activity'.each { act ->
String value = act.attributes()['android:configChanges']
if (value == null || value.isEmpty()) {
value = "keyboardHidden|orientation|screenSize|screenLayout|density|fontScale|locale"
if (value == null) value = ""
configChanges.eachWithIndex { config, index ->
if (index != configChanges.length - 1) {
value += config + "|"
} else {
value += config
}
}
act.attributes()['androidconfigChanges'] = value
} else {
String[] valueSplit = value.split("\\|")
if (!valueSplit.contains("keyboardHidden")) {
value += "|keyboardHidden"
}
if (!valueSplit.contains("orientation")) {
value += "|orientation"
}
if (!valueSplit.contains("screenSize")) {
value += "|screenSize"
}
if (!valueSplit.contains("screenLayout")) {
value += "|screenLayout"
}
if (!valueSplit.contains("density")) {
value += "|density"
}
if (!valueSplit.contains("fontScale")) {
value += "|fontScale"
}
if (!valueSplit.contains("locale")) {
value += "|locale"
println configChanges
configChanges.eachWithIndex { config, index ->
if (!valueSplit.contains(config)) {
value += ("|" + config)
}
}
act.attributes()['android:configChanges'] = value
}

Binary file not shown.

View File

@ -55,6 +55,10 @@
-dontwarn android.webkit.WebView
-dontwarn android.webkit.WebViewClient
### wechatSdk
### TODO 这里用 com.tencent.*{*;} 不起效?但其它地方可以?
-keep class com.tencent.**{*;}
### app models
-keep class com.gh.common.view.* {*;}
-keep class com.gh.gamecenter.db.info.* {*;}
@ -87,22 +91,6 @@
@androidx.annotation.Keep *;
}
### LoghubHelper
-keep class com.gh.loghub.* { *; }
### greenDAO 3
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties { *; }
-keep class org.greenrobot.greendao.* { *; }
# If you do not use SQLCipher:
-dontwarn org.greenrobot.greendao.database.**
### fastJson
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.* { *; }
### 广点通
-dontwarn com.qq.gdt.action.**
-keep class com.qq.gdt.action.* {*;}
@ -135,4 +123,12 @@
### GDT & TEA
-keep class com.gh.gamecenter.GdtHelper { *; }
-keep class com.gh.gamecenter.TeaHelper { *; }
-keep class com.gh.gamecenter.TeaHelper { *; }
### 阿里云日志
-keep class com.aliyun.sls.android.producer.* { *; }
-keep interface com.aliyun.sls.android.producer.* { *; }
### 中国移动一键登录
-dontwarn com.cmic.sso.sdk.**
-keep class com.cmic.sso.sdk.* { *; }

View File

@ -21,14 +21,10 @@
<uses-permission android:name="android.permission.VIBRATE" />
<!-- 允许应用程序改变Wi-Fi连接状态 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 允许应用程序打开系统窗口,显示其他应用程序 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 允许应用程序改变网络连接状态 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!-- 允许应用程序快捷方式 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- 允许应用程序读取日历-->
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<!-- 允许应用程序写入日历-->
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
@ -76,6 +72,7 @@
android:largeHeap="true"
android:resizeableActivity="true"
android:theme="@style/AppCompatTheme.APP"
android:networkSecurityConfig="@xml/network_security_config"
tools:replace="android:allowBackup"
tools:targetApi="n">
@ -83,6 +80,11 @@
android:name="io.sentry.auto-init"
android:value="false" />
<!-- 不让 sentry 读取系统事件 -->
<meta-data
android:name="io.sentry.breadcrumbs.system-events"
android:value="false" />
<!--android:launchMode = "singleTask"-->
<activity
android:name="com.gh.gamecenter.SplashScreenActivity"
@ -609,7 +611,8 @@
<activity
android:name=".energy.EnergyCenterActivity"
android:screenOrientation="portrait" />
android:screenOrientation="portrait"
android:launchMode="singleTask" />
<activity
android:name=".energy.EnergyHouseActivity"
@ -623,6 +626,27 @@
android:name=".qa.questions.draft.QuestionDraftActivity"
android:screenOrientation="portrait" />
<activity
android:name=".servers.GameServerTestActivity"
android:screenOrientation="portrait" />
<activity
android:name=".category2.CategoryV2Activity"
android:screenOrientation="portrait" />
<activity
android:name=".personal.DeliveryInfoActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.cmic.sso.sdk.activity.LoginAuthActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@android:style/Theme.Dialog"
android:screenOrientation="portrait"
android:launchMode="singleTop">
</activity>
<activity
android:name=".home.skip.PackageSkipActivity"
android:screenOrientation="portrait" />
@ -678,6 +702,11 @@
android:resource="@xml/provider_paths" />
</provider>
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
<receiver
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
android:exported="false">

View File

@ -1,9 +1,11 @@
package com.gh.base;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@ -13,6 +15,7 @@ import android.os.TransactionTooLargeException;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
@ -27,12 +30,16 @@ import androidx.lifecycle.Lifecycle;
import com.gh.base.fragment.BaseFragment;
import com.gh.common.constant.Constants;
import com.gh.common.tracker.IBusiness;
import com.gh.common.util.DialogHelper;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.ExtensionsKt;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.QuickLoginHelper;
import com.gh.common.util.RunningUtils;
import com.gh.common.util.SPUtils;
import com.gh.common.util.ShareUtils;
@ -42,11 +49,12 @@ import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.LoginActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SplashScreenActivity;
import com.gh.gamecenter.energy.EnergyCenterActivity;
import com.gh.gamecenter.eventbus.EBShowDialog;
import com.halo.assistant.HaloApp;
import com.lightgame.BaseAppCompatActivity;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Util_System_Keyboard;
import com.lightgame.utils.Utils;
import com.tencent.tauth.Tencent;
@ -59,6 +67,7 @@ import java.lang.ref.WeakReference;
import java.util.List;
import butterknife.ButterKnife;
import kotlin.Pair;
import pub.devrel.easypermissions.EasyPermissions;
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
@ -69,12 +78,13 @@ import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
* 需要工具栏的页面请继承{@link ToolBarActivity}
*/
public abstract class BaseActivity extends BaseAppCompatActivity implements EasyPermissions.PermissionCallbacks {
public abstract class BaseActivity extends BaseAppCompatActivity implements EasyPermissions.PermissionCallbacks, IBusiness {
// global dialog key
public final static String DOWNLOAD_HIJACK = "hijack";
public final static String LOGIN_EXCEPTION = "loginException";
public final static String PLUGGABLE = "plugin";
public final static String SIGNATURE_CONFLICT = "signature_conflict";
public final static int ID_ROOT_INDICATOR = 999;
public final int MAX_BUNDLE_SIZE = 300;
@ -82,6 +92,10 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
protected String mEntrance;
private boolean mIsExistLogoutDialog;
private boolean mHasAddTaskFloat = false;
private View mTaskBackView;
private WindowManager mWM;
private WindowManager.LayoutParams mWmParams;
protected final Handler mBaseHandler = new BaseHandler(this);
@ -144,11 +158,17 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
}
if (this.getClass().getName().equals(xapkUnzipActivity) && !TextUtils.isEmpty(xapkUrl)) {
DownloadEntity downloadEntity = DownloadManager.getInstance(this).getDownloadEntityByUrl(xapkUrl);
PackageInstaller.install(this, downloadEntity, false);
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
SPUtils.setString(Constants.SP_XAPK_URL, "");
if (downloadEntity != null) {
PackageInstaller.install(this, downloadEntity, false);
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
SPUtils.setString(Constants.SP_XAPK_URL, "");
}
}
}
if (this.getClass().getName().equals(EnergyCenterActivity.class.getName())) {
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
}
}
@SuppressWarnings("ConstantConditions")
@ -244,13 +264,19 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
if (DOWNLOAD_HIJACK.equals(showDialog.getType())) {
DialogUtils.showQqSessionDialog(this);// 建议用户联系客服
} else if (PLUGGABLE.equals(showDialog.getType())) {
DialogUtils.showPluginDialog(this, () -> {
DialogHelper.showPluginDialog(this, () -> {
if (FileUtils.isEmptyFile(showDialog.getPath())) {
toast(R.string.install_failure_hint);
} else {
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
}
return null;
});
} else if (SIGNATURE_CONFLICT.equals(showDialog.getType())) {
DialogHelper.showSignatureConflictDialog(this, () -> {
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
return null;
});
} else if (LOGIN_EXCEPTION.equals(showDialog.getType())) {
if (mIsExistLogoutDialog) return;
mIsExistLogoutDialog = true;
@ -262,8 +288,14 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
, StringUtils.buildString("", model, "")
, "知道了", "重新登录"
, null
, () -> startActivity(LoginActivity.getIntent(BaseActivity.this,
"你的账号已在另外一台设备登录多设备-重新登录"))
, () -> {
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(BaseActivity.this)) {
QuickLoginHelper.startLogin(BaseActivity.this, "你的账号已在另外一台设备登录多设备-重新登录");
} else {
startActivity(LoginActivity.getIntent(BaseActivity.this,
"你的账号已在另外一台设备登录多设备-重新登录"));
}
}
);
mBaseHandler.postDelayed(() -> mIsExistLogoutDialog = false, 5000);
} catch (Exception e) {
@ -276,6 +308,11 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
@Override
protected void onPause() {
super.onPause();
if (mWM != null && mTaskBackView != null && mHasAddTaskFloat) {
mWM.removeView(mTaskBackView);
mHasAddTaskFloat = false;
}
if (isFinishing()) {
onFinish();
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
@ -289,8 +326,87 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
@Override
protected void onResume() {
super.onResume();
if (SPUtils.getBoolean(Constants.SP_SHOW_TASK_FLOAT) && !this.getClass().getName().equals(EnergyCenterActivity.class.getName())) {
addTaskBackView();
mHasAddTaskFloat = true;
}
}
private void addTaskBackView() {
mWM = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
mWmParams = new WindowManager.LayoutParams();
mWmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
mWmParams.format = PixelFormat.RGBA_8888;
mWmParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
mWmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mWmParams.width = DisplayUtils.dip2px(76F);
mWmParams.height = DisplayUtils.dip2px(36F);
mWmParams.y = SPUtils.getInt(Constants.SP_TASK_FLOAT_LAST_Y, DisplayUtils.dip2px(114F));
mTaskBackView = View.inflate(this, R.layout.layout_task_back, null);
mTaskBackView.setOnClickListener(v -> {
// 如果当前是在键盘输入时,点击"返回任务"要先收起键盘
Util_System_Keyboard.hideSoftKeyboard(this);
startActivity(EnergyCenterActivity.Companion.getIntent(this));
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
mWM.removeView(mTaskBackView);
mHasAddTaskFloat = false;
});
setFloatTouchListener();
mWM.addView(mTaskBackView, mWmParams);
}
private void setFloatTouchListener() {
int screenHeight = getResources().getDisplayMetrics().heightPixels;
mTaskBackView.setOnTouchListener(new View.OnTouchListener() {
private int intervalY;
private int startY;
@Override
public boolean onTouch(View v, MotionEvent event) {
final int y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
intervalY = y;
startY = y;
break;
case MotionEvent.ACTION_MOVE:
mWmParams.y -= (y - intervalY);
if (mWmParams.y < 0) {
mWmParams.y = 0;
}
if (mWmParams.y > screenHeight) {
mWmParams.y = screenHeight;
}
if (mWM != null && mTaskBackView != null && mHasAddTaskFloat) {
mWM.updateViewLayout(mTaskBackView, mWmParams);
}
intervalY = y;
return true;
case MotionEvent.ACTION_UP:
// 滑动距离少于10视为点击返回false否则视为拖动返回true
if (Math.abs(y - startY) <= 10) {
return false;
} else {
// 记录位置
SPUtils.setInt(Constants.SP_TASK_FLOAT_LAST_Y, mWmParams.y);
return true;
}
}
return false;
}
});
}
/**
* 此回调可用于确认当前 activity 已经执行了 finish() 方法并处于 isFinishing 状态
*/
@ -375,12 +491,31 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (preventRecreateFragmentByFragmentManager()) {
outState = discardFragmentFromSaveInstanceState(outState);
}
long bundleSize = getBundleSize(outState);
if (bundleSize > MAX_BUNDLE_SIZE * 1024) {
outState.clear();
}
}
/**
* 是否停用 Activity 重建时 FragmentManager 根据 saveState 自动重建保存的 Fragment 的功能
*/
protected boolean preventRecreateFragmentByFragmentManager() {
return false;
}
private Bundle discardFragmentFromSaveInstanceState(Bundle outState) {
if (outState != null) {
outState.remove("android:support:fragments");
}
return outState;
}
private long getBundleSize(Bundle bundle) {
long dataSize;
Parcel obtain = Parcel.obtain();
@ -392,4 +527,9 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
}
return dataSize;
}
@Override
public Pair<String, String> getBusinessId() {
return null;
}
}

View File

@ -107,9 +107,6 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
AppExecutor.uiExecutor.executeWithDelay(Runnable {
Util_System_Keyboard.showSoftKeyboard(this)
}, 100)
AppExecutor.uiExecutor.executeWithDelay(Runnable {
mRichEditor.scrollTo(0, 1000000)
}, 500)
}

View File

@ -140,9 +140,8 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
EventBus.getDefault().register(this);
// For data binding.
if (getInflatedLayout() != null) {
mCachedView = getInflatedLayout();
} else {
mCachedView = getInflatedLayout();
if (mCachedView == null) {
mCachedView = View.inflate(getContext(), getLayoutId(), null);
}
@ -207,6 +206,10 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (container != null) {
container.removeView(mCachedView);
// TODO 页面重建 (framgent 的重新获取) 有大问题,这里只是修修补补
if (mCachedView != null && mCachedView.getParent() instanceof ViewGroup) {
((ViewGroup) mCachedView.getParent()).removeView(mCachedView);
}
}
return mCachedView;
}

View File

@ -11,12 +11,14 @@ package com.gh.base.fragment;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.view.View;
import com.gh.gamecenter.normal.NormalFragment;
@ -53,19 +55,21 @@ public abstract class BaseFragment_ViewPager extends NormalFragment implements D
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFragmentsList = new ArrayList<>();
initFragmentList(mFragmentsList);
mAdapter = BaseFragmentPagerAdapter.newInstance(getChildFragmentManager(), mFragmentsList);
final Bundle args = getArguments();
if (args != null) {
mCheckedIndex = args.getInt(ARGS_INDEX);
}
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mViewPager = (ViewPager) view.findViewById(getViewPagerId());
mViewPager = view.findViewById(getViewPagerId());
mFragmentsList = restoreFragments();
if (mFragmentsList.size() == 0) {
initFragmentList(mFragmentsList);
}
mAdapter = BaseFragmentPagerAdapter.newInstance(getChildFragmentManager(), mFragmentsList);
final Bundle args = getArguments();
if (args != null) {
mCheckedIndex = args.getInt(ARGS_INDEX);
}
mViewPager.setOffscreenPageLimit(mFragmentsList.size());
mViewPager.setAdapter(mAdapter);
if (mCheckedIndex < mFragmentsList.size()) {
@ -116,9 +120,24 @@ public abstract class BaseFragment_ViewPager extends NormalFragment implements D
fragment.onActivityResult(requestCode, resultCode, data);
}
}
}
public ArrayList<Fragment> restoreFragments() {
String tag = "android:switcher:" + mViewPager.getId() + ":";
ArrayList<Fragment> fragments = new ArrayList<>();
int childCount = getChildCount();
for (int index = 0; index < childCount; index++) {
Fragment fragment = getChildFragmentManager().findFragmentByTag(tag + index);
if (fragment != null) {
fragments.add(fragment);
}
}
return fragments;
}
public abstract int getChildCount();
public int getCurrentItem() {
return mViewPager != null ? mViewPager.getCurrentItem() : 0;
}

View File

@ -2,7 +2,6 @@ package com.gh.base.fragment
import android.os.Bundle
import com.gh.gamecenter.normal.NormalFragment
import com.lightgame.utils.Utils
/**
* 懒加载(支持多层嵌套)
@ -105,15 +104,25 @@ abstract class BaseLazyFragment : NormalFragment() {
isSupportVisible = visible
if (visible) {
if (mIsFirstVisible && view != null) {
// TODO 当 fragment 重建时这里的被调用很奇怪onActivityCreated 回调触发,但此时的 view 是空的,原因是 createView 还没被调用
// TODO 这样就造成了 onFragmentResume 里可能用到 view 的地方出现空指针异常,所以这里遇到 view 为空的时候 return 等下一次被调用才进去
if (view == null) {
return
}
if (mIsFirstVisible) {
mIsFirstVisible = false
onFragmentFirstVisible()
}
onFragmentResume()
dispatchChildVisibleState(true)
} else {
dispatchChildVisibleState(false)
onFragmentPause()
// 当 fragment 重建时,这个代码块可能在第一次 view 为空的 visible 后调用导致在 onFragmentPause 里可能用到 view 的地方出现空指针异常
if (!mIsFirstVisible) {
dispatchChildVisibleState(false)
onFragmentPause()
}
}
}

View File

@ -0,0 +1,68 @@
package com.gh.base.fragment
import android.view.View
import android.view.ViewStub
import com.gh.gamecenter.R
/**
* 这是在 BaseLazyFragment 之上添加了一些通用功能的抽象类
*
* 怎么将一个已有的 fragment 转化为懒加载 (延迟渲染) 的 fragment 呢?
* (继承 ListFragment 的类请改为继承 LazyListFragment)
*
* 0. 删掉旧的 getInflatedLayout() 的代码,现在由 getLayoutId() 提供 Stub 布局 (默认为 R.layout.fragment_stub若重写请注意提供 id 为 stub 的 ViewStub
* 1. 重写 getRealLayoutId(),提供实际要延迟渲染的 layout Id
* 1. 将原有在 onCreate() 的代码移动到 onFragmentFirstVisible()
* 2. 将原有在 onViewCreated() 的代码移动到 initRealView()
* 注意initRealView() 在 onFragmentFirstVisible() 中被调用,如果要初始化 viewModel 等非 UI 对象请在 super.onFragmentVisible() 调用)
* 3. 如需使用 ViewBinding ,在 onRealLayoutInflated() 的回调中初始化 ViewBinding 即可
* 4. onResume() 的代码移动到 onFragmentResume()onPause() 的代码移动到 onFragmentPause()
* 5. Done!
*/
abstract class LazyFragment : BaseLazyFragment() {
// ViewStub + ViewBinding 有莫名的 bug语法上没问题但编译时通不过。
private var mViewStub: ViewStub? = null
override fun getLayoutId() = R.layout.fragment_stub
override fun useButterKnife() = false
override fun initView(view: View?) {
super.initView(view)
mViewStub = mCachedView.findViewById(R.id.stub)
}
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
inflateRealView()
initRealView()
}
/**
* 真正 inflate View 的地方
*/
protected open fun inflateRealView() {
mViewStub?.layoutResource = getRealLayoutId()
mViewStub?.setOnInflateListener { _, inflatedView -> onRealLayoutInflated(inflatedView) }
mCachedView = mViewStub?.inflate()
}
/**
* 请在这个方法之后获取初始化后的各种 view
*
* 替换旧 fragment 实现时,等同于 onViewCreated
*/
protected open fun initRealView() {}
/**
* 提供要 stub inflate 的 layout
*/
protected abstract fun getRealLayoutId(): Int
/**
* 真实 layout inflate 完成的回调,可用于 viewBinding
*/
protected open fun onRealLayoutInflated(inflatedView: View) {}
}

View File

@ -8,18 +8,22 @@ import androidx.annotation.Keep
import androidx.appcompat.app.AppCompatActivity
import com.gh.base.CurrentActivityHolder
import com.gh.common.constant.Constants
import com.gh.common.loghub.LoghubUtils
import com.gh.common.tracker.Tracker
import com.gh.common.util.*
import com.gh.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.LoginActivity
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.energy.EnergyCenterActivity
import com.gh.gamecenter.energy.EnergyHouseActivity
import com.gh.gamecenter.entity.Badge
import com.gh.gamecenter.entity.MtaEvent
import com.gh.gamecenter.entity.NotificationUgc
import com.gh.gamecenter.energy.EnergyCenterActivity
import com.gh.gamecenter.energy.EnergyHouseActivity
import com.gh.gamecenter.help.QaFeedbackDialogFragment
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.security.BindPhoneActivity
@ -66,8 +70,12 @@ class DefaultJsApi(var context: Context) {
@JavascriptInterface
fun login(msg: Any) {
val intent = LoginActivity.getIntent(context, "浏览器")
context.startActivity(intent)
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
QuickLoginHelper.startLogin(context, "浏览器")
} else {
val intent = LoginActivity.getIntent(context, "浏览器")
context.startActivity(intent)
}
}
@JavascriptInterface
@ -219,7 +227,7 @@ class DefaultJsApi(var context: Context) {
@JavascriptInterface
fun showIncompatibleVersionDialog(msg: Any) {
DialogUtils.showLowVersionDialog(context)
DialogHelper.showUpgradeDialog(context)
}
@JavascriptInterface
@ -240,7 +248,7 @@ class DefaultJsApi(var context: Context) {
Base64ImageHolder.image = inviteEvent.poster.run {
if (this.startsWith("data:image/png;base64")) this.split(",")[1] else this
}
MessageShareUtils.getInstance(context).shareFromWeb(context, inviteEvent.way)
MessageShareUtils.getInstance(context).shareInviteFriends(context, inviteEvent.way)
} else {
ShareUtils.getInstance(context).shareInviteFriends(context, inviteEvent.url, inviteEvent.way)
}
@ -290,6 +298,50 @@ class DefaultJsApi(var context: Context) {
context.startActivity(EnergyHouseActivity.getIntent(context))
}
@JavascriptInterface
fun showQaFeedbackDialog(msg: Any) {
QaFeedbackDialogFragment.show(context as AppCompatActivity, msg.toString())
}
@JavascriptInterface
fun getMetaObject(msg: Any): String {
return LogUtils.getMetaObject().toString()
}
@JavascriptInterface
fun getLaunchId(msg: Any): String {
return Tracker.launchId
}
@JavascriptInterface
fun getSessionId(msg: Any): String {
return Tracker.sessionId
}
@JavascriptInterface
fun postLogEvent(event: Any) {
val logEvent = event.toString().toObject() ?: LogEvent()
debugOnly {
Utils.log("LogUtils->${logEvent.jsonString}")
}
LoghubUtils.log(logEvent.jsonString, logEvent.logStore, false)
}
@JavascriptInterface
fun startAvatarBorderPage(msg: Any) {
context.startActivity(AvatarBorderActivity.getIntent(context, msg.toString()))
}
@JavascriptInterface
fun isNetworkConnected(): Boolean {
return NetworkUtils.isNetworkConnected(context)
}
@JavascriptInterface
fun isWifiConnected(): Boolean {
return NetworkUtils.isWifiConnected(context)
}
@Keep
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)
@ -302,4 +354,6 @@ class DefaultJsApi(var context: Context) {
var url: String = "",
var poster: String = "")
@Keep
internal data class LogEvent(var jsonString: String = "", var logStore: String = "")
}

View File

@ -287,6 +287,7 @@ object DefaultUrlHandler {
val platformName = PlatformUtils.getInstance(context).getPlatformName(platform)
val gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID)
val packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5)
val isQaFeedback = uri.getQueryParameter(EntranceUtils.KEY_IS_QA_FEEDBACK) == "true"
val content = if (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) String.format("%s-%s-V%s",
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
if (TextUtils.isEmpty(platformName)) platform else platformName,
@ -299,7 +300,7 @@ object DefaultUrlHandler {
if (!TextUtils.isEmpty(qaId)) {
directToQa(context, qaTitle, qaId)
} else {
directToFeedback(context, content, EntranceUtils.ENTRANCE_BROWSER)
directToFeedback(context, content, null, isQaFeedback, EntranceUtils.ENTRANCE_BROWSER)
}
}
@ -307,7 +308,7 @@ object DefaultUrlHandler {
val position = uri.getQueryParameter("position") ?: ""
DirectUtils.directToHelpAndFeedback(context, position.toInt())
}
else -> DialogUtils.showLowVersionDialog(context)
else -> DialogHelper.showUpgradeDialog(context)
}
return true
} else if ("zhiqu" == uri.scheme) {
@ -365,7 +366,8 @@ object DefaultUrlHandler {
uri.path?.apply {
when {
contains("game") -> {
val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last() ?: ""
val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last()
?: ""
DirectUtils.directToGameDetail(context, gameId, entrance, autoDownload = false, traceEvent = null)
}
contains("question") -> {
@ -377,11 +379,12 @@ object DefaultUrlHandler {
DirectUtils.directToAnswerDetail(context, answerId, entrance, "")
}
}
contains("communities") && contains("article") -> {
((contains("bbs")) && contains("article") ||
(contains("communities")) && contains("article")) -> {
var communityId = ""
var type = ""
var typeId = ""
val split = replace("/communities", "").replace(".html", "").split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val split = replace("/communities", "").replace("/bbs", "").replace(".html", "").split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (text in split) {
if (TextUtils.isEmpty(communityId)) {
communityId = text
@ -395,7 +398,7 @@ object DefaultUrlHandler {
typeId = text
}
}
if ("articles" == type) {
if ("articles" == type || "article" == type) {
DirectUtils.directToCommunityArticle(
context, typeId, communityId,
entrance, "文章链接")
@ -403,7 +406,11 @@ object DefaultUrlHandler {
}
contains("article") -> {
val articleId = split("/")[2].replace(".html", "")
DirectUtils.directToArticle(context, articleId, entrance)
if (entrance == "隐私政策") {
DirectUtils.directToArticle(context, articleId, true, entrance)
} else {
DirectUtils.directToArticle(context, articleId, entrance)
}
}
contains("columns") -> {
val columnsId = split("/")[3]

View File

@ -2,6 +2,7 @@ package com.gh.common.constant;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
@ -11,9 +12,11 @@ import com.gh.common.util.PackageUtils;
import com.gh.common.util.SPUtils;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.SuggestionActivity;
import com.gh.gamecenter.entity.NewSettingsEntity;
import com.gh.gamecenter.entity.NewsEntity;
import com.gh.gamecenter.entity.SettingsEntity;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.retrofit.BiResponse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.halo.assistant.HaloApp;
@ -52,15 +55,18 @@ public class Config {
public static final String TTAD_APPID = BuildConfig.TTAD_APPID;
public static final String DOUYIN_CLIENTKEY = BuildConfig.DOUYIN_CLIENTKEY;
public static final String DOUYIN_CLIENTSECRET = BuildConfig.DOUYIN_CLIENTSECRET;
public static final String QUICK_LOGIN_APPID = BuildConfig.QUICK_LOGIN_APPID;
public static final String QUICK_LOGIN_APPKEY = BuildConfig.QUICK_LOGIN_APPKEY;
// http://www.ghzs666.com/article/${articleId}.html
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // ghzs/ghzs666 统一
public static final String PATCHES = "patches";
public static final String DEFAULT_CHANNEL = "test2";
public static final String DEFAULT_CHANNEL = "GH_TEST2";
private static String SETTINGS_KEY = "settingsKey";
private static SettingsEntity mSettingsEntity;
private static NewSettingsEntity mNewSettingsEntity;
public static final String FIX_DOWNLOAD_KEY = "isFixDownload";
public static final String FIX_PLUGIN_KEY = "isFixPlugin";
@ -203,6 +209,21 @@ public class Config {
return mSettingsEntity;
}
@Nullable
public static NewSettingsEntity getNewSettingsEntity() {
if (mNewSettingsEntity == null) {
try {
String json = SPUtils.getString(Constants.SP_NEW_SETTINGS);
if (!TextUtils.isEmpty(json)) {
mNewSettingsEntity = GsonUtils.fromJson(json, NewSettingsEntity.class);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return mNewSettingsEntity;
}
private static boolean isExistDownloadFilter() {
if (getSettings() == null || getSettings().getDownload() == null || getSettings().getDownload().size() == 0) {
return false;
@ -278,5 +299,17 @@ public class Config {
EventBus.getDefault().post(new EBReuse("Refresh"));
}
});
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<NewSettingsEntity>() {
@Override
public void onSuccess(NewSettingsEntity data) {
mNewSettingsEntity = data;
SPUtils.setString(Constants.SP_NEW_SETTINGS, GsonUtils.toJson(data));
}
});
}
}

View File

@ -32,9 +32,11 @@ public class Constants {
public static final String XPOSED_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer";
public static final String EB_QUIT_LOGIN = "quit_login";
public static final String EB_SHOW_AD = "show_ad";
public static final String EB_GAME_DETAIL = "eb_game_detail";
// 用于避免历史下载影响到部分依赖名字作为数据更新条件的修饰符
public static final String GAME_NAME_DECORATOR = " ";
@ -51,6 +53,8 @@ public class Constants {
public static final String RAW_GAME_ICON = "raw_game_icon";
public static final String GAME_ICON_SUBSCRIPT = "game_icon_subscript";
public static final String IS_PLATFORM_RECOMMEND = "isPlatformRecommend";
// 下载 id一般来说跟下载文件名一样
public static final String DOWNLOAD_ID = "download_id";
@ -70,7 +74,7 @@ public class Constants {
public static final String SP_IMEI = "imei";
public static final String SP_ANDROID_ID = "android_id";
public static final String LAST_INSTALL_GAME = "last_install_game";
//引导设置 “通知管理” 引导弹窗
@ -146,6 +150,23 @@ public class Constants {
public static final String SP_XAPK_UNZIP_ACTIVITY = "xapk_unzip_activity";
public static final String SP_XAPK_URL = "xapk_url";
//游戏详情推荐弹窗
public static final String SP_RECOMMEND_POPUP = "recommend_popup";
// 使用浏览器安装开关
public static final String SP_USE_BROWSER_TO_INSTALL = "use_browser_to_install";
// 游戏详情页底部使用浏览器安装提示
public static final String SP_SHOULD_SHOW_GAMEDETAIL_USE_BROWSER_TO_INSTALL_HINT = "should_show_gamedetail_use_browser_to_install_hint";
// 第一次普通安装推荐使用浏览器安装提示
public static final String SP_SHOULD_SHOW_USE_BROWSER_TO_INSTALL_HINT = "should_show_use_browser_to_install_hint";
//模拟器管理引导
public static final String SP_SIMULATOR_GUIDE = "simulator_guide";
//模拟器游戏引导
public static final String SP_SIMULATOR_GAME_GUIDE = "simulator_game_guide";
//首页视频播放进度
public static final String SP_HOME_VIDEO_PLAY_RECORD = "home_video_play_record";
@ -155,8 +176,22 @@ public class Constants {
// 是否已经填写邀请码
public static final String SP_HAS_COMPLETE_INVITE_CODE = "has_complete_invite_code";
// 签到提醒开关
public static final String SP_SIGN_REMIND = "sign_remind";
// 补充配置项
public static final String SP_NEW_SETTINGS = "new_settings";
// 头像挂件ID
public static final String SP_CHOOSE_AVATAR_ID = "choose_avatar_id";
// 是否显示返回任务悬浮图标
public static final String SP_SHOW_TASK_FLOAT = "show_task_float";
// 悬浮图标Y值
public static final String SP_TASK_FLOAT_LAST_Y = "task_float_last_y";
// 是否第一次进入新分类2.0
public static final String SP_FIRST_ENTER_CATEGORY_V2 = "first_enter_category_v2";
// 是否成功取过号
public static final String SP_HAS_GET_PHONE_INFO = "has_get_phone_info";
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
@ -200,8 +235,8 @@ public class Constants {
public static final String HELP_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=";
// 注销页面
public static final String LOGOUT_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_help_dev/help.html?content=5f6b1f02786564003944a693";
public static final String LOGOUT_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=5f534111b1f72909fc225672";
public static final String LOGOUT_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_help_dev/help.html?content=5f6b1f02786564003944a693&from=ghzs";
public static final String LOGOUT_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=5f534111b1f72909fc225672&from=ghzs";
// 商品详情
public static final String COMMODITY_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/product?from=ghzs";
@ -221,12 +256,48 @@ public class Constants {
// 邀请好友
public static final String INVITE_FRIENDS_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_activity_dev/inviteFriends.html#/invite";
public static final String INVITE_FRIENDS_ADDRESS = "https://static-web.ghzs.com/ghzs_activity/inviteFriends.html#/invite";
public static final String INVITE_FRIENDS_ADDRESS = "https://static-web.ghzs.com/ghzs_activity_prod/inviteFriends.html#/invite";
// 等级页面
public static final String LEVEL_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs-userhome-dev/index.html#/level";
public static final String LEVEL_ADDRESS = "https://static-web.ghzs.com/ghzs-userhome/index.html#/level";
// 兑换规则
public static final String EXCHANGE_RULE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/exchange-rule?from=ghzs";
public static final String EXCHANGE_RULE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/exchange-rule?from=ghzs";
// 光能规则
public static final String ENERGY_RULE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/energy-rule?from=ghzs";
public static final String ENERGY_RULE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/energy-rule?from=ghzs";
// 兑换商品
public static final String EXCHANGE_COMMODITY_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/exchange-log?from=ghzs";
public static final String EXCHANGE_COMMODITY_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/exchange-log?from=ghzs";
// 抽奖乐园
public static final String LOTTERY_PARADISE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/lottery-list?from=ghzs";
public static final String LOTTERY_PARADISE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/lottery-list?from=ghzs";
// 我的奖品
public static final String MY_PRIZE_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/mywin?from=ghzs";
public static final String MY_PRIZE_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/mywin?from=ghzs";
// 中奖订单详情
public static final String WIN_ORDER_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/win-order-detail?from=ghzs";
public static final String WIN_ORDER_DETAIL_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/win-order-detail?from=ghzs";
// 地址信息
public static final String ADDRESS_INFO_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/address-list?from=ghzs";
public static final String ADDRESS_INFO_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/address-list?from=ghzs";
// 领奖信息
public static final String PRIZE_INFO_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/user-info?from=ghzs";
public static final String PRIZE_INFO_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/user-info?from=ghzs";
// 提现信息
public static final String WITHDRAW_INFO_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/cash?from=ghzs";
public static final String WITHDRAW_INFO_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/cash?from=ghzs";
//最少需要多少数据才能上传
public static final int DATA_AMOUNT = 20;

View File

@ -46,12 +46,14 @@ import com.gh.common.util.NumberUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.RealNameHelper;
import com.gh.common.util.ReservationHelper;
import com.gh.common.view.DownloadProgressBar;
import com.gh.common.view.DrawableView;
import com.gh.common.view.GameIconView;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
import com.gh.download.server.BrowserInstallHelper;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
@ -66,6 +68,7 @@ import com.gh.gamecenter.entity.ServerCalendarEntity;
import com.gh.gamecenter.entity.TagStyleEntity;
import com.gh.gamecenter.entity.TestEntity;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.gamecenter.qa.entity.CommunityVideoEntity;
import com.lightgame.download.DownloadEntity;
@ -456,27 +459,37 @@ public class BindingAdapters {
return;
}
}
PackageCheckDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> {
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
BrowserInstallHelper.showBrowserInstallHintDialog(v.getContext(), () -> {
PackageCheckDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, () -> {
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> {
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
});
});
});
});
});
});
});
});
} else {
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location + ":" + gameEntity.getName());
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location + ":" + gameEntity.getName());
});
});
});
});
}
@ -518,12 +531,16 @@ public class BindingAdapters {
}
break;
case RESERVABLE:
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
LogUtils.logReservation(gameEntity, traceEvent);
updateReservation(progressBar, gameEntity);
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
LogUtils.logReservation(gameEntity, traceEvent);
updateReservation(progressBar, gameEntity);
});
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
});
});
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
});
break;
case RESERVED:
@ -550,8 +567,10 @@ public class BindingAdapters {
HistoryHelper.insertGameEntity(gameEntity);
}
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton()));
progressBar.getContext().startActivity(i);
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton()));
progressBar.getContext().startActivity(i);
});
break;
case UPDATING:
Utils.toast(progressBar.getContext(), "正在加急更新版本,敬请后续留意");
@ -731,7 +750,9 @@ public class BindingAdapters {
try {
ArrayList<TagStyleEntity> tagStyle = new ArrayList<>();
TestEntity test = gameEntity.getTest();
if (test != null) {
if (test != null
// 这个判断用于开测表列表
&& !"type_tag".equals(test.getGameTag())) {
TagStyleEntity typeTag = new TagStyleEntity();
typeTag.setName(test.getType() != null ? test.getType() : "");
typeTag.setBackground("FFF3E0");

View File

@ -0,0 +1,95 @@
package com.gh.common.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.os.Bundle
import android.view.*
import com.gh.base.fragment.BaseDialogFragment
import com.gh.gamecenter.R
import com.halo.assistant.HaloApp
abstract class BaseDraggableDialogFragment : BaseDialogFragment(), View.OnTouchListener {
private var mInitPositionY = 0f
private lateinit var mGestureDetector: GestureDetector
private lateinit var mRootView: View
private lateinit var mDragCloseView: View
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mRootView = getRootView()
mDragCloseView = getDragCloseView()
mDragCloseView.setOnTouchListener(this)
mGestureDetector = GestureDetector(requireContext(), SingleTapConfirm())
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val createDialog = super.onCreateDialog(savedInstanceState)
createDialog.setCanceledOnTouchOutside(true)
val window = createDialog.window
window?.setGravity(Gravity.BOTTOM)
window?.setWindowAnimations(R.style.community_publication_animation)
return createDialog
}
// dialog drag animation
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View, event: MotionEvent): Boolean {
if (mGestureDetector.onTouchEvent(event) && mRootView.y == 0F) {
v.performClick()
return true
}
when (event.action) {
MotionEvent.ACTION_DOWN -> {
mInitPositionY = mRootView.y - event.rawY
}
MotionEvent.ACTION_MOVE -> {
val offsetY = event.rawY + mInitPositionY
val dialogY = mRootView.y
if (dialogY + offsetY > 0) {
mRootView.animate()
.y(offsetY)
.setDuration(0)
.start()
} else {
resetDialogPosition()
}
}
MotionEvent.ACTION_CANCEL,
MotionEvent.ACTION_UP,
MotionEvent.ACTION_OUTSIDE -> {
if (mRootView.y >= mRootView.height / 2) {
dismissAllowingStateLoss()
} else {
resetDialogPosition(300)
}
}
else -> return false
}
return true
}
private fun resetDialogPosition(duration: Long = 0) {
mRootView.animate()
.y(0F)
.setDuration(duration)
.start()
}
private class SingleTapConfirm : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(event: MotionEvent): Boolean {
return true
}
}
override fun onStart() {
super.onStart()
val width = HaloApp.getInstance().application.resources.displayMetrics.widthPixels
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
}
abstract fun getRootView(): View
abstract fun getDragCloseView(): View
override fun getThemeRes(): Int = R.style.DialogFragmentDimAmount
}

View File

@ -60,26 +60,36 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
companion object {
fun showDeviceRemindDialog(context: Context, gameEntity: GameEntity) {
val datas = SPUtils.getString(Constants.SP_DEVICE_REMIND)
if (datas.isNotEmpty()) {
val pair = shouldShowDeviceRemindDialog(gameEntity)
if (pair.first) {
val dialog = DeviceRemindDialog(context, pair.second!!, gameEntity)
dialog.show()
}
}
}
fun shouldShowDeviceRemindDialog(gameEntity: GameEntity): Pair<Boolean, DeviceDialogEntity?> {
val datas = SPUtils.getString(Constants.SP_DEVICE_REMIND)
if (datas.isNotEmpty()) {
val type = object : TypeToken<List<DeviceDialogEntity>>() {}.type
val entitys = GsonUtils.gson.fromJson<List<DeviceDialogEntity>>(datas, type)
val entities = GsonUtils.gson.fromJson<List<DeviceDialogEntity>>(datas, type)
//1.判断设备是否匹配
val entity = entitys.find { it.manufacturer.toLowerCase().startsWith(Build.MANUFACTURER.toLowerCase()) }
?: return
val entity = entities.find { it.manufacturer.toLowerCase().startsWith(Build.MANUFACTURER.toLowerCase()) }
?: return Pair(false, null)
//2.判断游戏不含剔除标签
gameEntity.tagStyle.forEach {
if (entity.excludeTags.contains(it.name)) {
return
return Pair(false, null)
}
}
//3.不再弹出提示判断
val isNoRemindAgain = SPUtils.getBoolean(Constants.SP_NO_REMIND_AGAIN, false)
if (isNoRemindAgain) return
val dialog = DeviceRemindDialog(context, entity, gameEntity)
dialog.show()
if (isNoRemindAgain) return Pair(false, null)
return Pair(true, entity)
}
return Pair(false, null)
}
}

View File

@ -9,14 +9,14 @@ import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.util.DirectUtils
import com.gh.common.util.DisplayUtils
import com.gh.common.util.dip2px
import com.gh.common.util.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogGameOffServiceBinding
import com.gh.gamecenter.entity.GameEntity
import kotlinx.android.synthetic.main.dialog_game_off_service.*
// 游戏关闭下载弹窗
class GameOffServiceDialogFragment
@ -24,34 +24,47 @@ class GameOffServiceDialogFragment
: BaseDialogFragment() {
private var mDialog: GameEntity.Dialog? = null
private var mBinding: DialogGameOffServiceBinding? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.dialog_game_off_service, null)
return DialogGameOffServiceBinding
.inflate(inflater)
.apply { mBinding = this }
.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mDialog?.run {
titleTv.text = title
contentTv.text = HtmlCompat.fromHtml(content, HtmlCompat.FROM_HTML_MODE_LEGACY)
for (site in sites) {
val siteTv = TextView(context)
siteTv.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
topMargin = DisplayUtils.dip2px(12f)
}
siteTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f)
siteTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.theme_font))
siteTv.text = site.text
siteTv.paintFlags = siteTv.paintFlags or Paint.UNDERLINE_TEXT_FLAG
siteTv.setOnClickListener {
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
mBinding?.run {
mDialog?.run {
titleTv.text = title
contentTv.text = HtmlCompat.fromHtml(content, HtmlCompat.FROM_HTML_MODE_LEGACY)
okTv.setOnClickListener {
dismissAllowingStateLoss()
}
container.addView(siteTv)
// 过滤内容为空的元素
val notEmptySite = sites.filter { it.text.isNotBlank() }
notEmptySite.forEachIndexed { index, site ->
val siteTv = TextView(context)
siteTv.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
topMargin = 24F.dip2px()
if (index == notEmptySite.size - 1) bottomMargin = 8F.dip2px()
}
siteTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14F)
siteTv.setTextColor(R.color.theme_font.toColor())
siteTv.text = site.text
siteTv.paintFlags = siteTv.paintFlags or Paint.UNDERLINE_TEXT_FLAG
siteTv.setOnClickListener {
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
dismissAllowingStateLoss()
}
container.addView(siteTv)
}
}
}
}

View File

@ -1,12 +1,14 @@
package com.gh.common.dialog
import android.animation.ValueAnimator
import android.content.Context
import android.content.pm.PackageInfo
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentTransaction
@ -17,15 +19,21 @@ import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.common.view.CustomLinkMovementMethod
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentPackageCheckBinding
import com.gh.gamecenter.databinding.PackageCheckItemBinding
import com.gh.gamecenter.entity.DetectionObjectEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.LinkEntity
import com.gh.gamecenter.entity.PackageDialogEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.halo.assistant.HaloApp
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lightgame.dialog.BaseDialogFragment
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@ -34,6 +42,7 @@ import org.greenrobot.eventbus.ThreadMode
/**
* 包名检测弹窗
*/
// TODO 将 gameEntity 放到 argument 里再取出,避免重建时为空
class PackageCheckDialogFragment : BaseDialogFragment() {
private lateinit var binding: FragmentPackageCheckBinding
@ -41,12 +50,33 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private val mDuration = 3000
private var mDisposable: Disposable? = null
private var mAdapter: PackageCheckAdapter? = null
var packageDialogEntity: PackageDialogEntity? = null
private var mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
var gameEntity: GameEntity? = null
var callBack: DialogUtils.ConfirmListener? = null
private val dataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
val packageName = downloadEntity.packageName
val detectionObjects = gameEntity?.packageDialog?.detectionObjects
if (DownloadStatus.add == downloadEntity.status || DownloadStatus.done == downloadEntity.status) {
detectionObjects?.forEach { detectionObject ->
if (detectionObject.packages.contains(packageName)) {
val packageLink = gameEntity?.packageDialog?.links?.find { it.buttonLink }
LogUtils.uploadPackageCheck("pkg_check_pop_download", if (DownloadStatus.add == downloadEntity.status) "下载开始" else "下载完成",
gameEntity, packageLink?.text ?: "", packageLink?.title
?: "", downloadEntity.gameId, downloadEntity.getMetaExtra(Constants.GAME_NAME))
}
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
EventBus.getDefault().register(this)
gameEntity?.let {
LogUtils.uploadPackageCheck("pkg_check_pop_click", "出现弹窗", it, "", "", "", "")
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -56,7 +86,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
packageDialogEntity?.let {
gameEntity?.packageDialog?.let {
changeParams(it.detectionObjects.size)
binding.packageRv.layoutManager = LinearLayoutManager(requireContext())
@ -70,6 +100,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
it.links.forEachIndexed { index, link ->
val linkSpan = SpanBuilder(link.title ?: "").click(0, (link.title
?: "").length, R.color.theme_font, true) {
LogUtils.uploadPackageCheck("pkg_check_pop_click", "点击链接", gameEntity, link.text, link.title, "", "")
DirectUtils.directToLinkPage(requireContext(), link, "包名检测弹窗", "")
}.build()
spanBuilder.append(linkSpan)
@ -89,6 +120,10 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
binding.cancelTv.text = "我知道了"
binding.noRemindAgainCb.visibility = View.GONE
}
"OPTIONAL_CURRENT_HINT" -> {
binding.cancelTv.text = "我知道了"
binding.noRemindAgainCb.visibility = View.VISIBLE
}
else -> {
binding.cancelTv.text = "我知道了"
binding.noRemindAgainCb.visibility = View.VISIBLE
@ -96,7 +131,9 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
}
initListener(it)
}
checkPackage()
binding.root.post {
checkPackage()
}
}
private fun changeParams(size: Int) {
@ -108,15 +145,19 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private fun initListener(entity: PackageDialogEntity) {
binding.downloadBtn.setOnClickListener {
if (binding.noRemindAgainCb.isChecked) {
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity?.id}", true)
saveRecord(entity)
}
val isAllPackageInstalled = isAllPackageInstalled(entity)
val isAllPackageInstalled = isAllPackageInstalled(mAllInstalledPackages, entity)
if (isAllPackageInstalled) {
callBack?.onConfirm()
dismissAllowingStateLoss()
} else {
val packageLink = entity.links.find { it.buttonLink }
var packageLink = getNotInstalledLink(entity)
if (packageLink == null) {
packageLink = entity.links.find { it.buttonLink }
}
if (packageLink != null) {
LogUtils.uploadPackageCheck("pkg_check_pop_click", "点击前往下载", gameEntity, packageLink.text, packageLink.title, "", "")
DirectUtils.directToLinkPage(requireContext(), packageLink, "包名检测弹窗", "")
}
}
@ -127,22 +168,26 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
callBack?.onConfirm()
}
if (binding.noRemindAgainCb.isChecked) {
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity?.id}", true)
saveRecord(entity)
LogUtils.uploadPackageCheck("pkg_check_pop_click", "不再提示", gameEntity, "", "", "", "")
}
dismissAllowingStateLoss()
}
}
private fun saveRecord(entity: PackageDialogEntity) {
if (entity.level == "OPTIONAL_CURRENT_HINT") {
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity?.id}", true)
} else {
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity?.packageDialog?.id}", true)
}
}
private fun checkPackage() {
var index = 0
mTotalWidth = (DisplayUtils.getScreenWidth() - 108f.dip2px()).toFloat()
mDisposable = rxTimer(1) {
val width = (mTotalWidth / mDuration) * it
val params = binding.progressView.layoutParams as RelativeLayout.LayoutParams
params.width = width.toInt()
binding.progressView.layoutParams = params
packageDialogEntity?.detectionObjects?.let { objects ->
gameEntity?.packageDialog?.detectionObjects?.let { objects ->
if (objects.isNotEmpty()) {
val averageTime = if (objects.size == 1) {
mDuration
@ -160,24 +205,49 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
if (it >= mDuration) {
mDisposable?.dispose()
binding.downloadBtn.isEnabled = true
binding.progressText.text = "检测完成"
binding.progressView.background = ContextCompat.getDrawable(requireContext(), R.drawable.package_check_complete_bg)
}
}
val animator = ValueAnimator.ofInt(0, 100)
animator.duration = mDuration.toLong()
animator.interpolator = LinearInterpolator()
animator.addUpdateListener {
binding.progressBar.progress = it.animatedValue as Int
}
animator.start()
}
private fun getNotInstalledLink(packageDialogEntity: PackageDialogEntity): LinkEntity? {
val links = LinkedHashSet<LinkEntity>()
packageDialogEntity.detectionObjects.forEach { obj ->
if (!checkDetectionsInstalled(mAllInstalledPackages, obj.packages)) {
obj.assignDownload.forEach {
links.add(packageDialogEntity.links[it])
}
}
}
var link: LinkEntity? = null
if (links.size > 1) {
link = links.find { it.buttonLink } ?: links.toList()[0]
} else if (links.size == 1) {
link = links.toList()[0]
}
return link
}
override fun onStart() {
super.onStart()
val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
val height = ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
dialog?.setCanceledOnTouchOutside(true)
requireDialog().window?.setLayout(width, height)
requireDialog().setCanceledOnTouchOutside(true)
DownloadManager.getInstance(context).addObserver(dataWatcher)
}
override fun onResume() {
super.onResume()
packageDialogEntity?.let {
if (isAllPackageInstalled(it)) {
mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
gameEntity?.packageDialog?.let {
if (isAllPackageInstalled(mAllInstalledPackages, it)) {
callBack?.onConfirm()
dismissAllowingStateLoss()
}
@ -190,22 +260,25 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
if (mDisposable?.isDisposed == false) {
mDisposable?.dispose()
}
LogUtils.uploadPackageCheck("pkg_check_pop_click", "关闭弹窗", gameEntity, "", "", "", "")
DownloadManager.getInstance(context).removeObserver(dataWatcher)
}
//安装、卸载事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if ("安装" == busFour.type || "卸载" == busFour.type) {
mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
mAdapter?.notifyDataSetChanged()
}
}
class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
inner class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
private var index = -1
fun notifyPackages() {
index++
notifyDataSetChanged()
notifyItemChanged(index)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
@ -219,14 +292,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
val entity = entities[position]
holder.binding.entity = entity
if (position <= index) {
var isAllInstalled = false
entity.packages.forEach { packageName ->
val isInstalled = PackageUtils.getInstalledPackages(context, 0).find { it.packageName == packageName } != null
if (isInstalled) {
isAllInstalled = true
return@forEach
}
}
val isAllInstalled = checkDetectionsInstalled(mAllInstalledPackages, entity.packages)
if (isAllInstalled) {
holder.binding.statusTv.text = "已安装"
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
@ -246,59 +312,65 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
companion object {
@JvmStatic
fun show(activity: AppCompatActivity, packageDialogEntity: PackageDialogEntity?, callBack: DialogUtils.ConfirmListener) {
fun show(activity: AppCompatActivity, gameEntity: GameEntity, callBack: DialogUtils.ConfirmListener) {
val packageDialogEntity = gameEntity.packageDialog
if (packageDialogEntity == null) {
callBack.onConfirm()
return
}
if (isAllPackageInstalled(packageDialogEntity)) {
val allInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
if (isAllPackageInstalled(allInstalledPackages, packageDialogEntity)) {
callBack.onConfirm()
return
}
val isChoose = SPUtils.getBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity.id}", false)
if (packageDialogEntity.level == "OPTIONAL_HINT" && isChoose) {
callBack.onConfirm()
return
}
if (!activity.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) return
val isCurrentGameChoose = SPUtils.getBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity.id}", false)
if (packageDialogEntity.level == "OPTIONAL_CURRENT_HINT" && isCurrentGameChoose) {
callBack.onConfirm()
return
}
if (!activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) return
var dialogFragment = activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.simpleName) as? PackageCheckDialogFragment
if (dialogFragment == null) {
dialogFragment = PackageCheckDialogFragment()
dialogFragment.packageDialogEntity = packageDialogEntity
dialogFragment.gameEntity = gameEntity
dialogFragment.callBack = callBack
dialogFragment.show(activity.supportFragmentManager, PackageCheckDialogFragment::class.java.simpleName)
} else {
dialogFragment.packageDialogEntity = packageDialogEntity
dialogFragment.gameEntity = gameEntity
dialogFragment.callBack = callBack
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
transaction.show(dialogFragment)
transaction.commit()
}
}
fun isAllPackageInstalled(packageDialogEntity: PackageDialogEntity): Boolean {
var isAllInstalled = true
val allInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
val isPackagesInstall: (ArrayList<String>) -> Boolean = { packages ->
var isPackagesInstalled = false
packages.forEach { packageName ->
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
if (isInstalled) {
isPackagesInstalled = true
return@forEach
}
private fun checkDetectionsInstalled(allInstalledPackages: List<PackageInfo>, packages: ArrayList<String>): Boolean {
var isPackagesInstalled = false
packages.forEach { packageName ->
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
if (isInstalled) {
isPackagesInstalled = true
return@forEach
}
isPackagesInstalled
}
return isPackagesInstalled
}
fun isAllPackageInstalled(allInstalledPackages: List<PackageInfo>, packageDialogEntity: PackageDialogEntity): Boolean {
var isAllInstalled = true
packageDialogEntity.detectionObjects.forEach loop@{ obj ->
if (!isPackagesInstall(obj.packages)) {
if (!checkDetectionsInstalled(allInstalledPackages, obj.packages)) {
isAllInstalled = false
return isAllInstalled
}

View File

@ -14,10 +14,10 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentTransaction
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.util.DirectUtils.directToExternalBrowser
import com.gh.common.util.dip2px
import com.gh.common.view.CustomLinkMovementMethod
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
class PrivacyDialogFragment : BaseDialogFragment() {
@ -53,7 +53,8 @@ class PrivacyDialogFragment : BaseDialogFragment() {
}
override fun onClick(widget: View) {
directToExternalBrowser(context!!, context!!.getString(R.string.privacy_policy_url))
val intent = WebActivity.getIntent(requireContext(), context!!.getString(R.string.privacy_policy_url), true)
context?.startActivity(intent)
}
}, skipText.length - 9, skipText.length - 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
@ -65,7 +66,8 @@ class PrivacyDialogFragment : BaseDialogFragment() {
}
override fun onClick(widget: View) {
directToExternalBrowser(requireContext(), requireContext().getString(R.string.disclaimer_url))
val intent = WebActivity.getIntent(requireContext(), context!!.getString(R.string.disclaimer_url), true)
context?.startActivity(intent)
}
}, skipText.length - 4, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
descTv?.movementMethod = CustomLinkMovementMethod()

View File

@ -16,10 +16,14 @@ data class ExposureEntity(
val outerSequence: Int? = 0,
val platform: String? = "",
var isMirrorData: Boolean = false,
@SerializedName("is_web_download")
var isWebDownload: Boolean = false,
val downloadType: String? = "",
val downloadCompleteType: String? = "",
@SerializedName("display_type")
val displayType: String? = "",
@SerializedName("is_platform_recommend")
val isPlatformRecommend: Boolean? = false,
// 下载地址的 host 和 path
var host: String? = "",

View File

@ -9,10 +9,12 @@ import com.gh.common.exposure.meta.Meta
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.exposure.time.TimeUtil
import com.gh.common.util.getFirstElementDividedByDivider
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.entity.GameEntity
import com.lightgame.download.DownloadEntity
import kotlinx.android.parcel.Parcelize
import java.util.*
import kotlin.collections.ArrayList
@Keep
@Parcelize
@ -30,7 +32,10 @@ data class ExposureEvent(
// TODO 建一个 exposureEvent 池规避反复生成对象
@JvmStatic
fun createEvent(gameEntity: GameEntity?, source: List<ExposureSource>, eTrace: List<ExposureEvent>? = null, event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
fun createEvent(gameEntity: GameEntity?,
source: List<ExposureSource>,
eTrace: List<ExposureEvent>? = null,
event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
if (gameEntity?.getApk()?.size == 1) {
gameEntity.gameVersion = gameEntity.getApk().elementAtOrNull(0)?.version ?: ""
}
@ -40,12 +45,14 @@ data class ExposureEvent(
gameName = eTrace?.firstOrNull()?.payload?.gameName ?: gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
gameVersion = eTrace?.firstOrNull()?.payload?.gameVersion ?:gameEntity?.gameVersion,
isMirrorData = eTrace?.firstOrNull()?.payload?.isMirrorData ?: gameEntity?.shouldUseMirrorInfo() ?: false,
isWebDownload = BrowserInstallHelper.isUseBrowserToInstallEnabled() && BrowserInstallHelper.shouldUseBrowserToInstall(), // 实时的值,不用从 eTrace 里取
sequence = eTrace?.firstOrNull()?.payload?.sequence ?: gameEntity?.sequence,
outerSequence = eTrace?.firstOrNull()?.payload?.outerSequence ?: gameEntity?.outerSequence,
platform = eTrace?.firstOrNull()?.payload?.platform ?:gameEntity?.platform,
downloadType = gameEntity?.downloadType,
downloadCompleteType = gameEntity?.downloadCompleteType,
displayType = eTrace?.firstOrNull()?.payload?.displayType ?:gameEntity?.displayContent,
isPlatformRecommend = gameEntity?.isPlatformRecommend ?: false,
// ugly
welcomeDialogId = gameEntity?.welcomeDialogId ?: eTrace?.firstOrNull()?.payload?.welcomeDialogId,
welcomeDialogLinkTitle = gameEntity?.welcomeDialogTitle ?: eTrace?.firstOrNull()?.payload?.welcomeDialogLinkTitle),
@ -53,5 +60,19 @@ data class ExposureEvent(
eTrace = eTrace,
event = event).apply { gameEntity?.exposureEvent = this }
}
@JvmStatic
fun createEventWithSourceConcat(gameEntity: GameEntity?,
basicSource: List<ExposureSource>,
source: List<ExposureSource>,
eTrace: List<ExposureEvent>? = null,
event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
val concatSourceList = ArrayList<ExposureSource>().apply {
addAll(basicSource)
addAll(source)
}
return createEvent(gameEntity, concatSourceList, eTrace, event)
}
}
}

View File

@ -1,12 +1,10 @@
package com.gh.common.exposure
import com.aliyun.sls.android.sdk.model.LogGroup
import com.gh.common.exposure.time.TimeUtil
import com.aliyun.sls.android.producer.Log
import com.gh.common.loghub.LoghubHelper
import com.gh.common.util.toJson
import com.gh.common.util.tryWithDefaultCatch
import com.gh.gamecenter.BuildConfig
import com.gh.loghub.LgLOG
import com.gh.loghub.LoghubHelper
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import java.util.concurrent.ExecutorService
@ -22,13 +20,9 @@ import java.util.concurrent.ExecutorService
*/
object ExposureManager {
private const val ENDPOINT = "cn-qingdao.log.aliyuncs.com"
private const val PROJECT = "ghzs"
private const val STORE_SIZE = 100
private const val LOG_STORE = BuildConfig.EXPOSURE_REPO
private val loghubHelper = LoghubHelper.getInstance()
// exposureCache 用来过滤掉具有相同 id 的曝光事件,避免重复发送事件
private val exposureSet by lazy { hashSetOf<ExposureEvent>() }
private var exposureExecutor: ExecutorService? = null
@ -37,7 +31,6 @@ object ExposureManager {
@JvmStatic
fun init(excutor: ExecutorService) {
loghubHelper.init(HaloApp.getInstance().application, ENDPOINT, PROJECT, LOG_STORE) { TimeUtil.currentTimeMillis() }
exposureExecutor = excutor
exposureExecutor?.execute {
tryWithDefaultCatch {
@ -102,8 +95,7 @@ object ExposureManager {
if (exposureSet.size < STORE_SIZE && !forced || exposureSet.size == 0) return@execute
val exposureList = exposureSet.toList()
// uploadLogGroup 是一个异步方法LoghubHelper 里面实现了重传功能,所以这里交给它就好了
loghubHelper.uploadLogGroup(buildLogGroup(exposureList))
uploadExposures(exposureList)
Utils.log("Exposure", "提交了${exposureList.size}条曝光记录")
exposureSet.removeAll(exposureList)
@ -116,28 +108,22 @@ object ExposureManager {
return jsonWithMultipleBracket.replace("[[", "[").replace("]]", "]")
}
private fun buildLogGroup(eventList: List<ExposureEvent>): LogGroup {
val logGroup = LogGroup("sls android", "no ip")
eventList.forEach { logGroup.PutLog(buildLog(it)) }
return logGroup
private fun uploadExposures(eventList: List<ExposureEvent>) {
eventList.forEach {
LoghubHelper.uploadLog(buildLog(it), LOG_STORE)
}
}
private fun buildLog(event: ExposureEvent): LgLOG {
val log = LgLOG(TimeUtil.currentTime())
log.PutContent("id", event.id)
log.PutContent("payload", event.payload.toJson())
log.PutContent("event", event.event.toString())
log.PutContent("source", eliminateMultipleBrackets(event.source.toJson()))
log.PutContent("meta", event.meta.toJson())
log.PutContent("e-traces", if (event.eTrace != null) {
private fun buildLog(event: ExposureEvent) = Log().apply {
putContent("id", event.id)
putContent("payload", event.payload.toJson())
putContent("event", event.event.toString())
putContent("source", eliminateMultipleBrackets(event.source.toJson()))
putContent("meta", event.meta.toJson())
putContent("e-traces", if (event.eTrace != null) {
eliminateMultipleBrackets(event.eTrace?.toJson() ?: "")
} else "")
log.PutTime(event.time)
return log
logTime = event.time.toLong()
}
class FixedSizeLinkedHashSet<T>(var maxSize: Int) : LinkedHashSet<T>() {

View File

@ -97,6 +97,11 @@ object HistoryHelper {
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().deleteVideo(MyVideoEntity().apply { id = videoId }) } }
}
@JvmStatic
fun deleteAttentionVideoRecord() {
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().deleteAttentionVideoRecord() } }
}
@JvmStatic
fun emptyDatabase() {
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.clearAllTables() } }

View File

@ -0,0 +1,90 @@
package com.gh.common.loghub
import com.aliyun.sls.android.producer.*
import com.gh.common.util.isPublishEnv
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
/**
* 上传阿里云日志辅助类
*/
object LoghubHelper {
private const val ACCESS_KEY_ID = "LTAIV3i0sNc4TPK1"
private const val ACCESS_KEY_SECRET = "8dKtTPeE5WYA6ZCeuIBcIVp7eB0ir4"
private const val ENDPOINT = "cn-qingdao.log.aliyuncs.com"
private const val PROJECT = "ghzs"
private val mClientMaps by lazy { hashMapOf<String, LogProducerClient>() }
fun uploadLog(log: Log, logStore: String) {
getClient(logStore)?.addLog(log)
}
fun uploadLogs(logs: List<Log>, logStore: String) {
logs.forEach {
uploadLog(it, logStore)
}
}
private fun getClient(logStore: String): LogProducerClient? {
if (!mClientMaps.containsKey(logStore)) {
mClientMaps[logStore] = createClient(logStore)
}
return mClientMaps[logStore]
}
private fun createClient(logStore: String): LogProducerClient {
val config = LogProducerConfig(ENDPOINT, PROJECT, logStore, ACCESS_KEY_ID, ACCESS_KEY_SECRET).apply {
// 1 开启断点续传功能, 0 关闭
// 每次发送前会把日志保存到本地的binlog文件只有发送成功才会删除保证日志上传At Least Once
setPersistent(1)
// 持久化的文件名,需要保证文件所在的文件夹已创建。配置多个客户端时,不应设置相同文件
setPersistentFilePath(HaloApp.getInstance().application.filesDir.absolutePath + "/log.dat")
// 是否每次AddLog强制刷新高可靠性场景建议打开
setPersistentForceFlush(1)
// 持久化文件滚动个数建议设置成10。
setPersistentMaxFileCount(10)
// 每个持久化文件的大小建议设置成1-10M
setPersistentMaxFileSize(1024 * 1024)
// 本地最多缓存的日志数不建议超过1M通常设置为65536即可
setPersistentMaxLogCount(65536)
//网络连接超时时间整数单位秒默认为10
setConnectTimeoutSec(15)
//日志发送超时时间整数单位秒默认为15
setSendTimeoutSec(15)
//flusher线程销毁最大等待时间整数单位秒默认为1
setDestroyFlusherWaitSec(2)
//sender线程池销毁最大等待时间整数单位秒默认为1
setDestroySenderWaitSec(2)
//日志时间与本机时间之差,超过该大小后会根据 `drop_delay_log` 选项进行处理。
//一般此种情况只会在设置persistent的情况下出现即设备下线后超过几天/数月启动,发送退出前未发出的日志
//整数单位秒默认为7*24*3600即7天
setMaxLogDelayTime(7 * 24 * 3600)
//对于超过 `max_log_delay_time` 日志的处理策略
//0 不丢弃,把日志时间修改为当前时间; 1 丢弃,默认为 1 (丢弃)
setDropDelayLog(0)
//是否丢弃鉴权失败的日志0 不丢弃1丢弃
//默认为 0即不丢弃
setDropUnauthorizedLog(0)
}
return if (isPublishEnv()) {
LogProducerClient(config)
} else {
return LogProducerClient(config,
LogProducerCallback { resultCode, reqId, errorMessage, logBytes, compressedBytes ->
// resultCode 返回结果代码
// reqId 请求id
// errorMessage 错误信息没有为null
// logBytes 日志大小
// compressedBytes 压缩后日志大小
Utils.log("LoghubHelper -> ${String.format("%s %s %s %s %s",
LogProducerResult.fromInt(resultCode), reqId, errorMessage, logBytes, compressedBytes)}")
})
}
}
}

View File

@ -2,12 +2,10 @@ package com.gh.common.loghub
import android.app.Application
import androidx.annotation.Keep
import com.aliyun.sls.android.sdk.model.Log
import com.aliyun.sls.android.sdk.model.LogGroup
import com.aliyun.sls.android.producer.Log
import com.gh.common.exposure.ExposureEntity
import com.gh.common.exposure.meta.Meta
import com.gh.common.util.tryWithDefaultCatch
import com.gh.loghub.LoghubHelper
import org.json.JSONObject
import java.util.concurrent.ExecutorService
@ -67,10 +65,6 @@ object LoghubUtils {
}
}
private fun uploadLogGroup(logGroup: LogGroup, logStore: String) {
LoghubHelper.getInstance().uploadLogGroup(logGroup, logStore)
}
fun commitSavedLoghubEvents() {
loghubEventExecutor?.execute {
// TODO 初始化 loghubHelper 去掉这个 tryCatch 块
@ -79,37 +73,29 @@ object LoghubUtils {
val exposureList = loghubEventSet.toList()
createLogGroupAndUpload()
uploadEvents()
loghubEventSet.removeAll(exposureList)
loghubEventDao.deleteMany(exposureList)
}
}
}
private fun createLogGroupAndUpload() {
val logGroupHashMap = hashMapOf<String, LogGroup>()
private fun uploadEvents() {
for (event in loghubEventSet) {
if (!logGroupHashMap.containsKey(event.logStore)) {
logGroupHashMap[event.logStore] = LogGroup("sls android", "no ip")
}
val log = Log()
// 特殊处理以下logStore不需要用content包裹数据
if (event.logStore == "collection" || event.logStore == "common" || event.logStore == "halo-api-device-installed") {
val contentJson = JSONObject(event.content)
for (key in contentJson.keys()) {
log.PutContent(key, contentJson.get(key).toString())
log.putContent(key, contentJson.get(key).toString())
}
} else {
log.PutContent("current time ", event.time)
log.PutContent("content", event.content)
log.putContent("current time ", event.time)
log.putContent("content", event.content)
}
logGroupHashMap[event.logStore]?.PutLog(log)
}
for ((logStore, logGroup) in logGroupHashMap) {
uploadLogGroup(logGroup, logStore)
LoghubHelper.uploadLog(log, event.logStore)
}
}

View File

@ -10,10 +10,12 @@ import com.g00fy2.versioncompare.Version
import com.gh.common.util.*
import com.gh.download.DownloadManager
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.SimulatorGameRecordEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.EmptyResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.room.AppDatabase
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadDao
import com.lightgame.download.DownloadEntity
@ -109,7 +111,7 @@ object SimulatorGameManager {
.subscribe({
val intent = Intent()
intent.data = Uri.fromFile(File(downloadEntity.path))
if (gameEntity.simulatorType == "FBA") {
if (gameEntity.simulatorType == "FBA" || gameEntity.simulatorType == "FBN") {
val apkEntity = gameEntity.getApk()[0]
intent.putExtra("rom_name", apkEntity.packageName)
}
@ -157,16 +159,42 @@ object SimulatorGameManager {
*/
@SuppressLint("CheckResult")
@JvmStatic
fun recordDownloadSimulatorGames(gameId: String) {
fun recordDownloadSimulatorGames(gameId: String, type: String) {
val requestMap = hashMapOf<String, Any>()
requestMap["game_id"] = gameId
requestMap["package"] = "-"
val body = requestMap.createRequestBodyAny()
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.downloadSimulatorGames(HaloApp.getInstance().gid, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(EmptyResponse())
.compose(singleToMain())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
refreshSimulatorGame(gameId, type)
}
})
}
@SuppressLint("CheckResult")
private fun refreshSimulatorGame(gameId: String, type: String) {
val simulatorGameDao = AppDatabase.getInstance(HaloApp.getInstance()).simulatorGameDao()
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.getSimulatorGames(HaloApp.getInstance().gid, 1, getFilter(type))
.compose(singleToMain())
.subscribe(object : BiResponse<List<GameEntity>>() {
override fun onSuccess(data: List<GameEntity>) {
val simulatorGameRecordList = ArrayList<SimulatorGameRecordEntity>()
data.forEach {
val entity = it.convertSimulatorGameRecordEntity()
entity.isRecentlyPlayed = it.id == gameId
simulatorGameRecordList.add(entity)
}
simulatorGameDao.addSimulatorGameList(simulatorGameRecordList)
}
})
}
private fun getFilter(type: String): String {
return UrlFilterUtils.getFilterQuery("type", type)
}
/**
@ -181,8 +209,7 @@ object SimulatorGameManager {
val body = requestMap.toRequestBody()
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.postPlayedGame(UserManager.getInstance().userId, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(singleToMain())
.subscribe(EmptyResponse())
}
}
@ -223,6 +250,7 @@ object SimulatorGameManager {
/**
* 批量删除设备下载模拟器游戏的记录
*/
@JvmStatic
@SuppressLint("CheckResult")
fun deleteSimulatorGames(gameIds: List<String>, callback: () -> Unit) {
val requestMap = hashMapOf<String, Any>()

View File

@ -80,7 +80,7 @@ class ExampleAdapter(context: Context) : ListAdapter<AnswerEntity>(context), ISy
ItemViewType.ITEM_FOOTER -> {
val footerViewHolder = holder as FooterViewHolder
footerViewHolder.initItemPadding()
footerViewHolder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint)
footerViewHolder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver)
}
}
}

View File

@ -0,0 +1,24 @@
package com.gh.common.tracker
import android.app.Activity
import android.app.Application
import android.os.Bundle
// TODO SplashActivity 没有回调 onStart 和 onStop
class ActivityLifecycleWatcher(private val mTrack: ITrack) : Application.ActivityLifecycleCallbacks {
override fun onActivityStarted(activity: Activity) {
mTrack.onActivityStarted(activity)
}
override fun onActivityStopped(activity: Activity) {
mTrack.onActivityStopped(activity)
}
override fun onActivityDestroyed(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityResumed(activity: Activity) {}
}

View File

@ -0,0 +1,72 @@
package com.gh.common.tracker
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong
import kotlin.concurrent.fixedRateTimer
/**
* 应用声明周期观察者
*/
class AppLifecycleWatcher(private val mTrack: ITrack) : DefaultLifecycleObserver {
private var mWatchVisibleCount = 0 // 检查是否满足上传可见的次数
private val mLastVisibleTime by lazy { AtomicLong(0L) } // 最后可见时间
private val mIsVisible by lazy { AtomicBoolean(false) } // 当前是否可见
private val mWatchInterval by lazy { AtomicLong(MIN_WATCH_VISIBLE_INTERVAL) } // 与上次上报可见的间隔时间
init {
fixedRateTimer(FIXED_RATE_TIMER_NAME, initialDelay = MIN_WATCH_VISIBLE_INTERVAL, period = MIN_WATCH_VISIBLE_INTERVAL) {
if (mIsVisible.get()) {
// 单位间隔发送
val meetLogVisibleInterval = (mWatchVisibleCount++) * MIN_WATCH_VISIBLE_INTERVAL == mWatchInterval.get()
val equalToMinVisibleInterval = mWatchInterval.get() == MIN_WATCH_VISIBLE_INTERVAL
val equalToMaxVisibleInterval = mWatchInterval.get() == MAX_WATCH_VISIBLE_INTERVAL
if (meetLogVisibleInterval || equalToMinVisibleInterval) {
// 上报完重置计数
mWatchVisibleCount = 0
mTrack.onAppVisible(mWatchInterval.get() / 1000)
if (!equalToMaxVisibleInterval) {
mWatchInterval.set(mWatchInterval.get() * 2) // 间隔递增两倍
}
}
}
}
}
override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
if (mLastVisibleTime.get() == 0L
|| (mLastVisibleTime.get() + SESSION_ALIVE_INTERVAL) < System.currentTimeMillis() / 1000) {
mTrack.onSessionChanged(UUID.randomUUID().toString())
}
mIsVisible.set(true)
mTrack.onAppStarted()
}
override fun onStop(owner: LifecycleOwner) {
super.onStop(owner)
mIsVisible.set(false)
mLastVisibleTime.set(System.currentTimeMillis() / 1000)
mWatchInterval.set(MIN_WATCH_VISIBLE_INTERVAL)
mTrack.onAppStopped()
}
companion object {
private const val FIXED_RATE_TIMER_NAME = "APP_TRACKER_TIMER"
private const val SESSION_ALIVE_INTERVAL = 30L // 30s
private const val MIN_WATCH_VISIBLE_INTERVAL = 5000L // 5s
private const val MAX_WATCH_VISIBLE_INTERVAL = 320000L // 320s
}
}

View File

@ -0,0 +1,8 @@
package com.gh.common.tracker
import androidx.annotation.Nullable
interface IBusiness {
@Nullable
fun getBusinessId(): Pair<String, String>
}

View File

@ -0,0 +1,14 @@
package com.gh.common.tracker
import android.app.Activity
interface ITrack {
fun onActivityStarted(activity: Activity)
fun onActivityStopped(activity: Activity)
fun onAppStarted()
fun onAppVisible(interval: Long)
fun onAppStopped()
fun onSessionChanged(sessionId: String)
}

View File

@ -0,0 +1,70 @@
package com.gh.common.tracker
import android.app.Activity
import android.app.Application
import androidx.lifecycle.ProcessLifecycleOwner
import java.util.*
object Tracker : ITrack {
private var mSessionId: String = ""
private val mLaunchId by lazy { UUID.randomUUID().toString() }
val sessionId: String
get() = mSessionId
val launchId: String
get() = mLaunchId
private var mIsInitialized = false
@JvmStatic
fun init(application: Application) {
if (mIsInitialized) {
return
}
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleWatcher(this))
application.registerActivityLifecycleCallbacks(ActivityLifecycleWatcher(this))
mIsInitialized = true
}
override fun onActivityStarted(activity: Activity) {
val businessId = if (activity is IBusiness) activity.getBusinessId() else null
TrackerLogger.logActivityStart(
mLaunchId,
mSessionId,
System.identityHashCode(activity).toString(),
activity::class.java.simpleName,
businessId)
}
override fun onActivityStopped(activity: Activity) {
val businessId = if (activity is IBusiness) activity.getBusinessId() else null
TrackerLogger.logActivityStop(
mLaunchId,
mSessionId,
System.identityHashCode(activity).toString(),
activity::class.java.simpleName,
businessId)
}
override fun onAppStarted() {
TrackerLogger.logAppStart(mLaunchId, mSessionId)
}
override fun onAppVisible(interval: Long) {
TrackerLogger.logAppVisible(mLaunchId, mSessionId, interval)
}
override fun onAppStopped() {
TrackerLogger.logAppStop(mLaunchId, mSessionId)
}
override fun onSessionChanged(sessionId: String) {
mSessionId = sessionId
}
}

View File

@ -0,0 +1,178 @@
package com.gh.common.tracker
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.exposure.meta.MetaUtil.getBase64EncodedAndroidId
import com.gh.common.exposure.meta.MetaUtil.getBase64EncodedIMEI
import com.gh.common.loghub.LoghubUtils
import com.gh.common.util.tryCatchInRelease
import com.lightgame.utils.Utils
import org.json.JSONException
import org.json.JSONObject
object TrackerLogger {
private const val LOG_STORE = "launch_activity"
fun logAppStart(launchId: String, sessionId: String) {
logAppVisible(launchId, sessionId, 0)
}
fun logAppVisible(launchId: String, sessionId: String, interval: Long) {
val jsonObject = JSONObject()
val payloadObject = JSONObject()
tryCatchInRelease {
payloadObject.put("launch_id", launchId)
payloadObject.put("session_id", sessionId)
payloadObject.put("interval", interval)
jsonObject.put("event", "app_visible")
jsonObject.put("payload", payloadObject)
jsonObject.put("meta", getMeta())
}
uploadToLoghub(jsonObject, true)
}
fun logAppStop(launchId: String, sessionId: String) {
val jsonObject = JSONObject()
val payloadObject = JSONObject()
tryCatchInRelease {
payloadObject.put("launch_id", launchId)
payloadObject.put("session_id", sessionId)
jsonObject.put("event", "app_invisible")
jsonObject.put("payload", payloadObject)
jsonObject.put("meta", getMeta())
}
uploadToLoghub(jsonObject, true)
}
fun logActivityStart(launchId: String,
sessionId: String,
activityId: String,
activityName: String,
activityBusinessId: Pair<String, String>? = null) {
val jsonObject = JSONObject()
val payloadObject = JSONObject()
tryCatchInRelease {
payloadObject.put("launch_id", launchId)
payloadObject.put("session_id", sessionId)
payloadObject.put("activity_id", activityId)
payloadObject.put("activity_name", activityName)
if (activityBusinessId != null) {
payloadObject.put("activity_primary_business_id", activityBusinessId.first)
if (activityBusinessId.second.isNotEmpty()) {
payloadObject.put("activity_secondary_business_id", activityBusinessId.second)
}
}
jsonObject.put("event", "activity_visible")
jsonObject.put("payload", payloadObject)
jsonObject.put("meta", getMeta())
}
uploadToLoghub(jsonObject, false)
}
fun logActivityStop(launchId: String,
sessionId: String,
activityId: String,
activityName: String,
activityBusinessId: Pair<String, String>? = null) {
val jsonObject = JSONObject()
val payloadObject = JSONObject()
tryCatchInRelease {
payloadObject.put("launch_id", launchId)
payloadObject.put("session_id", sessionId)
payloadObject.put("activity_id", activityId)
payloadObject.put("activity_name", activityName)
if (activityBusinessId != null) {
payloadObject.put("activity_primary_business_id", activityBusinessId.first)
if (activityBusinessId.second.isNotEmpty()) {
payloadObject.put("activity_secondary_business_id", activityBusinessId.second)
}
}
jsonObject.put("event", "activity_invisible")
jsonObject.put("payload", payloadObject)
jsonObject.put("meta", getMeta())
}
uploadToLoghub(jsonObject, false)
}
@JvmStatic
fun logHomeTabSelected(launchId: String,
sessionId: String,
tabPosition: Int,
tabContent: String) {
val jsonObject = JSONObject()
val payloadObject = JSONObject()
tryCatchInRelease {
payloadObject.put("launch_id", launchId)
payloadObject.put("session_id", sessionId)
payloadObject.put("tab_position", tabPosition)
payloadObject.put("tab_content", tabContent)
jsonObject.put("event", "home_tab_select")
jsonObject.put("payload", payloadObject)
jsonObject.put("meta", getMeta())
}
uploadToLoghub(jsonObject, false)
}
@JvmStatic
fun logAppLaunch(launchId: String, sessionId: String) {
val jsonObject = JSONObject()
val payloadObject = JSONObject()
tryCatchInRelease {
payloadObject.put("launch_id", launchId)
payloadObject.put("session_id", sessionId)
jsonObject.put("event", "app_launch")
jsonObject.put("payload", payloadObject)
jsonObject.put("meta", getMeta())
}
uploadToLoghub(jsonObject, true)
}
@JvmStatic
fun logAppLaunchSuccessful(launchId: String, sessionId: String) {
val jsonObject = JSONObject()
val payloadObject = JSONObject()
tryCatchInRelease {
payloadObject.put("launch_id", launchId)
payloadObject.put("session_id", sessionId)
jsonObject.put("event", "app_launch_successful")
jsonObject.put("payload", payloadObject)
jsonObject.put("meta", getMeta())
}
uploadToLoghub(jsonObject, true)
}
private fun uploadToLoghub(jsonObject: JSONObject, uploadImmediately: Boolean) {
jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
Utils.log("Tracker -> $jsonObject")
LoghubUtils.log(jsonObject, LOG_STORE, uploadImmediately)
}
private fun getMeta(): JSONObject {
val (_, _, model, manufacturer, _, _, android_version, network, _, gid, _, channel, appVersion, userId) = MetaUtil.getMeta()
val metaObject = JSONObject()
try {
metaObject.put("dia", getBase64EncodedAndroidId())
metaObject.put("android_version", android_version)
metaObject.put("app_version", appVersion)
metaObject.put("channel", channel)
metaObject.put("gid", gid)
metaObject.put("jnfj", getBase64EncodedIMEI())
metaObject.put("manufacturer", manufacturer)
metaObject.put("model", model)
metaObject.put("network", network)
metaObject.put("user_id", userId)
} catch (e: JSONException) {
e.printStackTrace()
}
return metaObject
}
}

View File

@ -1,148 +0,0 @@
package com.gh.common.util
import android.content.ContentUris
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.CalendarContract.*
import android.text.TextUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.R
import java.util.*
/**
* 签到日历提醒辅助类
*/
object CalendarHelper {
private val CALENDAR_URL = Calendars.CONTENT_URI
private val CALENDAR_EVENT_URL = Events.CONTENT_URI
private val CALENDAR_REMINDER_URL = Reminders.CONTENT_URI
private const val CALENDARS_NAME = "guanghuan"
private const val CALENDARS_ACCOUNT_TYPE = BuildConfig.APPLICATION_ID
private const val CALENDARS_DISPLAY_NAME = "光环助手"
private fun checkAndAddCalendarAccount(context: Context): Int {
val oldId: Int = checkCalendarAccount(context)
return if (oldId >= 0) {
oldId
} else {
val addId: Long = addCalendarAccount(context)
if (addId >= 0) {
checkCalendarAccount(context)
} else {
-1
}
}
}
private fun checkCalendarAccount(context: Context): Int {
val userCursor: Cursor? = context.contentResolver.query(CALENDAR_URL,
null, null, null, null)
return userCursor?.use {
val count: Int = it.count
if (count > 0) { // 存在现有账户取第一个账户的id返回
it.moveToFirst()
it.getInt(userCursor.getColumnIndex(Calendars._ID))
} else {
-1
}
} ?: -1
}
private fun addCalendarAccount(context: Context): Long {
val value = ContentValues().apply {
put(Calendars.NAME, CALENDARS_NAME)
put(Calendars.ACCOUNT_NAME, CALENDARS_DISPLAY_NAME)
put(Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE)
put(Calendars.CALENDAR_DISPLAY_NAME, CALENDARS_DISPLAY_NAME)
put(Calendars.VISIBLE, 1)
put(Calendars.CALENDAR_COLOR, R.color.theme.toColor())
put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER)
put(Calendars.SYNC_EVENTS, 1)
put(Calendars.CALENDAR_TIME_ZONE, TimeZone.getDefault().id)
put(Calendars.OWNER_ACCOUNT, CALENDARS_NAME)
put(Calendars.CAN_ORGANIZER_RESPOND, 0)
}
var calendarUri: Uri = CALENDAR_URL
calendarUri = calendarUri.buildUpon()
.appendQueryParameter(CALLER_IS_SYNCADAPTER, "true")
.appendQueryParameter(Calendars.ACCOUNT_NAME, CALENDARS_NAME)
.appendQueryParameter(Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE)
.build()
val result: Uri? = context.contentResolver.insert(calendarUri, value)
return if (result == null) -1 else ContentUris.parseId(result)
}
fun insertCalendarEvent(context: Context,
title: String,
description: String,
beginTimeMillis: Long,
endTimeMillis: Long,
rRule: String?): Boolean {
val calendarId = checkAndAddCalendarAccount(context) // 获取日历账户的id
if (calendarId < 0) { // 获取账户id失败直接返回添加日历事件失败
return false
}
try {
/** 插入日程 */
val eventValues = ContentValues().apply {
if (rRule != null) put(Events.RRULE, rRule)
put(Events.DTSTART, beginTimeMillis)
put(Events.DTEND, endTimeMillis)
put(Events.TITLE, title)
put(Events.DESCRIPTION, description)
put(Events.CALENDAR_ID, calendarId)
put(Events.EVENT_TIMEZONE, TimeZone.getDefault().id)
}
val eUri: Uri? = context.contentResolver.insert(CALENDAR_EVENT_URL, eventValues)
val eventId = eUri?.let { ContentUris.parseId(it) }
if (eventId == 0L) { // 插入失败
return false
}
/** 插入提醒 - 依赖插入日程成功 */
val reminderValues = ContentValues()
// uri.getLastPathSegment();
reminderValues.put(Reminders.EVENT_ID, eventId)
reminderValues.put(Reminders.MINUTES, 0) // 准时提醒
reminderValues.put(Reminders.METHOD, Reminders.METHOD_ALERT)
val rUri: Uri? = context.contentResolver.insert(CALENDAR_REMINDER_URL, reminderValues)
if (rUri == null || ContentUris.parseId(rUri) == 0L) {
return false
}
} catch (e: Exception) {
e.printStackTrace()
return false
}
return true
}
fun deleteCalendarEvent(context: Context,
title: String): Boolean {
val eventCursor = context.contentResolver.query(CALENDAR_EVENT_URL,
null, null, null, null)
eventCursor?.use {
if (it.count > 0) {
// 遍历所有事件找到title跟需要查询的title一样的项
it.moveToFirst()
while (!it.isAfterLast) {
val eventTitle = eventCursor.getString(eventCursor.getColumnIndex("title"))
if (!TextUtils.isEmpty(title) && title == eventTitle) {
val id = eventCursor.getInt(eventCursor
.getColumnIndex(Calendars._ID)) // 取得id
val deleteUri = ContentUris.withAppendedId(CALENDAR_EVENT_URL, id.toLong())
val rows = context.contentResolver.delete(deleteUri, null, null)
return rows != -1
}
it.moveToNext()
}
}
}
return false
}
}

View File

@ -1,16 +1,14 @@
package com.gh.common.util;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import com.gh.common.avoidcallback.Callback;
import com.gh.common.constant.Constants;
import com.gh.gamecenter.LoginActivity;
import com.gh.gamecenter.manager.UserManager;
import com.lightgame.utils.Utils;
import org.jetbrains.annotations.Nullable;
/**
* Created by khy on 28/06/17.
@ -24,11 +22,15 @@ public class CheckLoginUtils {
LogUtils.login("dialog", null, entrance);
LogUtils.login("activity", null, entrance);
// 有可能App未启动
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
bundle.putString(EntranceUtils.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(context, bundle);
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
QuickLoginHelper.startLogin(context, entrance);
} else {
// 有可能App未启动
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
bundle.putString(EntranceUtils.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(context, bundle);
}
} else {
if (listener != null) {
listener.onLogin();

View File

@ -118,13 +118,13 @@ object CommentHelper {
}
val inflater = LayoutInflater.from(context)
val layout = inflater.inflate(R.layout.comment_more_option, null)
val layout = inflater.inflate(R.layout.layout_popup_container, null)
val popupWindow = BugFixedPopupWindow(layout,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT)
val container = layout.findViewById<LinearLayout>(R.id.container)
for (text in dialogOptions) {
val item = inflater.inflate(R.layout.comment_more_option_item, container, false)
val item = inflater.inflate(R.layout.layout_popup_option_item, container, false)
container.addView(item)
val hitText = item.findViewById<TextView>(R.id.hint_text)

View File

@ -2,88 +2,37 @@ package com.gh.common.util
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.Window
import android.widget.TextView
import com.gh.common.dialog.TrackableDialog
import com.gh.common.util.DialogUtils.checkDialogContext
import com.gh.gamecenter.AboutActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogAlertDefaultBinding
object DialogHelper {
/**
* Material Design 风格弹窗
* 光环常规弹窗
*
* @param context
* @param title 标题
* @param content 内容
* @param positiveText 确认按钮文本
* @param negativeText 取消按钮文本
* @param positiveClickCallback 确认按钮监听
* @param negativeClickCallback 取消按钮监听
* @param trackMtaEvent 是否记录出现、关闭弹窗MTA事件
* @param mtaEvent MTA 的事件名
* @param mtaKey MTA 的事件 Key
* extraConfig可选标题居中、内容居中、是否显示关闭按钮以及是否显示正文辅助文本等
*
* uiModificationCallback可用来手动微调样式的回调可使用 binding 来修改颜色、文字大小等
*/
fun showDialog(context: Context,
title: String,
content: CharSequence,
positiveText: String,
negativeText: String,
positiveClickCallback: (() -> Unit)? = null,
negativeClickCallback: (() -> Unit)? = null,
trackMtaEvent: Boolean = false,
mtaEvent: String = "",
mtaKey: String = ""): Dialog {
val solidContext = checkDialogContext(context)
val dialog = if (trackMtaEvent) {
TrackableDialog(solidContext, R.style.GhAlertDialog, mtaEvent, mtaKey)
} else {
Dialog(solidContext, R.style.GhAlertDialog)
}
val contentView = LayoutInflater.from(solidContext).inflate(R.layout.dialog_alert, null)
val contentTv = contentView.findViewById<TextView>(R.id.dialog_content)
val titleTv = contentView.findViewById<TextView>(R.id.dialog_title)
val negativeTv = contentView.findViewById<TextView>(R.id.dialog_negative)
val positiveTv = contentView.findViewById<TextView>(R.id.dialog_positive)
contentTv.text = content
titleTv.text = title
negativeTv.text = negativeText
positiveTv.text = positiveText
negativeTv.setOnClickListener {
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击" + negativeText)
negativeClickCallback?.invoke()
dialog.dismiss()
}
positiveTv.setOnClickListener {
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击$positiveText")
positiveClickCallback?.invoke()
dialog.dismiss()
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setContentView(contentView)
dialog.show()
return dialog
}
fun showRoundedCornerDialog(
fun showDialog(
context: Context,
title: String,
content: CharSequence,
hint: String? = "",
confirmText: String,
cancelText: String,
confirmClickCallback: (() -> Unit)? = null,
cancelClickCallback: (() -> Unit)? = null,
hintClickCallback: (() -> Unit)? = null,
extraConfig: Config? = null,
uiModificationCallback: ((binding: DialogAlertDefaultBinding) -> Unit)? = null,
trackMtaEvent: Boolean = false,
mtaEvent: String = "",
mtaKey: String = ""): Dialog {
@ -95,40 +44,58 @@ object DialogHelper {
Dialog(solidContext, R.style.GhAlertDialog)
}
val contentView = LayoutInflater.from(solidContext).inflate(R.layout.dialog_alert_default, null)
val contentTv = contentView.findViewById<TextView>(R.id.contentTv)
val titleTv = contentView.findViewById<TextView>(R.id.titleTv)
val hintTv = contentView.findViewById<TextView>(R.id.hintTv)
val cancelTv = contentView.findViewById<TextView>(R.id.cancelTv)
val confirmTv = contentView.findViewById<TextView>(R.id.confirmTv)
contentTv.text = content
titleTv.text = title
if (!hint.isNullOrEmpty()) {
hintTv.visibility = View.VISIBLE
hintTv.text = hint
hintTv.setOnClickListener {
hintClickCallback?.invoke()
val binding = DialogAlertDefaultBinding.inflate(LayoutInflater.from(solidContext))
val contentView = binding.root
binding.contentTv.text = content
binding.titleTv.text = title
extraConfig?.let {
if (it.hint.isNotEmpty()) {
binding.hintTv.visibility = View.VISIBLE
binding.hintTv.text = it.hint
}
if (it.centerTitle) {
binding.titleTv.gravity = Gravity.CENTER
}
if (it.centerContent) {
binding.contentTv.gravity = Gravity.CENTER
}
if (it.showCloseIcon) {
binding.closeContainer.visibility = View.VISIBLE
binding.closeContainer.setOnClickListener { dialog.dismiss() }
}
}
cancelTv.text = cancelText
confirmTv.text = confirmText
cancelTv.setOnClickListener {
if (cancelText.isEmpty()) {
binding.cancelTv.visibility = View.GONE
binding.centerDivider.visibility = View.GONE
}
binding.cancelTv.text = cancelText
binding.confirmTv.text = confirmText
binding.cancelTv.setOnClickListener {
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击$cancelText")
cancelClickCallback?.invoke()
dialog.dismiss()
}
confirmTv.setOnClickListener {
binding.confirmTv.setOnClickListener {
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击$confirmText")
confirmClickCallback?.invoke()
dialog.dismiss()
}
uiModificationCallback?.invoke(binding)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setContentView(contentView)
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.show()
return dialog
}
@ -137,6 +104,7 @@ object DialogHelper {
* For legacy java invocation
*/
@JvmStatic
@Deprecated("Kotlin 中请使用其它方法调用")
fun showDialog(context: Context,
title: String,
content: CharSequence,
@ -147,7 +115,87 @@ object DialogHelper {
trackMtaEvent: Boolean = false,
mtaEvent: String = "",
mtaKey: String = ""): Dialog {
return showDialog(context, title, content, positiveText, negativeText, { positiveClickCallback.onCallback() }, { negativeClickCallback.onCallback() }, trackMtaEvent, mtaEvent, mtaKey)
return showDialog(
context = context,
title = title,
content = content,
confirmText = positiveText,
cancelText = negativeText,
confirmClickCallback = { positiveClickCallback.onCallback() },
cancelClickCallback = { negativeClickCallback.onCallback() },
trackMtaEvent = trackMtaEvent,
mtaEvent = mtaEvent,
mtaKey = mtaKey)
}
@JvmStatic
fun showSignatureConflictDialog(context: Context,
confirmClickCallback: (() -> Unit)? = null) {
showDialog(
context,
"温馨提示",
"检测到安装包与已安装应用的签名不一致,需要卸载后才能安装,是否立即卸载",
"卸载",
"取消",
{ confirmClickCallback?.invoke() },
null,
Config(hint = "注意:卸载会让游戏数据丢失,请提前做好备份"),
{ binding -> binding.hintTv.setTextColor(R.color.theme_font.toColor()) }
)
}
@JvmStatic
fun showPluginDialog(context: Context,
confirmClickCallback: (() -> Unit)? = null) {
MtaHelper.onEvent("插件化", "插件化安装弹窗", "出现弹窗提示")
showDialog(
context,
"插件化安装",
"您将进行插件化安装以实现插件功能,此过程将卸载当前使用的版本并安装插件版本",
"确认,开始插件化",
"取消",
{
confirmClickCallback?.invoke()
MtaHelper.onEvent("插件化", "插件化安装弹窗", "确认并开始")
},
{ MtaHelper.onEvent("插件化", "插件化安装弹窗", "取消") },
Config(hint = "注意:卸载前请妥善保存游戏账号与密码"),
{ binding -> binding.hintTv.setTextColor(R.color.text_FF0000.toColor()) }
)
}
@JvmStatic
fun showUpgradeDialog(context: Context) {
showDialog(
context,
"提示",
"当前版本暂不支持该功能,\n建议您升级到最新版本体验哦",
"检查升级",
"取消",
confirmClickCallback = { context.startActivity(AboutActivity.getIntent(context, true)); },
uiModificationCallback = {
it.titleTv.gravity = Gravity.CENTER
it.contentTv.gravity = Gravity.CENTER
}
)
}
@JvmStatic
fun showDowngradeHintDialog(context: Context,
confirmClickCallback: (() -> Unit)? = null) {
showDialog(
context,
"温馨提示",
"您已安装较高版本,若要安装历史版本需先卸载再安装\n",
"我知道了",
"",
{ confirmClickCallback?.invoke() })
}
data class Config(val hint: String = "",
val showCloseIcon: Boolean = false,
val centerTitle: Boolean = false,
val centerContent: Boolean = false)
}

View File

@ -46,6 +46,7 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
@ -63,8 +64,11 @@ import com.gh.gamecenter.AboutActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SuggestionActivity;
import com.gh.gamecenter.adapter.viewholder.PrivacyPolicyItemViewHolder;
import com.gh.gamecenter.databinding.DialogBindPhoneBinding;
import com.gh.gamecenter.databinding.DialogOverseaConfirmationBinding;
import com.gh.gamecenter.databinding.DialogPackageParseErrorBinding;
import com.gh.gamecenter.databinding.DialogQuickLoginPermissionBinding;
import com.gh.gamecenter.databinding.DialogReceiveLibaoSuccessBinding;
import com.gh.gamecenter.databinding.DialogReportReasonBinding;
import com.gh.gamecenter.databinding.ImprintContentItemBinding;
import com.gh.gamecenter.databinding.PrivacyItemBinding;
@ -322,33 +326,6 @@ public class DialogUtils {
showCancelListenerDialog(context, "取消关注", content, "确定取消", "暂不取消", listener, cancelListener);
}
public static void showPluginDialog(Context context, final ConfirmListener listener) {
context = checkDialogContext(context);
MtaHelper.onEvent("插件化", "插件化安装弹窗", "出现弹窗提示");
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_plugin, null);
TextView negativeTv = contentView.findViewById(R.id.dialog_negative);
TextView positiveTv = contentView.findViewById(R.id.dialog_positive);
negativeTv.setOnClickListener(v -> {
dialog.dismiss();
MtaHelper.onEvent("插件化", "插件化安装弹窗", "取消");
});
positiveTv.setOnClickListener(view -> {
if (listener != null) {
listener.onConfirm();
}
dialog.dismiss();
MtaHelper.onEvent("插件化", "插件化安装弹窗", "确认并开始");
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
/**
* ios 风格弹窗
*
@ -809,33 +786,6 @@ public class DialogUtils {
dialog.show();
}
public static void showLowVersionDialog(Context context) {
final Context activityContext = checkDialogContext(context);
final Dialog dialog = new Dialog(activityContext, R.style.GhAlertDialog);
View contentView = LayoutInflater.from(activityContext).inflate(R.layout.dialog_alert, null);
TextView contentTv = contentView.findViewById(R.id.dialog_content);
TextView titleTv = contentView.findViewById(R.id.dialog_title);
TextView negativeTv = contentView.findViewById(R.id.dialog_negative);
TextView positiveTv = contentView.findViewById(R.id.dialog_positive);
contentTv.setText("链接超出范围,请检查升级至最新版本的光环助手");
titleTv.setText("提示");
negativeTv.setText("关闭");
positiveTv.setText("检查升级");
negativeTv.setOnClickListener(view -> dialog.dismiss());
positiveTv.setOnClickListener(view -> {
activityContext.startActivity(AboutActivity.getIntent(activityContext, true));
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
public static void showLowSystemVersionDialog(Context context) {
final Context activityContext = checkDialogContext(context);
@ -1109,7 +1059,7 @@ public class DialogUtils {
topContent.setText(entity.getTopContent());
bottomContent.setText(ExtensionsKt.fromHtml(entity.getBottomContent()));
bottomContent.setMovementMethod(CustomLinkMovementMethod.getInstance());
// Remove underline
Spannable sa = (Spannable) bottomContent.getText();
for (URLSpan u : sa.getSpans(0, sa.length(), URLSpan.class)) {
@ -2161,6 +2111,77 @@ public class DialogUtils {
dialog.show();
}
public static void showBindPhoneDialog(Context context, ConfirmListener listener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
DialogBindPhoneBinding binding = DialogBindPhoneBinding.inflate(LayoutInflater.from(context));
binding.positiveTv.setOnClickListener(v -> {
dialog.dismiss();
listener.onConfirm();
});
binding.closeIv.setOnClickListener(v -> {
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(binding.getRoot());
dialog.show();
}
public static void showReceiveLibaoSuccessDialog(Context context, String title, String des, String libaoCode, ConfirmListener listener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
DialogReceiveLibaoSuccessBinding binding = DialogReceiveLibaoSuccessBinding.inflate(LayoutInflater.from(context));
binding.title.setText(title);
binding.libaoCodeTv.setText(libaoCode);
binding.desTv.setText(des);
binding.confirm.setOnClickListener(v -> {
dialog.dismiss();
listener.onConfirm();
});
binding.cancel.setOnClickListener(v -> {
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(binding.getRoot());
dialog.show();
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
WindowManager.LayoutParams params = window.getAttributes();
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(60f);
window.setAttributes(params);
}
}
public static void showQuickLoginPermissionDialog(Context context, ConfirmListener confirmListener, CancelListener cancelListener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
DialogQuickLoginPermissionBinding binding = DialogQuickLoginPermissionBinding.inflate(LayoutInflater.from(context));
binding.confirmBtn.setOnClickListener(v -> {
dialog.dismiss();
confirmListener.onConfirm();
});
binding.cancelBtn.setOnClickListener(v -> {
dialog.dismiss();
cancelListener.onCancel();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(binding.getRoot());
dialog.show();
}
/**
* @param context may be is application context
* @return activity context

View File

@ -25,6 +25,7 @@ import com.gh.gamecenter.*
import com.gh.gamecenter.amway.AmwayActivity
import com.gh.gamecenter.catalog.CatalogActivity
import com.gh.gamecenter.category.CategoryDirectoryActivity
import com.gh.gamecenter.category2.CategoryV2Activity
import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.eventbus.EBReuse
@ -52,6 +53,7 @@ import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.security.BindPhoneActivity
import com.gh.gamecenter.servers.GameServerTestActivity
import com.gh.gamecenter.servers.GameServersActivity
import com.gh.gamecenter.subject.SubjectActivity
import com.gh.gamecenter.suggest.SuggestType
@ -209,6 +211,8 @@ object DirectUtils {
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
"category_v2" -> directCategoryV2(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
"block", "版块" -> {
if (linkEntity.link.isNullOrEmpty()) return
directToBlock(context,
@ -238,7 +242,7 @@ object DirectUtils {
"libao", "礼包" -> directToGiftDetail(context, linkEntity.link ?: "", entrance)
"feedback" -> directToFeedback(context, linkEntity.name, linkEntity.text, entrance)
"feedback" -> directToFeedback(context, linkEntity.name, linkEntity.text, false, entrance)
"qa", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
@ -302,6 +306,9 @@ object DirectUtils {
"toolkit" -> context.startActivity(ToolBoxActivity.getIntent(context, entrance))
"column_test" -> context.startActivity(GameServerTestActivity.getIntent(context, linkEntity.link
?: "", linkEntity.text ?: "", entrance))
"toolkit_detail" -> {
linkEntity.toolkit?.run {
if (url != null && url!!.contains(Config.URL_ARTICLE)) {
@ -325,7 +332,7 @@ object DirectUtils {
if (unknownCallback != null) {
unknownCallback.invoke()
} else {
DialogUtils.showLowVersionDialog(context)
DialogHelper.showUpgradeDialog(context)
}
}
}
@ -424,6 +431,20 @@ object DirectUtils {
jumpActivity(context, bundle)
}
/**
* 跳转到新闻详情
*/
@JvmStatic
fun directToArticle(context: Context, id: String, hideUselessInfo: Boolean, entrance: String? = null) {
if (id.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, NewsDetailActivity::class.java.simpleName)
bundle.putString(KEY_NEWSID, id)
bundle.putBoolean(KEY_HIDE_USELESS_INFO, hideUselessInfo)
jumpActivity(context, bundle)
}
/**
* 跳转至个人主页
*/
@ -438,6 +459,7 @@ object DirectUtils {
*/
@JvmStatic
fun directToHomeActivity(context: Context, userId: String?, position: Int, entrance: String? = null, path: String? = null) {
IntegralLogHelper.log("view_homepage", "个人主页")
val bundle = Bundle()
bundle.putString(KEY_USER_ID, userId)
bundle.putString(KEY_TO, UserHomeActivity::class.java.name)
@ -539,21 +561,27 @@ object DirectUtils {
// 反馈
@JvmStatic
fun directToFeedback(context: Context, content: String? = null, entrance: String? = null) {
directToFeedback(context, content, null, entrance)
directToFeedback(context, content, null, false, entrance)
}
@JvmStatic
fun directToFeedback(context: Context, content: String? = null, hintType: String? = null, entrance: String? = null) {
fun directToFeedback(context: Context, content: String? = null, hintType: String? = null, isQaFeedback: Boolean = false, entrance: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, SuggestionActivity::class.java.simpleName)
bundle.putString(KEY_CONTENT, content)
if (TextUtils.isEmpty(hintType)) {
bundle.putString(KEY_SUGGEST_HINT_TYPE, KEY_PLUGIN)
if (isQaFeedback) {
bundle.putBoolean(KEY_IS_QA_FEEDBACK, true)
bundle.putSerializable(KEY_SUGGESTTYPE, SuggestType.normal)
} else {
bundle.putString(KEY_SUGGEST_HINT_TYPE, hintType)
bundle.putString(KEY_CONTENT, content)
bundle.putSerializable(KEY_SUGGESTTYPE, SuggestType.gameQuestion)
if (TextUtils.isEmpty(hintType)) {
bundle.putString(KEY_SUGGEST_HINT_TYPE, KEY_PLUGIN)
} else {
bundle.putString(KEY_SUGGEST_HINT_TYPE, hintType)
}
}
bundle.putSerializable(KEY_SUGGESTTYPE, SuggestType.gameQuestion)
jumpActivity(context, bundle)
}
@ -978,6 +1006,20 @@ object DirectUtils {
jumpActivity(context, bundle)
}
/**
* 跳转新分类2.0
*/
@JvmStatic
fun directCategoryV2(context: Context, categoryId: String, categoryTitle: String, entrance: String? = null, path: String? = "") {
if (categoryId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, CategoryV2Activity::class.java.name)
bundle.putString(KEY_CATEGORY_ID, categoryId)
bundle.putString(KEY_CATEGORY_TITLE, categoryTitle)
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
jumpActivity(context, bundle)
}
/**
* 跳转到问题标签详情
*/
@ -1267,7 +1309,7 @@ object DirectUtils {
} else {
Constants.INVITE_FRIENDS_ADDRESS
}
directToFullScreenWebPage(context, url, false)
directToFullScreenWebPage(context, url, true)
}
/**
@ -1284,4 +1326,139 @@ object DirectUtils {
url = String.format(Locale.CHINA, "%s?timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至兑换规则
*/
@JvmStatic
fun directToExchangeRulePage(context: Context) {
var url: String = if (isPublishEnv()) {
Constants.EXCHANGE_RULE_ADDRESS
} else {
Constants.EXCHANGE_RULE_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s&timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至光能规则
*/
@JvmStatic
fun directToEnergyRulePage(context: Context) {
var url: String = if (isPublishEnv()) {
Constants.ENERGY_RULE_ADDRESS
} else {
Constants.ENERGY_RULE_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s&timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至兑换商品
*/
@JvmStatic
fun directToExchangeCommodityPage(context: Context) {
var url: String = if (isPublishEnv()) {
Constants.EXCHANGE_COMMODITY_ADDRESS
} else {
Constants.EXCHANGE_COMMODITY_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s&timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至抽奖乐园
*/
@JvmStatic
fun directToLotteryParadisePage(context: Context) {
var url: String = if (isPublishEnv()) {
Constants.LOTTERY_PARADISE_ADDRESS
} else {
Constants.LOTTERY_PARADISE_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s&timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至我的奖品
*/
@JvmStatic
fun directToMyPrizePage(context: Context) {
var url: String = if (isPublishEnv()) {
Constants.MY_PRIZE_ADDRESS
} else {
Constants.MY_PRIZE_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s&timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至中奖订单详情
*/
@JvmStatic
fun directToWinOrderDetail(context: Context, orderId: String, activityId: String) {
var url: String = if (isPublishEnv()) {
Constants.WIN_ORDER_DETAIL_ADDRESS
} else {
Constants.WIN_ORDER_DETAIL_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s&order_id=%s&activity_id=%s&timestamp=%d", url, orderId, activityId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至地址信息
*/
@JvmStatic
fun directToAddressInfo(context: Context) {
var url: String = if (isPublishEnv()) {
Constants.ADDRESS_INFO_ADDRESS
} else {
Constants.ADDRESS_INFO_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s&timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至领奖信息
*/
@JvmStatic
fun directToPrizeInfo(context: Context) {
var url: String = if (isPublishEnv()) {
Constants.PRIZE_INFO_ADDRESS
} else {
Constants.PRIZE_INFO_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s&timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至提现信息
*/
@JvmStatic
fun directToWithdrawInfo(context: Context) {
var url: String = if (isPublishEnv()) {
Constants.WITHDRAW_INFO_ADDRESS
} else {
Constants.WITHDRAW_INFO_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s&timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
}

View File

@ -21,67 +21,74 @@ object DownloadDialogHelper {
}
private fun retrieveAvailableDialog(gameEntity: GameEntity, apkEntity: ApkEntity): GameEntity.Dialog? {
if (gameEntity.downloadDialog.isNullOrEmpty()) return null
val downloadDialog = if (gameEntity.shouldUseMirrorInfo()) {
gameEntity.mirrorData?.downloadDialog
} else {
gameEntity.downloadDialog
}
for (dialog in gameEntity.downloadDialog!!) {
if (downloadDialog.isNullOrEmpty()) return null
for (dialog in downloadDialog) {
val versionName = PackageUtils.getVersionName()
val noticeVersions = dialog.rule.noticeVersions
if (noticeVersions.isEmpty() || noticeVersions.contains(versionName)) {
// 共有 8 种可能
// 1. 不指定包名、机型和系统版本
if (dialog.rule.packageName.isEmpty()
&& dialog.rule.models.isEmpty()
&& dialog.rule.systemVersions.isEmpty()) {
return dialog
}
// 共有 8 种可能
// 1. 不指定包名、机型和系统版本
if (dialog.rule.packageName.isEmpty()
&& dialog.rule.models.isEmpty()
&& dialog.rule.systemVersions.isEmpty()) {
return dialog
}
// 2. 指定包名不管机型和系统
if (dialog.rule.packageName == apkEntity.packageName
&& dialog.rule.models.isEmpty()
&& dialog.rule.systemVersions.isEmpty()) {
return dialog
}
// 2. 指定包名不管机型和系统
if (dialog.rule.packageName == apkEntity.packageName
&& dialog.rule.models.isEmpty()
&& dialog.rule.systemVersions.isEmpty()) {
return dialog
}
// 3. 指定机型不管包名和系统
if (dialog.rule.models.contains(Build.MODEL)
&& dialog.rule.packageName.isEmpty()
&& dialog.rule.systemVersions.isEmpty()) {
return dialog
}
// 3. 指定机型不管包名和系统
if (dialog.rule.models.contains(Build.MODEL)
&& dialog.rule.packageName.isEmpty()
&& dialog.rule.systemVersions.isEmpty()) {
return dialog
}
// 4. 指定系统不管包名和机型
if (dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
&& dialog.rule.packageName.isEmpty()
&& dialog.rule.models.isEmpty()) {
return dialog
}
// 4. 指定系统不管包名和机型
if (dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
&& dialog.rule.packageName.isEmpty()
&& dialog.rule.models.isEmpty()) {
return dialog
}
// 5. 指定包名和机型不管系统
if (dialog.rule.packageName == apkEntity.packageName
&& dialog.rule.models.contains(Build.MODEL)
&& dialog.rule.systemVersions.isEmpty()) {
return dialog
}
// 5. 指定包名和机型不管系统
if (dialog.rule.packageName == apkEntity.packageName
&& dialog.rule.models.contains(Build.MODEL)
&& dialog.rule.systemVersions.isEmpty()) {
return dialog
}
// 6. 指定包名和系统不管机型
if (dialog.rule.packageName == apkEntity.packageName
&& dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
&& dialog.rule.models.isEmpty()) {
return dialog
}
// 6. 指定包名和系统不管机型
if (dialog.rule.packageName == apkEntity.packageName
&& dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
&& dialog.rule.models.isEmpty()) {
return dialog
}
// 7. 指定机型和系统不管包名
if (dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
&& dialog.rule.models.contains(Build.MODEL)
&& dialog.rule.packageName.isEmpty()) {
return dialog
}
// 8.指定包名、机型和系统版本
if (dialog.rule.packageName == apkEntity.packageName
&& dialog.rule.models.contains(Build.MODEL)
&& dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)) {
return dialog
}
// 7. 指定机型和系统不管包名
if (dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)
&& dialog.rule.models.contains(Build.MODEL)
&& dialog.rule.packageName.isEmpty()) {
return dialog
}
// 8.指定包名、机型和系统版本
if (dialog.rule.packageName == apkEntity.packageName
&& dialog.rule.models.contains(Build.MODEL)
&& dialog.rule.systemVersions.contains(Build.VERSION.RELEASE)) {
return dialog
}
} else return null
}
return null

View File

@ -28,6 +28,7 @@ import com.gh.common.xapk.XapkInstaller;
import com.gh.common.xapk.XapkUnzipStatus;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
import com.gh.download.server.BrowserInstallHelper;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
@ -36,6 +37,7 @@ import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.LinkEntity;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DownloadConfig;
import com.lightgame.download.DownloadEntity;
@ -136,6 +138,7 @@ public class DownloadItemUtils {
holder.gameDownloadBtn.setText("已预约");
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(holder.gameDes.getContext(), R.color.aaaaaa));
holder.gameDownloadBtn.setBackgroundResource(R.drawable.button_round_f5f5f5);
updateItemViewStatus(holder, false, null);
}
}
@ -545,15 +548,19 @@ public class DownloadItemUtils {
if (clickCallback != null) {
clickCallback.onCallback();
}
PermissionHelper.checkStoragePermissionBeforeAction(context, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location);
RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
GamePermissionDialogFragment.show((AppCompatActivity) context, gameEntity, gameEntity.getInfo(), () -> {
PermissionHelper.checkStoragePermissionBeforeAction(context, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location);
});
});
});
});
});
@ -586,12 +593,18 @@ public class DownloadItemUtils {
if (str.equals(context.getString(R.string.download))) {
// 先弹下载弹窗(如果需要的话)
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
RealNameHelper.checkIfAuth(context, gameEntity, () -> {
GamePermissionDialogFragment.show((AppCompatActivity) context, gameEntity, gameEntity.getInfo(), () -> {
BrowserInstallHelper.showBrowserInstallHintDialog(context, () -> {
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity, () -> {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
});
});
});
});
});
});
@ -599,13 +612,19 @@ public class DownloadItemUtils {
DataLogUtils.uploadGameLog(context, gameEntity.getId(), gameEntity.getName(), entrance);
} else if (str.equals(context.getString(R.string.attempt))) {
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
RealNameHelper.checkIfAuth(context, gameEntity, () -> {
GamePermissionDialogFragment.show((AppCompatActivity) context, gameEntity, gameEntity.getInfo(), () -> {
BrowserInstallHelper.showBrowserInstallHintDialog(context, () -> {
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity, () -> {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
});
});
});
});
});
});
@ -671,6 +690,7 @@ public class DownloadItemUtils {
context.startActivity(DownloadManagerActivity.getDownloadMangerIntent(context,
apk.getUrl(), entrance + "+(" + location.split(":")[0] + ")"));
}
}
//下载
@ -692,8 +712,6 @@ public class DownloadItemUtils {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
DeviceRemindDialog.Companion.showDeviceRemindDialog(context, gameEntity);
EnergyTaskHelper.postEnergyTask("download_game", gameEntity.getId(), gameEntity.getApk().get(0).getPackageName());
} else {
Utils.toast(context, msg);
}
@ -732,7 +750,10 @@ public class DownloadItemUtils {
}
adapter.notifyItemChanged(position);
} else if (PackageUtils.isCanPluggable(apkEntity)) {
DialogUtils.showPluginDialog(context, () -> PackageInstaller.uninstall(context, path));
DialogHelper.showPluginDialog(context, () -> {
PackageInstaller.uninstall(context, path);
return null;
});
} else {
PackageInstaller.install(context, downloadEntity);
}

View File

@ -8,6 +8,7 @@ import com.gh.common.exposure.ExposureUtils
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.simulator.SimulatorDownloadManager
import com.gh.common.simulator.SimulatorGameManager
import com.gh.common.util.EnergyTaskHelper.postEnergyTask
import com.gh.common.xapk.XapkInstaller
import com.gh.download.DownloadDataHelper
import com.gh.download.DownloadManager
@ -126,6 +127,7 @@ object DownloadObserver {
} else {
statDoneEvent(downloadEntity)
postEnergyTask("download_game", downloadEntity.gameId, downloadEntity.packageName)
val platform = PlatformUtils.getInstance(mApplication)
.getPlatformName(downloadEntity.platform)
if (platform != null) {
@ -153,7 +155,7 @@ object DownloadObserver {
SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator,
SimulatorDownloadManager.SimulatorLocation.LAUNCH, downloadEntity.gameId, gameName, null)
}
SimulatorGameManager.recordDownloadSimulatorGames(downloadEntity.gameId)
SimulatorGameManager.recordDownloadSimulatorGames(downloadEntity.gameId, simulator.type)
SimulatorGameManager.postPlayedGame(downloadEntity.gameId, downloadEntity.packageName)
} else {
val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
@ -171,7 +173,11 @@ object DownloadObserver {
}
} else {
// 弹出卸载提示框
EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path))
if (downloadEntity.isPlugin) {
EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path))
} else {
EventBus.getDefault().post(EBShowDialog(BaseActivity.SIGNATURE_CONFLICT, downloadEntity.path))
}
}
}
}
@ -277,11 +283,12 @@ object DownloadObserver {
// "操作", "下载完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
}
val isPlatformRecommend = java.lang.Boolean.parseBoolean(downloadEntity.getMetaExtra(Constants.IS_PLATFORM_RECOMMEND))
ExposureUtils.logADownloadCompleteExposureEvent(
GameEntity(id = downloadEntity.gameId,
mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR),
gameVersion = downloadEntity.versionName ?: ""),
gameVersion = downloadEntity.versionName ?: "",
isPlatformRecommend = isPlatformRecommend),
downloadEntity.platform,
downloadEntity.exposureTrace,
downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown",

View File

@ -99,7 +99,7 @@ object EnergyTaskHelper {
@SuppressLint("CheckResult")
@JvmStatic
fun postInviteCodeTask(code: String, from: String, successCallback: () -> Unit, failCallback: () -> Unit) {
fun postInviteCodeTask(code: String, from: String, callback: (() -> Unit)?) {
if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0L) {
val taskParams = JSONObject()
taskParams.put("action", "enter_invite_code")
@ -120,14 +120,9 @@ object EnergyTaskHelper {
.subscribe(object : BiResponse<List<EnergyTaskCompleteEntity>>() {
override fun onSuccess(data: List<EnergyTaskCompleteEntity>) {
SPUtils.setBoolean(Constants.SP_HAS_COMPLETE_INVITE_CODE, true)
successCallback.invoke()
callback?.invoke()
data.forEach { showCompletePopup(it) }
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
failCallback.invoke()
}
})
}
}
@ -144,7 +139,9 @@ object EnergyTaskHelper {
isFocusable = true
isFocusableInTouchMode = true
setOnClickListener {
currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity))
if (currentActivity::class.java.simpleName != EnergyCenterActivity::class.java.simpleName) {
currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity))
}
}
}
val popWindow = PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, 88F.dip2px())

View File

@ -148,8 +148,10 @@ public class EntranceUtils {
public static final String KEY_RECOMMENDS_CONTENTS = "isRecommendsContents";
public static final String KEY_VERSION_UPDATE = "versionUpdate";
public static final String KEY_CHECK_QUESTION_CONCERN = "check_question_concern";
public static final String KEY_IS_COLUMN_COLLECTION = "is_column_collection";//是专题合集
public static final String KEY_DRAFT_ID = "draft_id";
public static final String KEY_KAIFU_LIST = "kaifuList";
public static final String KEY_CATEGORY = "category";
public static final String KEY_CATEGORY_ID = "category_id";
public static final String KEY_CATEGORY_TITLE = "category_title";
public static final String KEY_CATEGORY_INIT_TITLE = "category_init_title";
@ -167,6 +169,7 @@ public class EntranceUtils {
public static final String KEY_COLUMN_ID = "column_id";
public static final String KEY_AUTO_DOWNLOAD = "auto_download";
public static final String KEY_HIDE_SUGGEST_HINT = "hide_suggest_hint";
public static final String KEY_HIDE_USELESS_INFO = "hide_useless_info";
public static final String KEY_COMMUNITY_ARTICLE_ID = "communityArticleId";
public static final String KEY_ARTICLE_COMMENT_ID = "articleCommentId";
public static final String KEY_SHOW_ARTICLE_COMMENT = "showArticleComment";
@ -190,6 +193,7 @@ public class EntranceUtils {
public static final String KEY_UUID = "uuid";
public static final String KEY_IS_HOME_VIDEO = "isHomeVideo";
public static final String KEY_IS_HOME = "isHome";
public static final String KEY_TAB_COUNT = "tab_count";
public static final String KEY_WEB_SHARE = "webShare";
public static final String KEY_ACTIVITY_NAME = "activityName";//活动名称
public static final String KEY_PAGINATION_TYPE = "paginationType";//活动分页方式
@ -212,6 +216,7 @@ public class EntranceUtils {
public static final String KEY_CHANGE_PHONE = "changePhone";
public static final String KEY_CONFLICT_PHONE = "conflictPhone";
public static final String KEY_CONFLICT_USER = "conflictUser";
public static final String KEY_EXPOSURE_SOURCE = "exposure_source";
public static final String KEY_BBS_ID = "bbs_id";
public static final String KEY_DIAGNOSIS = "diagnosis";
public static final String KEY_SIMULATOR = "simulator";
@ -224,6 +229,13 @@ public class EntranceUtils {
public static final String KEY_CATEGORY_LIST = "categoty_list";
public static final String KEY_IS_FREE = "is_free";
public static final String KEY_IS_SIGN = "is_sign";
public static final String KEY_IS_CHOOSE_APK = "is_choose_apk";
public static final String KEY_TAB_INDEX = "tab_index";
public static final String KEY_IS_CATEGORY_V2 = "is_category_v2";
public static final String KEY_SUB_CATEGORY_ID = "sub_category_id";
public static final String KEY_IS_QA_FEEDBACK = "is_qa_feedback";
public static final String KEY_IS_CLICK_RECEIVE_BTN = "is_click_receive_btn";
public static final String KEY_SHOW_QUICK_LOGIN = "show_quick_login";
public static void jumpActivity(Context context, Bundle bundle) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);

View File

@ -4,6 +4,9 @@ import android.animation.Animator
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.text.*
@ -67,11 +70,16 @@ inline fun <reified VM : ViewModel> FragmentActivity.viewModelProvider(
/**
* 创建以 activity 为观察者上下文的 viewModel
* 额外的 key: 用于区分单 activity 多 viewModel 的情况 (如首页tab)
*/
inline fun <reified VM : ViewModel> Fragment.viewModelProviderFromParent(
provider: ViewModelProvider.Factory? = null
) =
ViewModelProviders.of(requireActivity(), provider).get(VM::class.java)
provider: ViewModelProvider.Factory? = null,
key: String = ""
) = if (key.isEmpty()) {
ViewModelProviders.of(requireActivity(), provider).get(VM::class.java)
} else {
ViewModelProviders.of(requireActivity(), provider).get(key, VM::class.java)
}
/**
* 创建以 activity 为观察者上下文的 viewModel
@ -113,12 +121,16 @@ fun ViewPager.addOnPageChangeListener(onSelected: ((position: Int) -> Unit)? = n
addOnPageChangeListener(listener)
}
fun ViewPager.addOnScrollStateChanged(onStateChanged: ((state: Int) -> Unit)? = null) {
fun ViewPager.doOnScroll(onStateChanged: ((state: Int) -> Unit)? = null,
onPageScrolled: ((position: Int, positionOffset: Float, positionOffsetPixels: Int) -> Unit)? = null,
onPageSelected: ((position: Int) -> Unit)? = null) {
val listener = object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
onPageScrolled?.invoke(position, positionOffset, positionOffsetPixels)
}
override fun onPageSelected(position: Int) {
onPageSelected?.invoke(position)
}
override fun onPageScrollStateChanged(state: Int) {
@ -477,6 +489,9 @@ fun Float.sp2px(): Int {
return (this * scale + 0.5f).toInt()
}
fun Float.roundTo(n: Int): Float {
return "%.${n}f".format(Locale.CHINA, this).toFloat()
}
/**
* PopupWindow 自动适配方向
@ -534,14 +549,6 @@ fun Fragment.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
})
}
fun Fragment.checkCalendarPermissionBeforeAction(action: (() -> Unit)) {
PermissionHelper.checkCalendarPermissionBeforeAction(requireContext(), object : EmptyCallback {
override fun onCallback() {
action.invoke()
}
})
}
fun FragmentActivity.checkReadPhoneStateAndStoragePermissionBeforeAction(action: (() -> Unit)) {
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(this, object : EmptyCallback {
override fun onCallback() {
@ -566,14 +573,6 @@ fun FragmentActivity.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
})
}
fun FragmentActivity.checkCalendarPermissionBeforeAction(action: (() -> Unit)) {
PermissionHelper.checkCalendarPermissionBeforeAction(this, object : EmptyCallback {
override fun onCallback() {
action.invoke()
}
})
}
/**
* List related.
*/
@ -628,7 +627,7 @@ fun <T> List<T>.safelyGetInRelease(index: Int): T? {
} else {
try {
this[index]
} catch (e : IndexOutOfBoundsException){
} catch (e: IndexOutOfBoundsException) {
e.printStackTrace()
null
}
@ -708,6 +707,10 @@ fun Int.toColor(): Int {
return ContextCompat.getColor(HaloApp.getInstance().application, this)
}
fun Int.toDrawable(): Drawable? {
return ContextCompat.getDrawable(HaloApp.getInstance().application, this)
}
fun Int.toResString(): String {
return HaloApp.getInstance().application.resources.getString(this)
}
@ -947,4 +950,11 @@ fun <T> singleToMain(): SingleTransformer<T, T> {
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
}
fun View.getBitmapFromView(): Bitmap? {
val bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
this.draw(canvas)
return bitmap
}

View File

@ -24,17 +24,24 @@ object HomePluggableHelper {
val apkList = gameEntity.getApk()
if (apkList.isNotEmpty()) {
val apk = apkList.first()
val filterData = mHomePluggableFilterDao.getDataByPkgName(apk.packageName)
if (filterData?.active == true) {
val filterTag = filterData.tag
return filterTag != "never" && apk.version != filterTag
tryCatchInRelease {
val filterData = mHomePluggableFilterDao.getDataByPkgName(apk.packageName)
if (filterData?.active == true) {
val filterTag = filterData.tag
return filterTag != "never" && apk.version != filterTag
}
}
}
return true
}
@JvmStatic
fun getPermanentInactivePluggablePackage() = mHomePluggableFilterDao.getDataByTag("never")
fun getPermanentInactivePluggablePackage(): List<HomePluggableFilterEntity>? {
tryCatchInRelease {
return mHomePluggableFilterDao.getDataByTag("never")
}
return emptyList()
}
@JvmStatic
fun activationFilterData() {

View File

@ -43,6 +43,8 @@ object ImageUtils {
private val LARGE_GIF_SIZE = 80F.dip2px()
private val STANDARD_GIF_SIZE = 60F.dip2px()
const val TARGET_WIDTH = R.dimen.width_placeholder
private val mImageUrlCacheSet by lazy { FixedSizeLinkedHashSet<String>(maxSize = 200) }
@JvmStatic
@ -86,7 +88,8 @@ object ImageUtils {
@JvmStatic
fun addLimitWidth(imageUrl: String?, width: Int?): String? {
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
val webpConfig = Config.getSettings()?.image?.oss?.webp ?: Config.getSettings()?.image?.oss?.gif
val webpConfig = Config.getSettings()?.image?.oss?.webp
?: Config.getSettings()?.image?.oss?.gif
if (jpegConfig != null) {
return if (width == 0 || width == null) {
"$imageUrl$webpConfig"
@ -298,10 +301,14 @@ object ImageUtils {
* @param isAutoPlayGif 是否禁止播放动图
*/
@JvmStatic
fun display(view: SimpleDraweeView?, url: String?, isAutoPlayGif: Boolean = true, processor: Postprocessor? = null) {
fun display(view: SimpleDraweeView?,
url: String?,
isAutoPlayGif: Boolean = true,
processor: Postprocessor? = null) {
if (url == null) return
val width = view?.layoutParams?.width
// 部分自适应宽高图片需要一个 TARGET_WIDTH 来避免加载过小图片
val width = (view?.getTag(TARGET_WIDTH) as? Int) ?: view?.layoutParams?.width
val height = view?.layoutParams?.height
var lowResUrl = ""
@ -351,7 +358,7 @@ object ImageUtils {
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
} else {
if (width != null && width > 0) {
highResUrl = resizeGif(url, view.width, height ?: 0)
highResUrl = resizeGif(url, view!!.width, height ?: 0)
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
} else {
view?.post {
@ -371,10 +378,10 @@ object ImageUtils {
// 加载大小是实际 ImageView 大小两倍的图片真的有意义吗?
val transformUrlX2 = addLimitWidth(url, width * 2)
val transformUrlX1 = addLimitWidth(url, width)
// 当网络为 WIFI 或 4G 且系统版本大于 5.0 && 手机内存大于 2G 才用高清图片
// 当网络为 WIFI 或 4G 且系统版本大于 5.0 && 手机内存大于 4G 才用高清图片 (x2)
transformUrl = if (NetworkUtils.isWifiOr4GConnected(context)
&& Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP
&& HaloApp.getInstance().deviceRamSize > 2500) {
&& HaloApp.getInstance().deviceRamSize > 4500) {
transformUrlX2
} else {
// 检查X2大图是否被缓存
@ -477,4 +484,22 @@ object ImageUtils {
fun getVideoSnapshot(videoUrl: String, progress: Long): String {
return "$videoUrl?x-oss-process=video/snapshot,t_$progress,f_jpg,w_0,h_0"
}
/**
* 虽然在 Application 里有使用子线程初始化但有可能出现初始化超时(卡住?)的情况,
* 这里反射获取 sDraweecontrollerbuildersupplier 根据是否有值确定是否被初始化了
*/
@JvmStatic
fun isFrescoInitialized(): Boolean {
val clazz = SimpleDraweeView::class.java
return try {
val field =
clazz.getDeclaredField("sDraweecontrollerbuildersupplier")
field.isAccessible = true
val obj = field[SimpleDraweeView::class.java]
obj != null
} catch (ignore: java.lang.Exception) {
false
}
}
}

View File

@ -0,0 +1,157 @@
package com.gh.common.util
import com.gh.common.loghub.LoghubUtils.log
import com.gh.common.tracker.Tracker.launchId
import com.gh.common.tracker.Tracker.sessionId
import com.lightgame.utils.Utils
import org.json.JSONObject
object IntegralLogHelper {
fun log(event: String, location: String) = log(event, location, null)
fun log(event: String, location: String, entrance: String? = null) {
val json = JSONObject().apply {
tryWithDefaultCatch {
put("meta", LogUtils.getMetaObject())
put("event", event)
put("location", location)
put("timestamp", System.currentTimeMillis() / 1000)
put("launch_id", launchId)
put("session_id", sessionId)
entrance?.let {
put("entrance", it)
}
}
}
debugOnly {
Utils.log("LogUtils->$json")
}
log(json, "score", false)
}
fun logTask(event: String, location: String, jobId: String, jobName: String, jobType: String) {
val json = JSONObject().apply {
tryWithDefaultCatch {
put("meta", LogUtils.getMetaObject())
put("event", event)
put("location", location)
put("timestamp", System.currentTimeMillis() / 1000)
put("launch_id", launchId)
put("session_id", sessionId)
put("job_id", jobId)
put("job_name", jobName)
put("job_type", jobType)
}
}
debugOnly {
Utils.log("LogUtils->$json")
}
log(json, "score", false)
}
fun logCommodityCategory(event: String, location: String, entrance: String, categoryId: String, categoryName: String) {
val json = JSONObject().apply {
tryWithDefaultCatch {
put("meta", LogUtils.getMetaObject())
put("event", event)
put("location", location)
put("timestamp", System.currentTimeMillis() / 1000)
put("launch_id", launchId)
put("session_id", sessionId)
put("entrance", entrance)
put("goods_species_id", categoryId)
put("goods_species_name", categoryName)
}
}
debugOnly {
Utils.log("LogUtils->$json")
}
log(json, "score", false)
}
fun logCommodity(event: String, location: String, commodityId: String, categoryId: String, categoryName: String) {
val json = JSONObject().apply {
tryWithDefaultCatch {
put("meta", LogUtils.getMetaObject())
put("event", event)
put("location", location)
put("timestamp", System.currentTimeMillis() / 1000)
put("launch_id", launchId)
put("session_id", sessionId)
put("goods_id", commodityId)
put("goods_species_id", categoryId)
put("goods_species_name", categoryName)
}
}
debugOnly {
Utils.log("LogUtils->$json")
}
log(json, "score", false)
}
fun logEnergyRange(event: String, location: String, range: String) {
val json = JSONObject().apply {
tryWithDefaultCatch {
put("meta", LogUtils.getMetaObject())
put("event", event)
put("location", location)
put("timestamp", System.currentTimeMillis() / 1000)
put("launch_id", launchId)
put("session_id", sessionId)
put("energy_range", range)
}
}
debugOnly {
Utils.log("LogUtils->$json")
}
log(json, "score", false)
}
fun logPendent(event: String, location: String, pendentId: String, pendentType: String? = null) {
val json = JSONObject().apply {
tryWithDefaultCatch {
put("meta", LogUtils.getMetaObject())
put("event", event)
put("location", location)
put("timestamp", System.currentTimeMillis() / 1000)
put("launch_id", launchId)
put("session_id", sessionId)
put("pendant_id", pendentId)
pendentType?.run {
put("pendant_type", this)
}
}
}
debugOnly {
Utils.log("LogUtils->$json")
}
log(json, "score", false)
}
fun logInviteResult(result: String, type: String? = null) {
val json = JSONObject().apply {
tryWithDefaultCatch {
put("meta", LogUtils.getMetaObject())
put("event", "invite_result")
put("location", "邀请途径面板")
put("timestamp", System.currentTimeMillis() / 1000)
put("launch_id", launchId)
put("session_id", sessionId)
put("invitation_result", result)
put("invitation_type", type)
}
}
debugOnly {
Utils.log("LogUtils->$json")
}
log(json, "score", false)
}
}

View File

@ -28,14 +28,17 @@ import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.retrofit.JSONObjectResponse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -151,9 +154,10 @@ public class LibaoUtils {
});
}
public static void setLiBaoBtnStatusRound(final TextView libaoBtn, String status, Context context) {
public static void setLiBaoBtnStatusRound(final TextView libaoBtn, LibaoEntity libaoEntity, boolean shouldUpdateStatus, Context context) {
String status = shouldUpdateStatus ? updateStatus(libaoEntity) : libaoEntity.getStatus();
libaoBtn.setTextColor(Color.WHITE);
if (TextUtils.isEmpty(status)) return;
if (status == null || TextUtils.isEmpty(status)) return;
switch (status) {
case "ling":
libaoBtn.setText(R.string.libao_ling);
@ -180,8 +184,8 @@ public class LibaoUtils {
break;
case "linged":
libaoBtn.setText(R.string.libao_linged);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
libaoBtn.setBackgroundResource(R.drawable.button_border_round_gray);
libaoBtn.setTextColor(context.getResources().getColor(R.color.button_gray));
break;
case "taoed":
libaoBtn.setText(R.string.libao_taoed);
@ -193,22 +197,16 @@ public class LibaoUtils {
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
break;
case "repeatLing":
libaoBtn.setText(R.string.libao_repeat_ling);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
break;
case "repeatLinged":
libaoBtn.setText(R.string.libao_repeat_ling);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
break;
case "repeatTao":
libaoBtn.setText(R.string.libao_repeat_tao);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
break;
case "repeatTao":
case "repeatTaoed":
libaoBtn.setText(R.string.libao_repeat_tao);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
break;
case "unshelve":
libaoBtn.setBackgroundResource(R.drawable.button_border_round_gray);
@ -227,14 +225,85 @@ public class LibaoUtils {
}
}
public static void initLibaoBtn(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity,
final boolean isInstallRequired, final LibaoDetailAdapter adapter, final String entrance) {
public static String updateStatus(LibaoEntity libaoEntity) {
String status = libaoEntity.getStatus();
setLiBaoBtnStatusRound(libaoBtn, status, context);
String beforeStatus = libaoEntity.getBeforeStatus();
if (libaoEntity.getRepeat() > 0 && libaoEntity.getMe() != null
&& libaoEntity.getMe().getUserDataLibaoList() != null) {
MeEntity userData = libaoEntity.getMe();
List<UserDataLibaoEntity> userDataLibaoList = userData.getUserDataLibaoList();
int repeat = libaoEntity.getRepeat();
int curStatusCount = 0; // 当前状态的领取/淘号数量
for (UserDataLibaoEntity userDataLibaoEntity : userDataLibaoList) {
if (beforeStatus != null && beforeStatus.equals(userDataLibaoEntity.getType())) {
curStatusCount++;
}
}
// 由领取到淘号的状态转换
if (repeat <= curStatusCount || curStatusCount == 0) { // 当前领取/淘号总数是否超过总重复领取次数 / 当前状态的礼包没有领取/淘号过
if (curStatusCount == 0 && ("ling".equals(beforeStatus) || "tao".equals(beforeStatus))) {
if (isCanLing(libaoEntity)) { // 恢复原始状态
return beforeStatus;
}
}
return status;
}
if ((("linged").equals(status) || ("taoed").equals(status)) &&
("ling".equals(beforeStatus) || "tao".equals(beforeStatus))) { //检查是否到了重复领取时间
if (isCanLing(libaoEntity)) {
if ("ling".equals(beforeStatus)) {
return "repeatLinged"; // 可以重复领取
} else {
return "repeatTaoed"; // 可以重复领取
}
} else {
if ("ling".equals(beforeStatus)) {
return "repeatLing"; // 预备重复领取
} else {
return "repeatTao"; // 预备重复领取
}
}
}
}
return status;
}
public static boolean isCanLing(LibaoEntity libaoEntity) {
List<UserDataLibaoEntity> userDataLibaoList = libaoEntity.getMe().getUserDataLibaoList();
UserDataLibaoEntity userDataLibaoEntity = userDataLibaoList.get(userDataLibaoList.size() - 1);
SimpleDateFormat formatDay = new SimpleDateFormat("dd", Locale.CHINA);
long lingTime = userDataLibaoEntity.getTime() * 1000;
long curTime = Utils.getTime(HaloApp.getInstance()) * 1000;
int lingDay = Integer.parseInt(formatDay.format(lingTime));
int curDay = Integer.parseInt(formatDay.format(curTime));
if (curDay != lingDay || curTime - lingTime > 24 * 60 * 60 * 1000) {
return true;
} else {
return false;
}
}
public static void initLibaoBtn(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity,
final boolean isInstallRequired, final LibaoDetailAdapter adapter, boolean shouldUpdateStatus, final String entrance) {
String status = libaoEntity.getStatus();
setLiBaoBtnStatusRound(libaoBtn, libaoEntity, shouldUpdateStatus, context);
if (adapter != null) {
if (libaoBtn.getText().toString().equals("再领")) {
libaoBtn.setText("再领一个");
}
if (libaoBtn.getText().toString().equals("再淘")) {
libaoBtn.setText("再淘一个");
}
}
libaoBtn.setOnClickListener(v -> {
String btnStatus = libaoBtn.getText().toString();
// 领取限制
CheckLoginUtils.checkLogin(context, "礼包详情-[" + btnStatus + "]", () -> {
if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) {
@ -280,6 +349,7 @@ public class LibaoUtils {
Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null);
}
break;
case "再领":
case "再领一个":
case "领取":
if ("repeatLing".equals(status)) {
@ -290,136 +360,140 @@ public class LibaoUtils {
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
}
break;
case "再淘":
case "再淘一个":
case "淘号":
if ("repeatTao".equals(status)) {
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
return;
}
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
@Override
public void postSucceed(Object response) {
if (loadingDialog != null) loadingDialog.dismiss();
JSONObject responseBody = (JSONObject) response;
String libaoCode = null;
try {
libaoCode = responseBody.getString("code");
} catch (JSONException e) {
e.printStackTrace();
}
if (TextUtils.isEmpty(libaoCode)) {
try {
String detail = responseBody.getString("detail");
switch (detail) {
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "淘号异常");
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
return;
}
Utils.toast(context, "淘号成功");
libaoEntity.setStatus("taoed");
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(context, "淘号成功"
, Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode))
, "关闭", " 复制礼包码"
, () -> {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(() -> {
Spanned msg = Html.fromHtml(
context.getString(R.string.taoed_copy_dialog
, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}, 300);
}
}, null);
}
@Override
public void postFailed(Throwable error) {
Utils.log("---" + error.toString());
if (loadingDialog != null) loadingDialog.dismiss();
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
if (exception.code() == 403) {
try {
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
String detail = errorJson.getString("detail");
// Utils.toast(context, "返回::" + detail);
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
break;
case "finish":
Utils.toast(context, "礼包领取时间已结束");
break;
case "fetched":
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
libaoBtn.setText("已淘号");
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
libaoEntity.setStatus("taoed");
break;
case "try tao":
case "used up":
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "操作失败");
break;
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(context, "礼包处理异常" + ex.toString());
}
return;
} else if (exception.code() == 401) {
return;
}
}
Utils.toast(context, "发生异常");
}
});
libaoTao(context, libaoBtn, libaoEntity, isInstallRequired, adapter, status, entrance);
break;
}
});
});
}
private static void libaoTao(Context context, TextView libaoBtn, LibaoEntity libaoEntity, boolean isInstallRequired, LibaoDetailAdapter adapter, String status, String entrance) {
if ("repeatTao".equals(status)) {
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
return;
}
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
@Override
public void postSucceed(Object response) {
if (loadingDialog != null) loadingDialog.dismiss();
JSONObject responseBody = (JSONObject) response;
String libaoCode = null;
boolean hasSame = false;
try {
hasSame = responseBody.getBoolean("has_same");
libaoCode = responseBody.getString("code");
} catch (JSONException e) {
e.printStackTrace();
}
if (TextUtils.isEmpty(libaoCode)) {
try {
String detail = responseBody.getString("detail").toLowerCase();
switch (detail) {
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "淘号异常");
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
return;
}
Utils.toast(context, "淘号成功");
libaoEntity.setStatus("taoed");
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
uploadEvent(libaoEntity, true, entrance);
final String finalLibaoCode = libaoCode;
String des;
if (!hasSame) {
des = "淘到的礼包码不保证可以兑换,请尽快前往游戏兑换";
} else {
des = "您已领取过相同的礼包,可能无法成功兑换,请自行尝试";
}
DialogUtils.showReceiveLibaoSuccessDialog(context, "淘号成功", des, finalLibaoCode, () -> {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(() -> {
Spanned msg = Html.fromHtml(
context.getString(R.string.taoed_copy_dialog
, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}, 300);
}
});
}
@Override
public void postFailed(Throwable error) {
Utils.log("---" + error.toString());
if (loadingDialog != null) loadingDialog.dismiss();
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
if (exception.code() == 403) {
try {
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
String detail = errorJson.getString("detail").toLowerCase();
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
break;
case "finish":
Utils.toast(context, "礼包领取时间已结束");
break;
case "fetched":
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
libaoBtn.setText("已淘号");
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
libaoEntity.setStatus("taoed");
break;
case "try tao":
case "used up":
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "操作失败");
break;
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(context, "礼包处理异常" + ex.toString());
}
return;
} else if (exception.code() == 401) {
return;
}
}
Utils.toast(context, "发生异常");
}
});
}
private static void libaoLing(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity, final LibaoDetailAdapter adapter,
final boolean isInstallRequired, String captchaCode, final String entrance) {
@ -435,45 +509,56 @@ public class LibaoUtils {
if (loadingDialog != null) loadingDialog.dismiss();
JSONObject responseBody = (JSONObject) response;
boolean hasSame = false; //是否领取过相同的礼包
String libaoCode = null;
int gameApkSize = 1;//游戏apk的size大于1为“多版本插件游戏”否则为“非插件游戏/单版本插件游戏”
try {
hasSame = responseBody.getBoolean("has_same");
libaoCode = responseBody.getString("code");
gameApkSize = responseBody.getInt("game_apk_size");
} catch (JSONException e) {
e.printStackTrace();
}
if (TextUtils.isEmpty(libaoCode)) {
Utils.toast(context, "领取异常");
return;
}
libaoEntity.setAvailable(libaoEntity.getAvailable() - 1);
libaoEntity.setStatus("linged");
EventBus.getDefault().post(new EBReuse("libaoChanged"));
uploadEvent(libaoEntity, false, entrance);
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "ling", Utils.getTime(context)));
adapter.notifyDataSetChanged();
final String finalLibaoCode = libaoCode;
boolean finalHasSame = hasSame;
int finalGameApkSize = gameApkSize;
NotificationHelper.showNotificationHintDialog(NotificationUgc.GIFT, isShow -> {
if (!isShow) {
DialogUtils.showWarningDialog(context, "领取成功", Html.fromHtml(context.getString(R.string.linged_dialog, finalLibaoCode))
, "关闭", " 复制礼包码"
, () -> {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(() -> {
Spanned msg = Html.fromHtml(context.getString(R.string.linged_copy_dialog, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}, 300);
}
}, null);
String des;
if (!finalHasSame) {
if (finalGameApkSize > 1) {
des = "礼包码将于60分钟后进入淘号池部分礼包兑换有平台限制请根据使用说明兑换";
} else {
des = "礼包码将于60分钟后进入淘号池,请尽快前往游戏兑换";
}
} else {
des = "您已领取过相同的礼包,可能无法成功兑换,请自行尝试";
}
DialogUtils.showReceiveLibaoSuccessDialog(context, "领取成功", des, finalLibaoCode, () -> {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(() -> {
Spanned msg = Html.fromHtml(context.getString(R.string.linged_copy_dialog, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}, 300);
}
});
}
return null;
});
}
@Override
@ -486,7 +571,7 @@ public class LibaoUtils {
try {
String string = exception.response().errorBody().string();
JSONObject errorJson = new JSONObject(string);
String detail = errorJson.getString("detail");
String detail = errorJson.getString("detail").toLowerCase();
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
@ -516,7 +601,7 @@ public class LibaoUtils {
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
libaoEntity.setStatus("used_up");
initLibaoBtn(context, libaoBtn, libaoEntity, isInstallRequired, adapter, entrance);
initLibaoBtn(context, libaoBtn, libaoEntity, isInstallRequired, adapter, false, entrance);
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
@ -544,6 +629,24 @@ public class LibaoUtils {
}, captchaCode);
}
private static void uploadEvent(LibaoEntity libaoEntity, boolean isTao, String entrance) {
String location = "";
if (!libaoEntity.getClickReceiveBtnIn()) {
location = "礼包详情";
} else {
if (entrance.contains("游戏详情")) {
location = "游戏详情";
} else if (entrance.contains("礼包中心:最新")) {
location = "礼包中心-最新";
} else if (entrance.contains("礼包中心:关注")) {
location = "礼包中心-关注";
}
}
String event = isTao ? "game_gift_dig_successful" : "game_gift_get_successful";
LogUtils.uploadReceiveGift(event, libaoEntity.getId(), libaoEntity.getName(), location,
libaoEntity.getGame() == null ? "" : libaoEntity.getGame().getId(), libaoEntity.getGame() == null ? "" : libaoEntity.getGame().getName());
}
public static boolean isAppInstalled(Context context, String packageName) {
List<PackageInfo> pinfo = PackageUtils.getInstalledPackages(context, 0);
if (pinfo != null) {

View File

@ -16,7 +16,9 @@ import com.gh.common.loghub.LoghubUtils;
import com.gh.common.loghub.SimpleLogContainerEntity;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.CommunityEntity;
import com.gh.gamecenter.entity.DetectionObjectEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.PackageDialogEntity;
import com.gh.gamecenter.entity.ShareResultEntity;
import com.gh.gamecenter.entity.SpecialColumn;
import com.gh.gamecenter.entity.StartupAdEntity;
@ -27,6 +29,7 @@ import com.gh.gamecenter.retrofit.RetrofitManager;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@ -236,6 +239,10 @@ public class LogUtils {
object.put("game_name", gameEntity.getName());
object.put("game_id", gameEntity.getId());
object.put("game_platform", gameEntity.getPlatform());
if (event != null) {
object.put("sequence", event.getPayload().getSequence());
object.put("outer_sequence", event.getPayload().getOuterSequence());
}
object.put("download_open", gameEntity.getDownloadOffStatus() == null ? "true" : "false");
} catch (JSONException e) {
e.printStackTrace();
@ -265,6 +272,7 @@ public class LogUtils {
object.put("device_model", android.os.Build.MODEL);
object.put("jnfj", MetaUtil.getBase64EncodedIMEI());
object.put("G_ID", UserManager.getInstance().getDeviceId());
object.put("oaid", HaloApp.getInstance().getOAID());
} catch (JSONException e) {
e.printStackTrace();
}
@ -595,6 +603,7 @@ public class LogUtils {
metaObject.put("network", meta.getNetwork());
metaObject.put("os", meta.getOs());
metaObject.put("userId", meta.getUserId());
metaObject.put("oaid", HaloApp.getInstance().getOAID());
} catch (JSONException e) {
e.printStackTrace();
@ -705,6 +714,120 @@ public class LogUtils {
LoghubUtils.log(object, "event", false);
}
public static void logGameDetailStrategyButtonEvent(String gameId,
String gameName,
String text) {
JSONObject object = new JSONObject();
try {
object.put("event", "game_detail_click_strategy_button");
object.put("timestamp", System.currentTimeMillis() / 1000);
object.put("meta", getMetaObject());
object.put("game_id", gameId);
object.put("game_name", gameName);
object.put("text", text);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void logServerTestAccessEvent(String entrance,
String entranceDetail,
String serverTestName,
String serverTestNote) {
JSONObject payload = new JSONObject();
try {
payload.put("server_test_name", serverTestName);
payload.put("server_test_note", serverTestNote);
payload.put("entrance", entrance);
payload.put("entrance_detail", entranceDetail);
} catch (JSONException e) {
e.printStackTrace();
}
logServerTestEvent("access_to_server_test", payload);
}
public static void logServerTestSelectTypeEvent(String buttonText,
String serverTestName,
String serverTestNote) {
JSONObject payload = new JSONObject();
try {
payload.put("server_test_name", serverTestName);
payload.put("server_test_note", serverTestNote);
payload.put("button_text", buttonText);
} catch (JSONException e) {
e.printStackTrace();
}
logServerTestEvent("server_test_select_type", payload);
}
public static void logServerTestSelectTimeEvent(String buttonText,
String serverTestName,
String serverTestNote) {
JSONObject payload = new JSONObject();
try {
payload.put("server_test_name", serverTestName);
payload.put("server_test_note", serverTestNote);
payload.put("button_text", buttonText);
} catch (JSONException e) {
e.printStackTrace();
}
logServerTestEvent("server_test_select_time", payload);
}
public static void logServerTestClickAllEvent(String serverTestName,
String serverTestNote) {
JSONObject payload = new JSONObject();
try {
payload.put("server_test_name", serverTestName);
payload.put("server_test_note", serverTestNote);
} catch (JSONException e) {
e.printStackTrace();
}
logServerTestEvent("server_test_click_all", payload);
}
public static void logServerTestClickMoreEvent(String serverTestName,
String serverTestNote,
String redirectType,
String redirectLink) {
JSONObject payload = new JSONObject();
try {
payload.put("server_test_name", serverTestName);
payload.put("server_test_note", serverTestNote);
payload.put("redirect_type", redirectType);
payload.put("redirect_link", redirectLink);
} catch (JSONException e) {
e.printStackTrace();
}
logServerTestEvent("server_test_click_more", payload);
}
private static void logServerTestEvent(String event, JSONObject payload) {
JSONObject object = new JSONObject();
try {
object.put("event", event);
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
object.put("payload", payload);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void logNewCatalogAppearanceEvent(String entrance, String key) {
logCatalogEvent("access_to_classification", entrance, key, -1, -1, -1, -1);
}
@ -812,4 +935,228 @@ public class LogUtils {
LoghubUtils.log(object, "event", false);
}
public static void logRecommendClick(String entrance, String recommendName, String linkType, String linkTitle, int sequence) {
JSONObject object = new JSONObject();
try {
object.put("event", "recommend_click");
object.put("timestamp", System.currentTimeMillis() / 1000);
object.put("meta", getMetaObject());
object.put("entrance", entrance);
object.put("recommend_name", recommendName);
object.put("link_type", linkType);
object.put("link_title", linkTitle);
object.put("sequence", sequence);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void uploadPackageCheck(String event, String action, GameEntity gameEntity, String linkTitle, String linkDesc, String downloadGameId, String downloadGameName) {
if (gameEntity == null) return;
PackageDialogEntity packageDialog = gameEntity.getPackageDialog();
if (packageDialog == null) return;
JSONObject object = new JSONObject();
JSONObject payloadObject = new JSONObject();
try {
object.put("event", event);
object.put("action", action);
payloadObject.put("game_id", gameEntity.getId());
payloadObject.put("game_name", gameEntity.getName());
payloadObject.put("link_title", linkTitle);
payloadObject.put("link_desc", linkDesc);
payloadObject.put("download_game_id", downloadGameId);
payloadObject.put("download_game_name", downloadGameName);
JSONArray detectionArray = new JSONArray();
for (DetectionObjectEntity entity : packageDialog.getDetectionObjects()) {
JSONObject detectionObject = new JSONObject();
detectionObject.put("text", entity.getText());
detectionObject.put("packages", new JSONArray(GsonUtils.toJson(entity.getPackages())));
detectionArray.put(detectionObject);
}
payloadObject.put("detection_objects", detectionArray);
object.put("meta", getMetaObject());
object.put("payload", payloadObject);
object.put("timestamp", System.currentTimeMillis() / 1000);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void logCategoryV2AppearanceEvent(String entrance, String classification) {
logCategoryV2Event("access_to_classification_v2", entrance, classification, "", "", "", "", "", -1, -1, -1, -1);
}
public static void logCategoryV2ClickSideEvent(String entrance, String classification, String sideClassification, int seq) {
logCategoryV2Event("click_side", entrance, classification, sideClassification, "", "", "", "", seq, -1, -1, -1);
}
public static void logCategoryV2ClickClassificationEvent(String entrance, String classification, String sideClassification, String classification1, String classification2, int seq1, int seq2) {
logCategoryV2Event("click_classification", entrance, classification, sideClassification, classification1, classification2, "", "", -1, -1, seq1, seq2);
}
public static void logCategoryV2ClickClassificationDeleteEvent(String entrance, String classification, String classification1, String classification2, String location) {
logCategoryV2Event("click_classification_delete", entrance, classification, "", classification1, classification2, "", location, -1, -1, -1, -1);
}
public static void logCategoryV2ClickDetermineEvent(String entrance, String classification, String classification2) {
logCategoryV2Event("click_determine", entrance, classification, "", "", classification2, "", "", -1, -1, -1, -1);
}
public static void logCategoryV2ClickResetEvent(String entrance, String classification, String classification2, String location) {
logCategoryV2Event("click_reset", entrance, classification, "", "", classification2, "", location, -1, -1, -1, -1);
}
public static void logSpecialCategoryV2BannerClickEvent(String entrance, String classification, String detail, int seq) {
logCategoryV2Event("category_lunbo_click_v2", entrance, classification, "", "", "", detail, "", seq, -1, -1, -1);
}
public static void logSpecialCategoryV2ContentClickEvent(String entrance, String classification, String detail, int seq) {
logCategoryV2Event("click_content_v2", entrance, classification, "", "", "", detail, "", seq, -1, -1, -1);
}
public static void logSpecialCategoryV2SpecificContentClickEvent(String entrance, String classification, String detail, int seq, int outSeq) {
logCategoryV2Event("click_content_list_v2", entrance, classification, "", "", "", detail, "", seq, outSeq, -1, -1);
}
public static void logCategoryV2Event(String event,
String entrance,
String classification,
String sideClassification,
String classification1,
String classification2,
String detail,
String location,
int seq,
int outSeq,
int seq1,
int seq2) {
JSONObject object = new JSONObject();
try {
object.put("event", event);
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
object.put("entrance", entrance);
object.put("classification", classification);
object.put("side_classification", sideClassification);
object.put("classification_1st", classification1);
object.put("classification_2nd", classification2);
object.put("detail", detail);
object.put("location", location);
object.put("sequence", seq);
object.put("outer_sequence", outSeq);
object.put("seq_1st", seq1);
object.put("seq_2nd", seq2);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void logGameDetailFixedTopArticleClick(String gameId, String gameName, String url) {
JSONObject object = new JSONObject();
try {
object.put("event", "game_detail_click_top_strategy");
object.put("game_id", gameId);
object.put("game_name", gameName);
object.put("top_strategy_url", url);
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void logHomeTopTabClick(String tabName, String linkType, String linkTitle, int sequence) {
JSONObject object = new JSONObject();
try {
object.put("event", "top_tab_click");
object.put("tab_name", tabName);
object.put("link_type", linkType);
object.put("link_title", linkTitle);
object.put("sequence", sequence);
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void uploadRecommendPopup(String event, String popupId, String gameId, String gameName,
String linkType, String linkTitle, String downloadGameId, String downloadGameName) {
JSONObject object = new JSONObject();
JSONObject payloadObject = new JSONObject();
try {
object.put("event", event);//recommend_pop_show推荐弹窗出现、recommend_pop_close推荐弹窗手动关闭、recommend_pop_link_click点击推荐弹窗链接、recommend_pop_download推荐弹窗下载开始、recommend_pop_download_complete推荐弹窗下载完成
payloadObject.put("recommend_pop_id", popupId);
payloadObject.put("game_id", gameId);
payloadObject.put("game_name", gameName);
if (!TextUtils.isEmpty(linkType)) {
payloadObject.put("link_type", linkType);
}
if (!TextUtils.isEmpty(linkTitle)) {
payloadObject.put("link_title", linkTitle);
}
if (!TextUtils.isEmpty(downloadGameId)) {
payloadObject.put("download_game_id", downloadGameId);
}
if (!TextUtils.isEmpty(downloadGameName)) {
payloadObject.put("download_game_name", downloadGameName);
}
object.put("payload", payloadObject);
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void uploadReceiveGift(String event, String giftId, String giftName, String location, String gameId, String gameName) {
JSONObject object = new JSONObject();
JSONObject payloadObject = new JSONObject();
try {
object.put("event", event);//game_gift_get_successful领取礼包、game_gift_dig_successful淘号
payloadObject.put("gift_id", giftId);
payloadObject.put("gift_name", giftName);
payloadObject.put("location", location);
payloadObject.put("game_id", gameId);
payloadObject.put("game_name", gameName);
object.put("payload", payloadObject);
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
}

View File

@ -8,6 +8,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
@ -69,6 +70,9 @@ public class MessageShareUtils {
private PopupWindow mPopupWindow;
private Bitmap shareBm; //分享截图
private String picName;
private ShareWay shareWay;
private boolean isFromInviteFriends = false;
private String mWriteBitmapPath;
private String[] mArrLabel = {"微信好友", "朋友圈", "QQ好友", "QQ空间", "保存"};
@ -80,15 +84,39 @@ public class MessageShareUtils {
R.drawable.share_save
};
public enum ShareWay {
qq("qq"),
qqZone("qq空间"),
weibo("微博"),
wechat("微信"),
wechatMoments("朋友圈");
private String name;
ShareWay(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
//QQ或者QQ空间分享回调处理
public IUiListener QqShareListener = new IUiListener() {
@Override
public void onComplete(Object o) {
Utils.toast(mContext, "分享成功");
if (isFromInviteFriends) {
IntegralLogHelper.INSTANCE.logInviteResult("成功", shareWay.getName());
}
}
@Override
public void onError(UiError uiError) {
if (isFromInviteFriends) {
IntegralLogHelper.INSTANCE.logInviteResult("失败", shareWay.getName());
}
// 单分享图片不支持显示未安装弹窗,手动调出
if (mActivity != null) {
Activity activity = mActivity.get();
@ -109,6 +137,9 @@ public class MessageShareUtils {
@Override
public void onCancel() {
Utils.toast(mContext, R.string.share_cancel_hint);
if (isFromInviteFriends) {
IntegralLogHelper.INSTANCE.logInviteResult("取消", shareWay.getName());
}
}
};
@ -125,6 +156,12 @@ public class MessageShareUtils {
mTencent = Tencent.createInstance(Config.TENCENT_APPID, context); //初始化QQ分享
mIWXAPI = WXAPIFactory.createWXAPI(context, Config.WECHAT_APPID); //初始化微信分享
mContext = context.getApplicationContext();
// 安卓11无法访问Android/data目录
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
mWriteBitmapPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/ShareImg/";
} else {
mWriteBitmapPath = context.getExternalCacheDir().getPath() + "/ShareImg/";
}
}
public static MessageShareUtils getInstance(Context context) {
@ -214,10 +251,16 @@ public class MessageShareUtils {
});
}
public void shareInviteFriends(Activity activity, String type) {
isFromInviteFriends = true;
shareFromWeb(activity, type);
}
public void shareFromWeb(Activity activity, String type) {
this.mActivity = new WeakReference<>(activity);
if ("weibo".equals(type)) {
shareWay = ShareWay.weibo;
weiboShare();
} else {
// base64转bitmap
@ -229,7 +272,7 @@ public class MessageShareUtils {
this.shareBm = bitmap;
// 保存图片
File file = new File(activity.getExternalCacheDir().getPath() + "/ShareImg");
File file = new File(mWriteBitmapPath);
if (!file.isDirectory()) {
file.delete();
file.mkdirs();
@ -242,15 +285,19 @@ public class MessageShareUtils {
// 分享
switch (type) {
case "qq" :
shareWay = ShareWay.qq;
qqShare();
break;
case "qq_zone" :
shareWay = ShareWay.qqZone;
qZoneShare();
break;
case "wechat" :
shareWay = ShareWay.wechat;
wechatShare();
break;
case "wechat_moments" :
shareWay = ShareWay.wechatMoments;
wechatMomentsShare();
break;
case "save" :
@ -267,7 +314,7 @@ public class MessageShareUtils {
Bundle params = new Bundle();
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE,
QQShare.SHARE_TO_QQ_TYPE_IMAGE);
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, mWriteBitmapPath + picName);
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, mContext.getString(R.string.app_name));
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT,
QQShare.SHARE_TO_QQ_FLAG_QZONE_ITEM_HIDE);
@ -287,7 +334,7 @@ public class MessageShareUtils {
Bundle params = new Bundle();
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE,
QQShare.SHARE_TO_QQ_TYPE_IMAGE);
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, mWriteBitmapPath + picName);
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, mContext.getString(R.string.app_name));
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT,
QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN);
@ -312,7 +359,7 @@ public class MessageShareUtils {
//官方分享
WXImageObject imgObj = new WXImageObject();
imgObj.setImagePath(mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
imgObj.setImagePath(mWriteBitmapPath + picName);
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;
@ -347,7 +394,7 @@ public class MessageShareUtils {
}
WXImageObject imgObj = new WXImageObject();
imgObj.setImagePath(mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
imgObj.setImagePath(mWriteBitmapPath + picName);
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;

View File

@ -5,6 +5,11 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.telephony.TelephonyManager;
import com.cmic.sso.sdk.auth.AuthnHelper;
import org.json.JSONException;
import org.json.JSONObject;
public class NetworkUtils {
/**
@ -75,6 +80,26 @@ public class NetworkUtils {
return false;
}
/**
* 判断是否打开数据流量(一键登录必须要打开流量才能获取到手机号码)
*
* AuthnHelper的getNetworkType方法用于获取用户当前的网络环境和运营商返回的是JSONObject其中
* operatorType字段获取网络运营商: 0.未知 1.移动流量 2.联通流量 3.电信流量,
* networkType字段获取网络状态0.未知1.流量 2.wifi3.数据流量+wifi
*/
public static boolean isOpenMobileData(Context context){
AuthnHelper helper = AuthnHelper.getInstance(context);
JSONObject jsonObject = helper.getNetworkType(context);
int net;
try {
net = Integer.parseInt(jsonObject.getString("networkType"));
if (net == 1 || net == 3) return true;
} catch (JSONException e) {
e.printStackTrace();
}
return false;
}
/**
* 获取当前网络连接的类型信息
*

View File

@ -58,7 +58,7 @@ object NotificationHelper {
when (ugc) {
NotificationUgc.LOGIN -> {
if (!isShowedLogin) {
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_LOGIN, true)
// 设置今天的时间,表示今天已经触发过了
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
@ -68,7 +68,7 @@ object NotificationHelper {
}
NotificationUgc.QUESTION -> {
if (!isShowedQuestion) {
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_QUESTION, true)
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
} else {
@ -77,7 +77,7 @@ object NotificationHelper {
}
NotificationUgc.ANSWER -> {
if (!isShowedAnswer) {
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_ANSWER, true)
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
} else {
@ -86,7 +86,7 @@ object NotificationHelper {
}
NotificationUgc.ARTICLE -> {
if (!isShowedArticle) {
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_ARTICLE, true)
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
} else {
@ -95,7 +95,7 @@ object NotificationHelper {
}
NotificationUgc.VIDEO -> {
if (!isShowedVideo) {
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_VIDEO, true)
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
} else {
@ -104,7 +104,7 @@ object NotificationHelper {
}
NotificationUgc.RATING -> {
if (!isShowedRating) {
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_RATING, true)
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
} else {
@ -113,7 +113,7 @@ object NotificationHelper {
}
NotificationUgc.GIFT -> {
if (!isShowedGift) {
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_GIFT, true)
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
} else {
@ -122,7 +122,7 @@ object NotificationHelper {
}
NotificationUgc.RESERVE_GAME -> {
if (!isShowedReserveGame) {
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_RESERVE_GAME, true)
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
} else {
@ -131,7 +131,7 @@ object NotificationHelper {
}
NotificationUgc.FEEDBACK -> {
if (!isShowedFeedback) {
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
show(AppManager.getInstance().recentActiveActivity as? AppCompatActivity, ugc, callBack)
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_FEEDBACK, true)
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
} else {

View File

@ -11,6 +11,7 @@ import androidx.core.content.FileProvider
import com.gh.common.constant.Constants
import com.gh.common.dialog.InstallPermissionDialogFragment
import com.gh.common.xapk.XapkInstaller
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.BuildConfig
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
@ -21,7 +22,6 @@ import java.io.File
object PackageInstaller {
/**
* 为了兼容java代码
*/
@ -55,7 +55,7 @@ object PackageInstaller {
if (isXapk) {
XapkInstaller.install(context, downloadEntity, showUnzipToast)
} else {
install(context, downloadEntity.path)
install(context, downloadEntity.isPlugin, downloadEntity.path)
}
}
}
@ -68,16 +68,30 @@ object PackageInstaller {
* 除非你已经确定该文件一定是Apk
*/
@JvmStatic
fun install(context: Context, pkgPath: String) {
fun install(context: Context, isPluggin: Boolean = false, pkgPath: String) {
try {
// 判断是否需要使用浏览器来进行安装
if (BrowserInstallHelper.isUseBrowserToInstallEnabled()
&& BrowserInstallHelper.shouldUseBrowserToInstall()) {
BrowserInstallHelper.downloadFile(pkgPath)
return
}
if (PackageUtils.isCanLaunchSetup(context, pkgPath)) {
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
val installIntent = getInstallIntent(context, pkgPath)
context.startActivity(installIntent)
} else {
DialogUtils.showPluginDialog(context) {
uninstall(context, pkgPath)
if (isPluggin) {
DialogHelper.showPluginDialog(context) {
uninstall(context, pkgPath)
}
} else {
// 非插件化的同包名不同签名冲突
DialogHelper.showSignatureConflictDialog(context) {
uninstall(context, pkgPath)
}
}
}
} catch (e: Exception) {

View File

@ -295,7 +295,7 @@ public class PackageUtils {
* 根据路径获取apk的包名
*/
public static String getPackageNameByPath(Context context, String path) {
// 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
// 大于 1G 的 APK 就走另类方法
if (isDeviceUnableToHandleBigApkFile(path)) {
@ -305,46 +305,45 @@ public class PackageUtils {
}
return getPackageNameByPathAlternative(path);
}
PackageManager packageManager = context.getApplicationContext().getPackageManager();
PackageInfo info = packageManager.getPackageArchiveInfo(path, 0);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
return appInfo.packageName;
}
return null;
}
/**
* 此设备是否不能调用 packageManager.getPackageArchiveInfo 来获取 APK 信息
*
* <p>
* 部分设备 (已知 vivo 5.1.1 及 5.0.1 的设备) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
*/
public static boolean isDeviceUnableToHandleBigApkFile(String path) {
if ("vivo".equals(Build.MANUFACTURER)
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
File file = new File(path);
if (file != null && file.length() > 1024 * 1024 * 1024) {
return true;
}
}
return false;
}
/**
* 从 APK 文件里读包名的另类方法
* 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
*
* <p>
* 令人迷惑的点:
* 1. 同样的代码,同样的 APK 在 demo 包里调用 packageManager.getPackageArchiveInfo 并不会 ANR
* 2. 把 packageManager.getPackageArchiveInfo 放在子线程调用一样会出现 ANR
* 3. demo 里 manifest 中 application 配置和 targetSdk 也改成与光环一样也不会出现 ANR
*
* <p>
* 大概是光环的某个配置触发了系统的 bug ?
*
*/
private static String getPackageNameByPathAlternative(String path) {
ApkFile apkParser = null;
@ -353,7 +352,7 @@ public class PackageUtils {
ApkMeta apkMeta = apkParser.getApkMeta();
apkParser.close();
return apkMeta.getPackageName();
} catch (Exception e) {
} catch (Throwable e) {
e.printStackTrace();
return null;
}
@ -446,6 +445,31 @@ public class PackageUtils {
return list;
}
public static ArrayList<String> getAllPackageNameIncludeGh(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
list.add(packageInfo.packageName);
}
}
return list;
}
/*
* 获取所有已安装的软件的包名(包括系统应用)
*/
public static ArrayList<String> getAllPackageNameIncludeSystemApps(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if (!context.getPackageName().equals(packageInfo.packageName)) {
list.add(packageInfo.packageName);
}
}
return list;
}
public static JSONArray getAppList(Context context) {
JSONArray jsonArray = new JSONArray();
try {
@ -544,7 +568,7 @@ public class PackageUtils {
gh_version = gh_version.substring(2);
try {
return Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion()) && apkEntity
.getForce() && gh_id.equals(gameId);
.getForce() && gh_id.equals(gameId);
} catch (NumberFormatException exception) {
// gh_id 可能出錯
exception.printStackTrace();
@ -554,6 +578,45 @@ public class PackageUtils {
return false;
}
public static boolean isNonPluginUpdatable(ApkEntity apkEntity, GameEntity gameEntity) {
// 非插件游戏更新
// ghVersion 不存在即是非插件游戏
if (TextUtils.isEmpty(apkEntity.getGhVersion())) {
String versionFromRequest = apkEntity.getVersion();
String versionFromInstalledApp = getVersionByPackage(apkEntity.getPackageName());
// 是否需要显示更新
boolean shouldShowUpdate = apkEntity.getForce();
if (shouldShowUpdate && !TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp)) {
// 根据版本判断是否需要更新
shouldShowUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
if (shouldShowUpdate) {
GameUpdateEntity updateEntity = new GameUpdateEntity();
updateEntity.setId(gameEntity.getId());
updateEntity.setName(gameEntity.getName());
updateEntity.setIcon(gameEntity.getIcon());
updateEntity.setPackageName(apkEntity.getPackageName());
updateEntity.setSize(apkEntity.getSize());
updateEntity.setVersion(apkEntity.getVersion());
updateEntity.setGhVersion(apkEntity.getGhVersion());
updateEntity.setUrl(apkEntity.getUrl());
updateEntity.setPlatform(apkEntity.getPlatform());
updateEntity.setEtag(apkEntity.getEtag());
updateEntity.setBrief(gameEntity.getBrief());
updateEntity.setTag(gameEntity.getTag());
updateEntity.setTagStyle(gameEntity.getTagStyle());
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
updateEntity.setPluginDesc(gameEntity.getPluginDesc());
updateEntity.setFormat(apkEntity.getFormat());
return true;
}
}
}
return false;
}
/**
* todo 统一判断
* <p>
@ -621,13 +684,6 @@ public class PackageUtils {
if (!pm.isScreenOn()) return false;
}
// 上面的判断逻辑可能还是不够用,还是有少部分
// Not allowed to start service Intent: app is in background 错误
// 这里补充个自有的规则
if (!HaloApp.getInstance().isRunningForeground) {
return false;
}
String packageName = context.getApplicationContext().getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
// The name of the process that this object is associated with.

View File

@ -0,0 +1,35 @@
package com.gh.common.util
import com.lightgame.utils.AppManager
/**
* 用来简单获取上一个跳转页面的跳转信息的辅助类
* 简单解藕,不想层层传递数据可以把简单数据放这里面
* 暂只支持单页面(上一 activity)记录,不支持连续跨页
*/
object PageSwitchDataHelper {
const val PAGE_BUSINESS_NAME = "page_business_name"
const val PAGE_BUSINESS_TYPE = "page_business_type"
const val PAGE_GAME_DETAIL_RECOMMEND = "page_game_detail_recommend"
private var mDataFromTheLastPage: Pair<String, HashMap<String, String>>? = null
@JvmStatic
fun popLastPageData(): HashMap<String, String>? {
AppManager.getInstance().previousActivity()?.let {
if (System.identityHashCode(it).toString() == mDataFromTheLastPage?.first
&& mDataFromTheLastPage?.second != null) {
return mDataFromTheLastPage!!.second.also { mDataFromTheLastPage = null }
}
}
return null
}
fun pushCurrentPageData(data: HashMap<String, String>) {
AppManager.getInstance().currentActivity()?.let {
mDataFromTheLastPage = Pair(System.identityHashCode(it).toString(), data)
}
}
}

View File

@ -9,8 +9,10 @@ import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import com.gh.common.constant.Constants
import com.gh.gamecenter.R
import com.tbruyelle.rxpermissions2.RxPermissions
object PermissionHelper {
@ -103,7 +105,7 @@ object PermissionHelper {
@JvmStatic
fun checkReadPhoneStateAndStoragePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
if (context is FragmentActivity) {
if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED
&& context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& context.checkCallingOrSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
emptyCallback.onCallback()
@ -143,7 +145,7 @@ object PermissionHelper {
fun checkReadPhoneStatePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
if (context is FragmentActivity) {
if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
emptyCallback.onCallback()
} else {
val rxPermission = RxPermissions(context)
@ -173,48 +175,6 @@ object PermissionHelper {
}
}
@SuppressLint("CheckResult")
@JvmStatic
fun checkCalendarPermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
if (context is FragmentActivity) {
val rxPermission = RxPermissions(context)
tryWithDefaultCatch {
rxPermission
.requestEachCombined(Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CALENDAR)
.subscribe { permission ->
when {
permission.granted -> {
emptyCallback.onCallback()
}
permission.shouldShowRequestPermissionRationale -> {
DialogUtils.showPermissionDialog(context,
"权限申请",
"光环助手需要日历权限,以保证能正常使用相关功能",
"重试",
"放弃",
{ checkCalendarPermissionBeforeAction(context, emptyCallback) },
null)
}
else -> {
DialogUtils.showPermissionDialog(context,
"权限申请",
"在设置-应用-光环助手-权限中开启日历权限,以保证能正常使用相关功能",
"去设置",
"放弃",
{
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:" + context.getPackageName())
context.startActivity(intent)
},
null)
}
}
}
}
}
}
/**
* 跳转到权限设置
*
@ -262,19 +222,21 @@ object PermissionHelper {
}
private fun showDialogBeforeRequestingStorageDialog(context: FragmentActivity, emptyCallback: EmptyCallback) {
DialogHelper.showRoundedCornerDialog(
DialogHelper.showDialog(
context,
title = "权限申请",
content = "光环助手将向您申请开启设备的存储权限,以保证能正常使用相关功能。拒绝授权将无法正常使用部分功能。",
hint = "查看权限应用场景",
cancelText = "放弃",
confirmText = "去授权",
hintClickCallback = {
DirectUtils.directToWebView(context, Constants.PERMISSION_SCENARIO_ADDRESS, "(权限弹窗)")
},
cancelClickCallback = null,
confirmClickCallback = {
checkStoragePermissionBeforeAction(context, emptyCallback)
confirmClickCallback = { checkStoragePermissionBeforeAction(context, emptyCallback) },
extraConfig = DialogHelper.Config(hint = "查看权限应用场景"),
uiModificationCallback = {
it.hintTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
it.hintTv.setOnClickListener {
DirectUtils.directToWebView(context, Constants.PERMISSION_SCENARIO_ADDRESS, "(权限弹窗)")
}
it.contentTv.setTextColor(ContextCompat.getColor(context, R.color.text_333333))
}
)
}

View File

@ -0,0 +1,320 @@
package com.gh.common.util
import android.Manifest
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.Window
import android.view.WindowManager
import com.cmic.sso.sdk.AuthThemeConfig
import com.cmic.sso.sdk.auth.AuthnHelper
import com.cmic.sso.sdk.auth.LoginClickListener
import com.cmic.sso.sdk.auth.TokenListener
import com.gh.common.constant.Config
import com.gh.common.constant.Constants
import com.gh.common.util.PermissionHelper.checkReadPhoneStatePermissionBeforeAction
import com.gh.common.util.ToastUtils.toast
import com.gh.gamecenter.LoginActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogQuickLoginBinding
import com.gh.gamecenter.databinding.SetWaitDialogBinding
import com.gh.gamecenter.entity.LoginTokenEntity
import com.gh.gamecenter.user.ApiResponse
import com.gh.gamecenter.user.LoginTag
import com.gh.gamecenter.user.UserRepository
import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
import org.json.JSONObject
import java.util.*
/**
* 一键登录辅助类
* 1.取号请求
* 2.授权请求
* 3.获取token
* 4.请求登录接口
*/
object QuickLoginHelper {
private var mAuthnHelper: AuthnHelper? = null
private var mTokenListener: TokenListener? = null
private var mPreDialog: Dialog? = null
private var mDialog: Dialog? = null
private var mToken: String = ""
private var mOpenAuthPageSuccess = false
private const val REQUEST_GET_PHONE_INFO_CODE = 100
private const val REQUEST_LOGIN_AUTH_CODE = 101
private const val ENTRANCE_DEFAULT = "一键登录"
private const val ENTRANCE_PERMISSION_DIALOG = "一键登录权限弹窗"
private const val AUTH_ACTIVITY_NAME = "com.cmic.sso.sdk.activity.LoginAuthActivity"
@JvmStatic
fun startLogin(context: Context, entrance: String) {
// 防止短时间多次调用
if (ClickUtils.isFastDoubleClick(991)) return
mOpenAuthPageSuccess = false
if (isPublishEnv()) {
AuthnHelper.setDebugMode(false)
} else {
AuthnHelper.setDebugMode(true)
}
mAuthnHelper = AuthnHelper.getInstance(context.applicationContext)
mAuthnHelper?.run {
authThemeConfig = getConfig(context, entrance)
// 授权页面的回调方法
setPageInListener { code, _ ->
// 返回码200087代表授权页成功拉起
if (code == "200087") {
if (mPreDialog != null && mPreDialog!!.isShowing) {
mPreDialog?.dismiss()
}
mOpenAuthPageSuccess = true
} else { // 不成功就调起验证码登录页
toastCode(code)
startCodeLoginPage(context, true)
}
}
// token回调
mTokenListener = TokenListener { requestCode: Int, jsonObject: JSONObject ->
val code = jsonObject.optString("resultCode")
// “103000”为成功
if (code == "103000") {
when (requestCode) {
REQUEST_GET_PHONE_INFO_CODE -> {
SPUtils.setBoolean(Constants.SP_HAS_GET_PHONE_INFO, true)
// 2.授权请求
mAuthnHelper!!.loginAuth(Config.QUICK_LOGIN_APPID, Config.QUICK_LOGIN_APPKEY, mTokenListener, REQUEST_LOGIN_AUTH_CODE)
}
REQUEST_LOGIN_AUTH_CODE -> {
// 3.获取token
mToken = jsonObject.optString("token")
}
}
} else if (code != "200020") { // 不成功就调起验证码登录页(200020代表授权页关闭)
toastCode(code)
startCodeLoginPage(context, true)
}
}
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
getPhoneInfo(context)
} else {
DialogUtils.showQuickLoginPermissionDialog(
context,
{
checkReadPhoneStatePermissionBeforeAction(context, object : EmptyCallback {
override fun onCallback() {
getPhoneInfo(context)
}
})
},
{
startCodeLoginPage(
context,
entrance = ENTRANCE_PERMISSION_DIALOG,
isFinishAuth = false,
isFromPermission = true
)
}
)
}
}
}
private fun getPhoneInfo(context: Context) {
mPreDialog = Dialog(context, R.style.DialogWindowTransparent).apply {
val binding = SetWaitDialogBinding.inflate(LayoutInflater.from(context)).apply {
setWaitMessage.text = "请求登录中"
}
requestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(binding.root)
setCanceledOnTouchOutside(false)
show()
}
// 1.取号请求
mAuthnHelper!!.getPhoneInfo(Config.QUICK_LOGIN_APPID, Config.QUICK_LOGIN_APPKEY, mTokenListener, REQUEST_GET_PHONE_INFO_CODE)
}
private fun getConfig(context: Context, entrance: String): AuthThemeConfig{
return AuthThemeConfig.Builder()
.setStatusBar(Color.WHITE, true) //状态栏颜色、是否高亮
.setAuthContentView(getCustomView(context)) //自定义布局
// 服务条款标题栏
.setClauseLayoutResID(R.layout.layout_quick_login_navigation, "backIv") //服务条款标题栏
.setNavTextColor(Color.BLACK) //服务条款标题颜色
.setNavTextSize(18) //服务条款标题字体大小
// 手机号码
.setNumberSize(20, true) //手机号码字体大小
.setNumberColor(R.color.text_333333.toColor()) //手机号码字体颜色
.setNumFieldOffsetY(95) //号码栏Y偏移量
// 登录按钮
.setLogBtnImgPath("login_btn_bg") //登录按钮背景
.setLogBtnText("本机号码一键登录", Color.WHITE, 16, false) //登录按钮相关
.setLogBtnOffsetY(170) //登录按钮Y偏移量
.setLogBtn(1000, 44) //登录按钮相关宽高
.setLogBtnMargin(20, 20) //登录按钮相对于屏幕左右边缘边距
// 回调
.setBackPressedListener {} //返回键回调
.setLogBtnClickListener(object : LoginClickListener {
override fun onLoginClickStart(context: Context, jsonObj: JSONObject?) {
LogUtils.login("logging", "一键登录", entrance)
mDialog = Dialog(context, R.style.DialogWindowTransparent).apply {
val binding = SetWaitDialogBinding.inflate(LayoutInflater.from(context)).apply {
setWaitMessage.text = R.string.logging.toResString()
}
requestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(binding.root)
setCanceledOnTouchOutside(false)
show()
}
}
override fun onLoginClickComplete(context: Context, jsonObj: JSONObject?) {
if (mToken.isNotBlank()) {
val params = HashMap<String, String>()
params["token"] = mToken
// 4.请求登录接口
UserRepository.getInstance(context).login(
JSONObject(params as Map<*, *>),
LoginTag.oauth,
object : BiCallback<LoginTokenEntity, ApiResponse<LoginTokenEntity>> {
override fun onFirst(first: LoginTokenEntity) {
if (mDialog != null && mDialog!!.isShowing) {
mDialog?.dismiss()
}
SPUtils.setBoolean(Constants.SP_HAS_GET_PHONE_INFO, false)
LogUtils.login("success", "一键登录", entrance)
finishAuthActivity()
}
override fun onSecond(second: ApiResponse<LoginTokenEntity>) {
if (mDialog != null && mDialog!!.isShowing) {
mDialog?.dismiss()
}
}
}
)
} else {
if (mDialog != null && mDialog!!.isShowing) {
mDialog?.dismiss()
}
}
}
}) //登录按钮回调
.setCheckBoxListener { _: Context?, _: JSONObject? ->
toast("请先勾选同意《${getOperatorType(context)}认证服务协议》《用户协议》《隐私政策》")
} //勾选回调
// 勾选框
.setCheckTipText("") //设置未勾选时弹出提示
.setCheckBoxImgPath("ic_quick_login_check", "ic_quick_login_uncheck", 12, 12) //勾选图片
// 服务条款、用户协议、隐私政策
.setPrivacyState(false) //默认不勾选
.setPrivacyAlignment("阅读并同意 " + AuthThemeConfig.PLACEHOLDER + " 用户协议 隐私政策",
"用户协议", R.string.disclaimer_url.toResString(),
"隐私政策", R.string.privacy_policy_url.toResString(),
"", "", "", "") //隐私条款的协议文本,自定义条款,自定义条款链接(支持四份条款)
.setPrivacyText(11, R.color.text_999999.toColor(), R.color.theme_font.toColor(), true, false) //条款文本设置
.setPrivacyMargin(30, 32) //隐私条款距离手机左右边缘的边距
.setPrivacyOffsetY(280) //隐私条款Y偏移量
// 语言
.setAppLanguageType(0) //0.中文简体1.中文繁体2.英文
// 转场动画
.setAuthPageActIn("anim_auth_in","anim_auth_out")
// .setAuthPageActOut("anim_auth_in","anim_auth_out")
// 整体布局
.setAuthPageWindowMode(WindowManager.LayoutParams.MATCH_PARENT, 360) //授权页窗口宽高比例
.setWindowBottom(1) //授权页是否居于底部0=居中;1=底部设置为1Y轴的偏移 失效
.setFitsSystemWindows(false)
.setThemeId(R.style.quickLoginDialog) //授权页弹窗主题
.build()
}
// 获取自定义布局View
@SuppressLint("SetTextI18n")
private fun getCustomView(context: Context): View {
return DialogQuickLoginBinding.inflate(LayoutInflater.from(context)).apply {
closeIv.setOnClickListener {
finishAuthActivity()
}
changeLoginBtn.setOnClickListener {
startCodeLoginPage(context, false)
}
descTv.text = "${getOperatorType(context)}提供认证服务"
}.root
}
// 获取运营商名称
private fun getOperatorType(context: Context): String {
mAuthnHelper?.run {
val jsonObject = getNetworkType(context)
tryWithDefaultCatch {
val net = jsonObject.optString("operatorType").toInt()
if (net == 1) return "中国移动"
if (net == 2) return "中国联通"
if (net == 3) return "中国电信"
}
}
return ""
}
private fun startCodeLoginPage(context: Context, isFinishAuth: Boolean) {
startCodeLoginPage(context, ENTRANCE_DEFAULT, isFinishAuth, false)
}
private fun startCodeLoginPage(context: Context, entrance: String, isFinishAuth: Boolean, isFromPermission: Boolean) {
if (mPreDialog != null && mPreDialog!!.isShowing) {
tryWithDefaultCatch {
mPreDialog?.dismiss()
}
}
if (isFinishAuth) {
finishAuthActivity()
}
val status = when {
isFromPermission -> LoginActivity.STATUS_FROM_QUICK_LOGIN_PERMISSION
mOpenAuthPageSuccess -> LoginActivity.STATUS_FROM_QUICK_LOGIN_PAGE
else -> LoginActivity.STATUS_DEFAULT
}
context.startActivity(LoginActivity.getIntent(context, entrance, status))
}
@JvmStatic
fun finishAuthActivity() {
mAuthnHelper?.quitAuthActivity()
// 调用quitAuthActivity()方法有概率会关不掉授权页所以使用在调用quitAuthActivity()方法后判断当前Activity是否还是AuthActivity如果是则finish
AppManager.getInstance().recentActiveActivity?.run {
if (localClassName == AUTH_ACTIVITY_NAME) {
finish()
}
}
}
private fun toastCode(code: String) {
debugOnly {
Utils.log("QuickLoginHelper -> code = $code")
}
// if (code == "200023" || code == "200028") {
// toast("验证码登录")
// } else {
// toast(code)
// }
}
}

View File

@ -0,0 +1,50 @@
package com.gh.common.util
import android.content.Context
import com.gh.gamecenter.UserInfoEditActivity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.user.UserViewModel
import java.util.*
object RealNameHelper {
@JvmStatic
fun checkIfAuth(context: Context, gameEntity: GameEntity, callback: EmptyCallback) {
if (gameEntity.auth?.switch == "on") {
if ((gameEntity.auth?.timeStart == "00:00" && gameEntity.auth?.timeEnd == "00:00")
|| withinTimeRange(gameEntity.auth?.timeStart, gameEntity.auth?.timeEnd)) {
context.ifLogin("") {
if (!UserManager.getInstance().isAuth) {
context.startActivity(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD))
} else {
callback.onCallback()
}
}
} else {
callback.onCallback()
}
} else {
callback.onCallback()
}
}
private fun withinTimeRange(timeStart: String?, timeEnd: String?): Boolean {
val realTimeEnd = if (timeEnd == "00:00") "23:59" else timeEnd
val startHourAndMinuteArray = timeStart?.split(":")
val endHourAndMinuteArray = realTimeEnd?.split(":")
val calStart = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, startHourAndMinuteArray?.first()!!.toInt())
set(Calendar.MINUTE, startHourAndMinuteArray.secondOrNull()!!.toInt())
}
val calEnd = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, endHourAndMinuteArray?.first()!!.toInt())
set(Calendar.MINUTE, endHourAndMinuteArray.secondOrNull()!!.toInt())
}
return (Calendar.getInstance().after(calStart) && Calendar.getInstance().before(calEnd))
}
}

View File

@ -0,0 +1,144 @@
package com.gh.common.util
import com.gh.common.constant.Constants
import com.gh.common.dialog.DeviceRemindDialog
import com.gh.gamecenter.entity.*
import com.google.gson.reflect.TypeToken
import com.halo.assistant.HaloApp
object RecommendPopupHelper {
fun getRecommendPopup(gameEntity: GameEntity?, popups: ArrayList<RecommendPopupEntity>?): RecommendPopupEntity? {
if (gameEntity == null || popups.isNullOrEmpty()) return null
//判断是否触发设备弹窗
val pair = DeviceRemindDialog.shouldShowDeviceRemindDialog(gameEntity)
if (pair.first) return null
//判断是否为多版本游戏
if (gameEntity.getApk().isEmpty() || gameEntity.getApk().size > 1) return null
val downloadBtnText = GameUtils.getDownloadBtnText(HaloApp.getInstance(), gameEntity, PluginLocation.only_game)
val filterEntities = arrayListOf<RecommendPopupEntity>()
loop@ for (entity in popups) {
//判断是否符合下载类型
val downloadType = entity.recommendPackage.getDownloadType()
if (!downloadType.contains(downloadBtnText)) continue
//判断是否符合安装包大小限制
val minSize = entity.recommendPackage.minSize
val sizeStr = gameEntity.getApk()[0].size ?: continue
val size = sizeStr.substring(0, sizeStr.length - 2).toFloat()
if (size < minSize) continue
//判断是否符合包名限制
val nameRule = entity.recommendPackage.nameRule
val packages = entity.recommendPackage.details
val installedPackages = PackageUtils.getAllPackageNameIncludeGh(HaloApp.getInstance())
var isMatchSuccess = true
val checkInstalled: (splitPackages: List<String>) -> Boolean = {
var isInstalled = false
it.forEach { packageName ->
if (installedPackages.contains(packageName)) {
isInstalled = true
return@forEach
}
}
isInstalled
}
when (nameRule) {
"installed" -> {
//设备上安装了指定的包名才生效(需全部满足)
packages.forEach {
val splitPackages = it.split("")
val isInstalled = checkInstalled(splitPackages)
if (!isInstalled) {
isMatchSuccess = false
return@forEach
}
}
}
"uninstalled" -> {
//设备上未安装指定的包名才生效(需全部满足)
packages.forEach {
val splitPackages = it.split("")
val isInstalled = checkInstalled(splitPackages)
if (isInstalled) {
isMatchSuccess = false
return@forEach
}
}
}
else -> {
isMatchSuccess = true
}
}
if (!isMatchSuccess) continue
filterEntities.add(entity)
}
return if (filterEntities.isEmpty()) {
null
} else {
val recommendPopupEntity = filterEntities[0]
if (checkFrequencyIsMatch(recommendPopupEntity)) {
recommendPopupEntity
} else {
null
}
}
}
fun checkFrequencyIsMatch(entity: RecommendPopupEntity): Boolean {
//判断是否符合通知频率 一次once, 累计次数count, 每周一次weekly, 每天一次daily, 每次always
val plan = entity.notice.plan
val times = entity.notice.times
//[{"popupId":"6074ff265b58135844aec523","showTime":1618391319457,"count":1}]
val recordStr = SPUtils.getString(Constants.SP_RECOMMEND_POPUP)
val type = object : TypeToken<ArrayList<RecommendRecord>>() {}.type
val records = GsonUtils.gson.fromJson<ArrayList<RecommendRecord>>(recordStr, type)
?: arrayListOf()
val recommendRecord = records.find { it.popupId == entity.id }
val showTime = recommendRecord?.showTime ?: 0L
val count = recommendRecord?.count ?: 0
when (plan) {
"once" -> {
if (recommendRecord != null) return false
}
"count" -> {
if (count >= times) return false
}
"weekly" -> {
if (TimeUtils.isThisWeek(showTime)) return false
}
"daily" -> {
if (TimeUtils.isToday(showTime)) return false
}
"always" -> {
//do nothing
}
}
return true
}
fun saveRecord(popup: RecommendPopupEntity) {
val plan = popup.notice.plan
val recordStr = SPUtils.getString(Constants.SP_RECOMMEND_POPUP)
val type = object : TypeToken<ArrayList<RecommendRecord>>() {}.type
val records = GsonUtils.gson.fromJson<ArrayList<RecommendRecord>>(recordStr, type)
?: arrayListOf()
val recommendRecord = records.find { it.popupId == popup.id }
if (recommendRecord == null) {
records.add(RecommendRecord(popup.id, System.currentTimeMillis(), 1))
} else {
if (plan == "count") {
recommendRecord.count = recommendRecord.count + 1
}
recommendRecord.showTime = System.currentTimeMillis()
}
SPUtils.setString(Constants.SP_RECOMMEND_POPUP, GsonUtils.toJson(records))
}
}

View File

@ -104,6 +104,24 @@ public class ShareUtils {
}
}
public enum ShareType {
qq("qq"),
qqZone("qq空间"),
weibo("微博"),
wechat("微信"),
wechatMoments("朋友圈");
private String name;
ShareType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
private String[] arrLabel = {"微信好友", "朋友圈", "QQ好友", "QQ空间", "新浪微博", "短信", "复制链接", "取消"};
private WeakReference<PopupWindow> popupWindow;
@ -113,6 +131,7 @@ public class ShareUtils {
public static ShareEntrance shareEntrance;//分享入口(事件上报和视频分享统计用)
public static String resourceId = "";//分享内容的id(事件上报用)
public static ShareEntity shareEntity;//分享信息(事件上报用)
private static ShareType mShareType;//分享类型(事件上报用)
private WeakReference<Activity> mActivity;
@ -126,6 +145,9 @@ public class ShareUtils {
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "success",
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
EnergyTaskHelper.postEnergyTaskForShare(ShareUtils.shareEntrance.getName(), ShareUtils.resourceId, ShareUtils.shareEntity.getShareUrl());
if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) {
IntegralLogHelper.INSTANCE.logInviteResult("成功", mShareType.getName());
}
}
@Override
@ -133,6 +155,9 @@ public class ShareUtils {
Utils.toast(mContext, R.string.share_fail_hint);
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "fail",
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) {
IntegralLogHelper.INSTANCE.logInviteResult("失败", mShareType.getName());
}
}
@Override
@ -140,6 +165,9 @@ public class ShareUtils {
Utils.toast(mContext, R.string.share_cancel_hint);
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "cancel",
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) {
IntegralLogHelper.INSTANCE.logInviteResult("取消", mShareType.getName());
}
}
};
@ -188,18 +216,23 @@ public class ShareUtils {
// 分享
switch (way) {
case "qq" :
mShareType = ShareType.qq;
qqShare();
break;
case "qq_zone" :
mShareType = ShareType.qqZone;
qZoneShare();
break;
case "wechat" :
mShareType = ShareType.wechat;
wechatShare();
break;
case "wechat_moments" :
mShareType = ShareType.wechatMoments;
wechatMomentsShare();
break;
case "weibo" :
mShareType = ShareType.weibo;
sinaWeiboShare();
break;
}
@ -693,6 +726,10 @@ public class ShareUtils {
return mTitle;
}
public String getShareUrl() {
return shareUrl;
}
private class ShareRecyclerViewAdapter extends RecyclerView.Adapter<ShareRecyclerViewAdapter.ViewHolder> {
private OnItemClickListener listener;

View File

@ -48,6 +48,12 @@ object TimeUtils {
return testDate
}
//获取当前的小时24小时制
fun getCurrentHour(): Int {
val calendar = Calendar.getInstance()
return calendar.get(Calendar.HOUR_OF_DAY)
}
//判断是不是今天
fun isToday(timestamp: Long): Boolean {
val format = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)
@ -60,6 +66,15 @@ object TimeUtils {
return false
}
//判断是不是本周
fun isThisWeek(timestamp: Long): Boolean {
val calendar = Calendar.getInstance()
val currentWeek = calendar[Calendar.WEEK_OF_YEAR]
calendar.time = Date(timestamp)
val paramWeek = calendar[Calendar.WEEK_OF_YEAR]
return paramWeek == currentWeek
}
/**
* 判断时间戳是多少天前
*/
@ -77,6 +92,23 @@ object TimeUtils {
return days.toInt()
}
/**
* 判断传入时间戳与当前日期的差值,返回单位为天
*/
fun getDaysOffset(timestamp: Long): Int {
var days: Long = 0
val format = SimpleDateFormat("yyyyMMdd", Locale.getDefault())
try {
val today = format.parse(format.format(Date())).time
val day = timestamp * 1000
days = (day - today) / 86400000
} catch (e: ParseException) {
e.printStackTrace()
}
return days.toInt()
}
/**
* 格式化视频时长

View File

@ -51,6 +51,7 @@ public class TimestampUtils {
whiteList.add(".*tasks:check.*");
whiteList.add(".*novice_tasks.*");
whiteList.add(".*daily_tasks.*");
whiteList.add(".*fixed_tasks.*");
whiteList.add(".*energies.*");
}

View File

@ -2,21 +2,17 @@ package com.gh.common.view
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.RelativeLayout
import androidx.cardview.widget.CardView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.GenericDraweeHierarchy
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
import com.facebook.drawee.generic.RoundingParams
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.util.ImageUtils
import com.gh.common.util.dip2px
import com.gh.common.util.px2dip
import com.gh.common.util.toColor
import com.gh.gamecenter.R
@ -25,6 +21,8 @@ class AvatarBorderView : ConstraintLayout {
var avatarView: SimpleDraweeView? = null
var borderView: SimpleDraweeView? = null
var badgeView: SimpleDraweeView? = null
var avatarContainer: CardView? = null
var avatarBorderView: View? = null
private var mAvatarWidth = 100f
private var mBadgeWidth = 30f
private var mAvatarBorderColor = Color.parseColor("#ffffff")
@ -61,21 +59,39 @@ class AvatarBorderView : ConstraintLayout {
avatarView = findViewById(R.id.avatarView)
borderView = findViewById(R.id.borderView)
badgeView = findViewById(R.id.badgeView)
avatarContainer = findViewById(R.id.avatarContainer)
avatarBorderView = findViewById(R.id.avatarBorderView)
changeLayoutParams()
}
private fun changeLayoutParams() {
avatarContainer?.apply {
radius = mAvatarWidth / 2
cardElevation = 0F
}
avatarView?.apply {
val params = layoutParams
params.width = mAvatarWidth.toInt()
params.height = mAvatarWidth.toInt()
layoutParams = params
val roundingParams = RoundingParams.asCircle()
val roundingParams = RoundingParams.fromCornersRadius(mAvatarWidth)
roundingParams.borderColor = mAvatarBorderColor
roundingParams.borderWidth = mAvatarBorderWidth
hierarchy?.roundingParams = roundingParams
}
avatarBorderView?.apply {
val params = layoutParams
params.width = mAvatarWidth.toInt()
params.height = mAvatarWidth.toInt()
layoutParams = params
val drawable = GradientDrawable().apply {
setColor(R.color.transparent.toColor())
shape = GradientDrawable.OVAL
setStroke(mAvatarBorderWidth.toInt(), mAvatarBorderColor)
}
background = drawable
}
borderView?.apply {
val params = layoutParams
if (mRatio > 0) {

View File

@ -0,0 +1,226 @@
package com.gh.common.view
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.gh.common.util.dip2px
import com.gh.common.util.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.SidebarsEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.google.android.flexbox.FlexboxLayout
class CategoryFilterView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : LinearLayout(context, attrs, defStyleAttr) {
private var mTypeTv: TextView
private var mCatalogTv: TextView
private var mSizeTv: TextView
private var mTypeContainer: View
private var mCatalogContainer: View
private var mSizeContainer: View
private var mTypeFilterArray = arrayOf(SortType.RECOMMENDED, SortType.NEWEST, SortType.RATING)
private var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
private var mOnCategoryFilterSetupListener: OnCategoryFilterSetupListener? = null
init {
View.inflate(context, R.layout.layout_category_filter, this)
mTypeTv = findViewById(R.id.type_tv)
mCatalogTv = findViewById(R.id.catalog_tv)
mSizeTv = findViewById(R.id.size_tv)
mTypeContainer = findViewById(R.id.container_type)
mCatalogContainer = findViewById(R.id.container_category)
mSizeContainer = findViewById(R.id.container_size)
mTypeTv.text = mTypeFilterArray[0].value
mTypeContainer.setOnClickListener {
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
}
mCatalogContainer.setOnClickListener {
mOnCategoryFilterSetupListener?.onSetupSortCategory()
}
mSizeContainer.setOnClickListener {
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
}
}
fun setOnConfigSetupListener(onCategoryFilterSetupListener: OnCategoryFilterSetupListener) {
mOnCategoryFilterSetupListener = onCategoryFilterSetupListener
}
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
if (highlightIt) {
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
targetTextView.setTextColor(Color.WHITE)
} else {
targetTextView.background = null
targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_757575))
}
}
private fun showSelectTypePopupWindow(containerView: View, typeTv: TextView, typeText: String) {
val drawableUp = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_up)
val drawableDown = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_down)
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
typeTv.setTextColor(R.color.theme_font.toColor())
typeTv.setCompoundDrawables(null, null, drawableUp, null)
val inflater = LayoutInflater.from(typeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val windowWidth = typeTv.context.resources.displayMetrics.widthPixels - 80F.dip2px()
val popupWindow = PopupWindow(
layout,
windowWidth,
LayoutParams.WRAP_CONTENT)
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (type in mTypeFilterArray) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = windowWidth / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
tv.text = type.value
toggleHighlightedTextView(tv, typeText == type.value)
tv.tag = type.value
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
typeTv.text = type.value
mOnCategoryFilterSetupListener?.onSetupSortType(type)
}
}
popupWindow.setOnDismissListener {
typeTv.setTextColor(R.color.text_757575.toColor())
typeTv.setCompoundDrawables(null, null, drawableDown, null)
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun showSelectSizePopupWindow(containerView: View, sizeTv: TextView, sizeText: String) {
val drawableUp = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_up)
val drawableDown = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_down)
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
sizeTv.setTextColor(R.color.theme_font.toColor())
sizeTv.setCompoundDrawables(null, null, drawableUp, null)
val inflater = LayoutInflater.from(sizeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val windowWidth = sizeTv.context.resources.displayMetrics.widthPixels - 80F.dip2px()
val popupWindow = PopupWindow(
layout,
windowWidth,
LayoutParams.WRAP_CONTENT)
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
sizeFilterArray = if (sizeFilterArray == null) {
getDefaultSizeFilterArray()
} else {
sizeFilterArray?.apply {
if (firstOrNull()?.text != "全部大小") {
add(0, SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
}
}
}
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (size in sizeFilterArray!!) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = windowWidth / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
tv.text = size.text
toggleHighlightedTextView(tv, sizeText == size.text)
tv.tag = size.text
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
sizeTv.text = size.text
mOnCategoryFilterSetupListener?.onSetupSortSize(size)
}
}
popupWindow.setOnDismissListener {
sizeTv.setTextColor(R.color.text_757575.toColor())
sizeTv.setCompoundDrawables(null, null, drawableDown, null)
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
return arrayListOf<SubjectSettingEntity.Size>().apply {
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下"))
add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M"))
add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M"))
add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G"))
add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上"))
}
}
interface OnCategoryFilterSetupListener {
fun onSetupSortSize(sortSize: SubjectSettingEntity.Size)
fun onSetupSortType(sortType: SortType)
fun onSetupSortCategory()
}
enum class SortType(val value: String) {
RECOMMENDED("热门推荐"),
NEWEST("最新上线"),
RATING("最高评分")
}
}

View File

@ -0,0 +1,199 @@
package com.gh.common.view
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.dip2px
import com.gh.common.util.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.ItemFilterBinding
import com.gh.gamecenter.databinding.LayoutFilterBinding
import com.google.android.flexbox.FlexboxLayout
// TODO 把 ConfigFilterView 的上层实现切换到继承这个类实现
class FilterView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
: ConstraintLayout(context, attrs, defStyleAttr) {
private var mBinding: LayoutFilterBinding? = null
private var mMainFilterList: ArrayList<String> = arrayListOf()
private var mSubFilterList: ArrayList<String> = arrayListOf()
private var mSelectedMainFilter: String = ""
private var mSelectedSubFilter: String = ""
init {
mBinding = LayoutFilterBinding.inflate(LayoutInflater.from(context), this, true)
}
fun setupFilter(mainFilterList: ArrayList<String>,
defaultSelectedMainFilter: String? = null,
subFilterList: ArrayList<String>,
subFilterText: String,
mainFilterSelectedCallback: ((String) -> Unit),
subFilterSelectedCallback: ((String) -> Unit)) {
mMainFilterList = mainFilterList
mSubFilterList = subFilterList
mBinding?.subFilterTv?.text = subFilterText
mBinding?.subFilterTv?.setOnClickListener {
showSelectionPopupWindow(this, it as TextView, mSelectedSubFilter) { selectedText ->
subFilterSelectedCallback.invoke(selectedText)
}
}
mBinding?.filterRecyclerView?.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
mBinding?.filterRecyclerView?.adapter = FilterAdapter(
context,
mMainFilterList,
defaultSelectedMainFilter ?: mainFilterList.first()) {
mainFilterSelectedCallback.invoke(it)
}
}
fun updateSelectedMainFilter(filter: String) {
mSelectedMainFilter = filter
(mBinding?.filterRecyclerView?.adapter as? FilterAdapter)?.updateSelectedFilter(filter)
mBinding?.filterRecyclerView?.smoothScrollToPosition(mMainFilterList.indexOf(filter))
}
fun updateSelectedSubFilter(filter: String) {
mSelectedSubFilter = filter
mBinding?.subFilterTv?.text = filter
}
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
if (highlightIt) {
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
targetTextView.setTextColor(Color.WHITE)
} else {
targetTextView.background = null
targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_757575))
}
}
private fun showSelectionPopupWindow(containerView: View,
subFilterTv: TextView,
subFilterText: String,
selectedCallback: ((String) -> Unit)) {
val drawableUp = ContextCompat.getDrawable(subFilterTv.context, R.drawable.ic_filter_arrow_up)
val drawableDown = ContextCompat.getDrawable(subFilterTv.context, R.drawable.ic_filter_arrow_down)
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
subFilterTv.setTextColor(R.color.theme_font.toColor())
subFilterTv.setCompoundDrawables(null, null, drawableUp, null)
val inflater = LayoutInflater.from(subFilterTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT)
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
flexboxLayout.setPadding(16F.dip2px(), 0, 0, 8F.dip2px())
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (filter in mSubFilterList) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
tv.text = filter
if (subFilterText == filter) {
toggleHighlightedTextView(tv, true)
} else {
toggleHighlightedTextView(tv, false)
}
tv.tag = filter
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
subFilterTv.text = filter
updateSelectedSubFilter(filter)
selectedCallback.invoke(filter)
}
}
popupWindow.setOnDismissListener {
subFilterTv.setTextColor(R.color.text_757575.toColor())
subFilterTv.setCompoundDrawables(null, null, drawableDown, null)
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
// 在模拟器上会有 1dp 的位移
popupWindow.showAsDropDown(containerView, 0, -6)
}
class FilterAdapter(val context: Context,
private val mFilterList: ArrayList<String>,
private val mDefaultSelectedFilter: String,
private val mClickCallback: (String) -> Unit)
: RecyclerView.Adapter<FilterAdapter.FilterViewHolder>() {
private var mSelectedFilter = mDefaultSelectedFilter
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FilterViewHolder {
return FilterViewHolder(ItemFilterBinding.inflate(LayoutInflater.from(context)))
}
override fun getItemCount() = mFilterList.size
override fun onBindViewHolder(holder: FilterViewHolder, position: Int) {
if (mSelectedFilter == "") {
mSelectedFilter = mFilterList.first()
}
if (mSelectedFilter == mFilterList[position]) {
holder.binding.titleTv.setBackgroundResource(R.drawable.bg_tag_text)
holder.binding.titleTv.setTextColor(R.color.white.toColor())
} else {
holder.binding.titleTv.setBackgroundColor(Color.WHITE)
holder.binding.titleTv.setTextColor(R.color.text_777777.toColor())
}
holder.binding.titleTv.text = mFilterList[position]
holder.binding.root.setOnClickListener {
mClickCallback.invoke(mFilterList[position])
updateSelectedFilter(mFilterList[position])
}
}
fun updateSelectedFilter(incomingSelectedFilter: String) {
if (mSelectedFilter != incomingSelectedFilter) {
mSelectedFilter = incomingSelectedFilter
notifyDataSetChanged()
}
}
class FilterViewHolder(var binding: ItemFilterBinding) : RecyclerView.ViewHolder(binding.root)
}
}

View File

@ -5,11 +5,11 @@ import android.text.TextUtils
import android.util.AttributeSet
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.facebook.drawee.generic.RoundingParams
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.util.DisplayUtils
import com.gh.common.util.ImageUtils
import com.gh.common.util.dip2px
import com.gh.common.util.goneIf
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.GameEntity
@ -17,7 +17,7 @@ import kotlinx.android.synthetic.main.layout_game_icon.view.*
class GameIconView : ConstraintLayout {
private var mCornerRadius = 10
private var mCornerRadius = 0
private var mBorderColor = 0
private var mGameIconOverlayColor = 0
private var mBorderWidth = 1
@ -36,24 +36,13 @@ class GameIconView : ConstraintLayout {
View.inflate(context, R.layout.layout_game_icon, this)
val ta = context.obtainStyledAttributes(attrs, R.styleable.GameIconView)
mCornerRadius = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconCornerRadius, DisplayUtils.dip2px(10F))
mCornerRadius = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconCornerRadius, DisplayUtils.dip2px(0F))
mBorderColor = ta.getColor(R.styleable.GameIconView_gameIconBorderColor, 0)
mGameIconOverlayColor = ta.getColor(R.styleable.GameIconView_gameIconOverlayColor, 0)
mBorderWidth = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconBorderWidth, 1)
mFadeDuration = ta.getInt(R.styleable.GameIconView_gameIconFadeDuration, -1)
ta.recycle()
val roundingParams = RoundingParams.fromCornersRadius(mCornerRadius.toFloat())
if (mGameIconOverlayColor != 0) {
roundingParams.overlayColor = mGameIconOverlayColor
}
if (mBorderColor != 0) {
roundingParams.setBorder(mBorderColor, mBorderWidth.toFloat())
}
gameIconIv.hierarchy.roundingParams = roundingParams
gameIconDecoratorIv.hierarchy.roundingParams = roundingParams
if (mFadeDuration != -1) {
gameIconIv.hierarchy.fadeDuration = mFadeDuration
}
@ -77,4 +66,59 @@ class GameIconView : ConstraintLayout {
fun getIconDecoratorIv(): SimpleDraweeView = gameIconDecoratorIv
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
val cornerRadius = getCornerRadius(w)
// 一些设备(没错,又是 vivo),代码设置 CardView 的 radius 无效(xml 设置有效)
// 被迫再设置一次 SimpleDraweeView 的 radius :(
val roundingParams = RoundingParams.fromCornersRadius(cornerRadius)
if (mGameIconOverlayColor != 0) {
roundingParams.overlayColor = mGameIconOverlayColor
}
if (mBorderColor != 0) {
roundingParams.setBorder(mBorderColor, mBorderWidth.toFloat())
}
gameIconIv.hierarchy.roundingParams = roundingParams
gameIconDecoratorIv.hierarchy.roundingParams = roundingParams
}
private fun getCornerRadius(width: Int): Float {
// XML 的圆角设置优先级更高
if (mCornerRadius != 0) {
return mCornerRadius.toFloat()
}
return when {
width <= SIZE_36 -> RADIUS_8
width >= SIZE_88 -> RADIUS_20
width >= SIZE_80 -> RADIUS_18
width >= SIZE_72 -> RADIUS_16
width >= SIZE_64 -> RADIUS_14
width >= SIZE_48 -> RADIUS_12
width >= SIZE_40 -> RADIUS_10
else -> RADIUS_8
}
}
companion object {
val RADIUS_8 = 8F.dip2px().toFloat()
val RADIUS_10 = 10F.dip2px().toFloat()
val RADIUS_12 = 12F.dip2px().toFloat()
val RADIUS_14 = 14F.dip2px().toFloat()
val RADIUS_16 = 16F.dip2px().toFloat()
val RADIUS_18 = 18F.dip2px().toFloat()
val RADIUS_20 = 20F.dip2px().toFloat()
val SIZE_36 = 36F.dip2px()
val SIZE_40 = 40F.dip2px()
val SIZE_48 = 48F.dip2px()
val SIZE_64 = 64F.dip2px()
val SIZE_72 = 72F.dip2px()
val SIZE_80 = 80F.dip2px()
val SIZE_88 = 88F.dip2px()
}
}

View File

@ -39,6 +39,7 @@ class ImageContainerView : LinearLayout {
//图片之间的间距
private val mItemSpace = 4f.dip2px()
private var mOffset = 0
private var index = 0
constructor(context: Context) : this(context, null)
@ -50,12 +51,21 @@ class ImageContainerView : LinearLayout {
private fun initView(attrs: AttributeSet?) {
orientation = HORIZONTAL
val ta = context.obtainStyledAttributes(attrs, R.styleable.ImageContainerView)
val offset = ta.getDimensionPixelSize(R.styleable.ImageContainerView_offset, 0)
mDefaultWidth = (DisplayUtils.getScreenWidth() - offset.toFloat() - mItemSpace * 2) / 3
mFixdWidth = (DisplayUtils.getScreenWidth() - offset.toFloat() - mItemSpace * 2) * 2 / 3
mOffset = ta.getDimensionPixelSize(R.styleable.ImageContainerView_offset, 0)
calculateWidth()
ta.recycle()
}
private fun calculateWidth() {
mDefaultWidth = (DisplayUtils.getScreenWidth() - mOffset.toFloat() - mItemSpace * 2) / 3
mFixdWidth = (DisplayUtils.getScreenWidth() - mOffset.toFloat() - mItemSpace * 2) * 2 / 3
}
fun setOffset(offset: Float) {
mOffset = offset.dip2px()
calculateWidth()
}
fun bindData(entity: AnswerEntity, entrance: String = "", path: String = "") {
mAnswerEntity = entity
mEntrance = entrance

View File

@ -60,6 +60,8 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
private static final AccessibilityDelegate ACCESSIBILITY_DELEGATE = new AccessibilityDelegate();
private Boolean mIsParentViewImplNestedScrolling = false;
private boolean mInterceptHorizontalScrollDispatch = true;
public NestedScrollWebView2(Context context, AttributeSet attrs) {
super(context, attrs);
init();
@ -97,7 +99,9 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
getParent().requestDisallowInterceptTouchEvent(true);
if (mInterceptHorizontalScrollDispatch) {
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.dispatchTouchEvent(ev);
}
@ -825,4 +829,8 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
return false;
}
}
public void enableHorizontalScrollDispatch() {
mInterceptHorizontalScrollDispatch = false;
}
}

View File

@ -0,0 +1,38 @@
package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.view.ViewGroup
import androidx.core.view.forEach
import com.google.android.material.tabs.TabLayout
class NoDefaultMinWidthTabLayout : TabLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
if (tabCount > 5) {
val tabLayout = getChildAt(0) as ViewGroup
val childCount = tabLayout.childCount
if (childCount > 0) {
val widthPixels = MeasureSpec.getSize(widthMeasureSpec)
val tabMinWidth = widthPixels / childCount
var remainderPixels = widthPixels % childCount
tabLayout.forEach {
if (remainderPixels > 0) {
it.minimumWidth = tabMinWidth + 1
remainderPixels--
} else {
it.minimumWidth = tabMinWidth
}
}
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}

View File

@ -14,7 +14,9 @@ import android.view.ViewGroup;
import com.gh.common.util.DisplayUtils;
import com.gh.gamecenter.R;
import com.google.android.material.tabs.TabLayout;
import com.lightgame.utils.Utils;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.viewpager.widget.ViewPager;
@ -34,6 +36,8 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
private int mIndicatorColor = 0;
private boolean mDisableIndicatorScaling = false;
private GradientDrawable mGradientDrawable;
private Drawable mCustomDrawable;
@ -48,9 +52,11 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
public TabIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mIndicatorWidth = (int) context.getResources().getDimension(R.dimen.default_tab_indicator_width);
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabIndicatorView);
if (a.hasValue(R.styleable.TabIndicatorView_indicatorColor)) {
mIndicatorColor = a.getColor(R.styleable.TabIndicatorView_indicatorColor, 0);
mIndicatorColor = a.getColor(R.styleable.TabIndicatorView_indicatorColor, ContextCompat.getColor(context, R.color.theme_font));
mGradientDrawable = new GradientDrawable();
mGradientDrawable.setShape(GradientDrawable.RECTANGLE);
mGradientDrawable.setColor(mIndicatorColor);
@ -59,6 +65,9 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
if (a.hasValue(R.styleable.TabIndicatorView_indicatorDrawable)) {
mCustomDrawable = a.getDrawable(R.styleable.TabIndicatorView_indicatorDrawable);
}
if (a.hasValue(R.styleable.TabIndicatorView_disableIndicatorScaling)) {
mDisableIndicatorScaling = a.getBoolean(R.styleable.TabIndicatorView_disableIndicatorScaling, false);
}
a.recycle();
}
@ -68,6 +77,11 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
mIndicatorHeight = MeasureSpec.getSize(heightMeasureSpec);
}
public void updateIndicatorDrawable(Drawable drawable) {
mCustomDrawable = drawable;
invalidate();
}
public void setupWithTabLayout(final TabLayout tableLayout) {
mTabLayout = tableLayout;
@ -119,7 +133,23 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
} else {
drawable = getResources().getDrawable(R.drawable.ask_tab_indicator_bg); // 固定Indicator背景 有需要可以自行更改
}
drawable.setBounds(l, t, r, b);
// 是否需要禁用指示器拉伸
if (mDisableIndicatorScaling) {
int currentWidth = r - l;
int newLeft = l;
int newRight = r;
if (currentWidth != mIndicatorWidth) {
int widthOffset = currentWidth - mIndicatorWidth;
newLeft = l + (widthOffset / 2);
newRight = newLeft + mIndicatorWidth;
}
drawable.setBounds(newLeft, t, newRight, b);
} else {
drawable.setBounds(l, t, r, b);
}
drawable.draw(canvas);
}

View File

@ -0,0 +1,99 @@
package com.gh.common.view
import android.content.Context
import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.util.AttributeSet
import android.view.View
import android.widget.ProgressBar
import androidx.core.content.ContextCompat
import com.gh.common.util.dip2px
import com.gh.gamecenter.R
class ThumbProgressBar : ProgressBar {
private var mThumbDrawable: Drawable? = null
//Thumb的宽度
private var mThumbDrawableWidth = 0
//Thumb的高度
private var mThumbDrawableHeight = 0
//进度条高度
private var mProgressBarHeight = 12f.dip2px()
//Thumb偏移量
private val mDefaultThumbOffset = 13f.dip2px()
//ProgressBar左右偏移量
private val mProgressBarPadding = 12f.dip2px()
private var mPaint: Paint
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
init {
mThumbDrawable = ContextCompat.getDrawable(context, R.drawable.icon_package_check_rocket)
mThumbDrawableWidth = mThumbDrawable?.intrinsicWidth ?: 0
mThumbDrawableHeight = mThumbDrawable?.intrinsicHeight ?: 0
mPaint = Paint()
mPaint.isAntiAlias = true
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val dh = if (mThumbDrawableHeight > mProgressBarHeight) mThumbDrawableHeight else mProgressBarHeight
setMeasuredDimension(
View.getDefaultSize(0, widthMeasureSpec),
dh
)
//LayerDrawable使用setBounds可能无效
if (progressDrawable is LayerDrawable) {
(progressDrawable as LayerDrawable).setLayerInset(0,
mProgressBarPadding,
(mThumbDrawableHeight - mProgressBarHeight) / 2,
mProgressBarPadding,
(mThumbDrawableHeight - mProgressBarHeight) / 2
)
(progressDrawable as LayerDrawable).setLayerInset(1,
mProgressBarPadding,
(mThumbDrawableHeight - mProgressBarHeight) / 2,
mProgressBarPadding,
(mThumbDrawableHeight - mProgressBarHeight) / 2
)
} else {
progressDrawable.setBounds(
mProgressBarPadding,
(mThumbDrawableHeight - mProgressBarHeight) / 2,
measuredWidth - mProgressBarPadding,
measuredHeight - (mThumbDrawableHeight - mProgressBarHeight) / 2
)
}
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val percent = progress.toFloat() / max
val progressWidth = measuredWidth - paddingLeft - paddingRight - mProgressBarPadding * 2
var offsetX =
progressWidth * percent + paddingLeft - mDefaultThumbOffset + mProgressBarPadding
if (offsetX < 0) {
offsetX = 0f
}
if (offsetX > measuredWidth - mThumbDrawableWidth) {
offsetX = (measuredWidth - mThumbDrawableWidth).toFloat()
}
val bitmapDrawable = mThumbDrawable as BitmapDrawable
val bitmap = bitmapDrawable.bitmap
canvas.drawBitmap(bitmap, offsetX, 0f, mPaint)
}
}

View File

@ -67,6 +67,7 @@ public class DWebView extends WebView {
private ArrayList<CallInfo> callInfoList;
private InnerJavascriptInterface innerJavascriptInterface = new InnerJavascriptInterface();
private Handler mainHandler = new Handler(Looper.getMainLooper());
private OnScrollChangedListener mOnScrollChangedCallback;
private class InnerJavascriptInterface {
@ -1045,4 +1046,21 @@ public class DWebView extends WebView {
e.printStackTrace();
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (mOnScrollChangedCallback != null) {
mOnScrollChangedCallback.onScroll(l - oldl, t - oldt);
}
}
public void setOnScrollChangedListener(
final OnScrollChangedListener onScrollChangedCallback) {
mOnScrollChangedCallback = onScrollChangedCallback;
}
public interface OnScrollChangedListener {
void onScroll(int dx, int dy);
}
}

View File

@ -120,8 +120,8 @@ public class PagerLayoutManager extends LinearLayoutManager {
if (viewIdle != null) {
positionIdle = getPosition(viewIdle);
}
int childCount = getChildCount();
// if (mOnViewPagerListener != null && childCount == 1) {
// int childCount = getChildCount();
int childCount = getItemCount();
if (mOnViewPagerListener != null && positionIdle != mLastPosition) {
mOnViewPagerListener.onPageSelected(positionIdle,
positionIdle == childCount - 1);

View File

@ -121,9 +121,14 @@ object XapkInstaller : IXapkUnzipListener {
DownloadManager.getInstance(mContext).updateDownloadEntity(downloadEntity)
}
SentryHelper.onEvent("XAPK_UNZIP_ERROR",
// 仅官网渠道上报 XAPK 异常信息
if (HaloApp.getInstance().channel == "GH_206") {
SentryHelper.onEvent(
"XAPK_UNZIP_ERROR",
"gameName", downloadEntity.name,
"errorDigest", exception.localizedMessage)
"errorDigest", exception.localizedMessage
)
}
debugOnly {
Utils.log("unzip", "onFailure->$exception")
@ -142,7 +147,7 @@ object XapkInstaller : IXapkUnzipListener {
return@execute
}
PackageInstaller.install(mContext, pkgPath)
PackageInstaller.install(mContext, downloadEntity.isPlugin, pkgPath)
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.SUCCESS.name

View File

@ -1,6 +1,7 @@
package com.gh.common.xapk
import android.os.Environment
import com.gh.common.util.debounceActionWithInterval
import com.gh.common.util.getExtension
import com.gh.common.util.throwException
import com.gh.common.util.throwExceptionInDebug
@ -91,7 +92,10 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
mUnzipListener.onCancel(mDownloadEntity)
return
} else {
mUnzipListener.onProgress(mDownloadEntity, outputFile.path, unzipSize, unzipProgress)
// 防止多次短时间内多次触发onProgress方法导致阻塞主线程低端机会出现十分明显的卡顿
debounceActionWithInterval(-1, 500) {
mUnzipListener.onProgress(mDownloadEntity, outputFile.path, unzipSize, unzipProgress)
}
}
}
}
@ -203,8 +207,10 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
private fun getUnzipSize(path: String): Long {
var totalSize = 0L
for (entry in ZipFile(File(path)).entries()) {
totalSize += entry.size
ZipFile(File(path)).use {
for (entry in it.entries()) {
totalSize += entry.size
}
}
return totalSize
}

View File

@ -29,6 +29,7 @@ import com.gh.common.util.HomePluggableHelper;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.PageSwitchDataHelper;
import com.gh.common.util.SPUtils;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.ApkEntity;
@ -279,11 +280,18 @@ public class DownloadManager implements DownloadStatusListener {
ExtensionsKt.addMetaExtra(downloadEntity, Constants.DOWNLOAD_ID, downloadId);
ExtensionsKt.addMetaExtra(downloadEntity, Constants.RAW_GAME_ICON, gameEntity.getRawIcon());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_ICON_SUBSCRIPT, gameEntity.getIconSubscript());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.IS_PLATFORM_RECOMMEND, apkEntity.getRecommend() != null ? "true" : "false");
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_NAME, gameEntity.getName());
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
ExtensionsKt.addMetaExtra(downloadEntity, Constants.SIMULATOR_GAME, apkEntity.getFormat());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.SIMULATOR, GsonUtils.toJson(gameEntity.getSimulator()));
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_NAME, gameEntity.getName());
}
HashMap<String, String> map = PageSwitchDataHelper.popLastPageData();
if (map != null && map.containsKey(PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND)) {
ExtensionsKt.addMetaExtra(downloadEntity, PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND, "true");
}
int installed = 0;
for (ApkEntity apk : gameEntity.getApk()) {
if (PackagesManager.isInstalled(apk.getPackageName())) {
@ -295,13 +303,15 @@ public class DownloadManager implements DownloadStatusListener {
// todo 不是应该实时判断吗?
if (PackageUtils.isCanPluggable(apkEntity)) {
downloadEntity.setPluggable(true);
} else if (PackageUtils.isCanUpdate(apkEntity, gameEntity.getId())) {
} else if (PackageUtils.isCanUpdate(apkEntity, gameEntity.getId())
|| PackageUtils.isNonPluginUpdatable(apkEntity, gameEntity)) {
downloadEntity.setUpdate(true);
}
downloadEntity.setPlugin(!TextUtils.isEmpty(apkEntity.getGhVersion()));
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, gameEntity.getId());
gameEntity.setIsPlatformRecommend(apkEntity.getRecommend() != null);
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, downloadType);
// 将下载事件放入 downloadEntity 中供下载完成时取出使用
@ -658,7 +668,7 @@ public class DownloadManager implements DownloadStatusListener {
// 将原来安装完成后在 downloadService 完成的功能放到这里,尝试避免因为 ANR 造成闪退
AppExecutor.getUiExecutor().executeWithDelay(() -> {
mDownloadDao.removeErrorMessage(entry.getUrl());
DownloadTask task = DataChanger.INSTANCE.getDownloadingTasks().get(entry.getUrl());
if (task != null) {
task.cancel();
@ -669,7 +679,7 @@ public class DownloadManager implements DownloadStatusListener {
DataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl());
DataChanger.INSTANCE.notifyDataChanged(entry);
DownloadStatusManager.getInstance().onTaskCancelled(entry);
Utils.log(DownloadManager.class.getSimpleName(), "cancel");
}, 0);
}

View File

@ -7,6 +7,7 @@ import com.gh.common.constant.Constants
import com.gh.common.loghub.LoghubUtils
import com.gh.common.runOnIoThread
import com.gh.common.util.*
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.entity.GameDigestEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.manager.UserManager
@ -74,6 +75,8 @@ object PackageObserver {
if ("安装" == busFour.type) {
mPackageViewModel.addInstalledGame(packageName)
BrowserInstallHelper.onApkInstalled(mDownloadEntity?.path)
if (mDownloadEntity != null) {
if (mDownloadEntity.isPluggable) {
val kv6: MutableMap<String, Any> = HashMap()
@ -121,10 +124,11 @@ object PackageObserver {
if ("卸载" == busFour.type) {
mPackageViewModel.addUninstalledGame(packageName)
if (mDownloadEntity != null && mDownloadEntity.isPluggable) {
val kv6: MutableMap<String, Any> = HashMap()
kv6["安装或卸载"] = "卸载完成"
DataUtils.onEvent(application, "插件化", mDownloadEntity.name, kv6)
mDownloadEntity?.let {
if (it.isPluggable || it.isUpdate) {
val kv6: MutableMap<String, Any> = HashMap()
kv6["安装或卸载"] = "卸载完成"
DataUtils.onEvent(application, "插件化", mDownloadEntity.name, kv6)
// DataUtils.onMtaEvent(this,
// "插件化_新",
@ -132,7 +136,8 @@ object PackageObserver {
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "卸载完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
PackageInstaller.install(application, mDownloadEntity)
PackageInstaller.install(application, mDownloadEntity)
}
}
// 更新已安装游戏

View File

@ -70,9 +70,9 @@ object ExoCacheManager {
if (requestLength == bytesCached) {
threads.remove(videoUri)
}
if (BuildConfig.DEBUG) {
Utils.log("$requestLength--$bytesCached--$newBytesCached")
}
// if (BuildConfig.DEBUG) {
// Utils.log("$requestLength--$bytesCached--$newBytesCached")
// }
}, threads[videoUri])
} catch (e: Throwable) {
threads.remove(videoUri)

View File

@ -1,7 +1,6 @@
package com.gh.download.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.*
@ -14,14 +13,15 @@ import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.RecyclerView.SmoothScroller
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.TimeElapsedHelper
import com.gh.common.dialog.BaseDraggableDialogFragment
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.*
import com.gh.download.DownloadManager
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogDownloadBinding
import com.gh.gamecenter.entity.ApkEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.halo.assistant.HaloApp
@ -34,8 +34,7 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.*
class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
class DownloadDialog : BaseDraggableDialogFragment() {
private lateinit var mGameEntity: GameEntity
private lateinit var mViewModel: DownloadViewModel
@ -43,8 +42,6 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
private lateinit var mElapsedHelper: TimeElapsedHelper
private lateinit var mGestureDetector: GestureDetector
private var mAdapter: DownloadDialogAdapter? = null
private var mTraceEvent: ExposureEvent? = null
@ -61,7 +58,6 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
private var mEntrance: String = "" // 入口位置
private var mLocation: String = "" // 最终位置
private var mInitPositionY = 0f
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
@ -84,16 +80,6 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val createDialog = super.onCreateDialog(savedInstanceState)
createDialog.setCanceledOnTouchOutside(true)
val window = createDialog.window
window?.setGravity(Gravity.BOTTOM)
window?.setWindowAnimations(R.style.community_publication_animation)
return createDialog
}
override fun onCreate(savedInstanceState: Bundle?) {
EventBus.getDefault().register(this)
super.onCreate(savedInstanceState)
@ -105,6 +91,9 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
val factory = DownloadViewModel.Factory(HaloApp.getInstance().application, mGameEntity)
mViewModel = ViewModelProviders.of(this, factory).get(DownloadViewModel::class.java)
if (savedInstanceState != null) {
mViewModel.getAllPackageName()
}
mViewModel.listLiveData.observeNonNull(this, callback = { itemList ->
mAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, false, mTraceEvent, mEntrance, mLocation)
mBinding.contentList.layoutManager = createLayoutManager(itemList)
@ -121,8 +110,18 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
val itemList: MutableList<DownloadDialogItemData> = ArrayList()
saveApkList?.forEach { apk ->
mViewModel.setSortValueToApkEntity(apk)
itemList.add(DownloadDialogItemData(normal = apk))
}
val count = itemList.count { it.normal?.recommend != null }
if (count % 2 != 0) {
itemList.add(DownloadDialogItemData(normal = ApkEntity(order = DownloadViewModel.SORT_RECOMMEND_EMPTY)))
}
itemList.sortWith(Comparator { o1, o2 ->
(o2.normal?.order ?: 0) - (o1.normal?.order ?: 0)
})
if (collection.downloadInstruction.isNotEmpty()) {
itemList.add(DownloadDialogItemData(instruction = collection.downloadInstruction))
}
@ -176,8 +175,6 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
dismissAllowingStateLoss()
}
}
mGestureDetector = GestureDetector(requireContext(), SingleTapConfirm())
mBinding.dragClose.setOnTouchListener(this)
mBinding.back.setOnTouchListener(this)
mBinding.downloadNotice.setOnTouchListener(this)
@ -289,13 +286,6 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
// }
}
override fun onStart() {
super.onStart()
val width = HaloApp.getInstance().application.resources.displayMetrics.widthPixels
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
}
override fun onBack(): Boolean {
if (mCollectionAdapter != null && mAdapter != null) {
postBrowseMta()
@ -305,55 +295,9 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
return super.onBack()
}
// dialog drag animation
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View, event: MotionEvent): Boolean {
if (mGestureDetector.onTouchEvent(event) && mBinding.root.y == 0F) {
v.performClick()
return true
}
when (event.action) {
MotionEvent.ACTION_DOWN -> {
mInitPositionY = mBinding.root.y - event.rawY
}
MotionEvent.ACTION_MOVE -> {
val offsetY = event.rawY + mInitPositionY
val dialogY = mBinding.root.y
if (dialogY + offsetY > 0) {
mBinding.root.animate()
.y(offsetY)
.setDuration(0)
.start()
} else {
resetDialogPosition()
}
}
MotionEvent.ACTION_CANCEL,
MotionEvent.ACTION_UP,
MotionEvent.ACTION_OUTSIDE -> {
if (mBinding.root.y >= mBinding.root.height / 2) {
dismissAllowingStateLoss()
} else {
resetDialogPosition(300)
}
}
else -> return false
}
return true
}
private fun resetDialogPosition(duration: Long = 0) {
mBinding.root.animate()
.y(0F)
.setDuration(duration)
.start()
}
private class SingleTapConfirm : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(event: MotionEvent): Boolean {
return true
}
}
override fun getRootView(): View = mBinding.root
override fun getDragCloseView(): View = mBinding.dragClose
//安装、卸载事件
@Subscribe(threadMode = ThreadMode.MAIN)

View File

@ -8,6 +8,7 @@ import com.gh.base.OnViewClickListener
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.DirectUtils
import com.gh.common.util.MtaHelper
import com.gh.common.util.dip2px
import com.gh.common.util.throwExceptionInDebug
import com.gh.gamecenter.NewsDetailActivity
import com.gh.gamecenter.QaActivity
@ -74,6 +75,14 @@ class DownloadDialogAdapter(context: Context,
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is DownloadDialogSectionItemViewHolder -> {
(holder.binding.root.layoutParams as RecyclerView.LayoutParams).apply {
topMargin = if (position > 0) {
if (position - 1 >= 0 && (listData[position - 1].installed != null || listData[position - 1].normal != null)) {
4f.dip2px()
} else 12f.dip2px()
} else 0
holder.binding.root.layoutParams = this
}
holder.binding.type = listData[position].section
}
is DownloadDialogLinkItemViewHolder -> {
@ -102,7 +111,7 @@ class DownloadDialogAdapter(context: Context,
}
}
is DownloadDialogInstructionItemViewHolder -> {
holder.bindItem(listData[position].instruction!!)
holder.bindItem(listData, position, mEntrance)
}
is DownloadDialogPlatformRequestItemViewHolder -> {
holder.bindItem(viewModel.gameEntity)
@ -112,7 +121,7 @@ class DownloadDialogAdapter(context: Context,
throwExceptionInDebug("合集页面不应该存在该条数据", isCollectionPage)
}
is DownloadDialogItemViewHolder -> {
holder.bindItem(listData[position].normal!!, viewModel, isCollectionPage, mTraceEvent, mEntrance, mPath, mLocation)
holder.bindItem(listData, position, viewModel, isCollectionPage, mTraceEvent, mEntrance, mPath, mLocation)
}
}
}

View File

@ -41,7 +41,7 @@ class DownloadDialogInstalledItemViewHolder(val binding: DownloadDialogInstalled
binding.launch.visibility = View.GONE
if (apkCollection != null) {
binding.remark.goneIf(apkCollection.remark.isEmpty())
binding.root.setBackgroundResource(R.drawable.download_dialog_item_collection_background)
// binding.root.setBackgroundResource(R.drawable.download_dialog_item_collection_background)
} else {
binding.remark.goneIf(apkEntity.remark.isEmpty())
}

View File

@ -1,18 +1,36 @@
package com.gh.download.dialog
import android.graphics.Color
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.DefaultUrlHandler
import com.gh.common.util.EntranceUtils
import com.gh.common.util.dip2px
import com.gh.gamecenter.databinding.DownloadDialogInstructionItemBinding
class DownloadDialogInstructionItemViewHolder(val binding: DownloadDialogInstructionItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bindItem(instruction: String) {
fun bindItem(listData: List<DownloadDialogItemData>, position: Int, entrance: String) {
val instruction = listData[position].instruction
binding.webView.loadDataWithBaseURL(
null,
"<body style='margin:0;padding:0;'>$instruction</body>",
"<body style='margin:0;padding:0;color:#666666;font-size:12px;line-height:18px;'>$instruction</body>",
"text/html",
"utf-8", null)
binding.webView.settings
binding.webView.setBackgroundColor(Color.TRANSPARENT)
binding.webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return DefaultUrlHandler.interceptUrl(binding.root.context, url ?: "", entrance)
}
}
val topOffset = if (position - 1 >= 0 && (listData[position - 1].normal?.url.isNullOrEmpty() || listData[position - 1].normal?.recommend != null)) 0 else 12f.dip2px()
(binding.root.layoutParams as RecyclerView.LayoutParams).apply {
topMargin = topOffset
binding.root.layoutParams = this
}
}
}

View File

@ -2,7 +2,10 @@ package com.gh.download.dialog
import android.content.Context
import android.view.View
import android.widget.RelativeLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseActivity
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.Config
@ -13,6 +16,7 @@ import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.*
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.download.DownloadManager
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DownloadDialogItemBinding
@ -29,7 +33,8 @@ import com.lightgame.utils.Utils
class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bindItem(apkEntity: ApkEntity,
fun bindItem(listData: List<DownloadDialogItemData>,
position: Int,
viewModel: DownloadViewModel,
isCollectionPage: Boolean,
traceEvent: ExposureEvent?,
@ -37,6 +42,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
path: String,
location: String) {
val apkEntity = listData[position].normal!!
val gameEntity = viewModel.gameEntity
val apkLink = apkEntity.apkLink
val apkCollection = apkEntity.apkCollection
@ -49,38 +55,45 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
apkCollection != null -> ApkEntity(
platformIcon = apkCollection.newIcon,
platformName = apkCollection.name,
recommend = apkCollection.recommend,
remark = apkCollection.remark)
else -> apkEntity
}
binding.root.setBackgroundResource(R.drawable.download_dialog_item_background)
binding.containerView.setBackgroundResource(R.drawable.download_dialog_item_background)
binding.status.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
changeRecommendUI(apkEntity, listData, position)
if (apkLink != null) {
binding.downloadStatusIcon.visibility = View.VISIBLE
binding.downloadStatusIcon.visibility = View.GONE
binding.status.visibility = View.VISIBLE
binding.progressbar.visibility = View.GONE
binding.install.visibility = View.GONE
binding.remark.goneIf(apkLink.remark.isEmpty())
binding.status.text = "点击查看"
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_collection_status_link)
binding.root.setBackgroundResource(R.drawable.download_dialog_installed_background)
binding.status.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(binding.status.context, R.drawable.download_dialog_collection_status_link), null)
binding.containerView.setBackgroundResource(R.drawable.download_dialog_installed_background)
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.LINK)
} else if (apkCollection != null || (!isCollectionPage && apkEntity.downloadInstruction.isNotEmpty())) {
binding.root.visibility = View.VISIBLE
binding.downloadStatusIcon.visibility = View.VISIBLE
binding.progressbar.visibility = View.GONE
binding.install.visibility = View.GONE
binding.status.visibility = View.GONE
if (apkCollection != null) {
binding.remark.goneIf(apkCollection.remark.isEmpty())
binding.root.setBackgroundResource(R.drawable.download_dialog_item_collection_background)
} else {
binding.remark.goneIf(apkEntity.remark.isEmpty())
}
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_status_collection)
binding.downloadStatusIcon.setImageResource(if (apkEntity.recommend != null) R.drawable.download_dialog_status_collection else R.drawable.download_dialog_status_collection_gray)
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.COLLECTION)
} else {
if (apkEntity.url.isNullOrEmpty()) {
binding.root.visibility = View.INVISIBLE
return
}
binding.root.visibility = View.VISIBLE
val downloadEntity = DownloadManager.getInstance(HaloApp.getInstance().application).getDownloadEntityByUrl(apkEntity.url)
if (downloadEntity != null) {
binding.downloadStatusIcon.visibility = View.VISIBLE
@ -104,17 +117,17 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
binding.remark.goneIf(apkEntity.remark.isEmpty())
if (PackageUtils.isCanUpdate(apkEntity, gameEntity.id)) {
binding.downloadStatusIcon.visibility = View.VISIBLE
binding.status.visibility = View.VISIBLE
binding.status.text = "可更新"
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_collection_status_update)
binding.status.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(binding.status.context, R.drawable.download_dialog_collection_status_update), null)
binding.downloadStatusIcon.visibility = View.GONE
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.UPDATE)
} else if (PackageUtils.getGhId(apkEntity.packageName) == gameEntity.id ||
PackagesManager.isInstalled(apkEntity.packageName) && Config.getSettings()?.gameDownloadBlackList?.contains(apkEntity.packageName) == true) {
binding.downloadStatusIcon.visibility = View.GONE
binding.status.visibility = View.VISIBLE
binding.root.setBackgroundResource(R.drawable.download_dialog_installed_background)
binding.containerView.setBackgroundResource(R.drawable.download_dialog_installed_background)
var isFilter = false
Config.getSettings()?.gameDownloadBlackList?.forEach { pkgName ->
@ -131,12 +144,13 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
// 点击启动
binding.status.text = "点击启动"
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.LAUNCH)
binding.status.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(binding.status.context, R.drawable.download_dialog_collection_status_launch), null)
}
} else {
binding.downloadStatusIcon.visibility = View.VISIBLE
binding.status.visibility = View.GONE
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_status_download)
binding.downloadStatusIcon.setImageResource(if (apkEntity.recommend != null) R.drawable.download_dialog_status_download else R.drawable.download_dialog_status_download_gray)
if (PackageUtils.isCanPluggable(apkEntity)) {
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.PLUGGABLE)
} else {
@ -150,6 +164,25 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
binding.executePendingBindings()
}
private fun changeRecommendUI(apkEntity: ApkEntity, listData: List<DownloadDialogItemData>, position: Int) {
(binding.containerView.layoutParams as RelativeLayout.LayoutParams).apply {
topMargin = if (apkEntity.recommend != null) 4f.dip2px() else 0
binding.containerView.layoutParams = this
}
(binding.root.layoutParams as RecyclerView.LayoutParams).apply {
bottomMargin = if (apkEntity.recommend != null) {
if ((position + 1 < listData.size && listData[position + 1].normal?.recommend == null) ||
(position + 2 < listData.size && listData[position + 2].normal?.recommend == null)) {
20f.dip2px()
} else 16f.dip2px()
} else 8f.dip2px()
binding.root.layoutParams = this
}
if (apkEntity.recommend != null) {
binding.containerView.background = ContextCompat.getDrawable(binding.root.context, R.drawable.bg_download_dialog_item_recommend)
}
}
companion object {
fun getDownloadingStatusText(downloadEntity: DownloadEntity): String {
return when (downloadEntity.status) {
@ -212,7 +245,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
DownloadManager.getInstance(it.context).cancel(apkEntity.url)
} else {
if (PackageUtils.isCanPluggable(apkEntity)) {
DialogUtils.showPluginDialog(it.context) {
DialogHelper.showPluginDialog(it.context) {
PackageInstaller.uninstall(it.context, downloadEntity.path)
}
} else {
@ -278,23 +311,27 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
// todo 有时间存储判断统一处理
val msg = FileUtils.isCanDownload(context, apkEntity.size)
if (msg.isNullOrEmpty()) {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
BrowserInstallHelper.showBrowserInstallHintDialog(context, object : EmptyCallback {
override fun onCallback() {
PackageCheckDialogFragment.show(context as AppCompatActivity, gameEntity.packageDialog, DialogUtils.ConfirmListener {
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
DownloadManager.createDownload(
context,
apkEntity,
gameEntity,
downloadMethod,
entrance,
location,
isSubscribe, traceEvent)
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
override fun onCallback() {
PackageCheckDialogFragment.show(context as AppCompatActivity, gameEntity, DialogUtils.ConfirmListener {
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
DownloadManager.createDownload(
context,
apkEntity,
gameEntity,
downloadMethod,
entrance,
location,
isSubscribe, traceEvent)
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
}
})
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
}
})
})
}
})
}
})

View File

@ -1,17 +1,16 @@
package com.gh.download.dialog
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.*
import com.gh.common.constant.Config
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.entity.ApkEntity
import com.gh.gamecenter.entity.GameCollectionEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.Recommend
import com.gh.gamecenter.manager.PackagesManager
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadStatus
import java.util.*
import java.util.concurrent.ConcurrentHashMap
@ -35,10 +34,11 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
private var mAllApkList: MutableList<ApkEntity> = ArrayList()
private var mInstalledApkList: MutableList<ApkEntity> = ArrayList()
private var mOtherApkList: MutableList<ApkEntity> = ArrayList()
private var allPackageName: ArrayList<String>? = null
var otherSectionPosition = -1
init {
getAllPackageName()
if (gameEntity.pluggableCollection != null) {
collectionLiveData.postValue(gameEntity.pluggableCollection)
} else {
@ -46,6 +46,10 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
}
}
fun getAllPackageName() {
allPackageName = PackageUtils.getAllPackageName(HaloApp.getInstance())
}
fun initListData() {
mAllApkList = ArrayList()
mInstalledApkList = ArrayList()
@ -95,6 +99,10 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
}
mInstalledApkList.sortWith(Comparator { o1, o2 -> o2.order - o1.order })
val count = mOtherApkList.count { it.recommend != null }
if (count % 2 != 0) {
mOtherApkList.add(ApkEntity(order = SORT_RECOMMEND_EMPTY, recommend = Recommend()))
}
mOtherApkList.sortWith(Comparator { o1, o2 -> o2.order - o1.order })
val itemList: MutableList<DownloadDialogItemData> = ArrayList()
@ -126,14 +134,20 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
listLiveData.postValue(itemList)
}
private fun setSortValueToApkEntity(apkEntity: ApkEntity) {
apkEntity.apkCollection?.saveApkEntity?.forEach { saveApk ->
val sortValue = getSortValue(saveApk)
if (apkEntity.order < sortValue) {
apkEntity.order = sortValue
fun setSortValueToApkEntity(apkEntity: ApkEntity) {
if (apkEntity.apkCollection?.recommend != null) {
apkEntity.recommend = apkEntity.apkCollection?.recommend
apkEntity.order = getSortValue(apkEntity)
} else {
apkEntity.apkCollection?.saveApkEntity?.forEach { saveApk ->
val sortValue = getSortValue(saveApk)
if (apkEntity.order < sortValue) {
apkEntity.order = sortValue
apkEntity.recommend = saveApk.recommend
apkEntity.apkCollection?.recommend = saveApk.recommend
}
}
}
if (apkEntity.order == 0) {
apkEntity.order = getSortValue(apkEntity)
}
@ -141,34 +155,37 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
private fun getSortValue(apkEntity: ApkEntity): Int {
val packageName = apkEntity.packageName
if (apkEntity.recommend != null) {
return SORT_RECOMMEND
}
val downloadEntity = DownloadManager.getInstance(getApplication()).getDownloadEntityByUrl(apkEntity.url)
if (downloadEntity == null) {
if (PackagesManager.isInstalled(packageName)) {
if (PackageUtils.isCanPluggable(apkEntity)) {
return SORT_PLUGGABLE
} else if (PackageUtils.isCanUpdate(apkEntity, gameEntity.id)) {
return SORT_UPDATE
} else if (PackageUtils.getGhId(packageName) == gameEntity.id) {
return SORT_NORMAL_LAUNCH
when {
PackageUtils.isCanPluggable(apkEntity) -> {
return SORT_PLUGGABLE
}
PackageUtils.isCanUpdate(apkEntity, gameEntity.id) -> {
return SORT_UPDATE
}
PackageUtils.getGhId(packageName) == gameEntity.id -> {
return SORT_NORMAL_LAUNCH
}
}
}
return SORT_NORMAL
} else {
return if (downloadEntity.status == DownloadStatus.done) {
if (downloadEntity.isPluggable) {
SORT_PLUGGABLE_INSTALL
} else if (downloadEntity.isUpdate) {
SORT_UPDATE_INSTALL
} else {
SORT_NORMAL_INSTALL
when {
downloadEntity.isPluggable -> SORT_PLUGGABLE_INSTALL
downloadEntity.isUpdate -> SORT_UPDATE_INSTALL
else -> SORT_NORMAL_INSTALL
}
} else {
if (downloadEntity.isPluggable) {
SORT_PLUGGABLE_DOWNLOADING
} else if (downloadEntity.isUpdate) {
SORT_UPDATE_DOWNLOADING
} else {
SORT_NORMAL_DOWNLOADING
when {
downloadEntity.isPluggable -> SORT_PLUGGABLE_DOWNLOADING
downloadEntity.isUpdate -> SORT_UPDATE_DOWNLOADING
else -> SORT_NORMAL_DOWNLOADING
}
}
}
@ -243,7 +260,7 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
// 仅用于多平台面板的已安装判断
private fun isInstalled(packageName: String): Boolean {
val ghId = PackageUtils.getGhId(packageName)
return PackagesManager.isInstalled(packageName)
return (PackagesManager.isInstalled(packageName) || allPackageName?.contains(packageName) == true)
&& (ghId == null || ghId == gameEntity.id)
&& Config.getSettings()?.gameDownloadBlackList?.contains(packageName) != true
}
@ -257,6 +274,9 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
companion object {
// 需要修改排序的话,只需要修改以下数值即可(由大到小排序)
const val SORT_RECOMMEND = 12
const val SORT_RECOMMEND_EMPTY = 11
const val SORT_PLUGGABLE_INSTALL = 10
const val SORT_PLUGGABLE_DOWNLOADING = 9
const val SORT_PLUGGABLE = 8

View File

@ -0,0 +1,238 @@
package com.gh.download.server
import android.content.Context
import android.os.Build
import android.util.Base64
import com.gh.common.constant.Config
import com.gh.common.constant.Constants
import com.gh.common.exposure.ExposureEntity
import com.gh.common.exposure.ExposureEvent
import com.gh.common.loghub.LoghubUtils
import com.gh.common.util.*
import com.gh.gamecenter.ShellActivity
import com.google.gson.JsonObject
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.net.URLEncoder
import java.util.*
object BrowserInstallHelper {
// 随便选的 32321 居然在部分 vivo 手机上被占用,喷了
private const val PORT = 40705
private val mServer by lazy { getServer() }
private val mFileNameSet by lazy { hashSetOf<String>() }
private val mContext by lazy { HaloApp.getInstance().application }
private val mAllInstalledPackageList: ArrayList<String> by lazy {
PackageUtils.getAllPackageNameIncludeSystemApps(HaloApp.getInstance().applicationContext)
}
private fun getServer(): DownloadServer {
val server = DownloadServer(PORT)
for (packageName in mAllInstalledPackageList) {
if (packageName.contains("com.freeme") || packageName.contains("com.zhuoyi")) {
server.isBuggyDevice = true
break
}
}
return server
}
fun downloadFile(filePath: String) {
var fileName = filePath.substringAfterLast(File.separator)
// 山寨机没有 .apk 后缀但有 Content-Type 管用,还是给它补上 .apk 后缀
if (!mServer.isBuggyDevice) {
fileName = fileName.removeSuffix(DownloadServer.APK_SUFFIX)
}
val downloadUrl = "http://127.0.0.1:$PORT/$fileName"
if (!mServer.isAlive) startServer()
mFileNameSet.add(fileName)
if (mServer.isBuggyDevice) {
val encodedString = Base64.encodeToString(URLEncoder.encode(downloadUrl).trim().toByteArray(), Base64.NO_WRAP)
DirectUtils.directToExternalBrowser(mContext, "https://down-and.ghzs.com/redirect?location=base64($encodedString)")
} else {
DirectUtils.directToExternalBrowser(mContext, downloadUrl)
}
}
@JvmStatic
fun shouldUseBrowserToInstall(): Boolean {
if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
return true
}
return false
}
/**
* 是否显示使用浏览器来安装弹窗
*/
private fun shouldShowUseBrowserToInstallHint(): Boolean {
return if (isUseBrowserToInstallEnabled()) {
if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
false
} else {
SPUtils.getBoolean(Constants.SP_SHOULD_SHOW_USE_BROWSER_TO_INSTALL_HINT, true)
}
} else {
false
}
}
/**
* 是否显示游戏详情页使用浏览器安装提示
*/
fun shouldShowGameDetailUseBrowserToInstallHint(): Boolean {
return if (isUseBrowserToInstallEnabled()) {
// if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
// false
// } else {
SPUtils.getBoolean(Constants.SP_SHOULD_SHOW_GAMEDETAIL_USE_BROWSER_TO_INSTALL_HINT, true)
// }
} else {
false
}
}
fun hideGameDetailUseBrowserToInstallHint() {
SPUtils.setBoolean(Constants.SP_SHOULD_SHOW_GAMEDETAIL_USE_BROWSER_TO_INSTALL_HINT, false)
}
@JvmStatic
fun showBrowserInstallHintDialog(context: Context, callback: EmptyCallback) {
if (!shouldShowUseBrowserToInstallHint()) {
callback.onCallback()
return
}
logOrdinaryBrowserEvent(Type.SWITCH_INSTALL_DIALOG)
SPUtils.setBoolean(Constants.SP_SHOULD_SHOW_USE_BROWSER_TO_INSTALL_HINT, false)
val manufacturer = Build.MANUFACTURER.toUpperCase(Locale.CHINA)
var contentText = "当前安装方式为助手安装,如果出现游戏无法安装的问题,可选择切换安装方式为“浏览器安装”"
if (manufacturer == "OPPO" || manufacturer == "VIVO") {
contentText = "当前安装方式为助手安装,下载安装游戏需要验证账户密码或指纹。如需免密码安装,可选择切换安装方式为“浏览器安装”"
}
DialogHelper.showDialog(
context,
title = "温馨提示",
content = contentText,
confirmText = "切换安装方式",
cancelText = "继续下载",
confirmClickCallback = {
val intent = ShellActivity.getIntent(context, ShellActivity.Type.SWITCH_INSTALL_METHOD, null)
context.startActivity(intent)
logOrdinaryBrowserEvent(Type.SWITCH_INSTALL_DIALOG_ACCESS)
},
cancelClickCallback = {
callback.onCallback()
logOrdinaryBrowserEvent(Type.SWITCH_INSTALL_DIALOG_QUIT)
},
extraConfig = DialogHelper.Config(hint = "修改路径:我的光环-设置-切换安装方式")
)
}
/**
* 浏览器安装的后台开关
*/
@JvmStatic
fun isUseBrowserToInstallEnabled(): Boolean {
val settingsEntity = Config.getNewSettingsEntity()
if (settingsEntity == null) {
return false
} else {
if (settingsEntity.installModel.status == "matched") {
return true
}
settingsEntity.installModel.packages?.let {
for (packageName in it) {
if (mAllInstalledPackageList.contains(packageName)) {
return true
}
}
}
return false
}
}
fun onApkInstalled(path: String?) {
path?.let {
val fileName = path.substringAfterLast(File.separator).removeSuffix(DownloadServer.APK_SUFFIX)
// 更新下载名称 set确定是否需要关闭下载服务
mFileNameSet.remove(fileName)
stopServerIfNeeded()
}
}
private fun startServer() {
try {
mServer.start()
} catch (e: Exception) {
e.printStackTrace()
Utils.toast(mContext, "浏览器下载服务开启失败")
}
}
private fun stopServerIfNeeded() {
// 下载的文件都下载完了
if (mFileNameSet.size == 0) {
mServer.stop()
}
}
/**以下为日志相关方法**/
fun logWebDownloadStarted(exposureEvent: ExposureEvent, downloadId: String, isDownloadComplete: Boolean) {
val jsonObject = JSONObject()
tryCatchInRelease {
jsonObject.put("event", if (isDownloadComplete) "web_download_complete" else "web_download")
jsonObject.put("payload", exposureEvent2JSONObject(exposureEvent.payload, downloadId))
jsonObject.put("meta", LogUtils.getMetaObject())
jsonObject.put("source", JSONArray(GsonUtils.toJson(exposureEvent.source)))
jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
}
Utils.log(jsonObject.toString())
LoghubUtils.log(jsonObject, "event", false)
}
private fun exposureEvent2JSONObject(payload: ExposureEntity, downloadId: String): JSONObject {
val string = (GsonUtils.gson.toJsonTree(payload) as JsonObject).apply {
addProperty("uni_filename", "$downloadId${DownloadServer.APK_SUFFIX}")
}.toString()
return JSONObject(string)
}
fun logOrdinaryBrowserEvent(type: Type) {
val jsonObject = JSONObject()
tryCatchInRelease {
jsonObject.put("event", type.toString().toLowerCase(Locale.CHINA))
jsonObject.put("meta", LogUtils.getMetaObject())
jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
}
Utils.log(jsonObject.toString())
LoghubUtils.log(jsonObject, "event", false)
}
enum class Type {
SWITCH_INSTALL_DIALOG,
SWITCH_INSTALL_DIALOG_QUIT,
SWITCH_INSTALL_DIALOG_ACCESS,
SWITCH_INSTALL_GUIDE_ACCESS,
SWITCH_INSTALL_GUIDE_QUIT,
SWITCH_INSTALL_SETTING,
SWITCH_INSTALL_SETTING_APP,
SWITCH_INSTALL_SETTING_WEB
}
}

View File

@ -0,0 +1,109 @@
package com.gh.download.server
import com.gh.common.constant.Constants
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.getMetaExtra
import com.gh.common.util.toObject
import com.gh.download.DownloadManager
import com.halo.assistant.HaloApp
import com.lightgame.download.FileUtils
import fi.iki.elonen.NanoHTTPD
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
import java.io.File
import java.io.FileInputStream
import java.util.concurrent.TimeUnit
class DownloadServer(port: Int) : NanoHTTPD(port) {
private val mPublishSubject: PublishSubject<String> = PublishSubject.create()
private val mCompositeDisposable: CompositeDisposable = CompositeDisposable()
// 是否是山寨机
var isBuggyDevice: Boolean = false
init {
// 某些浏览器会开启多线程下载,如果不 throttle 的话会出现多次调用
val disposable = mPublishSubject
.distinctUntilChanged()
.throttleWithTimeout(500, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.subscribe({
logBrowserDownload(it, false)
}, {})
mCompositeDisposable.add(disposable)
}
/**
* 默认截掉 .apk 后缀的原因是部分系统判断到 url 后缀为 .apk 就会调用系统下载器而不是浏览器下载 apk (下载完成不会自动触发安装)
*/
override fun serve(fileName: String?,
method: Method?,
headers: MutableMap<String, String>?,
parms: MutableMap<String, String>?,
files: MutableMap<String, String>?): Response {
var filePath = FileUtils.getDownloadDir(HaloApp.getInstance()) + fileName
if (!filePath.contains(APK_SUFFIX)) {
filePath += APK_SUFFIX
}
var file = File(filePath)
// 找不到名字全匹配的文件时,进入文件夹里检索一遍
if (!file.exists() && fileName != null && !fileName.contains("favicon")) {
// 后台可能上传后缀有为 ".apk.apk" 的包!
val fileDir = File(FileUtils.getDownloadDir(HaloApp.getInstance()))
fileDir.listFiles { dir, name ->
if (name.contains(fileName.removePrefix(File.separator))) {
file = File(dir.path + File.separator + name)
return@listFiles true
}
return@listFiles false
}
}
mPublishSubject.onNext(filePath)
return if (file.exists()) {
val fileType = FileUtils.getFileMimeType(HaloApp.getInstance().applicationContext, filePath)
?: "application/vnd.android.package-archive"
// TODO 山寨机给了文件长度会下载失败,有空再看看为什么
if (isBuggyDevice) {
newChunkedResponse(Response.Status.OK, fileType, DownloadFileInputStream(file)).apply {
addHeader("Content-Disposition", "inline; filename=\"$filePath")
}
} else {
newFixedLengthResponse(Response.Status.OK, fileType, DownloadFileInputStream(file), file.length())
}
} else {
newFixedLengthResponse("找不到文件")
}
}
companion object {
const val APK_SUFFIX = ".apk"
fun logBrowserDownload(path: String, isDownloadComplete: Boolean) {
for (download in DownloadManager.getInstance(HaloApp.getInstance()).allDownloadEntity) {
if (download.path == path) {
download.exposureTrace?.toObject<ExposureEvent>()?.let {
BrowserInstallHelper.logWebDownloadStarted(it, download.getMetaExtra(Constants.DOWNLOAD_ID), isDownloadComplete)
}
break
}
}
}
}
}
class DownloadFileInputStream(val file: File?) : FileInputStream(file) {
override fun read(b: ByteArray?, off: Int, len: Int): Int {
// 不为 BUFFER_LENGTH 的时候算是下载完了
if (len != 16 * 1024) {
DownloadServer.logBrowserDownload(file?.path ?: "", true)
}
return super.read(b, off, len)
}
}

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.entity.SubjectRecommendEntity
import com.gh.gamecenter.game.GameFragment
@ -36,4 +35,8 @@ class BlockActivity : NormalActivity() {
return "板块"
}
override fun getBusinessId(): Pair<String, String> {
return Pair(targetFragment?.arguments?.getParcelable<SubjectRecommendEntity>(EntranceUtils.KEY_BLOCK_DATA)?.link ?: "", "")
}
}

View File

@ -2,8 +2,11 @@ package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import com.gh.common.util.EntranceUtils;
import com.halo.assistant.fragment.ApkCleanerFragment;
/**
@ -13,7 +16,14 @@ public class CleanApkActivity extends NormalActivity {
@NonNull
public static Intent getIntent(Context context) {
return getTargetIntent(context, CleanApkActivity.class, ApkCleanerFragment.class);
return getIntent(context, false);
}
@NonNull
public static Intent getIntent(Context context, Boolean isChooseApk) {
Bundle bundle = new Bundle();
bundle.putBoolean(EntranceUtils.KEY_IS_CHOOSE_APK, isChooseApk);
return getTargetIntent(context, CleanApkActivity.class, ApkCleanerFragment.class, bundle);
}
}

View File

@ -16,6 +16,8 @@ import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.gamedetail.GameDetailFragment;
import com.halo.assistant.HaloApp;
import kotlin.Pair;
import static com.gh.common.constant.Constants.GAME_DETAIL_COME_IN;
/**
@ -48,6 +50,7 @@ public class GameDetailActivity extends NormalActivity {
public static void startGameDetailActivity(Context context, GameEntity gameEntity, String entrance) {
DataUtils.onMtaEvent(context, "详情页面", "游戏详情", gameEntity != null ? gameEntity.getName() : "");
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_GAMEID, gameEntity.getId());
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
bundle.putParcelable(GameEntity.TAG, gameEntity);
context.startActivity(getTargetIntent(context, GameDetailActivity.class, GameDetailFragment.class, bundle));
@ -117,6 +120,7 @@ public class GameDetailActivity extends NormalActivity {
bundle.putInt(EntranceUtils.KEY_TARGET, defaultTab);
}
bundle.putString(EntranceUtils.KEY_GAMEID, gameEntity.getId());
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
bundle.putParcelable(GameEntity.TAG, gameEntity);
context.startActivity(getTargetIntent(context, GameDetailActivity.class, GameDetailFragment.class, bundle));
@ -187,6 +191,7 @@ public class GameDetailActivity extends NormalActivity {
public static void startGameDetailCommentActivity(Context context, GameEntity game, String entrance) {
Bundle bundle = new Bundle();
bundle.putParcelable(GameEntity.TAG, game);
bundle.putString(EntranceUtils.KEY_GAMEID, game.getId());
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
bundle.putBoolean(EntranceUtils.KEY_SKIP_GAME_COMMENT, true);
context.startActivity(getTargetIntent(context, GameDetailActivity.class, GameDetailFragment.class, bundle));
@ -198,6 +203,7 @@ public class GameDetailActivity extends NormalActivity {
public static void startGameDetailByShortcut(Context context, GameEntity game, int tab, String entrance) {
Bundle bundle = new Bundle();
bundle.putParcelable(GameEntity.TAG, game);
bundle.putString(EntranceUtils.KEY_GAMEID, game.getId());
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
bundle.putInt(EntranceUtils.KEY_TARGET, tab);
context.startActivity(getTargetIntent(context, GameDetailActivity.class, GameDetailFragment.class, bundle));
@ -255,6 +261,16 @@ public class GameDetailActivity extends NormalActivity {
return "游戏详情";
}
@Override
public Pair<String, String> getBusinessId() {
GameDetailFragment fragment = (GameDetailFragment) getTargetFragment();
if (fragment.getArguments() != null) {
return new Pair<>(fragment.getArguments().getString(EntranceUtils.KEY_GAMEID), "");
} else {
return null;
}
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(new ContextWrapper(newBase) {

View File

@ -195,8 +195,9 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
}
mArticleDetailBtn.setOnClickListener {
val intent = ArticleDetailActivity.getIntent(this, CommunityEntity(mAnswerEntity?.communityId
?: "", mAnswerEntity?.communityName ?: ""), mAnswerEntity?.id
val intent = ArticleDetailActivity.getIntent(this, CommunityEntity(if (!mAnswerEntity?.communityId.isNullOrEmpty()) mAnswerEntity?.communityId
?: "" else mAnswerEntity?.articleCommunityId ?: "", mAnswerEntity?.communityName
?: ""), mAnswerEntity?.id
?: "", mEntrance, "")
startActivity(intent)
finish()
@ -625,9 +626,9 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
var out: OutputStream? = null
try {
val fileName: String = if (mShowBase64Image) {
MD5Utils.getUrlMD5(curUrl!!.substring(0, 50)) + ".png"
MD5Utils.getContentMD5(System.currentTimeMillis().toString()) + ".png"
} else {
curUrl!!.substring(curUrl.lastIndexOf("/"))
Uri.parse(curUrl).lastPathSegment.toString()
}
val savePath = Environment.getExternalStorageDirectory().absolutePath + "/Pictures/ghzhushou/"
val file = File(savePath)

View File

@ -3,6 +3,7 @@ package com.gh.gamecenter;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Message;
import android.text.TextUtils;
@ -12,6 +13,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -21,11 +23,13 @@ import com.gh.base.OnRequestCallBackListener;
import com.gh.base.ToolBarActivity;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.util.ApkActiveUtils;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DetailDownloadUtils;
import com.gh.common.util.DeviceTokenUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.ExtensionsKt;
import com.gh.common.util.LibaoUtils;
import com.gh.common.view.CustomDividerItemDecoration;
import com.gh.common.view.DownloadProgressBar;
import com.gh.common.view.VerticalItemDecoration;
import com.gh.download.DownloadManager;
@ -50,6 +54,7 @@ import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.jetbrains.annotations.NotNull;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@ -101,6 +106,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
private String mListStatus; // 记录列表领取状态(防止状态在详情改变导致列表状态改变)
private String mName;
private String mTitle;
private boolean isClickReceiveBtnIn = false;//是否点击领取按钮进入
@Override
protected void handleMessage(Message msg) {
@ -129,6 +135,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
mLibaoEntity.setStatus("repeatTaoed"); // 可以重复领取
}
mAdapter.notifyItemChanged(0);
performClickReceiveBtn();
}
}
@ -155,14 +162,19 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
false, mEntrance, mName, mTitle, null); // 下载按钮ViewHolder
}
@NonNull
public static Intent getIntent(Context context, LibaoEntity libaoEntity, String entrance) {
public static Intent getIntent(Context context, LibaoEntity libaoEntity, boolean isClickReceiveBtnIn, String entrance) {
Intent intent = new Intent(context, LibaoDetailActivity.class);
HaloApp.put(LibaoEntity.TAG, libaoEntity);
intent.putExtra(EntranceUtils.KEY_ENTRANCE, entrance);
intent.putExtra(EntranceUtils.KEY_IS_CLICK_RECEIVE_BTN, isClickReceiveBtnIn);
return intent;
}
@NonNull
public static Intent getIntent(Context context, LibaoEntity libaoEntity, String entrance) {
return getIntent(context, libaoEntity, false, entrance);
}
@NonNull
public static Intent getIntentById(Context context, String id, String entrance) {
Intent intent = new Intent(context, LibaoDetailActivity.class);
@ -172,7 +184,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
}
@Override
protected void onSaveInstanceState(Bundle outState) {
protected void onSaveInstanceState(@NotNull Bundle outState) {
super.onSaveInstanceState(outState);
HaloApp.put(LibaoEntity.TAG, mAdapter.getLibaoEntity());
}
@ -183,6 +195,10 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
mName = getString(R.string.libao_detail);
setNavigationTitle(mName);
mLibaoEntity = (LibaoEntity) HaloApp.get(LibaoEntity.TAG, false);
isClickReceiveBtnIn = getIntent().getBooleanExtra(EntranceUtils.KEY_IS_CLICK_RECEIVE_BTN, false);
if (mLibaoEntity != null) {
mLibaoEntity.setClickReceiveBtnIn(isClickReceiveBtnIn);
}
mIsScroll = true;
@ -194,14 +210,14 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
return mIsScroll;
}
});
mLibaoDetailRv.addItemDecoration(new VerticalItemDecoration(this, 8, true));
mLibaoDetailRv.addItemDecoration(new VerticalItemDecoration(this, 8, false));
mLibaoDetailRv.setAdapter(mAdapter);
mNoConnection.setOnClickListener(v -> {
mSkeleton.show();
mNoConnection.setVisibility(View.GONE);
mLlLoading.setVisibility(View.VISIBLE);
mBaseHandler.postDelayed(() -> getGameDigest(), 1000);
mBaseHandler.postDelayed(this::getGameDigest, 1000);
});
if (mLibaoEntity == null) {
@ -210,10 +226,10 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
getLibaoDigest(id);
}
} else {
getGameDigest();
if (!mLibaoEntity.isActive()) {
checkLibaoStatus();
}
getGameDigest();
}
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mDetailBottom.getLayoutParams();
@ -270,6 +286,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
if (isCanLing()) { // 恢复原始状态
mLibaoEntity.setStatus(beforeStatus);
mAdapter.notifyItemChanged(0);
performClickReceiveBtn();
}
}
return;
@ -288,11 +305,30 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
mLibaoEntity.setStatus("repeatTao"); // 预备重复领取
}
mAdapter.notifyItemChanged(0);
performClickReceiveBtn();
DeviceTokenUtils.syncServerTime(LibaoDetailActivity.this);
mBaseHandler.sendEmptyMessageDelayed(0, 5000);
}
}
} else {
performClickReceiveBtn();
}
}
private void performClickReceiveBtn() {
if (isClickReceiveBtnIn) {
CheckLoginUtils.checkLogin(this, mEntrance, () ->
mLibaoDetailRv.postDelayed(() -> {
if (mAdapter.libaoDetailTopViewHolder != null) {
try {
mAdapter.libaoDetailTopViewHolder.libaoCopyBtn.performClick();
} catch (Exception e) {
e.printStackTrace();
}
}
}, 200)
);
}
}
@ -358,13 +394,10 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
// 获取游戏摘要
private void getGameDigest() {
if (mLibaoEntity.getGame() == null) return;
String gameId = mLibaoEntity.getGame().getId();
if (RegionSettingHelper.shouldThisGameBeFiltered(gameId)) {
return;
}
RetrofitManager.getInstance(this).getSensitiveApi().getGameNewsDigest(gameId)
.map(ApkActiveUtils.filterMapper)
.subscribeOn(Schedulers.io())
@ -378,7 +411,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
// 添加启动弹窗的相关信息
if (mEntrance.contains(EntranceUtils.ENTRANCE_WELCOME)
&& ExtensionsKt.countOccurrences(mEntrance,("+")) <= 1) {
&& ExtensionsKt.countOccurrences(mEntrance, ("+")) <= 1) {
mGameEntity.setWelcomeDialogInfoIfAvailable();
}
@ -422,10 +455,8 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
mLlLoading.setVisibility(View.GONE);
mLibaoDetailRv.setVisibility(View.VISIBLE);
}
// 从存号箱进入 获取userData后 检查领取状态(是否可以重复领取/重复淘号)
if (mLibaoEntity.isActive() && mLibaoEntity.getMe() != null) {
if ("ling".equals(mLibaoEntity.getStatus()) || "tao".equals(mLibaoEntity.getStatus())) {
List<UserDataLibaoEntity> userLibaooList = mLibaoEntity.getMe().getUserDataLibaoList();
if (userLibaooList != null && userLibaooList.size() > 0) {
@ -437,10 +468,10 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
}
}
}
checkLibaoStatus();
} else {
performClickReceiveBtn();
}
mSkeleton.hide();
}

View File

@ -16,6 +16,10 @@ import com.gh.gamecenter.fragment.LoginFragment;
public class LoginActivity extends NormalActivity {
public static final int STATUS_DEFAULT = 0; // 默认(隐藏一键登录按钮)
public static final int STATUS_FROM_QUICK_LOGIN_PAGE = 1; // 从一键登录的授权页过来
public static final int STATUS_FROM_QUICK_LOGIN_PERMISSION = 2; // 从一键登录的电话权限弹窗过来
@Override
protected Intent provideNormalIntent() {
return getTargetIntent(this, LoginActivity.class, LoginFragment.class);
@ -23,8 +27,14 @@ public class LoginActivity extends NormalActivity {
@NonNull
public static Intent getIntent(Context context, String entrance) {
return getIntent(context, entrance, STATUS_DEFAULT);
}
@NonNull
public static Intent getIntent(Context context, String entrance, int status) {
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
bundle.putInt(EntranceUtils.KEY_SHOW_QUICK_LOGIN, status);
return getTargetIntent(context, LoginActivity.class, LoginFragment.class, bundle);
}

View File

@ -21,6 +21,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
import com.gh.base.AppUncaughtHandler;
@ -32,6 +33,8 @@ import com.gh.common.avoidcallback.AvoidOnResultManager;
import com.gh.common.constant.Config;
import com.gh.common.constant.Constants;
import com.gh.common.exposure.meta.MetaUtil;
import com.gh.common.history.HistoryDatabase;
import com.gh.common.history.HistoryHelper;
import com.gh.common.repository.ReservationRepository;
import com.gh.common.simulator.SimulatorGameManager;
import com.gh.common.util.ActivationHelper;
@ -48,6 +51,7 @@ import com.gh.common.util.ErrorHelper;
import com.gh.common.util.ExtensionsKt;
import com.gh.common.util.GsonUtils;
import com.gh.common.util.HomePluggableHelper;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.LogUtils;
import com.gh.common.util.LunchType;
import com.gh.common.util.MtaHelper;
@ -77,10 +81,15 @@ import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.normal.NormalFragment;
import com.gh.gamecenter.packagehelper.PackageViewModel;
import com.gh.gamecenter.qa.CommunityFragment;
import com.gh.gamecenter.retrofit.BiResponse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.room.AppDatabase;
import com.gh.gamecenter.room.dao.SimulatorGameDao;
import com.gh.gamecenter.suggest.SuggestSelectFragment;
import com.gh.gamecenter.suggest.SuggestType;
import com.github.piasy.biv.BigImageViewer;
import com.github.piasy.biv.loader.fresco.FrescoImageLoader;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
@ -94,6 +103,7 @@ import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.jetbrains.annotations.NotNull;
import org.json.JSONObject;
import java.io.BufferedReader;
@ -103,13 +113,17 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import kotlin.jvm.functions.Function1;
import okhttp3.MediaType;
@ -162,7 +176,17 @@ public class MainActivity extends BaseActivity {
super.onCreate(savedInstanceState);
setStatusBarColor(Color.TRANSPARENT);
mMainWrapperFragment = new MainWrapperFragment();
if (!ImageUtils.isFrescoInitialized()) {
try {
BigImageViewer.initialize(FrescoImageLoader.with(this));
} catch (Throwable e) {
e.printStackTrace();
}
}
Fragment fragmentFromFM = getSupportFragmentManager().findFragmentById(R.id.layout_activity_content);
mMainWrapperFragment = fragmentFromFM != null ? (MainWrapperFragment) fragmentFromFM : new MainWrapperFragment();
if (savedInstanceState != null) {
mMainWrapperFragment.setArguments(savedInstanceState);
} else if (getIntent() != null) {
@ -260,8 +284,11 @@ public class MainActivity extends BaseActivity {
// 上传数据
DataCollectionManager.getInstance(getApplicationContext()).upload();
// 获取默认配置
Config.getGhzsSettings();
if (Config.getSettings() == null) {
Config.getGhzsSettings();
}
// 初始化PlatformUtils
PlatformUtils.getInstance(getApplicationContext());
// // 友盟记录启动
@ -286,6 +313,58 @@ public class MainActivity extends BaseActivity {
SPUtils.setBoolean(Constants.SP_NON_WIFI_TIPS, true);
//重置首页视频播放进度
SPUtils.setString(Constants.SP_HOME_VIDEO_PLAY_RECORD, "");
// 重新打开APP重置"显示返回任务悬浮图标"标志位
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
postAttentionVideoRecord();
deleteSimulatorGame();
}
//上传关注视频浏览记录
@SuppressLint("CheckResult")
private void postAttentionVideoRecord() {
if (UserManager.getInstance().isLoggedIn()) {
Map<String, Object> requestMap = new HashMap<>();
HistoryDatabase.Companion.getInstance().videoHistoryDao()
.getAttentionVideoRecord()
.flatMap((Function<List<String>, SingleSource<ResponseBody>>) strings -> {
requestMap.put("cache_video_ids", strings);
RequestBody body = ExtensionsKt.toRequestBody(requestMap);
return RetrofitManager.getInstance(HaloApp.getInstance())
.getApi()
.postAttentionVideoRecord(UserManager.getInstance().getUserId(), body);
})
.subscribeOn(Schedulers.io())
.subscribe(new BiResponse<ResponseBody>() {
@Override
public void onSuccess(ResponseBody data) {
HistoryHelper.deleteAttentionVideoRecord();
}
});
}
}
//查询到模拟器游戏表中逻辑删除的数据后,删除服务器中的记录
@SuppressLint("CheckResult")
private void deleteSimulatorGame() {
SimulatorGameDao dao = AppDatabase.getInstance(HaloApp.getInstance()).simulatorGameDao();
dao.getSimulatorGameByDeleted()
.subscribeOn(Schedulers.io())
.subscribe(new BiResponse<List<String>>() {
@Override
public void onSuccess(List<String> data) {
if (!data.isEmpty()) {
SimulatorGameManager.deleteSimulatorGames(data, () -> {
for (String id : data) {
dao.deleteSimulatorGameById(id);
}
return null;
});
}
}
});
}
@Override
@ -367,17 +446,20 @@ public class MainActivity extends BaseActivity {
}
private void hideAd(boolean forceToHide) {
if (forceToHide
|| AdHelper.startupAd.getValue() == null) {
if (forceToHide || AdHelper.startupAd.getValue() == null) {
showAd = false;
getIntent().putExtra(SHOW_AD, false);
findViewById(R.id.maskContainer).setVisibility(View.GONE);
View view = findViewById(R.id.maskContainer);
if (view != null) {
view.setVisibility(View.GONE);
}
mMainWrapperFragment.getWelcomeDialog();
checkDialog();
}
}
private void checkDialog() {
// 检查通知权限
checkNotificationPermission();
@ -393,6 +475,9 @@ public class MainActivity extends BaseActivity {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
containerView.setElevation(500F);
}
containerView.setOnClickListener(v -> {
// do nothing 只是为了点击拦截事件,避免传递到下面的页面
});
adContentTv.setText(ad.getDesc());
adContentTv.setVisibility(View.VISIBLE);
if (ad.getButton()) {
@ -619,7 +704,7 @@ public class MainActivity extends BaseActivity {
}
@Override
protected void onSaveInstanceState(Bundle outState) {
protected void onSaveInstanceState(@NotNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(CURRENT_PAGE, mMainWrapperFragment.getCurrentItem());
if (mMainWrapperFragment != null) {
@ -627,6 +712,11 @@ public class MainActivity extends BaseActivity {
}
}
@Override
protected boolean preventRecreateFragmentByFragmentManager() {
return true;
}
@Override
protected int getLayoutId() {
if (showAd) {
@ -839,6 +929,7 @@ public class MainActivity extends BaseActivity {
}
mPackageViewModel.checkData();
deleteSimulatorGame();
}
}
@ -878,4 +969,5 @@ public class MainActivity extends BaseActivity {
Intent intent = MainActivity.getMainIntent(context);
context.startActivity(intent);
}
}

View File

@ -125,6 +125,8 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
private NewsEntity mNewsEntity;
private DownloadEntity mDownloadEntity;
private Boolean mHideUselessInfo = false;
private Handler handler = new Handler();
private long[] mHits = new long[2];
@ -185,7 +187,6 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
intent.putExtra(NewsEntity.TAG, newsEntity);
context.startActivity(intent);
}
}
@ -247,19 +248,26 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
mViewSkeletonScreen = Skeleton.bind(mSkeletonView).shimmer(false).load(R.layout.news_detail_skeleton).show();
// init toolbar
setNavigationTitle("");
setToolbarMenu(R.menu.menu_news_detail);
mNewsShare = getMenuItem(R.id.menu_share);
mNewsCollection = getMenuItem(R.id.menu_collect);
mNewsShare.setVisible(false);
mNewsCollection.setVisible(false);
mNoneDataTv.setText("页面不见了");
// init RecyclerView
mDetailRv.setHasFixedSize(true);
mDetailRv.setLayoutManager(new FixLinearLayoutManager(this));
mDetailRv.addItemDecoration(new VerticalItemDecoration(this, 8, false));
adapter = new NewsDetailAdapter(this, this, mEntrance);
mHideUselessInfo = getIntent().getBooleanExtra(EntranceUtils.KEY_HIDE_USELESS_INFO, false);
setToolbarMenu(R.menu.menu_news_detail);
mNewsShare = getMenuItem(R.id.menu_share);
mNewsCollection = getMenuItem(R.id.menu_collect);
mNewsShare.setVisible(false);
mNewsCollection.setVisible(false);
if (mHideUselessInfo) {
getMenuItem(R.id.menu_download).setVisible(false);
}
adapter = new NewsDetailAdapter(this, this, mHideUselessInfo, mEntrance);
mDetailRv.setAdapter(adapter);
newsId = getIntent().getStringExtra(EntranceUtils.KEY_NEWSID);
@ -277,7 +285,9 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
adapter.setType(mNewsEntity.getType());
adapter.setTitle(mNewsEntity.getTitle());
adapter.getNewsDetail();
mNewsShare.setVisible(true);
if (!mHideUselessInfo) {
mNewsShare.setVisible(true);
}
}
} else {
getNewsDigest(newsId);
@ -447,12 +457,14 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
@Override
public void loadDone() { // 通知更新收藏按钮
mNewsCollection.setVisible(true);
NewsDetailEntity newsDetailEntity = adapter.getNewsDetailEntity();
if (newsDetailEntity.getMe() != null && newsDetailEntity.getMe().isArticleFavorite()) {
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_select);
} else {
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_unselect);
if (!mHideUselessInfo) {
mNewsCollection.setVisible(true);
NewsDetailEntity newsDetailEntity = adapter.getNewsDetailEntity();
if (newsDetailEntity.getMe() != null && newsDetailEntity.getMe().isArticleFavorite()) {
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_select);
} else {
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_unselect);
}
}
}
@ -507,7 +519,9 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
adapter.setTitle(response.getTitle());
adapter.getNewsDetail();
mNewsShare.setVisible(true);
if (!mHideUselessInfo) {
mNewsShare.setVisible(true);
}
HistoryHelper.insertNewsEntity(mNewsEntity);
@ -635,11 +649,16 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
public void onResponse(GameEntity response) {
ApkActiveUtils.filterHideApk(response);
gameEntity = response;
adapter.setGameEntity(gameEntity);
adapter.notifyItemInserted(1);
mDetailBottomLl.setVisibility(View.VISIBLE);
DetailDownloadUtils.detailInitDownload(getDetailViewHolder(), true);
if (!mHideUselessInfo) {
adapter.setGameEntity(gameEntity);
adapter.notifyItemInserted(1);
mDetailBottomLl.setVisibility(View.VISIBLE);
DetailDownloadUtils.detailInitDownload(getDetailViewHolder(), true);
} else {
mDetailBottomLl.setVisibility(View.GONE);
}
// GdtHelper.INSTANCE.logAction(ActionType.PAGE_VIEW,
// GdtHelper.CONTENT_TYPE, "ARTICLE",

View File

@ -126,6 +126,10 @@ public abstract class NormalActivity extends ToolBarActivity {
return super.dispatchTouchEvent(ev);
}
public Fragment getTargetFragment() {
return mTargetFragment;
}
public int getFragmentPlaceholderId() {
return R.id.normal_content;
}

View File

@ -8,6 +8,7 @@ import com.gh.base.ToolBarActivity
import com.gh.base.fragment.BaseFragment
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.amway.AmwaySuccessFragment
import com.halo.assistant.fragment.SwitchInstallMethodFragment
/**
* ShellActivity 用来包裹那些几乎没有交互且运营也不会想要知道页面访问量的静态 fragment (如安利墙的评论提交成功页面)
@ -28,12 +29,11 @@ class ShellActivity : ToolBarActivity() {
when (intentType) {
Type.AMWAY_SUCCESS -> startFragment(AmwaySuccessFragment().with(bundle))
Type.SWITCH_INSTALL_METHOD -> startFragment(SwitchInstallMethodFragment())
}
}
override fun getLayoutId(): Int {
return R.layout.activity_shell
}
override fun getLayoutId() = R.layout.activity_shell
private fun startFragment(fragment: BaseFragment<Any>) {
mFragment = fragment
@ -43,6 +43,7 @@ class ShellActivity : ToolBarActivity() {
companion object {
const val INTENT_TYPE = "intent_type"
@JvmStatic
fun getIntent(context: Context, type: Type, extraParcelable: Parcelable? = null): Intent {
val intent = Intent(context, ShellActivity::class.java)
intent.putExtra(INTENT_TYPE, type.value)
@ -52,7 +53,8 @@ class ShellActivity : ToolBarActivity() {
}
enum class Type(val value: String) {
AMWAY_SUCCESS("amway_success");
AMWAY_SUCCESS("amway_success"),
SWITCH_INSTALL_METHOD("switch_install_method");
companion object {
fun fromString(typeString: String): Type {

View File

@ -27,6 +27,8 @@ import com.gh.common.AppExecutor;
import com.gh.common.constant.Config;
import com.gh.common.constant.Constants;
import com.gh.common.dialog.PrivacyDialogFragment;
import com.gh.common.tracker.Tracker;
import com.gh.common.tracker.TrackerLogger;
import com.gh.common.util.AdHelper;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DeviceTokenUtils;
@ -104,6 +106,8 @@ public class SplashScreenActivity extends BaseActivity {
super.onCreate(savedInstanceState);
TrackerLogger.logAppLaunch(Tracker.INSTANCE.getLaunchId(), Tracker.INSTANCE.getSessionId());
// 处理助手已经在后台运行导致的再次启动助手
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
finish();
@ -287,6 +291,8 @@ public class SplashScreenActivity extends BaseActivity {
private void launchMainActivity() {
HaloApp.getInstance().postInit(true);
TrackerLogger.logAppLaunchSuccessful(Tracker.INSTANCE.getLaunchId(), Tracker.INSTANCE.getSessionId());
getAd();
prefetchData();
@ -343,10 +349,6 @@ public class SplashScreenActivity extends BaseActivity {
}
}
private void getUniqueId() {
DataUtils.getGid();
}
private void prefetchData() {
AppExecutor.getIoExecutor().execute(() -> {
Config.getGhzsSettings();

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