Compare commits

...

342 Commits

Author SHA1 Message Date
278dcc33be Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/catalog/CatalogFragment.kt
#	app/src/main/java/com/gh/gamecenter/catalog/SubCatalogFragment.kt
2021-02-27 10:58:57 +08:00
87be3bed61 Merge branch 'hotfix-v4.6.1-271-generic_crash' into 'release'
Hotfix v4.6.1 271 generic crash

See merge request halo/assistant-android!98
2021-02-27 10:42:34 +08:00
078b102152 Update .gitmodules 2021-02-27 10:32:08 +08:00
85e97bc64d 修改包名检测弹窗按钮热区大小 2021-02-25 15:39:59 +08:00
951ac06948 Merge branch 'dev' of git.ghzs.com:halo/assistant-android into dev 2021-02-25 15:20:30 +08:00
92cdb6fdbb 修复低于 vivo 低于 5.1.1 版本系统的设备获取大文件APK包名会 ANR 的问题 2021-02-25 15:20:20 +08:00
lyr
cb0dd1d082 正式发布环境隐藏光能签到入口、邀请码输入框、上报光能任务 2021-02-25 15:18:06 +08:00
276655a8ec 更新打包脚本,仅正式包上传 mapping 2021-02-24 18:15:43 +08:00
df8b612188 恢复 R8 2021-02-24 18:01:30 +08:00
4d413eb1f2 关闭 R8 (Sentry 服务端暂未支持 mapping 自动上传) 2021-02-24 09:34:20 +08:00
d496ab0283 Merge branch 'release' into 'dev'
Merge hotfix changes

See merge request halo/assistant-android!96
2021-02-23 16:08:58 +08:00
b519ff6aac Merge branch 'dev-4.7.0' into 'dev'
Merge 4.7.0 changes

See merge request halo/assistant-android!95
2021-02-23 16:05:09 +08:00
8c05d2be8a 修复 5.1.1 系统的 vivo 设备安装大文件的 ANR 问题 2021-02-23 10:41:55 +08:00
23dd89198b 修复 5.1.1 系统的 vivo 设备安装大文件的 ANR 问题 2021-02-22 18:41:41 +08:00
6569ab2d33 修改模拟器不上传记录问题 2021-02-22 16:42:32 +08:00
1bead6a756 Merge branch 'hotfix-v4.6.1-271-crash' into 'release'
修改Sentry上一些闪退问题

See merge request halo/assistant-android!94
2021-02-08 16:14:13 +08:00
c0df3af298 尝试替换ConnectionPool类中的线程池,避免OutOfMemoryError: pthread_create failed 2021-02-08 09:52:08 +08:00
lyr
267363f46d 1.修复oppo手机无法启动服务问题;
2.修复新分类页面对象未初始化问题;
3.修复新分类页下载通知包名为空问题;
4.修复新分类中子分类列表为空问题;
5.修复问题反馈页游标越界问题;
6.修复个人信息编辑页获取菜单为空问题
2021-02-07 14:40:37 +08:00
44cf54aee6 1.修改WebView闪退问题
2.修改已安装列表更新数据时闪退问题
3.修改包名检测弹窗弹出闪退问题
2021-02-07 10:17:20 +08:00
lyr
322d7117f8 完成积分体系第2期 2021-02-05 17:54:31 +08:00
c8684f837a 修复闪退问题
1. 修复首页游戏库数据库更新闪退问题
2. 修复部分设备获取下载列表时的闪退问题
3. 修复重复发送设备应用列表的问题
2021-02-05 17:40:56 +08:00
9e5ecf1520 尝试解决TransactionTooLargeException异常 2021-02-05 17:03:14 +08:00
2df94dddc5 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-05 10:49:37 +08:00
1731980e88 升级fresco版本至2.4.0 2021-02-05 10:49:17 +08:00
f789f0cb73 正式环境接口改为 4.7.0 2021-02-04 20:57:44 +08:00
d043a89f3e 修复在部分设备上启动广告会闪烁的问题 2021-02-04 20:41:46 +08:00
4ab0f066df 修复在部分设备上首页广告消失过早的问题 2021-02-04 20:31:57 +08:00
096679029b Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-04 20:20:35 +08:00
2634228d21 光环助手V4.7.0-首页游戏功能强化(视频自动播放)(20210204测试问题3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1122 2021-02-04 20:20:14 +08:00
a33784221d 完成光环前端优化汇总(0203测试:2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1138 2021-02-04 20:05:34 +08:00
2ef7216bda 光环助手V4.7.0-首页游戏功能强化(视频自动播放)(20210204测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1122 2021-02-04 19:22:22 +08:00
2554fab389 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-04 18:25:49 +08:00
a4e3121489 【光环助手V_4.7.0】论坛交互优化(0204测试补充3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-04 18:25:27 +08:00
8dfde8ddd0 修復同包名遊戲安裝完成時可能誤刪錯誤遊戲的問題 2021-02-04 18:17:25 +08:00
63403c7c29 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-04 17:18:17 +08:00
aa9269aecc 【光环助手V_4.7.0】论坛交互优化(0202PM UI补充3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-04 17:17:57 +08:00
489e7105bb 添加 mapping 上传配置 (测试暂未通过) 2021-02-04 16:18:16 +08:00
8dbc407503 修复启动弹窗先于首页出现的问题 2021-02-04 16:08:56 +08:00
3e032fa540 修复 gh_version 异常造成的闪退 2021-02-04 16:07:51 +08:00
3df381b255 处理帖子是纯文字不会滚动到评论位置 2021-02-04 15:20:29 +08:00
7c59181bc6 提交LGLibrary 2021-02-04 11:59:27 +08:00
9244a65371 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-04 11:52:49 +08:00
a7b8b678f7 【光环助手V_4.7.0】论坛交互优化(0204AM补充2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-04 11:52:31 +08:00
9877d4d51e 优化包名检测弹窗弹出速度 2021-02-04 11:44:15 +08:00
32b4570738 修复下载游戏历史版本 游戏 ID 异常的问题 2021-02-04 11:04:45 +08:00
lyr
af3fdb3cfb 光环助手V4.7.0-新分类精选页功能优化_20210203测试问题_第4、5点 https://git.ghzs.com/pm/halo-app-issues/-/issues/1123#note_89121 2021-02-04 10:47:28 +08:00
5ce992ee63 【光环助手V_4.7.0】论坛交互优化(0204AM补充1) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-04 10:22:04 +08:00
ba17019428 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-04 10:00:45 +08:00
f77087907f 修改帖子详情定位到评论位置错位问题 2021-02-04 10:00:16 +08:00
3080f59ef6 Merge remote-tracking branch 'origin/dev-4.7.0' into dev-4.7.0 2021-02-04 09:52:03 +08:00
74b1f388e2 修复大图不能放大的问题 2021-02-04 09:51:53 +08:00
dcbc2fe352 还原自滚动专题优化 2021-02-04 09:37:56 +08:00
b892c58c52 【光环助手V_4.7.0】论坛交互优化(0203PM补充) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-04 09:36:21 +08:00
0a455c7b09 修改跳转游戏详情评论tab位置错误 2021-02-03 18:17:36 +08:00
7a254c4609 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-03 17:39:01 +08:00
4f08a4b9d2 光环助手V4.7.0-首页游戏功能强化(视频自动播放)(曝光) https://git.ghzs.com/pm/halo-app-issues/-/issues/1122 2021-02-03 17:29:35 +08:00
75670b7801 完成启动图功能强化(0203测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1131 2021-02-03 17:05:19 +08:00
af386f6bdc 解决禅道bug 226,229 2021-02-03 15:19:41 +08:00
ff813d8784 【光环助手V_4.7.0】论坛交互优化(0202测试补充3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-03 15:05:32 +08:00
dba87fe09c 【光环助手V_4.7.0】论坛交互优化(0202测试补充3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-03 15:02:33 +08:00
cf13003c2a 【光环助手V_4.7.0】论坛交互优化(0202PMUI补充:1,2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-03 14:26:27 +08:00
7fe337c557 【光环助手V_4.7.0】论坛交互优化(0202测试补充1,2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-03 11:32:53 +08:00
1902ed29c1 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-02 18:28:09 +08:00
a67927e9e7 修改包名检测弹窗显示逻辑 2021-02-02 18:27:51 +08:00
33b6835ae6 完成启动图功能强化(0202测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1131 2021-02-02 18:22:42 +08:00
1ca6a2c795 修复游戏下载红点更新问题 2021-02-02 17:36:35 +08:00
372230092a 去掉自滚动栏目的焦点 2021-02-02 17:11:54 +08:00
2ee1db1074 修复镜像游戏在已安装显示成 null 的问题 2021-02-02 17:11:16 +08:00
caabf416bb Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-02 17:01:50 +08:00
d33d0e98c9 光环助手V4.7.0-首页游戏功能强化(视频自动播放)(20210202测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1122 2021-02-02 17:01:30 +08:00
a4a029f31e 完成启动图功能强化(数据埋点) https://git.ghzs.com/pm/halo-app-issues/-/issues/1131 2021-02-02 16:49:48 +08:00
lyr
3b8d34f8c3 解决禅道问题221(【UI优化】在我的光环,界面上下滑动昵称重叠的问题) 2021-02-02 14:43:23 +08:00
2368e268bf 【光环助手V_4.7.0】论坛交互优化(0201测试反馈) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-02 14:15:22 +08:00
6390198899 修改点击安装包解析错误弹窗的确定按钮没有删除安装包 2021-02-02 09:25:32 +08:00
4a6aef4caa javassit动态修改DiskLruCache#trimToSize 2021-02-01 23:04:43 +08:00
91529f51a3 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-01 18:54:18 +08:00
57096b2b08 首页滑动视频不跳转进度 2021-02-01 18:53:54 +08:00
40f1f57844 完成光环前端优化汇总(8,9,10,11) https://git.ghzs.com/pm/halo-app-issues/-/issues/1138 2021-02-01 18:42:36 +08:00
b9da7fbcb8 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-01 16:14:26 +08:00
7138177df2 光环前端优化汇总(2021年1月)(5) https://git.ghzs.com/pm/halo-app-issues/-/issues/1138 2021-02-01 16:13:55 +08:00
aa4cf291dc Merge remote-tracking branch 'origin/dev-4.7.0' into dev-4.7.0 2021-02-01 16:03:34 +08:00
8f4c1651a3 Merge branch 'release' into dev-4.7.0
# Conflicts:
#	app/src/main/java/com/gh/common/exposure/ExposureManager.kt
#	app/src/main/java/com/gh/common/loghub/LoghubUtils.kt
#	app/src/main/java/com/gh/common/videolog/VideoRecordUtils.kt
#	app/src/main/java/com/gh/download/DownloadManager.java
#	app/src/main/java/com/gh/gamecenter/SplashScreenActivity.java
#	app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GameDetailMoreDialog.kt
#	app/src/main/java/com/halo/assistant/HaloApp.java
#	dependencies.gradle
#	libraries/LGLibrary
2021-02-01 15:50:53 +08:00
30a6cfd7d9 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-01 15:45:42 +08:00
c1abb977bf 【光环助手V_4.7.0】论坛交互优化(UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-01 15:45:23 +08:00
fef633e9d8 缺省渠道改为 TEST 2021-02-01 14:53:38 +08:00
5207b5675c 光环助手V4.7.0-首页游戏功能强化(视频自动播放)(20200129UI测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1122 2021-02-01 09:44:48 +08:00
b7059abcee Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-02-01 09:21:50 +08:00
45a84fc45c 【光环助手V_4.7.0】论坛交互优化(0128测试反馈) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-02-01 09:21:22 +08:00
cf96b00036 无网络不使用启动广告 2021-02-01 09:20:37 +08:00
49dacc472d 更新 okhttp 修复 bio==null 闪退 2021-02-01 09:19:34 +08:00
72d069ad7e 提高首页图集的滚动流畅度 2021-01-31 18:19:22 +08:00
2f49e05891 完成专题合集首页图片优化(20200129UI测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1124 2021-01-31 14:16:07 +08:00
fd2d277470 启用 R8 2021-01-29 18:51:11 +08:00
fc52694fdc webview 支持视频带声音自动播放 2021-01-29 15:51:35 +08:00
7123b3d59a 【光环助手V_4.7.0】论坛交互优化(UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-01-29 15:43:42 +08:00
7684c247bf Merge branch 'hotfix-v4.6.0-270-install_observer' into 'release'
修复下载完成状态通知问题

See merge request halo/assistant-android!92
2021-01-29 12:35:59 +08:00
f2b9d26e8a 修复下载完成状态通知问题 2021-01-29 12:29:22 +08:00
6d5d407aa8 【光环助手V_4.7.0】论坛交互优化(UI测试问题1-5) https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-01-29 10:06:05 +08:00
338de605ec 版本增加至 4.6.1 2021-01-28 18:24:54 +08:00
53930b0257 修改帖子详情底部布局 2021-01-28 18:02:15 +08:00
34d5e2cc29 光环助手V4.7.0-外部应用跳转光环助手功能优化(UI测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1130 2021-01-28 16:47:38 +08:00
591a694bdf Merge branch 'hotfix-v4.6.0-270-generic_crash' into 'release'
Hotfix v4.6.0 270 generic crash

See merge request halo/assistant-android!91
2021-01-28 16:25:02 +08:00
9fd9a4ebcc 捕抓日志上报数据库因为磁盘空间不足引起的闪退 2021-01-28 16:23:58 +08:00
f2712c3db7 将接收到安装完成事件后的操作从 DownloadService 移至 DownloadManger 2021-01-28 16:22:01 +08:00
61c2c7b218 Merge branch 'hotfix-v4.6.0-270-generic_crash' into 'release'
修复 4.6.0 的闪退

See merge request halo/assistant-android!90
2021-01-28 15:44:26 +08:00
8a54c47d9e 修复闪退问题
1. 捕抓个别 vivo 设备初始化下载证书时拿不到文件的闪退
2. 捕抓 ViewPager 和 ScrollView 在部分设备上多指操作的闪退
3. 捕抓接收商店应用跳转时链接格式不支持造成的闪退
4. 修复光环应用内更新弹窗关闭弹窗后偶发的闪退
5. 修复游戏评分列表数据更新时偶发的闪退
6. 修复下载管理已安装列表更新排序时偶发的闪退
7. 捕抓搜索历史数据库/日志上报数据库因为磁盘空间不足引起的闪退
8. 捕抓内存回收对象时因为系统缺陷导致的超时闪退
2021-01-28 15:44:26 +08:00
7f60a575a4 草稿箱恢复显示回答草稿 2021-01-28 15:16:13 +08:00
eb2dd7c6b8 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-01-28 14:45:39 +08:00
ae8433d8bd 修改首页游戏遮罩 2021-01-28 14:45:14 +08:00
7ec4ba6582 Merge branch 'hotfix-v4.6.0-270-crash' into 'release'
修改sentry上的一些闪退问题

See merge request halo/assistant-android!89
2021-01-28 14:19:11 +08:00
190434a855 完成存储权限弹窗优化(0127测试) https://git.ghzs.com/pm/halo-app-issues/-/issues/1128 2021-01-28 09:50:57 +08:00
4b82e40eb4 修复启动页在 MIUI 上的显示问题 2021-01-27 18:13:42 +08:00
d8e858ddb8 统一 toast 管理 2021-01-27 18:11:11 +08:00
9b8c8f328d 修改禅道bug 204、206、208 2021-01-27 17:47:12 +08:00
lyr
bebdbe64cd Merge remote-tracking branch 'origin/hotfix-v4.6.0-270-crash' into hotfix-v4.6.0-270-crash
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/WeiBoShareActivity.java
#	app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java
2021-01-27 17:36:34 +08:00
lyr
a0555d6ffc 1.修复由于游戏获取Apk为空导致的闪退问题;
2.修复回答编辑-上传图片时,图片路径返回为空导致的闪退问题;
3.修复绑定手机冲突时手机位数不够11位导致的闪退问题;
4.修复微博分享时icon为空导致的闪退问题;
5.修复关于页面-检查更新,更新信息返回后执行刷新页面操作,但页面已经销毁导致的闪退问题;
6.修复WebFragment(网页)下载跳转到自带浏览器,但页面还未添加到Activity导致的闪退问题
2021-01-27 17:31:46 +08:00
d6674efe4a 光环助手V4.7.0-外部应用跳转光环助手功能优化(修改数据上报) https://git.ghzs.com/pm/halo-app-issues/-/issues/1130 2021-01-27 16:09:25 +08:00
20235c6908 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-01-27 15:55:43 +08:00
bc155d580c 光环助手V4.7.0-外部应用跳转光环助手功能优化(修改数据上报) https://git.ghzs.com/pm/halo-app-issues/-/issues/1130 2021-01-27 15:55:14 +08:00
9cf852b490 1.修改视频流闪退问题
2.修改游戏详情顶部视频闪退问题
3.修改上报闪退日志闪退问题
4.修改游戏详情点击下载按钮闪退问题
5.修改我的预约页面数组越界问题
6.修改发布提问选择图片闪退问题
7.修改用户主页视频tab下拉刷新过程中滑动页面闪退问题
8.修改点击下载按钮数组越界问题
9.修改游戏详情即将被销毁点击更多操作弹窗闪退问题
10.修改Activity被销毁关闭下载模拟器弹窗闪退问题
11.修改Activity被销毁关闭游戏标签弹窗闪退问题
12.修改视频流下载游戏闪退问题
13.修改游戏详情点击分享闪退问题
14.修改分享微博闪退问题
15.修改图片预览闪退问题
2021-01-27 15:39:06 +08:00
f32bc837b4 Merge branch 'feature-issues1129' into 'dev-4.7.0'
完成更新推送弹窗新增官网下载地址 https://git.ghzs.com/pm/halo-app-issues/-/issues/1129

See merge request halo/assistant-android!88
2021-01-27 11:32:11 +08:00
36efcdb75a 完成更新推送弹窗新增官网下载地址 https://git.ghzs.com/pm/halo-app-issues/-/issues/1129 2021-01-27 11:31:26 +08:00
a232ef9d03 Merge branch 'hotfix-v4.6.0-270-gid' into 'release'
修复应用重建时 gid 为空的问题

See merge request halo/assistant-android!87
2021-01-27 10:37:19 +08:00
05b90bd5b4 修复应用重建时 gid 为空的问题 2021-01-26 17:41:25 +08:00
bc382e6f31 完成禅道bug 200、202 2021-01-26 17:04:15 +08:00
116d71bb9c Merge branch 'feature-issues1130' into 'dev-4.7.0'
Feature issues1130

See merge request halo/assistant-android!86
2021-01-26 16:17:29 +08:00
2aadb78301 Feature issues1130 2021-01-26 16:17:29 +08:00
lyr
22801846e4 Merge remote-tracking branch 'origin/dev-4.7.0' into dev-4.7.0 2021-01-26 15:31:44 +08:00
lyr
f9f6886250 优化模拟器卸载操作 2021-01-26 15:31:34 +08:00
30c8d4db02 Merge branch 'dev-4.7.0' of git.ghzs.com:halo/assistant-android into dev-4.7.0 2021-01-26 15:28:30 +08:00
08a5ea100e 光环前端优化汇总(2021年1月)(3,7) https://git.ghzs.com/pm/halo-app-issues/-/issues/1138 2021-01-26 15:28:12 +08:00
db33ed0d0d 还原进程限制代码 2021-01-26 12:00:49 +08:00
fd424b0204 将接收到安装完成事件后的操作从 DownloadService 移至 DownloadManger 2021-01-26 11:54:20 +08:00
lyr
c1bf0a628f 光环前端优化汇总(2021年1月)第1、2点 https://git.ghzs.com/pm/halo-app-issues/-/issues/1138 2021-01-26 11:25:42 +08:00
086bf75314 复用下载线程 2021-01-25 18:24:53 +08:00
af31fdc562 Merge branch 'feature-issues1124' into 'dev-4.7.0'
完成专题合集首页图片优化 https://git.ghzs.com/pm/halo-app-issues/-/issues/1124

See merge request halo/assistant-android!85
2021-01-25 17:12:49 +08:00
99e0a2e0a2 完成专题合集首页图片优化 https://git.ghzs.com/pm/halo-app-issues/-/issues/1124 2021-01-25 17:11:56 +08:00
069d0db00e 删除无用资源和代码 2021-01-25 16:48:43 +08:00
68f1343c93 Merge branch 'feature-startup_ad' into 'dev-4.7.0'
Feature startup ad

See merge request halo/assistant-android!84
2021-01-25 12:01:28 +08:00
fbe25c9099 完成启动图功能强化 (附带冷启动速度优化) https://git.ghzs.com/pm/halo-app-issues/-/issues/1131 2021-01-25 12:01:28 +08:00
9b893bcb42 Merge branch 'feature-issues1122' into 'dev-4.7.0'
Feature issues1122

See merge request halo/assistant-android!83
2021-01-25 09:45:15 +08:00
5182d4cd8d 光环助手V4.7.0-首页游戏功能强化 https://git.ghzs.com/pm/halo-app-issues/-/issues/1122 2021-01-25 09:45:15 +08:00
lyr
cce077de96 光环助手V4.7.0-新分类精选页功能优化 二、前端功能-第3点 pm/halo-app-issues#1123 2021-01-21 10:01:28 +08:00
lyr
03092a0ec1 光环助手V4.7.0-新分类精选页功能优化 二、前端功能-第3点 pm/halo-app-issues#1123 (漏传部分) 2021-01-21 10:01:28 +08:00
lyr
4906ecc06b 光环助手V4.7.0-新分类精选页功能优化 二、前端功能-第3点 https://git.ghzs.com/pm/halo-app-issues/-/issues/1123#note_86465 2021-01-21 10:01:27 +08:00
lyr
7a831ce646 光环助手V4.7.0-新分类精选页功能优化 二(1、2)https://git.ghzs.com/pm/halo-app-issues/-/issues/1123 2021-01-21 10:01:27 +08:00
290a26c4e2 完善权限跳转逻辑 2021-01-20 14:21:59 +08:00
571080b1e5 Merge branch 'feature-issues1128' into 'dev-4.7.0'
Feature issues1128

See merge request halo/assistant-android!81
2021-01-20 11:36:18 +08:00
d9567138ee 完成存储权限弹窗优化(权限应用场景跳转地址暂缺) pm/halo-app-issues#1128 2021-01-20 11:36:18 +08:00
4a31f74dcb Merge branch 'hotfix-v4.6.0-270-generic_crash' into 'release'
修复一些闪退

See merge request halo/assistant-android!80
2021-01-20 11:25:11 +08:00
79cf96b161 Merge branch 'hotfix-v4.6.0-270-crash' into 'release'
1.处理个人主页由于个人信息未初始化导致的闪退;2.处理绑定手机由于ServiceId未初始化导致的闪退

See merge request halo/assistant-android!79
2021-01-20 11:23:30 +08:00
7fdd4dbf04 修复一些闪退
1. 修复部分设备获取 ROM 信息时的闪退
2. 修复启动时预约游戏弹窗页面重建时的闪退
2021-01-20 11:22:28 +08:00
lyr
8eeeb5de60 1.处理个人主页由于个人信息未初始化导致的闪退;2.处理绑定手机由于ServiceId未初始化导致的闪退 2021-01-20 10:34:19 +08:00
150109cef4 修复镜像游戏的包 id 与原游戏 id 不一时出现的按钮状态不变更问题 2021-01-19 17:10:18 +08:00
7e7cc38d6d 优化全局图片加载 2021-01-19 17:04:14 +08:00
b3df30680e 更新头条推广SDK 2021-01-19 14:56:00 +08:00
f73048d3a5 Merge branch 'release' into dev-4.7.0
# Conflicts:
#	app/src/main/java/com/gh/common/exposure/ExposureManager.kt
#	app/src/main/java/com/gh/common/videolog/VideoRecordUtils.kt
#	app/src/main/res/drawable-nodpi/splash_01.webp
2021-01-19 12:02:39 +08:00
c540c14e1c Merge branch 'hotfix-v4.6.0-270-install_status' into 'release'
修复已安装的应用下载按钮状态更新不及时的问题

See merge request halo/assistant-android!77
2021-01-18 09:21:50 +08:00
f216bf4097 Merge branch 'feature-bbs' into dev-4.7.0 2021-01-18 09:13:45 +08:00
a42bcbd160 增加问题草稿功能 2021-01-15 16:30:06 +08:00
bc6786b21e 修复已安装的应用下载按钮状态更新不及时的问题 2021-01-15 11:51:28 +08:00
47e357143c 资源图片批量转webp,删掉部分废弃代码和文件 2021-01-14 17:05:14 +08:00
74eb8ad0e8 Merge branch 'feature-reduce_memory_usage' into 'dev-4.7.0'
优化线程使用

See merge request halo/assistant-android!75
2021-01-13 17:24:18 +08:00
d2fc927ffb 优化线程管理,减少闲置线程数量 2021-01-13 17:24:18 +08:00
db4b049591 Add new gdt account 2021-01-13 15:56:57 +08:00
lyr
86db2b5688 优化模拟器游戏列表加载 2021-01-13 14:46:14 +08:00
baa1c9f9e5 Merge branch 'dev-4.7.0' into feature-bbs 2021-01-13 11:38:03 +08:00
be3a3e82af 修改游戏详情预约闪退问题 2021-01-13 11:34:12 +08:00
120ea26455 编辑帖子/回答上传图片取消加载弹窗,改为占位图 2021-01-13 11:22:40 +08:00
fc476ca889 Merge remote-tracking branch 'origin/dev' into dev 2021-01-13 09:11:59 +08:00
fc36ce6a03 更换启动引导图 https://git.ghzs.com/pm/halo-app-issues/-/issues/1136 2021-01-13 09:11:49 +08:00
0a1d330c2f 修复自动搜索页面的下载按钮复用问题 2021-01-12 15:32:53 +08:00
lyr
e5ec42576c 光环助手V4.7.0-积分体系(第2期)--积分第1期优化 第3点 https://git.ghzs.com/pm/halo-app-issues/-/issues/1127 2021-01-12 14:35:32 +08:00
lyr
b57f74a411 修改非全屏WebFragment标题栏被状态栏遮盖的问题 2021-01-12 12:00:12 +08:00
cb3884ea2e 【光环助手V_4.7.0】论坛交互优化 https://git.ghzs.com/pm/halo-app-issues/-/issues/1135 2021-01-12 10:02:30 +08:00
lyr
0cb3184e35 解决禅道问题179(【光能】光能数值的显示问题) 2021-01-11 16:39:09 +08:00
lyr
76c5009fbc 1.修复模拟器游戏页-全选删除整个列表之后由于数组越界导致的闪退问题;2.修改模拟器列表初次加载卡顿问题 2021-01-11 10:13:30 +08:00
lyr
312ec153f1 修复更新版本后模拟器游戏记录被清空问题 2021-01-08 18:39:12 +08:00
1ef79df4c5 Merge branch 'release' into 'dev'
Fix crash

See merge request halo/assistant-android!74
2021-01-08 11:11:08 +08:00
d7a809f8a6 Merge branch 'hotfix-v4.5.4-254-database' into 'release'
捕抓数据库满了的时候的异常

See merge request halo/assistant-android!73
2021-01-08 11:10:42 +08:00
ebadeeb873 捕抓数据库满了的时候的异常 2021-01-08 11:08:14 +08:00
55155ee8ae Merge branch 'release' into 'dev'
捕抓部分 SqliteFullException

See merge request halo/assistant-android!72
2021-01-08 10:26:40 +08:00
be98a6b6d6 Merge branch 'hotfix-v4.5.4-254-database' into 'release'
捕抓视频日志数据库满了的时候的异常

See merge request halo/assistant-android!71
2021-01-08 10:04:22 +08:00
e2f396f8c7 捕抓视频日志数据库满了的时候的异常 2021-01-08 10:03:26 +08:00
2a8024368a 优化通用列表对比实现,提高性能 2021-01-07 16:16:46 +08:00
0cd025b42d 更新依赖 2021-01-07 16:11:40 +08:00
lyr
d6adda78c4 修复禅道问题182(【模拟器游戏】模拟器游戏显示问题) 2021-01-07 11:56:54 +08:00
99708d7801 Merge branch 'dev-4.6.0' into 'dev'
Feature 4.6.0

See merge request halo/assistant-android!70
2021-01-07 10:00:38 +08:00
584986a9d5 Merge branch 'release' into dev-4.6.0
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/game/columncollection/detail/ColumnCollectionDetailActivity.kt
2021-01-07 09:55:42 +08:00
507da05841 Merge remote-tracking branch 'origin/hotfix-v4.5.4-254-crash' into release
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorGameListFragment.kt
2021-01-07 09:52:22 +08:00
72a8fe4764 将下载文件夹的名字从 gh-download 改成 gh-files,避免被华为手机管家清理 2021-01-07 09:30:30 +08:00
lyr
f9f23f6324 WebFragment和光能屋-顶部栏适配小米型号手机 2021-01-06 18:31:38 +08:00
e2964f93c7 完成曝光数据统计优化(20210106测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1087 2021-01-06 18:04:30 +08:00
cb2a9a3ca0 修改模拟器游戏下载完成后数据上传错误 2021-01-06 17:43:38 +08:00
lyr
ea68941bb9 修改模拟器列表页由于复用产生的错误点击问题 2021-01-06 14:58:15 +08:00
lyr
b598d331d4 修复光能任务列表的空指针错误 2021-01-06 14:33:41 +08:00
lyr
d7b876bfed 1.修复未安装QQ情况下分享图片闪退问题;2.修复缺少专题ID时进入专题合集页面闪退问题;3.修复由于"Fragment未添加到Activity时"进入个人主页闪退问题;4.修复文章编辑页-上传图片时,由于返回的文件路径为空导致创建图片文件失败的闪退问题;5.修复模拟器游戏页由于数组越界导致的闪退问题;6.修复进入WebFragment(即网页)时,由于获取参数为空导致的闪退问题 2021-01-06 10:53:00 +08:00
lyr
6aca60080a 修复光能中心底部和透明导航栏重叠问题 2021-01-06 10:22:07 +08:00
59d76688b9 优化全局预览图->大图的显示 2021-01-06 09:53:03 +08:00
8e5e677228 完成曝光数据统计优化(20201230测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1087 2021-01-05 17:41:00 +08:00
dd1bfcaddd 正式接口切换到 4.6.0,测试接口更改 host 2021-01-05 15:47:02 +08:00
f4c66e1ab7 Merge branch 'hotfix-4.5.4-crash' into 'release'
修改sentry闪退问题

See merge request halo/assistant-android!66
2021-01-05 15:44:44 +08:00
6ebdf6e42a 1.修改选择头像闪退问题
2.修改视频评论闪退问题
3.修改模拟游戏列表闪退问题
4.尝试修改5.0系统手机找不到vector资源文件问题
5.修改用户信息修改页面闪退问题
2021-01-05 15:44:44 +08:00
4c01dd442b Merge branch 'hotfix-v4.5.4-254-generic_crash' into release
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/category/CategoryDirectoryFragment.kt
2021-01-05 15:17:57 +08:00
ac226e3301 修复闪退
1. 修复旧分类页偶发的空指针闪退
2. 修复多进程判断偶发的空指针闪退
3. 捕抓调用关闭 WebView 安全浏览 API 闪退异常
4. 捕抓通用列表刷新时多线程读写造成的数组越界
2021-01-05 15:14:34 +08:00
lyr
569f1b8cf1 微调"光能中心"UI 2021-01-05 09:38:17 +08:00
lyr
46f5da88a6 光环助手V4.6.0-积分体系(第1期)--光能屋 20201230UI测试 https://git.ghzs.com/pm/halo-app-issues/-/issues/1062#note_83290 和 光环助手V4.6.0-新增[光能中心-订单管理] 1231-补充1 https://git.ghzs.com/pm/halo-app-issues/-/issues/1061#note_83483 2021-01-04 18:36:10 +08:00
f5b876b018 Merge branch 'hotfix-v4.5.4-254-generic_crash' into 'release'
修复闪退

See merge request halo/assistant-android!63
2021-01-04 18:12:34 +08:00
c5df856023 修复闪退
1. 修复部分机器获取 rom 名字时的闪退
2. 修复下载管理偶发的闪退
3. 修复上报安装应用列表偶发的闪退
4. 修复回答详情数据异常时点击收藏的闪退
2021-01-04 18:05:38 +08:00
lyr
4f775847dc 还原"我的光环"页面,点击右上角便签可进入新的"我的光环"页面 2021-01-04 14:35:23 +08:00
lyr
f53710fdf5 光环助手V4.6.0-新增[光能中心-任务管理] 1230测试 https://git.ghzs.com/pm/halo-app-issues/-/issues/1063#note_83291 2021-01-04 11:26:16 +08:00
80c56def08 Merge branch 'release' into 'dev-4.6.0'
Fix crash

See merge request halo/assistant-android!62
2020-12-31 18:19:27 +08:00
a1d88d999e Merge branch 'hotfix-v4.5.4-254-intent_crash' into 'release'
捕抓跳转外部浏览器 intent 异常

See merge request halo/assistant-android!61
2020-12-31 18:18:52 +08:00
fbc6f6adaa Merge branch 'hotfix-4.5.4-crash' into 'release'
修改sentry闪退问题

See merge request halo/assistant-android!59
2020-12-31 18:17:28 +08:00
e7c55b2467 捕抓跳转外部浏览器 intent 异常 2020-12-31 18:15:50 +08:00
2c45bb1da9 1.处理更换头像挂件闪退问题
2.添加游戏投稿选择文件失败toast提示
2020-12-31 18:09:51 +08:00
173825dc74 Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-31 09:15:54 +08:00
a63e28809b 修改禅道问题65 2020-12-31 09:15:26 +08:00
0eb8cb6e66 修复卸载应用时下载安装按钮状态变更可能不及时的问题 2020-12-30 21:22:18 +08:00
e1514e2b25 Merge branch 'release' into dev-4.6.0 2020-12-30 18:15:47 +08:00
bef0da821b 去掉下载管理-已安装列表的多线程读写 2020-12-30 18:14:53 +08:00
54741729f3 Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-30 18:09:00 +08:00
e2640c22f8 修改论坛信息流图片计数标签显示规则 2020-12-30 18:08:38 +08:00
2f16d5ba99 修复游戏详情页提示弹窗的弹出异常 2020-12-30 17:48:56 +08:00
1d5301f887 修复我的关注页的取消关注列表更新问题,修复在部分设备上的游戏详情页触摸切换tab不灵敏问题 2020-12-30 17:24:52 +08:00
cc09c702f7 Merge branch 'release' into dev-4.6.0 2020-12-30 16:50:43 +08:00
6b2a88766e 修复下载管理-已安装列表的闪退问题 2020-12-30 16:49:48 +08:00
lyr
0eb629fe67 1.修复漏上报"下载游戏"、"玩游戏"、"分享游戏详情"光能任务的问题;2.前端取消上报"注册"和"登录"光能任务 2020-12-30 15:29:56 +08:00
44c398c9fb Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-30 15:17:32 +08:00
96122c5919 【光环助手V4.6.0】论坛发布流程优化(1229测试反馈2) https://git.ghzs.com/pm/halo-app-issues/-/issues/1086 2020-12-30 15:17:13 +08:00
bd4c438036 修复前端测试汇总(20201229测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1098 2020-12-30 15:04:38 +08:00
adc8648f5a 完成曝光数据统计优化(20201229测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1087 2020-12-30 11:34:05 +08:00
8eb3922a33 【光环助手V4.6.0】论坛发布流程优化(201230-UI测试问题汇总) https://git.ghzs.com/pm/halo-app-issues/-/issues/1086 2020-12-30 11:03:59 +08:00
30743bb015 Merge remote-tracking branch 'origin/release' into dev-4.6.0
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/servers/add/AddKaiFuActivity.kt
#	app/src/main/java/com/gh/gamecenter/servers/patch/PatchKaifuActivity.kt
#	app/src/main/java/com/gh/gamecenter/video/upload/view/UploadVideoActivity.kt
#	dependencies.gradle
#	libraries/LGLibrary
2020-12-30 10:38:11 +08:00
853f51ad0e Merge branch 'hotfix-v4.5.4-254-generic_crash' into 'release'
处理闪退

See merge request halo/assistant-android!57
2020-12-30 10:30:15 +08:00
763aad99ee 1. 修复视频编辑封面页偶发的初始化异常闪退
2. 修复我的游戏评论数据变更时的数组越界闪退
3. 修复部分设备跳转查看应用使用情况时的闪退
2020-12-30 10:28:03 +08:00
2ed2317b02 Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-29 19:47:39 +08:00
0663f3eb2b 【光环助手V4.6.0】论坛发布流程优化(1229测试反馈1,2,3,5,6) https://git.ghzs.com/pm/halo-app-issues/-/issues/1086 2020-12-29 19:47:20 +08:00
11a2eeae7a 修复帖子评论详情父评论点赞不同步的问题 2020-12-29 18:21:40 +08:00
lyr
8c2619bb22 Merge remote-tracking branch 'origin/dev-4.6.0' into dev-4.6.0 2020-12-29 17:13:07 +08:00
lyr
46320fe07d 光环助手V4.6.0-积分体系(第1期)--光能中心 20201229UI测试-图1/2 https://git.ghzs.com/pm/halo-app-issues/-/issues/1065#note_82979 和 光能助手V4.6.0-积分体系(第1期)-- 我的光环优化 20201229UI测试 https://git.ghzs.com/pm/halo-app-issues/-/issues/1066#note_82978 2020-12-29 17:12:54 +08:00
1ee933b115 Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-29 17:12:51 +08:00
1d9152ca1a 完成禅道问题56,66 2020-12-29 17:12:34 +08:00
lyr
81ebf21bb9 光环前端优化汇总(2020年12月)20201229补充分类精选页问题 https://git.ghzs.com/pm/halo-app-issues/-/issues/1098#note_82895 2020-12-29 16:17:15 +08:00
dd4bf98f28 补充记录曝光位置页面 https://git.ghzs.com/pm/halo-app-issues/-/issues/1087 2020-12-29 15:59:15 +08:00
ba3a06da43 完成光环前端优化汇总(20201226测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1098 2020-12-29 15:12:53 +08:00
6fe096383c 更新依赖库 2020-12-29 15:10:32 +08:00
d16f99958f 【光环助手V4.6.0】论坛发布流程优化(201226-UI测试问题汇总2-4) https://git.ghzs.com/pm/halo-app-issues/-/issues/1086 2020-12-29 15:05:19 +08:00
5fa3aa42dc Merge remote-tracking branch 'origin/hotfix-4.5.4-254-crash' into release
# Conflicts:
#	libraries/LGLibrary
2020-12-29 14:20:50 +08:00
lyr
f4f28a2daa 解决禅道问题139(【光能中心】兑换区--“前往光能屋查看更多”悬浮窗出现机制) 2020-12-29 12:55:56 +08:00
3c1cd14bdc Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-29 11:52:47 +08:00
6dcc251312 光环助手V4.6.0-游戏预约功能(第三期)(1226测试1) https://git.ghzs.com/pm/halo-app-issues/-/issues/1082 2020-12-29 11:52:29 +08:00
f692aa4bff 修复曝光数据统计优化(20201228测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1087 2020-12-29 11:14:44 +08:00
7cde55ebe0 1.修改webview页面闪退问题
2.修改已安装列表闪退问题
3.修改通知权限弹窗闪退问题
4.修改Activity已关闭后web页面延迟alert而导致的闪退问题
5.修改点击视频流更多按钮闪退问题
6.修改AppUncaughtHandler捕获异常后关闭所有Activity闪退问题
7.修改一些数组越界问题
2020-12-29 10:43:35 +08:00
lyr
94eba08af4 解决禅道问题127(【光能中心】商品分类重复显示问题)、135(【光能屋】滑动界面,光能屋模块的背景问题)、139(【光能中心】兑换区--“前往光能屋查看更多”悬浮窗出现机制) 2020-12-29 10:18:14 +08:00
2bf207661c 补充安全隐患排查的更改 https://git.ghzs.com/pm/halo-app-issues/-/issues/1093 2020-12-29 10:03:21 +08:00
2fff7f60c2 完成前端优化汇总(20201225测试问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1098 2020-12-28 17:51:28 +08:00
lyr
1b3c93ebb5 解决禅道问题133(【手机登录】多次点击第三方登录会弹出多个登录界面)、135(【光能屋】滑动界面,光能屋模块的背景问题) 2020-12-28 17:13:06 +08:00
lyr
5b529b044e 光环助手V4.6.0-积分体系(第1期)--光能中心(2020-12-28 产品测试APP端问题)https://git.ghzs.com/pm/halo-app-issues/-/issues/1065#note_82696 和 光环助手V4.6.0-积分体系(第1期)--光能屋(2020-12-28 产品测试APP端问题)https://git.ghzs.com/pm/halo-app-issues/-/issues/1062#note_82698 2020-12-28 16:10:39 +08:00
91f417f479 Merge branch 'hotfix-v4.5.4-254-generic_crash' into 'release'
处理简单闪退

See merge request halo/assistant-android!55
2020-12-28 16:03:56 +08:00
fc0bf595bd 1. 修复偶发的点击安装按钮空指针闪退
2. 修复停留在微信登录页面时下载完成触发的闪退
3. 修复游戏详情页面自定义栏目展开按钮在部分设备上的数组越界闪退
4. 修复分类详情列表页面偶发的空指针闪退
5. 修复游戏管理游戏下载页面的数组越界闪退
6. 修复游戏评论回复页面偶发的空指针闪退
7. 修复通用评论页(视频、答案和文章)列表偶发的空指针闪退
8. 修复问题详情页面偶发的空指针闪退
9. 修复历史修改版本页面偶发的空指针闪退
10. 修复新增开服页面偶发的空指针闪退
11. 修复修改开服页面偶发的空指针闪退
12. 修复视频合集页面偶发的空指针闪退
13. 修复上传视频页面偶发的空指针闪退
14. 修复全局页面点返回键偶发的闪退
15. 修复反馈页面偶发的空指针闪退
16. 修复微博分享页面偶发的空指针闪退
17. 修复游戏新闻搜索页面偶发的空指针闪退
18. 修复全局下载进度更新偶发的闪退
2020-12-28 15:58:32 +08:00
lyr
c0f6499577 光环助手V4.6.0-积分体系(第1期)--光能中心 20201225UI测试 https://git.ghzs.com/pm/halo-app-issues/-/issues/1065#note_82546 和 光环助手V4.6.0-积分体系(第1期)--光能屋 20201225UI测试 https://git.ghzs.com/pm/halo-app-issues/-/issues/1062#note_82549 2020-12-28 14:32:12 +08:00
b9bef384f1 还原正常安装 Intent 2020-12-28 11:37:02 +08:00
58bfae2fdb 【光环助手V4.6.0】论坛首页信息流UI展示规则优化(201228-UI测试问题汇总) https://git.ghzs.com/pm/halo-app-issues/-/issues/1052 2020-12-28 11:04:40 +08:00
d2c2fff884 Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-28 09:46:23 +08:00
ab178c47b5 【光环助手V4.6.0】论坛发布流程优化(遗留UI问题) https://git.ghzs.com/pm/halo-app-issues/-/issues/1086 2020-12-28 09:46:04 +08:00
40be004376 适配登录错误码 https://git.ghzs.com/pm/halo-app-issues/-/issues/1095 2020-12-27 11:57:09 +08:00
0b501c9ce1 下载管理"安装/继续下载"补充权限申请 2020-12-27 10:56:12 +08:00
cff82379f5 升级版本至 4.5.4 2020-12-26 19:08:25 +08:00
825503bd58 Merge branch 'hotfix-v4.5.3-253-multidex' into 'release'
处理分 dex 问题

See merge request halo/assistant-android!54
2020-12-26 19:05:58 +08:00
77a715a4bd 处理分 dex 问题 2020-12-26 19:01:04 +08:00
78b233c506 预览长图默认显示顶部区域 2020-12-26 15:31:08 +08:00
a6e799bb9a 【光环助手V4.6.0】论坛首页信息流UI展示规则优化(201225-UI测试问题汇总3) https://git.ghzs.com/pm/halo-app-issues/-/issues/1052 2020-12-26 14:41:54 +08:00
b65992099a Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-26 14:09:35 +08:00
3d1a5f52bf debug环境开启严格模式 2020-12-26 14:09:15 +08:00
82d0d5745c 【光环助手V4.6.0】论坛发布流程优化(201226-UI测试问题汇总) https://git.ghzs.com/pm/halo-app-issues/-/issues/1086 2020-12-26 14:07:47 +08:00
fe7968cb32 Merge branch 'feature-issues1087' into 'dev-4.6.0'
https://git.ghzs.com/pm/halo-app-issues/-/issues/1087

See merge request halo/assistant-android!53
2020-12-26 11:49:59 +08:00
94c503af74 完成部分曝光统计优化 https://git.ghzs.com/pm/halo-app-issues/-/issues/1087 2020-12-26 11:49:59 +08:00
bdd9815ffc Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-25 17:31:41 +08:00
693acceca8 光环助手V4.6.0-游戏预约功能(第三期)(201222-UI测试问题汇总) https://git.ghzs.com/pm/halo-app-issues/-/issues/1082 2020-12-25 17:31:23 +08:00
lyr
90971bc299 Merge remote-tracking branch 'origin/dev-4.6.0' into dev-4.6.0 2020-12-25 16:45:07 +08:00
lyr
e5b3613348 光能助手V4.6.0-积分体系(第1期)-- 我的光环优化 - 20201225UI测试 https://git.ghzs.com/pm/halo-app-issues/-/issues/1066#note_82491 2020-12-25 16:44:52 +08:00
652ca8f69c 1.修改帖子图片计数标签 2.修改帖子提交按钮 2020-12-25 16:43:07 +08:00
f15e351c1e Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-25 16:21:02 +08:00
47c81c3dac 【光环助手V4.6.0】论坛首页信息流UI展示规则优化(201225-UI测试问题汇总) https://git.ghzs.com/pm/halo-app-issues/-/issues/1052 2020-12-25 16:20:32 +08:00
7453a61e4f Merge remote-tracking branch 'origin/dev-4.6.0' into dev-4.6.0 2020-12-25 15:57:42 +08:00
911f6397e8 处理合并冲突 2020-12-25 15:54:52 +08:00
lyr
8d21a4f774 修复光能模块若干bug 2020-12-25 15:53:02 +08:00
991c54b680 Merge remote-tracking branch 'origin/release' into dev-4.6.0
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt
#	dependencies.gradle
2020-12-25 15:47:51 +08:00
48dcb5089b Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-25 15:40:31 +08:00
461efe7101 【光环助手V4.6.0】论坛发布流程优化(201224-UI测试问题汇总) https://git.ghzs.com/pm/halo-app-issues/-/issues/1086 2020-12-25 15:40:13 +08:00
lyr
0735161a20 光环前端优化汇总(2020年12月)7/8 https://git.ghzs.com/pm/halo-app-issues/-/issues/1098 2020-12-24 16:53:44 +08:00
093c1e2b15 【光环助手V4.6.0】论坛首页信息流UI展示规则优化(1224需求说明) https://git.ghzs.com/pm/halo-app-issues/-/issues/1052 2020-12-24 16:36:01 +08:00
7d0e02c899 Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-24 16:08:22 +08:00
8294913f04 【光环助手V4.6.0】论坛发布流程优化201223-UI测试问题汇总1-9 https://git.ghzs.com/pm/halo-app-issues/-/issues/1086 2020-12-24 16:07:56 +08:00
lyr
e811c4f90b 增加web页跳转光能屋的JS调用方法;优化光能模块 2020-12-24 11:27:38 +08:00
69e248b389 版本更改为 4.5.3 2020-12-24 11:12:37 +08:00
43f6bfc4c2 Merge branch 'hotfix-v4.5.2-252-updateLogic' into 'release'
Hotfix v4.5.2 252 update logic

See merge request halo/assistant-android!52
2020-12-24 11:09:56 +08:00
c8b81ab56a 优化模拟器游戏在下载按钮中的判断逻辑 2020-12-24 11:08:34 +08:00
aa41fd98e8 重置下载按钮的文字显示优先级 2020-12-24 10:49:49 +08:00
lyr
ff6c4c2de9 光能值最多显示9999+ 2020-12-24 09:23:02 +08:00
lyr
136761d2f7 光能模块web页的url增加"from=ghzs",以此标志是从助手跳转 2020-12-23 18:18:17 +08:00
9374fc5264 将部分数据库操作移动到工作线程 2020-12-23 18:11:27 +08:00
lyr
324aaa5056 统一修改光能模块命名 2020-12-23 18:03:51 +08:00
f22afbd819 修复横向专题推荐图标复用问题 2020-12-23 17:47:22 +08:00
e149231cb2 完成对上报 IMEI 和 ANDROID_ID 的简单转码 https://git.ghzs.com/pm/halo-app-issues/-/issues/1093 2020-12-23 17:12:23 +08:00
lyr
9c8155ddf8 1.添加跳转光能中心的JS调用方法;2.客服通知增加"订单中心"和"光能记录"类型 2020-12-23 17:07:23 +08:00
dd95419a36 Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-23 15:03:49 +08:00
870b10dd13 【光环助手V4.6.0】论坛首页信息流UI展示规则优化(201222-UI测试问题汇总1-7) https://git.ghzs.com/pm/halo-app-issues/-/issues/1052 2020-12-23 15:02:53 +08:00
lyr
637b426649 优化光能模块 2020-12-23 14:13:54 +08:00
ee8ce87e28 Merge branch 'hotfix-v4.5.2-252-crash' into 'release'
处理一些数组越界闪退

See merge request halo/assistant-android!51
2020-12-23 10:58:40 +08:00
a944a7f730 处理一些数组越界闪退 2020-12-23 10:55:37 +08:00
lyr
fdbb16b45f 修复光能模块若干bug 2020-12-23 10:11:25 +08:00
lyr
29bc098dcf Merge branch 'feature-guangneng' into dev-4.6.0 2020-12-22 18:05:24 +08:00
lyr
b2433cf13a 光环助手V4.6.0-积分体系(第1期)--光能中心(首页部分)https://git.ghzs.com/pm/halo-app-issues/-/issues/1065 和 光环助手V4.6.0-积分体系(第1期)--光能屋(首页部分)https://git.ghzs.com/pm/halo-app-issues/-/issues/1062 2020-12-22 17:15:32 +08:00
e908e23bb2 sentry 事件别名去掉编译时间 2020-12-22 17:02:07 +08:00
1a4dc827b5 Merge branch 'dev-4.6.0' of git.ghzs.com:halo/assistant-android into dev-4.6.0 2020-12-22 16:27:31 +08:00
9fd5e65fa2 添加测试用打包脚本 2020-12-22 16:25:56 +08:00
5405dcd30e 更新 compileSDK版本至30 2020-12-22 16:08:40 +08:00
5c35f7fe5d 完成镜像游戏上报标记字段 https://git.ghzs.com/pm/halo-app-issues/-/issues/1085 2020-12-22 14:54:46 +08:00
fc907a398f 完成光环前端优化汇总(12月)(1,2,4,6) https://git.ghzs.com/pm/halo-app-issues/-/issues/1098 2020-12-22 11:02:50 +08:00
1b8dc6eba0 优化ImageContainerView 2020-12-22 10:26:38 +08:00
c17a36c866 修改大家都在玩分割线不显示问题 2020-12-21 18:31:48 +08:00
a29cf832f1 修复详情页大家都在玩推荐图标显示问题 2020-12-21 18:05:53 +08:00
c9a628a5e9 修改提问、发帖子论坛图标不显示问题 2020-12-21 17:45:07 +08:00
165ba01afd Merge branch 'hotfix-v4.5.2-252-crash' into 'release'
修复v4.5.2版本闪退问题

See merge request halo/assistant-android!50
2020-12-21 16:36:23 +08:00
a39a8c2cce 1.修复视频流滑动闪退问题 2.修复WebView闪退问题 2020-12-21 16:02:00 +08:00
4002f138bb Merge branch 'feature-issues1082' into dev-4.6.0 2020-12-21 15:09:15 +08:00
48fdb38902 光环助手V4.6.0-游戏预约功能(第三期)https://git.ghzs.com/pm/halo-app-issues/-/issues/1082 2020-12-21 15:07:53 +08:00
38a3120ea1 添加应用内游戏详情url拦截 https://git.ghzs.com/pm/halo-app-issues/-/issues/1103 2020-12-21 14:33:55 +08:00
c0e370dfd2 修复横向专题的热门推荐图标显示问题 2020-12-21 14:31:31 +08:00
e4765089fa Merge branch 'hotfix-v4.5.2-252-genericCrash' into 'release'
修复一些空指针和数组越界闪退

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

See merge request halo/assistant-android!48
2020-12-21 11:19:15 +08:00
e406c90027 修复一些空指针和数组越界闪退 2020-12-21 11:17:34 +08:00
e7c4886219 缩窄 Sentry ANR 的上报条件避免日志轰炸 2020-12-21 10:15:20 +08:00
80a2e4f336 修复点击预览图片position错误问题 2020-12-17 17:24:19 +08:00
9f5940c6f6 【光环助手V4.6.0】论坛首页信息流UI展示规则优化 https://git.ghzs.com/pm/halo-app-issues/-/issues/1052 2020-12-17 16:33:14 +08:00
d01fda44b3 版本号改为 4.6.0 2020-12-15 09:44:59 +08:00
2020033bc0 测试环境API版本改为v4d6d0 2020-12-11 09:29:34 +08:00
dc2c8e590c Merge branch 'feature-bbs_publish' into dev-4.6.0 2020-12-11 09:19:20 +08:00
b115db51e9 【光环助手V4.6.0】论坛发布流程优化 https://git.ghzs.com/pm/halo-app-issues/-/issues/1086 2020-12-10 18:22:54 +08:00
lyr
7d194c7078 光能助手V4.6.0-积分体系(第1期)-- 我的光环优化 https://git.ghzs.com/pm/halo-app-issues/-/issues/1066 2020-12-08 10:31:13 +08:00
1998 changed files with 21673 additions and 11175 deletions

1
.gitignore vendored
View File

@ -7,5 +7,6 @@ local.properties
captures/
build/
release-app/
test-app/
scripts/apk-channel/
app/src/test/java/com/gh/gamecenter

2
.gitmodules vendored
View File

@ -1,4 +1,4 @@
[submodule "libraries/LGLibrary"]
path = libraries/LGLibrary
url = git@gitlab.ghzs.com:android/common-library.git
url = git@git.ghzs.com:android/common-library.git
branch = master

View File

@ -2,9 +2,7 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' // kotlin
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
// apkChannelPackage
apply plugin: 'channel'
apply plugin: "com.gh.gamecenter.plugin"
import groovy.xml.XmlUtil
@ -38,6 +36,10 @@ android {
javaMaxHeapSize "4g"
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
defaultConfig {
multiDexEnabled true
@ -184,6 +186,8 @@ android {
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
manifestPlaceholders.put("APPLOG_SCHEME","rangersapplog.byAx6uYt".toLowerCase())
}
gdt {
@ -200,23 +204,6 @@ android {
}
}
// apkChannelPackage
channel {
//多渠道包的输出目录默认为new File(project.buildDir,"channel")
baseOutputDir = new File(project.buildDir, "channel")
//多渠道包的命名规则,默认为:${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}
apkNameFormat = '${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}'
}
rebuildChannel {
// baseDebugApk = 已有Debug APK
// baseReleaseApk = 已有Release APK
// //默认为new File(project.buildDir, "rebuildChannel/debug")
// debugOutputDir = Debug渠道包输出目录
// //默认为new File(project.buildDir, "rebuildChannel/release")
// releaseOutputDir = Release渠道包输出目录
}
repositories {
flatDir {
dirs 'libs', 'libs/aars'
@ -237,8 +224,8 @@ dependencies {
debugImplementation "com.gu.android:toolargetool:${toolargetool}"
debugImplementation "com.github.nichbar:WhatTheStack:$whatTheStack"
implementation "androidx.core:core:${core}"
implementation "androidx.fragment:fragment:${fragment}"
implementation "androidx.core:core-ktx:${core}"
implementation "androidx.fragment:fragment-ktx:${fragment}"
implementation "androidx.multidex:multidex:${multiDex}"
implementation "androidx.appcompat:appcompat:${appCompat}"
implementation "androidx.cardview:cardview:${cardView}"
@ -259,7 +246,7 @@ dependencies {
implementation "com.kyleduo.switchbutton:library:${switchButton}"
implementation "com.facebook.fresco:fresco:${fresco}"
implementation "com.facebook.fresco:animated-gif:${fresco}"
implementation "com.facebook.fresco:animated-gif-lite:${fresco}"
implementation "com.facebook.fresco:animated-drawable:${fresco}"
implementation "com.squareup.okhttp3:okhttp:${okHttp}"
@ -328,7 +315,7 @@ dependencies {
implementation "com.ethanhua:skeleton:${skeleton}"
implementation "io.supercharge:shimmerlayout:${shimmerlayout}"
implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:${mta}"
implementation "com.walkud.rom.checker:RomChecker:${romChecker}"
implementation "com.github.nichbar:AndroidRomChecker:${romChecker}"
debugImplementation "com.github.nichbar.chucker:library:$chucker"
releaseImplementation "com.github.nichbar.chucker:library-no-op:$chucker"
@ -342,15 +329,21 @@ dependencies {
implementation "net.lingala.zip4j:zip4j:${zip4j}"
implementation "io.sentry:sentry-android:$sentry"
// plugin 需要字符串,故不能用值
implementation "io.sentry:sentry-android:3.2.0"
implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
// implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
implementation("com.github.nichbar.BigImageViewer:BigImageViewer:$bigImageViewer", {
exclude group: 'com.squareup.okhttp3'
exclude group: 'androidx.swiperefreshlayout'
exclude group: 'com.github.bumptech.glide'
})
implementation "com.github.nichbar.BigImageViewer:FrescoImageLoader:$bigImageViewer"
implementation "com.github.nichbar.BigImageViewer:FrescoImageViewFactory:$bigImageViewer"
implementation "com.github.PhilJay:MPAndroidChart:${chart}"
implementation "com.github.hsiafan:apk-parser:$apkParser"
implementation project(':libraries:LGLibrary')
// implementation project(':libraries:MTA')
implementation project(':libraries:QQShare')

View File

@ -1,20 +1,3 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
#--------- remove logs start ----------------
-assumenosideeffects class com.lightgame.config.CommonDebug {
@ -26,126 +9,62 @@
public static void logMethodWithParams(...);
}
#-assumenosideeffects class com.lightgame.config.CommonDebug {*;}
#-dontoptimize
-assumenosideeffects class com.lightgame.utils.Utils {
public static void log(...);
}
#--------- remove logs end ----------------
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod
-dontwarn InnerClasses
# TODO Dicard sourceFile in final release build but remain in internal build.
-renamesourcefileattribute SourceFile
# Keep Attribute
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod,SourceFile,LineNumberTable
# OrmLite uses reflection
-keep class com.j256.**
-keepclassmembers class com.j256.** { *; }
-keep enum com.j256.**
-keepclassmembers enum com.j256.** { *; }
-keep interface com.j256.**
-keepclassmembers interface com.j256.** { *; }
# OrmLite
-keep class com.j256.*
-keepclassmembers class com.j256.* { *; }
-keep enum com.j256.*
-keepclassmembers enum com.j256.* { *; }
-keep interface com.j256.*
-keepclassmembers interface com.j256.* { *; }
-dontwarn com.j256.**
#okhttp3
-dontwarn com.squareup.okhttp3.**
-dontwarn okio.**
-keep class com.squareup.okhttp3.** { *;}
# stetho
-keep class com.facebook.stetho.** { *; }
-dontwarn com.facebook.stetho.**
# Retrofit 2.2
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
# Retrofit 2.X
## https://square.github.io/retrofit/ ##
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
# rxjava
-keep class rx.schedulers.Schedulers {
public static <methods>;
}
-keep class rx.schedulers.ImmediateScheduler {
public <methods>;
}
-keep class rx.schedulers.TestScheduler {
public <methods>;
}
-keep class rx.schedulers.Schedulers {
public static ** test();
}
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
long producerNode;
long consumerNode;
}
-dontwarn rx.internal.util.**
## AutoScrollViewPager
-keep class cn.trinea.android.** { *; }
-keepclassmembers class cn.trinea.android.** { *; }
### AutoScrollViewPager
-keep class cn.trinea.android.* { *; }
-keepclassmembers class cn.trinea.android.* { *; }
-dontwarn cn.trinea.android.**
## butterknife
# Retain generated class which implement Unbinder.
#-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
#
## Prevent obfuscation of types which use ButterKnife annotations since the simple name
## is used to reflectively look up the generated ViewBinding.
#-keep class butterknife.*
#-keepclasseswithmembernames class * { @butterknife.* <methods>; }
#-keepclasseswithmembernames class * { @butterknife.* <fields>; }
### Butterknife
-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
-keep class butterknife.*
-keepclasseswithmembernames class * { @butterknife.* <methods>; }
-keepclasseswithmembernames class * { @butterknife.* <fields>; }
-dontwarn butterknife.internal.**
-keep class **$$ViewInjector { *; }
-keepnames class * { @butterknife.InjectView *;}
-dontwarn butterknife.Views$InjectViewProcessor
-dontwarn com.gc.materialdesign.views.**
# eventbus
-keepattributes *Annotation*
-keepclassmembers class ** {
### eventbus
-keepclassmembers class * {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
### Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}
# weiboSdk
-keep class com.sina.weibo.sdk.** { *; }
### weiboSdk
-keep class com.sina.weibo.sdk.* { *; }
-dontwarn android.webkit.WebView
-dontwarn android.webkit.WebViewClient
# app models
-keep class com.gh.common.view.** {*;}
-keep class com.gh.gamecenter.db.info.** {*;}
-keep class com.gh.gamecenter.entity.** {*;}
-keep class com.gh.gamecenter.qa.entity.** {*;}
-keep class com.gh.gamecenter.retrofit.** {*;}
-keep class com.gh.gamecenter.eventbus.** {*;}
-keep class * extends rx.Subscriber
### app models
-keep class com.gh.common.view.* {*;}
-keep class com.gh.gamecenter.db.info.* {*;}
-keep class com.gh.gamecenter.entity.* {*;}
-keep class com.gh.gamecenter.qa.entity.* {*;}
-keep class com.gh.gamecenter.retrofit.* {*;}
-keep class com.gh.gamecenter.eventbus.* {*;}
-keep class com.gh.gamecenter.video.detail.* {*;}
#---------------------------------webview------------------------------------
###
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
@ -153,93 +72,54 @@
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String);
}
#----------------------------------------------------------------------------
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
-keepclassmembers enum * { *; }
##---------------End: proguard configuration for Gson ----------
# ------ bugly ---------
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# easypermission
### easypermission
-keepclassmembers class * {
@pub.devrel.easypermissions.AfterPermissionGranted <methods>;
}
# 重命名文件为SourceFile再配合mapping符号表可以拿到真实的类名
-renamesourcefileattribute SourceFile
# 保留源文件行号
-keepattributes SourceFile,LineNumberTable
# TODO What's this ?
-ignorewarnings
### Keep Annotation
-keep @androidx.annotation.Keep class *
-keepclassmembers class ** {
-keepclassmembers class * {
@androidx.annotation.Keep *;
}
-keep class com.gh.loghub.** { *; }
### LoghubHelper
-keep class com.gh.loghub.* { *; }
### greenDAO 3
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
-keep class org.greenrobot.greendao.** { *; }
-keep class **$Properties { *; }
-keep class org.greenrobot.greendao.* { *; }
# If you do not use SQLCipher:
-dontwarn org.greenrobot.greendao.database.**
# If you do not use RxJava:
-dontwarn rx.**
-dontwarn org.greenrobot.greendao.rx.**
-dontwarn org.greenrobot.greendao.**
### fastJson
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.** { *; }
-keepattributes Signature
-keepattributes Annotation
-keep class com.alibaba.fastjson.* { *; }
### 广点通
-dontwarn com.qq.gdt.action.**
-keep class com.qq.gdt.action.** {*;}
-keep class com.qq.gdt.action.* {*;}
### AndroidX
-keep class androidx.core.app.CoreComponentFactory { *; }
#阿里云上传
-keep class com.alibaba.sdk.android.oss.** { *; }
### 阿里云上传
-keep class com.alibaba.sdk.android.oss.* { *; }
-dontwarn okio.**
-dontwarn org.apache.commons.codec.binary.**
#视频相关
-keep class com.shuyu.gsyvideoplayer.video.** { *; }
### 视频相关
-keep class com.shuyu.gsyvideoplayer.video.* { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.**
-keep class com.shuyu.gsyvideoplayer.video.base.** { *; }
-keep class com.shuyu.gsyvideoplayer.video.base.* { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.base.**
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
-keep class com.shuyu.gsyvideoplayer.utils.* { *; }
-dontwarn com.shuyu.gsyvideoplayer.utils.**
-keep class tv.danmaku.ijk.** { *; }
-keep class tv.danmaku.ijk.* { *; }
-dontwarn tv.danmaku.ijk.**
-keep public class * extends android.view.View{
*** get*();
@ -249,23 +129,10 @@
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#穿山甲
-keep class com.bytedance.sdk.openadsdk.** { *; }
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
-keep class com.pgl.sys.ces.* {*;}
-keep class com.gyf.immersionbar.* {*;}
-dontwarn com.gyf.immersionbar.**
-keep class com.taobao.securityjni.**{*;}
-keep class com.taobao.wireless.security.**{*;}
-keep class com.ut.secbody.**{*;}
-keep class com.taobao.dp.**{*;}
-keep class com.alibaba.wireless.security.**{*;}
-keep class com.alibaba.sdk.android.**{*;}
-keep class com.ut.**{*;}
-keep class com.ta.**{*;}
-keep class com.alibaba.sdk.android.*{*;}
-keep class com.ut.*{*;}
-keep class com.ta.*{*;}
### GDT & TEA
-keep class com.gh.gamecenter.GdtHelper { *; }
-keep class com.gh.gamecenter.TeaHelper { *; }

View File

@ -31,6 +31,8 @@ object GdtHelper {
GDTAction.init(application, "1111012969", "9d3d9da5b0948a317c03d08f14d445dc")
} else if (channel == "GH_729") {
GDTAction.init(application, "1111013063", "f53dabf458a356b101d99fc4069eb7f1")
} else if (channel == "GH_765") {
GDTAction.init(application, "1111327925", "588d503f0990f98f9b2394fbb795c570")
} else {
GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a")
}

View File

@ -23,8 +23,12 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 允许应用程序打开系统窗口,显示其他应用程序 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 创建快捷方式的权限 -->
<!-- 允许应用程序快捷方式 -->
<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"
@ -603,6 +607,26 @@
android:name=".forum.search.ForumOrUserSearchActivity"
android:screenOrientation="portrait" />
<activity
android:name=".energy.EnergyCenterActivity"
android:screenOrientation="portrait" />
<activity
android:name=".energy.EnergyHouseActivity"
android:screenOrientation="portrait" />
<activity
android:name=".personal.NewPersonalActivity"
android:screenOrientation="portrait" />
<activity
android:name=".qa.questions.draft.QuestionDraftActivity"
android:screenOrientation="portrait" />
<activity
android:name=".home.skip.PackageSkipActivity"
android:screenOrientation="portrait" />
<!-- &lt;!&ndash; 使用小米/华为推送弹窗功能提高推送成功率&ndash;&gt;-->
<!-- <activity-->
<!-- android:name="com.gh.gamecenter.PushProxyActivity"-->

View File

@ -25,8 +25,9 @@ import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeoutException;
import io.sentry.core.Sentry;
import io.sentry.Sentry;
public class AppUncaughtHandler implements UncaughtExceptionHandler {
@ -38,19 +39,21 @@ public class AppUncaughtHandler implements UncaughtExceptionHandler {
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
new Thread(new Runnable() {
@Override
public void run() {
public void uncaughtException(Thread t, Throwable e) {
if (("FinalizerWatchdogDaemon").equals(t.getName())
&& e instanceof TimeoutException) {
// ignore timeoutException
// detail can be found in this didi tech blog post https://mp.weixin.qq.com/s?__biz=MzU1ODEzNjI2NA==&mid=2247487185&idx=2&sn=cf2d9e10053f625bde0f61d246f14870&source=41#wechat_redirect
} else {
new Thread(() -> {
Looper.prepare();
Utils.toast(mContext.getApplicationContext(), "\"光环助手\"发生错误");
Looper.loop();
}
});
saveLocalLog(mContext, ex);
Sentry.captureException(ex);
restart(mContext);
});
saveLocalLog(mContext, e);
restart(mContext);
Sentry.captureException(e);
}
}
public static void restart(final Context context) {

View File

@ -8,6 +8,8 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Parcel;
import android.os.TransactionTooLargeException;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
@ -41,6 +43,7 @@ import com.gh.gamecenter.LoginActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SplashScreenActivity;
import com.gh.gamecenter.eventbus.EBShowDialog;
import com.halo.assistant.HaloApp;
import com.lightgame.BaseAppCompatActivity;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
@ -72,6 +75,8 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
public final static String DOWNLOAD_HIJACK = "hijack";
public final static String LOGIN_EXCEPTION = "loginException";
public final static String PLUGGABLE = "plugin";
public final static int ID_ROOT_INDICATOR = 999;
public final int MAX_BUNDLE_SIZE = 300;
@NonNull
protected String mEntrance;
@ -116,6 +121,7 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (useEventBus()) EventBus.getDefault().register(this);
if (useButterKnife()) ButterKnife.bind(this);
mEntrance = getIntent().getStringExtra(KEY_ENTRANCE);
@ -206,6 +212,7 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
tv.measure(0, 0);
tv.setAlpha(0.15F);
tv.setId(ID_ROOT_INDICATOR);
int height = tv.getMeasuredHeight();
int width = tv.getMeasuredWidth();
tv.setPadding(DisplayUtils.dip2px(20), 0, DisplayUtils.dip2px(20), 0);
@ -359,4 +366,30 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
}
return resources;
}
/**
* ActivityThread每次调用onSaveInstanceState时outState大小都会累加最终会导致{@link TransactionTooLargeException}异常
* 解决方案判断每次获取到的outState大小当达到300k时手动clear掉
*/
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
long bundleSize = getBundleSize(outState);
if (bundleSize > MAX_BUNDLE_SIZE * 1024) {
outState.clear();
}
}
private long getBundleSize(Bundle bundle) {
long dataSize;
Parcel obtain = Parcel.obtain();
try {
obtain.writeBundle(bundle);
dataSize = obtain.dataSize();
} finally {
obtain.recycle();
}
return dataSize;
}
}

View File

@ -9,15 +9,18 @@ import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.webkit.JavascriptInterface
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import butterknife.OnClick
import com.gh.common.util.DialogUtils
import com.gh.common.util.MtaHelper
import com.gh.common.AppExecutor
import com.gh.common.util.*
import com.gh.common.view.RichEditor
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity
import com.gh.gamecenter.qa.article.edit.ArticleEditActivity
import com.gh.gamecenter.qa.editor.GameActivity
import com.gh.gamecenter.qa.editor.InsertAnswerWrapperActivity
import com.gh.gamecenter.qa.editor.InsertArticleWrapperActivity
@ -26,6 +29,7 @@ import com.gh.gamecenter.qa.entity.AnswerEntity
import com.gh.gamecenter.qa.entity.ArticleEntity
import com.gh.gamecenter.qa.entity.EditorInsertEntity
import com.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_Keyboard
import com.lightgame.utils.Utils
import com.lightgame.view.CheckableImageView
import kotterknife.bindView
@ -33,15 +37,15 @@ import kotterknife.bindView
abstract class BaseRichEditorActivity : ToolBarActivity() {
val mRichEditor by bindView<RichEditor>(R.id.rich_editor)
val mDraftBtn by bindView<TextView>(R.id.draft_btn)
private val mEditorTextNumTv by bindView<TextView>(R.id.editorTextNumTv)
private val mEditorFont by bindView<CheckableImageView>(R.id.editor_font)
private val mEditorLink by bindView<CheckableImageView>(R.id.editor_link)
private val mEditorParagraph by bindView<CheckableImageView>(R.id.editor_paragraph)
private val mEditorFontBold by bindView<CheckableImageView>(R.id.editor_font_bold)
private val mEditorFontItalic by bindView<CheckableImageView>(R.id.editor_font_italic)
private val mEditorFontStrikeThrough by bindView<CheckableImageView>(R.id.editor_font_strikethrough)
private val mEditorFontUnderline by bindView<CheckableImageView>(R.id.editor_font_underline)
private val mEditorParagraphH1 by bindView<CheckableImageView>(R.id.editor_paragraph_h1)
private val mEditorParagraphH2 by bindView<CheckableImageView>(R.id.editor_paragraph_h2)
private val mEditorParagraphH3 by bindView<CheckableImageView>(R.id.editor_paragraph_h3)
@ -50,9 +54,15 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
private val mEditorFontContainer by bindView<View>(R.id.editor_font_container)
private val mEditorParagraphContainer by bindView<View>(R.id.editor_paragraph_container)
private val mEditorLinkContainer by bindView<View>(R.id.editor_link_container)
private val mEditorInsertDetail by bindView<View>(R.id.editor_insert_detail)
private val mEditorInsertDetailContainer by bindView<View>(R.id.editor_insert_detail_container)
val mAddLabelContainer by bindView<View>(R.id.add_label_container)
val mAddLabelTv by bindView<TextView>(R.id.add_label_tv)
val mLabelNumTv by bindView<TextView>(R.id.label_num_tv)
val mLabelArrowIv by bindView<ImageView>(R.id.label_arrow)
val mTagsContainer by bindView<FrameLayout>(R.id.tagsContainer)
private var mCurrentParagraphStyle = ""
private var mIsExtendedKeyboardShow = false
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -63,29 +73,50 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
when (requestCode) {
INSERT_ANSWER_CODE -> {
val answer = data?.getParcelableExtra<AnswerEntity>(AnswerEntity::class.java.simpleName)
if (answer != null) insertData = EditorInsertEntity.transform(answer)
if (answer != null) {
mRichEditor.focusEditor()
insertData = EditorInsertEntity.transform(answer)
mRichEditor.insertCustomStyleLink(insertData)
}
}
INSERT_ARTICLE_CODE -> {
val article = data?.getParcelableExtra<ArticleEntity>(ArticleEntity::class.java.simpleName)
if (article != null) insertData = EditorInsertEntity.transform(article)
if (article != null) {
mRichEditor.focusEditor()
insertData = EditorInsertEntity.transform(article)
mRichEditor.insertCustomStyleLink(insertData)
}
}
INSERT_GAME_CODE -> {
val game = data?.getParcelableExtra<GameEntity>(GameEntity::class.java.simpleName)
if (game != null) insertData = EditorInsertEntity.transform(game)
if (game != null) {
mRichEditor.focusEditor()
insertData = EditorInsertEntity.transform(game)
mRichEditor.insertCustomStyleLink(insertData)
}
}
VideoActivity.INSERT_VIDEO_CODE -> {
val video = data?.getParcelableExtra<MyVideoEntity>(MyVideoEntity::class.java.simpleName)
if (video != null) mRichEditor.insertCustomVideo(video)
return
if (video != null) {
mRichEditor.focusEditor()
mRichEditor.insertCustomVideo(video)
}
}
}
closeExtendedKeyboard()
AppExecutor.uiExecutor.executeWithDelay(Runnable {
Util_System_Keyboard.showSoftKeyboard(this)
}, 100)
AppExecutor.uiExecutor.executeWithDelay(Runnable {
mRichEditor.scrollTo(0, 1000000)
}, 500)
mRichEditor.insertCustomStyleLink(insertData)
}
@SuppressLint("AddJavascriptInterface")
@SuppressLint("AddJavascriptInterface", "ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAddLabelContainer.visibility = if (this is ArticleEditActivity) View.VISIBLE else View.GONE
mRichEditor.setPadding(20, 15, 20, 15)
// 防止个别手机在Js里无法获取粘贴内容
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
@ -93,12 +124,59 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
mRichEditor.addJavascriptInterface(OnEditorTextChangeListener(), "OnEditorTextChangeListener")
mRichEditor.setInputEnabled(true)
mDraftBtn.text = if (this is AnswerEditActivity) {
"回答草稿"
} else "帖子草稿"
mRichEditor.setOnTouchListener { _, _ ->
if (mIsExtendedKeyboardShow) {
closeExtendedKeyboard()
Util_System_Keyboard.showSoftKeyboard(this)
//是否消费事件根据mRichEditor是否含有焦点决定mRichEditor没有焦点则不消费事件
mRichEditor.hasFocus()
} else false
}
}
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.editor_paragraph,
fun closeExtendedKeyboard() {
mEditorInsertDetailContainer.visibility = View.GONE
mEditorFont.isChecked = false
mEditorLink.isChecked = false
mAddLabelContainer.isSelected = false
mIsExtendedKeyboardShow = false
}
protected fun controlEditorInsertContainerEnabled(isEnabled: Boolean) {
mEditorFont.isEnabled = isEnabled
}
fun changeAddLabel(isLabelContainerShow: Boolean) {
if (isLabelContainerShow) {
mLabelNumTv.visibility = View.GONE
mLabelArrowIv.visibility = View.VISIBLE
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.theme_font))
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
mAddLabelContainer.background = ContextCompat.getDrawable(this, R.drawable.bg_editor_insert_add_label)
} else {
val selectedLabel = getSelectedLabel()
if (selectedLabel == 0) {
mAddLabelTv.text = "添加标签"
mLabelNumTv.visibility = View.GONE
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.text_666666))
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(this, R.drawable.ic_add_label), null, null, null)
} else {
mAddLabelTv.text = "标签"
mLabelNumTv.visibility = View.VISIBLE
mLabelNumTv.text = selectedLabel.toString()
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.theme_font))
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
}
mLabelArrowIv.visibility = View.GONE
mAddLabelContainer.background = ContextCompat.getDrawable(this, R.drawable.border_round_stroke_eee_999)
}
}
open fun getSelectedLabel(): Int = 0
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.add_label_container, R.id.editor_font_underline,
R.id.editor_font_bold, R.id.editor_font_italic, R.id.editor_font_strikethrough,
R.id.editor_paragraph_h1, R.id.editor_paragraph_h2, R.id.editor_paragraph_h3,
R.id.editor_paragraph_h4, R.id.editor_font_container, R.id.editor_paragraph_container,
@ -107,31 +185,13 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
fun onRichClick(view: View) {
when (view.id) {
R.id.editor_font -> {
mEditorFont.isChecked = !mEditorFont.isChecked
mEditorParagraph.isChecked = false
mEditorLink.isChecked = false
mEditorFontContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorParagraphContainer.visibility = if (!mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = if (!mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorInsertDetail.visibility = mEditorFontContainer.visibility
}
R.id.editor_paragraph -> {
mEditorParagraph.isChecked = !mEditorParagraph.isChecked
mEditorFont.isChecked = false
mEditorLink.isChecked = false
mEditorParagraphContainer.visibility = if (mEditorParagraph.isChecked) View.VISIBLE else View.GONE
mEditorFontContainer.visibility = if (!mEditorParagraph.isChecked) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = if (!mEditorParagraph.isChecked) View.VISIBLE else View.GONE
mEditorInsertDetail.visibility = mEditorParagraphContainer.visibility
controlEditorFontContainer()
}
R.id.editor_link -> {
mEditorLink.isChecked = !mEditorLink.isChecked
mEditorFont.isChecked = false
mEditorParagraph.isChecked = false
mEditorLinkContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorParagraphContainer.visibility = if (!mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorFontContainer.visibility = if (!mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorInsertDetail.visibility = mEditorLinkContainer.visibility
controlEditorLinkContainer()
}
R.id.add_label_container -> {
controlAddLabelContainer()
}
R.id.editor_font_bold -> {
mEditorFontBold.isChecked = !mEditorFontBold.isChecked
@ -155,6 +215,14 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-删除线")
}
}
R.id.editor_font_underline -> {
mEditorFontUnderline.isChecked = !mEditorFontUnderline.isChecked
mRichEditor.setUnderline()
if (mEditorFontUnderline.isChecked) {
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-下滑线")
}
}
R.id.editor_paragraph_h1 -> {
if (mEditorParagraphH1.isChecked) {
mRichEditor.formatBlock()
@ -213,12 +281,93 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
startActivityForResult(GameActivity.getIntent(this, GameActivity.INSERT_GAME_TITLE), INSERT_GAME_CODE)
}
R.id.editor_link_video -> {
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-视频")
startActivityForResult(VideoActivity.getIntent(this), VideoActivity.INSERT_VIDEO_CODE)
PermissionHelper.checkStoragePermissionBeforeAction(this,
object : EmptyCallback {
override fun onCallback() {
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-视频")
startActivityForResult(VideoActivity.getIntent(this@BaseRichEditorActivity), VideoActivity.INSERT_VIDEO_CODE)
}
})
}
}
}
private fun controlEditorFontContainer() {
mEditorFont.isChecked = !mEditorFont.isChecked
mEditorLink.isChecked = false
mAddLabelContainer.isSelected = false
val isShouldDelay = if (mEditorFont.isChecked) {
Util_System_Keyboard.hideSoftKeyboard(this)
true
} else {
Util_System_Keyboard.showSoftKeyboard(this)
false
}
mEditorInsertDetailContainer.postDelayed({
mEditorInsertDetailContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorFontContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorParagraphContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = View.GONE
mTagsContainer.visibility = View.GONE
mIsExtendedKeyboardShow = mEditorFont.isChecked
changeAddLabel(false)
}, if (isShouldDelay) 200 else 0L)
}
private fun controlEditorLinkContainer() {
mEditorLink.isChecked = !mEditorLink.isChecked
mEditorFont.isChecked = false
mAddLabelContainer.isSelected = false
val isShouldDelay = if (mEditorLink.isChecked) {
Util_System_Keyboard.hideSoftKeyboard(this)
true
} else {
Util_System_Keyboard.showSoftKeyboard(this)
false
}
mEditorInsertDetailContainer.postDelayed({
mEditorInsertDetailContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorFontContainer.visibility = View.GONE
mEditorParagraphContainer.visibility = View.GONE
mTagsContainer.visibility = View.GONE
mIsExtendedKeyboardShow = mEditorLink.isChecked
changeAddLabel(false)
}, if (isShouldDelay) 200 else 0L)
}
fun controlAddLabelContainer() {
mEditorLink.isChecked = false
mEditorFont.isChecked = false
mAddLabelContainer.isSelected = !mAddLabelContainer.isSelected
val isShouldDelay = if (mAddLabelContainer.isSelected) {
Util_System_Keyboard.hideSoftKeyboard(this)
changeAddLabel(true)
true
} else {
Util_System_Keyboard.showSoftKeyboard(this)
changeAddLabel(false)
false
}
mEditorInsertDetailContainer.postDelayed({
mEditorInsertDetailContainer.visibility = if (mAddLabelContainer.isSelected) View.VISIBLE else View.GONE
mTagsContainer.visibility = if (mAddLabelContainer.isSelected) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = View.GONE
mEditorFontContainer.visibility = View.GONE
mEditorParagraphContainer.visibility = View.GONE
mIsExtendedKeyboardShow = mAddLabelContainer.isSelected
}, if (isShouldDelay) 200 else 0L)
}
override fun handleBackPressed(): Boolean {
if (mIsExtendedKeyboardShow) {
closeExtendedKeyboard()
return true
}
return super.handleBackPressed()
}
private inner class OnCursorChangeListener {
@JavascriptInterface
fun onElements(elements: String) {
@ -237,6 +386,7 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
mEditorFontBold.isChecked = elements.contains(ELEMENT_NAME_BOLD)
mEditorFontItalic.isChecked = elements.contains(ELEMENT_NAME_ITALIC)
mEditorFontStrikeThrough.isChecked = elements.contains(ELEMENT_NAME_STRIKE)
mEditorFontUnderline.isChecked = elements.contains(ELEMENT_NAME_UNDERLINE)
mEditorParagraphH1.isChecked = elements.contains(ELEMENT_PARAGRAPH_H1)
mEditorParagraphH2.isChecked = elements.contains(ELEMENT_PARAGRAPH_H2)
mEditorParagraphH3.isChecked = elements.contains(ELEMENT_PARAGRAPH_H3)
@ -264,7 +414,9 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
@JavascriptInterface
fun onTextChange(count: Int) {
val num = if (count > MAX_INPUT_TEXT_NUM) MAX_INPUT_TEXT_NUM - count else count
mEditorTextNumTv.text = num.toString()
mEditorTextNumTv.post {
mEditorTextNumTv.text = num.toString()
}
}
}
@ -274,6 +426,7 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
const val ELEMENT_NAME_BOLD = " b "
const val ELEMENT_NAME_ITALIC = " i "
const val ELEMENT_NAME_STRIKE = " strike "
const val ELEMENT_NAME_UNDERLINE = " u "
const val ELEMENT_PARAGRAPH_H1 = " h1 "
const val ELEMENT_PARAGRAPH_H2 = " h2 "
const val ELEMENT_PARAGRAPH_H3 = " h3 "

View File

@ -7,6 +7,7 @@ import android.os.Bundle;
import com.gh.common.notifier.Notifier;
import com.gh.common.util.DataUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.SplashScreenActivity;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.AppManager;
@ -41,7 +42,9 @@ public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallba
//FIXME 这里应该只是部分Activity需要
try {
// 初始化gameMap
DownloadManager.getInstance(activity).initGameMap();
if (!(activity instanceof SplashScreenActivity)) {
DownloadManager.getInstance(activity).initGameMap();
}
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -0,0 +1,17 @@
package com.gh.base
import java.util.concurrent.ThreadFactory
import java.util.concurrent.atomic.AtomicInteger
class GHThreadFactory(threadNamePrefix: String) : ThreadFactory {
private val THREAD_NAME_STEM = "${threadNamePrefix}_%d"
private val mThreadId = AtomicInteger(0)
override fun newThread(r: Runnable?): Thread {
val t = Thread(r)
t.name = String.format(THREAD_NAME_STEM, mThreadId.getAndIncrement())
return t
}
}

View File

@ -9,6 +9,8 @@ import com.gh.gamecenter.R;
import com.lightgame.utils.RuntimeUtils;
import com.lightgame.utils.Utils;
import java.lang.reflect.Field;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
@ -29,7 +31,7 @@ public class BaseDialogFragment extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Dialog dialog = new Dialog(getActivity(), R.style.DialogWindowTransparent);
final Dialog dialog = new Dialog(getActivity(), getThemeRes());
dialog.setCanceledOnTouchOutside(false);
dialog.setOnKeyListener((dialog1, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK && !ClickUtils.isFastDoubleClick()) {
@ -41,6 +43,10 @@ public class BaseDialogFragment extends DialogFragment {
return dialog;
}
public int getThemeRes() {
return R.style.DialogWindowTransparent;
}
public void toast(@StringRes int res) {
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED))
toast(getString(res));
@ -71,7 +77,22 @@ public class BaseDialogFragment extends DialogFragment {
transaction.show(fragment);
transaction.commit();
} else {
super.show(manager, tag);
try {
Class<?> clazz = DialogFragment.class;
Field dismissed = clazz.getDeclaredField("mDismissed");
dismissed.setAccessible(true);
dismissed.set(this, false);
Field shownByMe = clazz.getDeclaredField("mShownByMe");
shownByMe.setAccessible(true);
shownByMe.set(this, true);
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(this, tag);
transaction.commitAllowingStateLoss();
} catch (Exception e) {
super.show(manager, tag);
e.printStackTrace();
}
}
}
}

View File

@ -10,6 +10,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentManager;
import com.gh.common.util.ExtensionsKt;
import com.gh.gamecenter.R;
/**
@ -87,7 +88,11 @@ public class WaitingDialogFragment extends BaseDialogFragment {
@Override
public void dismissAllowingStateLoss() {
mBackListener = null;
super.dismissAllowingStateLoss();
try {
super.dismissAllowingStateLoss();
} catch (Exception e) {
e.printStackTrace();
}
}
public static class WaitingDialogData {

View File

@ -2,12 +2,13 @@ package com.gh.common
import android.os.Handler
import android.os.Looper
import com.gh.base.GHThreadFactory
import com.gh.common.AppExecutor.ioExecutor
import com.gh.common.AppExecutor.lightWeightIoExecutor
import com.gh.common.AppExecutor.logExecutor
import com.gh.common.AppExecutor.uiExecutor
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.Executor
import java.util.concurrent.Executors
import java.util.concurrent.*
/**
* APP 线程池管理类
@ -15,16 +16,30 @@ import java.util.concurrent.Executors
* [ioExecutor] 是一个最大线程数固定的线程池,较为繁重的 IO 任务可以交给它
* [uiExecutor] 是主线程的包裹,需要切换至主线程执行可以用它
* [lightWeightIoExecutor] 是一个单线程的线程池,轻量级且需要保证同一线程的 IO 任务可以交给它
*
* [logExecutor] 只为上传 log 而使用的线程池
*/
object AppExecutor {
private val mCoreSize = Runtime.getRuntime().availableProcessors()
private val mMinimumPoolSize = 6.coerceAtLeast(mCoreSize * 2)
private val mMaximumPoolSize = 32.coerceAtLeast(mCoreSize * 8)
@JvmStatic
val uiExecutor by lazy { MainThreadExecutor() }
@JvmStatic
val lightWeightIoExecutor by lazy { Executors.newSingleThreadExecutor() }
val lightWeightIoExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_LIGHT_WEIGHT_IO_THREAD")) }
@JvmStatic
val ioExecutor = Executors.newCachedThreadPool() // 用 by lazy 可能影响初始化速度
val logExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_LOG_THREAD")) }
@JvmStatic
val ioExecutor = ThreadPoolExecutor(
mMinimumPoolSize,
mMaximumPoolSize,
20L, TimeUnit.SECONDS,
LinkedBlockingQueue<Runnable>(1000),
GHThreadFactory("GH_IO_THREAD"))
val cachedScheduler by lazy { Schedulers.from(ioExecutor) }

View File

@ -17,6 +17,8 @@ import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.entity.Badge
import com.gh.gamecenter.entity.MtaEvent
import com.gh.gamecenter.entity.NotificationUgc
import com.gh.gamecenter.energy.EnergyCenterActivity
import com.gh.gamecenter.energy.EnergyHouseActivity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
@ -115,6 +117,7 @@ class DefaultJsApi(var context: Context) {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
EnergyTaskHelper.postEnergyTask("bind_wechat")
handler.complete(true)
}
@ -198,6 +201,7 @@ class DefaultJsApi(var context: Context) {
@JavascriptInterface
fun updateRegulationTestStatus(msg: Any) {
if (msg.toString().toLowerCase(Locale.getDefault()) == "pass") {
EnergyTaskHelper.postEnergyTask("finish_etiquette_exam")
SPUtils.setString(Constants.SP_REGULATION_TEST_PASS_STATUS, "pass")
}
}
@ -228,6 +232,20 @@ class DefaultJsApi(var context: Context) {
MessageShareUtils.getInstance(context).shareFromWeb(context, imageShareEvent.type)
}
@JavascriptInterface
fun inviteFriends(event: Any) {
val inviteEvent = event.toString().toObject() ?: InviteFriendsEvent()
val context = CurrentActivityHolder.getCurrentActivity()
if ("poster" == inviteEvent.type) {
Base64ImageHolder.image = inviteEvent.poster.run {
if (this.startsWith("data:image/png;base64")) this.split(",")[1] else this
}
MessageShareUtils.getInstance(context).shareFromWeb(context, inviteEvent.way)
} else {
ShareUtils.getInstance(context).shareInviteFriends(context, inviteEvent.url, inviteEvent.way)
}
}
@JavascriptInterface
fun bindPhone(msg: Any) {
val intent = BindPhoneActivity.getNormalIntent(context, false)
@ -257,10 +275,31 @@ class DefaultJsApi(var context: Context) {
runOnUiThread { DirectUtils.directToWebView(context, url.toString(), "内部网页") }
}
@JavascriptInterface
fun postWearBadgeTask(msg: Any) {
EnergyTaskHelper.postEnergyTask("wear_badge")
}
@JavascriptInterface
fun startEnergyCenter(msg: Any) {
context.startActivity(EnergyCenterActivity.getIntent(context))
}
@JavascriptInterface
fun startEnergyHouse(msg: Any) {
context.startActivity(EnergyHouseActivity.getIntent(context))
}
@Keep
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)
@Keep
internal data class ImageShareEvent(var image: String = "", var type: String = "")
@Keep
internal data class InviteFriendsEvent(var type: String = "",
var way: String = "",
var url: String = "",
var poster: String = "")
}

View File

@ -344,6 +344,11 @@ object DefaultUrlHandler {
return true
}
// 处理内部页面逻辑
if (transformNormalScheme(context, url, entrance)) {
return true
}
if ("http" != uri.scheme && "https" != uri.scheme) return true
return false
}
@ -360,7 +365,7 @@ object DefaultUrlHandler {
uri.path?.apply {
when {
contains("game") -> {
val gameId = uri.getQueryParameter("gameId") ?: ""
val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last() ?: ""
DirectUtils.directToGameDetail(context, gameId, entrance, autoDownload = false, traceEvent = null)
}
contains("question") -> {

View File

@ -11,6 +11,7 @@ import com.gh.gamecenter.entity.TimeEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
import kotlin.concurrent.fixedRateTimer
object FixedRateJobHelper {
@ -35,7 +36,7 @@ object FixedRateJobHelper {
// 时间校对10分钟一次
if ((mExecuteCount * CHECKER_PERIOD) % TIME_PERIOD == 0L) {
RetrofitManager.getInstance(HaloApp.getInstance().application).api.time
.subscribeOn(AppExecutor.cachedScheduler)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<TimeEntity>() {
override fun onResponse(response: TimeEntity?) {
val serverTime = response?.time

View File

@ -5,6 +5,7 @@ import android.app.Application
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import com.gh.base.GHThreadFactory
import com.halo.assistant.HaloApp
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
@ -29,31 +30,31 @@ class TimeElapsedHelper(val fragment: Fragment?, val activity: Activity?) {
init {
activity?.application?.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
override fun onActivityStarted(a: Activity?) {
override fun onActivityStarted(a: Activity) {
}
override fun onActivitySaveInstanceState(a: Activity?, outState: Bundle?) {
override fun onActivitySaveInstanceState(a: Activity, outState: Bundle) {
}
override fun onActivityStopped(a: Activity?) {
override fun onActivityStopped(a: Activity) {
}
override fun onActivityCreated(a: Activity?, savedInstanceState: Bundle?) {
override fun onActivityCreated(a: Activity, savedInstanceState: Bundle?) {
}
override fun onActivityPaused(a: Activity?) {
override fun onActivityPaused(a: Activity) {
if (activity == a) {
pauseCounting()
}
}
override fun onActivityResumed(a: Activity?) {
override fun onActivityResumed(a: Activity) {
if (activity == a) {
resumeCounting()
}
}
override fun onActivityDestroyed(a: Activity?) {
override fun onActivityDestroyed(a: Activity) {
if (activity == a) {
HaloApp.getInstance().application.unregisterActivityLifecycleCallbacks(this)
}
@ -114,7 +115,7 @@ class TimeElapsedHelper(val fragment: Fragment?, val activity: Activity?) {
}
object TimeElapsedThreadHolder {
val threadService: ExecutorService by lazy { Executors.newSingleThreadExecutor() }
val threadService: ExecutorService by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("TIME_ELAPSED_THREAD")) }
}
interface TimeoutCallback {

View File

@ -56,7 +56,7 @@ public class Config {
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // ghzs/ghzs666 统一
public static final String PATCHES = "patches";
public static final String DEFAULT_CHANNEL = "GH_TEST";
public static final String DEFAULT_CHANNEL = "TEST";
private static String SETTINGS_KEY = "settingsKey";

View File

@ -27,12 +27,14 @@ public class Constants {
public static final String GAME_DETAIL_COME_IN = "game_detail_come_in"; // 从游戏详情进入
public static final String SPLASH_AD = "splash_ad"; // 启动广告
public static final String XPOSED_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer";
public static final String EB_QUIT_LOGIN = "quit_login";
public static final String EB_SHOW_AD = "show_ad";
// 用于避免历史下载掺和到普通下载状态的 ID 修饰符
public static final String GAME_ID_DIVIDER = ":";
// 用于避免历史下载影响到部分依赖名字作为数据更新条件的修饰符
public static final String GAME_NAME_DECORATOR = " ";
@ -49,10 +51,17 @@ public class Constants {
public static final String RAW_GAME_ICON = "raw_game_icon";
public static final String GAME_ICON_SUBSCRIPT = "game_icon_subscript";
// 下载 id一般来说跟下载文件名一样
public static final String DOWNLOAD_ID = "download_id";
public static final String GHZS_GAME_ID = "5ae4462c2924bc7936438d07";
public static final String EXTRA_DOWNLOAD_TYPE = "extra_download_type";
public static final String SILENT_UPDATE = "静默更新";
public static final String SIMULATOR_DOWNLOAD = "下载模拟器";
public static final String SIMULATOR_GAME = "simulator_game";
public static final String SIMULATOR = "simulator";
public static final String GAME_NAME = "game_name";
public static final String SIMULATOR_DOWNLOAD_START_TIME = "simulator_download_start_time";
public static final String LAST_GHZS_UPDATE_FILE_SIZE = "last_ghzs_update_file_size";
@ -61,6 +70,8 @@ public class Constants {
public static final String SP_IMEI = "imei";
public static final String SP_ANDROID_ID = "android_id";
public static final String LAST_INSTALL_GAME = "last_install_game";
//引导设置 “通知管理” 引导弹窗
public static final String SP_SHOWED_NOTIFICATION_LOGIN = "show_notification_login_hint";
@ -106,8 +117,6 @@ public class Constants {
public static final String SP_FILTER_TAGS = "filter_tags";
//实名认证弹窗分类数据
public static final String SP_AUTH_DIALOG = "auth_dialog";
//顶部视频进度保存,重启恢复
public static final String SP_TOP_VIDEO_SCHEDULE = "top_video_schedule";
//我的光环小红点提示
public static final String SP_GH_RED_POINT_REMIND = "gh_red_point_remind";
//论坛首页引导
@ -131,10 +140,24 @@ public class Constants {
public static final String SP_BRAND_NEW_USER = "brand_new_user";
//包名检测是否点击不再提示
public static final String SP_PACKAGE_CHECK = "package_check";
//游戏详情预约引导提示
public static final String SP_GAME_DETAIL_RESERVE_GUIDE = "game_detail_reserve_guide";
public static final String SP_XAPK_UNZIP_ACTIVITY = "xapk_unzip_activity";
public static final String SP_XAPK_URL = "xapk_url";
//首页视频播放进度
public static final String SP_HOME_VIDEO_PLAY_RECORD = "home_video_play_record";
// 用户是否曾经永久拒绝过存储权限
public static final String SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION = "user_has_permanently_denied_storage_permission";
// 是否已经填写邀请码
public static final String SP_HAS_COMPLETE_INVITE_CODE = "has_complete_invite_code";
// 签到提醒开关
public static final String SP_SIGN_REMIND = "sign_remind";
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
public static final String REGEX_ACCOUNT = "^[a-zA-Z_]\\w{5,17}$";
@ -169,6 +192,9 @@ public class Constants {
//版规声明
public static final String FORUM_REGULATIONS_NEWS_ID = "5f4db9cc34d44d01b92fd670";
// 权限使用场景地址
public static final String PERMISSION_SCENARIO_ADDRESS = "https://resource.ghzs.com/page/permissions/android.html";
//帮助内容详情
public static final String HELP_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_help_dev/help.html?content=";
public static final String HELP_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=";
@ -177,6 +203,30 @@ public class Constants {
public static final String LOGOUT_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_help_dev/help.html?content=5f6b1f02786564003944a693";
public static final String LOGOUT_ADDRESS = "https://static-web.ghzs.com/ghzs_help/help.html?content=5f534111b1f72909fc225672";
// 商品详情
public static final String COMMODITY_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/product?from=ghzs";
public static final String COMMODITY_DETAIL_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/product?from=ghzs";
// 光能记录
public static final String ENERGY_RECORD_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/record?from=ghzs";
public static final String ENERGY_RECORD_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/record?from=ghzs";
// 订单中心
public static final String ORDER_CENTER_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/orders?from=ghzs";
public static final String ORDER_CENTER_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/orders?from=ghzs";
// 订单详情
public static final String ORDER_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/order-detail?from=ghzs";
public static final String ORDER_DETAIL_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/order-detail?from=ghzs";
// 邀请好友
public static final String INVITE_FRIENDS_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_activity_dev/inviteFriends.html#/invite";
public static final String INVITE_FRIENDS_ADDRESS = "https://static-web.ghzs.com/ghzs_activity/inviteFriends.html#/invite";
// 等级页面
public static final String LEVEL_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs-userhome-dev/index.html#/level";
public static final String LEVEL_ADDRESS = "https://static-web.ghzs.com/ghzs-userhome/index.html#/level";
//最少需要多少数据才能上传
public static final int DATA_AMOUNT = 20;

View File

@ -4,6 +4,8 @@ import android.content.DialogInterface
import android.os.Bundle
import android.view.KeyEvent
import android.view.View
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import com.gh.common.util.MtaHelper
import com.lightgame.dialog.BaseDialogFragment
import java.util.concurrent.atomic.AtomicBoolean
@ -63,4 +65,29 @@ abstract class BaseTrackableDialogFragment : BaseDialogFragment() {
open fun trackWithBasicDeviceInfo() = false
override fun show(manager: FragmentManager, tag: String?) {
val fragment = manager.findFragmentByTag(tag)
if (fragment != null) {
val transaction = manager.beginTransaction()
transaction.show(fragment)
transaction.commit()
} else {
try {
val clazz: Class<*> = DialogFragment::class.java
val dismissed = clazz.getDeclaredField("mDismissed")
dismissed.isAccessible = true
dismissed[this] = false
val shownByMe = clazz.getDeclaredField("mShownByMe")
shownByMe.isAccessible = true
shownByMe[this] = true
val transaction = manager.beginTransaction()
transaction.add(this, tag)
transaction.commitAllowingStateLoss()
} catch (e: Exception) {
super.show(manager, tag)
e.printStackTrace()
}
}
}
}

View File

@ -215,7 +215,7 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
class LooperHandle(val mAdapter: BannerAdapter) : Handler() {
private val mWeakReference: WeakReference<BannerAdapter> = WeakReference(mAdapter)
override fun handleMessage(msg: Message?) {
override fun handleMessage(msg: Message) {
val adapter = mWeakReference.get()
adapter?.scrollToNextPage()
adapter?.startScroll()

View File

@ -1,5 +1,6 @@
package com.gh.common.dialog
import android.app.Dialog
import android.graphics.Paint
import android.os.Bundle
import android.util.TypedValue
@ -13,7 +14,6 @@ import androidx.core.text.HtmlCompat
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.util.DirectUtils
import com.gh.common.util.DisplayUtils
import com.gh.common.util.MtaHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.GameEntity
import kotlinx.android.synthetic.main.dialog_game_off_service.*
@ -21,7 +21,7 @@ import kotlinx.android.synthetic.main.dialog_game_off_service.*
// 游戏关闭下载弹窗
class GameOffServiceDialogFragment
// : BaseTrackableDialogFragment()
:BaseDialogFragment() {
: BaseDialogFragment() {
private var mDialog: GameEntity.Dialog? = null
@ -56,6 +56,10 @@ class GameOffServiceDialogFragment
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply { setCanceledOnTouchOutside(true) }
}
// override fun getEvent(): String {
// return "游戏下载状态按钮"
// }

View File

@ -67,7 +67,7 @@ class NotificationHintDialogFragment : BaseTrackableDialogFragment() {
activateTv.setOnClickListener {
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击立即开启")
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "${styleEntity.scenes}_${styleEntity.styleNo}_点击立即开启")
dismiss()
dismissAllowingStateLoss()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//这种方案适用于 API 26, 即8.0含8.0)以上可以用
val intent = Intent()
@ -80,7 +80,7 @@ class NotificationHintDialogFragment : BaseTrackableDialogFragment() {
}
closeIv.setOnClickListener {
dismiss()
dismissAllowingStateLoss()
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击关闭")
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "${styleEntity.scenes}_${styleEntity.styleNo}_点击关闭")
}

View File

@ -10,6 +10,7 @@ import android.widget.RelativeLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseRecyclerViewHolder
@ -107,7 +108,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private fun initListener(entity: PackageDialogEntity) {
binding.downloadBtn.setOnClickListener {
if (binding.noRemindAgainCb.isChecked) {
SPUtils.setBoolean(Constants.SP_PACKAGE_CHECK, true)
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity?.id}", true)
}
val isAllPackageInstalled = isAllPackageInstalled(entity)
if (isAllPackageInstalled) {
@ -126,7 +127,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
callBack?.onConfirm()
}
if (binding.noRemindAgainCb.isChecked) {
SPUtils.setBoolean(Constants.SP_PACKAGE_CHECK, true)
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity?.id}", true)
}
dismissAllowingStateLoss()
}
@ -254,12 +255,14 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
callBack.onConfirm()
return
}
val isChoose = SPUtils.getBoolean(Constants.SP_PACKAGE_CHECK, false)
val isChoose = SPUtils.getBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity.id}", false)
if (packageDialogEntity.level == "OPTIONAL_HINT" && isChoose) {
callBack.onConfirm()
return
}
if (!activity.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) return
var dialogFragment = activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.simpleName) as? PackageCheckDialogFragment
if (dialogFragment == null) {
dialogFragment = PackageCheckDialogFragment()
@ -280,11 +283,12 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
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 = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0).find { it.packageName == packageName } != null
packages.forEach { packageName ->
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
if (isInstalled) {
isPackagesInstalled = true
return@forEach

View File

@ -13,9 +13,13 @@ data class ExposureEntity(
val gameName: String? = "",
val gameVersion: String? = "",
val sequence: Int? = 0,
val outerSequence: Int? = 0,
val platform: String? = "",
var isMirrorData: Boolean = false,
val downloadType: String? = "",
val downloadCompleteType: String? = "",
@SerializedName("display_type")
val displayType: String? = "",
// 下载地址的 host 和 path
var host: String? = "",

View File

@ -10,6 +10,7 @@ import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.exposure.time.TimeUtil
import com.gh.common.util.getFirstElementDividedByDivider
import com.gh.gamecenter.entity.GameEntity
import com.lightgame.download.DownloadEntity
import kotlinx.android.parcel.Parcelize
import java.util.*
@ -35,13 +36,16 @@ data class ExposureEvent(
}
return ExposureEvent(
payload = ExposureEntity(
gameId = gameEntity?.id?.getFirstElementDividedByDivider(Constants.GAME_ID_DIVIDER),
gameName = gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
gameVersion = gameEntity?.gameVersion,
sequence = gameEntity?.sequence,
platform = gameEntity?.platform,
gameId = gameEntity?.id?.getFirstElementDividedByDivider(DownloadEntity.GAME_ID_DIVIDER),
gameName = eTrace?.firstOrNull()?.payload?.gameName ?: gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
gameVersion = eTrace?.firstOrNull()?.payload?.gameVersion ?:gameEntity?.gameVersion,
isMirrorData = eTrace?.firstOrNull()?.payload?.isMirrorData ?: gameEntity?.shouldUseMirrorInfo() ?: false,
sequence = eTrace?.firstOrNull()?.payload?.sequence ?: gameEntity?.sequence,
outerSequence = eTrace?.firstOrNull()?.payload?.outerSequence ?: gameEntity?.outerSequence,
platform = eTrace?.firstOrNull()?.payload?.platform ?:gameEntity?.platform,
downloadType = gameEntity?.downloadType,
downloadCompleteType = gameEntity?.downloadCompleteType,
displayType = eTrace?.firstOrNull()?.payload?.displayType ?:gameEntity?.displayContent,
// ugly
welcomeDialogId = gameEntity?.welcomeDialogId ?: eTrace?.firstOrNull()?.payload?.welcomeDialogId,
welcomeDialogLinkTitle = gameEntity?.welcomeDialogTitle ?: eTrace?.firstOrNull()?.payload?.welcomeDialogLinkTitle),

View File

@ -11,20 +11,16 @@ import io.reactivex.functions.Consumer
*/
class ExposureListener(var fragment: Fragment, var exposable: IExposable) : RecyclerView.OnScrollListener() {
var throttleBus: ExposureThrottleBus? = null
val throttleBus: ExposureThrottleBus by lazy { ExposureThrottleBus(Consumer { commitExposure(it) }, Consumer(Throwable::printStackTrace)) }
var layoutManager: LinearLayoutManager? = null
var visibleState: ExposureThrottleBus.VisibleState? = null
init {
fragment.fragmentManager?.registerFragmentLifecycleCallbacks(
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
throttleBus = ExposureThrottleBus(Consumer { commitExposure(it) }, Consumer(Throwable::printStackTrace))
}
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
visibleState?.let { commitExposure(it) }
throttleBus?.clear()
throttleBus.clear()
}
override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {
@ -44,7 +40,7 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
layoutManager?.run {
visibleState = ExposureThrottleBus.VisibleState(findFirstVisibleItemPosition(), findLastVisibleItemPosition())
throttleBus?.postVisibleState(visibleState!!)
throttleBus.postVisibleState(visibleState!!)
}
}

View File

@ -9,7 +9,7 @@ import com.gh.loghub.LgLOG
import com.gh.loghub.LoghubHelper
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import java.util.concurrent.Executors
import java.util.concurrent.ExecutorService
/**
* A handful tool for committing logs to aliyun loghub.
@ -31,17 +31,19 @@ object ExposureManager {
// exposureCache 用来过滤掉具有相同 id 的曝光事件,避免重复发送事件
private val exposureSet by lazy { hashSetOf<ExposureEvent>() }
private val exposureExecutor by lazy { Executors.newSingleThreadExecutor() }
private var exposureExecutor: ExecutorService? = null
private val exposureCache by lazy { FixedSizeLinkedHashSet<String>(300) }
private val exposureDao by lazy { ExposureDatabase.buildDatabase(HaloApp.getInstance().application).logHubEventDao() }
@JvmStatic
fun init() {
fun init(excutor: ExecutorService) {
loghubHelper.init(HaloApp.getInstance().application, ENDPOINT, PROJECT, LOG_STORE) { TimeUtil.currentTimeMillis() }
exposureExecutor.execute {
val eventList = exposureDao.getAll()
exposureSet.addAll(eventList)
exposureExecutor = excutor
exposureExecutor?.execute {
tryWithDefaultCatch {
val eventList = exposureDao.getAll()
exposureSet.addAll(eventList)
}
}
}
@ -49,7 +51,7 @@ object ExposureManager {
* Log a single exposure event.
*/
fun log(event: ExposureEvent) {
exposureExecutor.execute {
exposureExecutor?.execute {
try {
if (!exposureCache.contains(event.id)) {
// Catch `android.database.sqlite.SQLiteFullException: database or disk is full` exception.
@ -71,7 +73,7 @@ object ExposureManager {
* Log a collection of exposure event.
*/
fun log(eventList: List<ExposureEvent>) {
exposureExecutor.execute {
exposureExecutor?.execute {
for (event in eventList) {
try {
if (!exposureCache.contains(event.id)) {
@ -94,7 +96,7 @@ object ExposureManager {
* @param forced Ignore all restrictions.
*/
fun commitSavedExposureEvents(forced: Boolean = false) {
exposureExecutor.execute {
exposureExecutor?.execute {
tryWithDefaultCatch {
// TODO 初始化 loghubHelper 去掉这个 tryCatch 块
if (exposureSet.size < STORE_SIZE && !forced || exposureSet.size == 0) return@execute
@ -138,7 +140,7 @@ object ExposureManager {
return log
}
internal class FixedSizeLinkedHashSet<T>(var maxSize: Int) : LinkedHashSet<T>() {
class FixedSizeLinkedHashSet<T>(var maxSize: Int) : LinkedHashSet<T>() {
override fun add(element: T): Boolean {
if (size == maxSize) {
pop()

View File

@ -2,35 +2,39 @@ package com.gh.common.exposure
import android.text.TextUtils
import com.g00fy2.versioncompare.Version
import com.gh.common.constant.Constants
import com.gh.common.util.PackageUtils
import com.gh.common.util.toObject
import com.gh.gamecenter.entity.ApkEntity
import com.gh.gamecenter.entity.GameEntity
import com.halo.assistant.HaloApp
import java.util.*
import com.lightgame.download.DownloadEntity
object ExposureUtils {
private val mDownloadCompleteTraceEventIdSet = ExposureManager.FixedSizeLinkedHashSet<String>(3)
@JvmStatic
fun logADownloadExposureEvent(entity: GameEntity,
platform: String?,
traceEvent: ExposureEvent?,
downloadType: DownloadType): ExposureEvent {
val gameEntity = entity.clone()
gameEntity.id = if (entity.id.contains(Constants.GAME_ID_DIVIDER)) {
entity.id.split(Constants.GAME_ID_DIVIDER).toTypedArray()[0]
gameEntity.id = if (entity.id.contains(DownloadEntity.GAME_ID_DIVIDER)) {
entity.id.split(DownloadEntity.GAME_ID_DIVIDER).toTypedArray()[0]
} else {
entity.id
}
gameEntity.gameVersion = entity.getApk().elementAtOrNull(0)?.version ?: gameEntity.gameVersion
gameEntity.gameVersion = entity.getApk().elementAtOrNull(0)?.version
?: gameEntity.gameVersion
gameEntity.platform = platform
gameEntity.downloadType = downloadType.toString()
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
source = traceEvent?.source ?: ArrayList(),
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
event = ExposureType.DOWNLOAD)
ExposureManager.log(exposureEvent)
if (!TextUtils.isEmpty(entity.id)) {
ExposureManager.log(exposureEvent)
}
return exposureEvent
}
@ -45,6 +49,16 @@ object ExposureUtils {
gameEntity.platform = platform
gameEntity.downloadCompleteType = downloadType.toString()
val traceEvent = trace?.toObject<ExposureEvent>()
if (TextUtils.isEmpty(entity.id)) return
// 避免生成 trace 相同的下载完成事件,根据日志看下载完成的同一秒有可能生成两条
if (mDownloadCompleteTraceEventIdSet.contains(traceEvent?.id)) {
return
}
traceEvent?.payload?.gameId?.let { mDownloadCompleteTraceEventIdSet.add(it) }
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
source = traceEvent?.source ?: ArrayList(),
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
@ -80,6 +94,15 @@ object ExposureUtils {
}
}
@JvmStatic
fun updateExposureSequence(gameList: List<GameEntity>?) {
gameList?.let {
for ((index, game) in it.withIndex()) {
game.sequence = index
}
}
}
enum class DownloadType {
DOWNLOAD,

View File

@ -8,10 +8,10 @@ import kotlinx.android.parcel.Parcelize
@Parcelize
data class Meta(
val mac: String? = "",
val imei: String? = "",
val jnfj: String? = "",
val model: String? = "",
val manufacturer: String? = "",
val android_id: String? = "",
val dia: String? = "",
val android_sdk: Int? = -1,
val android_version: String? = "",
val network: String? = "",

View File

@ -11,6 +11,7 @@ import android.telephony.TelephonyManager
import android.text.TextUtils
import com.gh.common.constant.Constants
import com.gh.common.util.SPUtils
import com.gh.common.util.tryWithDefaultCatch
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.manager.UserManager
import com.halo.assistant.HaloApp
@ -26,13 +27,25 @@ object MetaUtil {
private var imei: String? = null
private var base64EncodedImei: String? = null
private var androidId: String? = null
private var base64EncodedAndroidId: String? = null
private var romName: String? = null
private var romVersion: String? = null
fun refreshMeta() {
if (romName == null) {
tryWithDefaultCatch {
romName = RomIdentifier.getRom().name
romVersion = RomIdentifier.getRom().versionName
}
}
m = Meta(mac = "",
imei = getIMEI(),
jnfj = getBase64EncodedIMEI(),
model = getModel(),
manufacturer = getManufacturer(),
android_id = getAndroidId(),
dia = getBase64EncodedAndroidId(),
android_sdk = getAndroidSDK(),
android_version = getAndroidVersion(),
network = getNetwork(),
@ -43,7 +56,7 @@ object MetaUtil {
appVersion = BuildConfig.VERSION_NAME,
userId = UserManager.getInstance().userId,
exposureVersion = BuildConfig.EXPOSURE_VERSION,
rom = RomIdentifier.getRom().name + "" + RomIdentifier.getRom().versionName)
rom = romName + "" + romVersion)
}
fun getMeta(): Meta {
@ -107,6 +120,10 @@ object MetaUtil {
@JvmStatic
fun getBase64EncodedIMEI(): String {
if (imei == null) {
getIMEI()
}
if (TextUtils.isEmpty(base64EncodedImei) && imei != null) {
try {
base64EncodedImei = android.util.Base64.encodeToString(getIMEI().trim().toByteArray(), android.util.Base64.NO_WRAP)
@ -119,6 +136,24 @@ object MetaUtil {
return base64EncodedImei ?: ""
}
@JvmStatic
fun getBase64EncodedAndroidId(): String {
if (androidId == null) {
getAndroidId()
}
if (TextUtils.isEmpty(base64EncodedAndroidId) && androidId != null) {
try {
base64EncodedAndroidId = android.util.Base64.encodeToString(getAndroidId().trim().toByteArray(), android.util.Base64.NO_WRAP)
} catch (e: java.lang.Exception) {
e.printStackTrace()
return ""
}
}
return base64EncodedAndroidId ?: ""
}
fun getModel(): String? {
return Build.MODEL
}

View File

@ -1,7 +1,6 @@
package com.gh.common.filter
import android.annotation.SuppressLint
import com.gh.common.AppExecutor
import com.gh.common.constant.Constants
import com.gh.common.util.SPUtils
import com.gh.common.util.debounceActionWithInterval
@ -14,6 +13,7 @@ import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Function
import io.reactivex.schedulers.Schedulers
object RegionSettingHelper {
@ -67,7 +67,7 @@ object RegionSettingHelper {
RetrofitManager.getInstance(HaloApp.getInstance().application)
.sensitiveApi
.getRegionSetting(HaloApp.getInstance().channel)
.subscribeOn(AppExecutor.cachedScheduler)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<RegionSetting>() {
override fun onSuccess(data: RegionSetting) {
@ -76,7 +76,7 @@ object RegionSettingHelper {
}
override fun onFailure(exception: Exception) {
SPUtils.getString(SP_SETTING).toObject<RegionSetting>()?.let {
SPUtils.getString(SP_SETTING)?.toObject<RegionSetting>()?.let {
updateSettingsInMemory(it)
}
}

View File

@ -15,7 +15,7 @@ import com.gh.gamecenter.room.converter.*
import com.gh.gamecenter.room.dao.*
import com.halo.assistant.HaloApp
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 7, exportSchema = false)
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 8, exportSchema = false)
@TypeConverters(CountConverter::class,
CommunityConverter::class,
TimeConverter::class,
@ -23,8 +23,10 @@ import com.halo.assistant.HaloApp
ThumbnailConverter::class,
TagStyleListConverter::class,
StringArrayListConverter::class,
ListStringConverter::class,
CommunityVideoConverter::class,
UserConverter::class)
UserConverter::class,
ImageInfoConverter::class)
abstract class HistoryDatabase : RoomDatabase() {
@ -69,6 +71,14 @@ abstract class HistoryDatabase : RoomDatabase() {
}
}
val MIGRATION_7_8: Migration = object : Migration(7, 8) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("Alter TABLE ArticleEntity add images TEXT NOT NULL DEFAULT ''")
database.execSQL("Alter TABLE ArticleEntity add imagesInfo TEXT NOT NULL DEFAULT ''")
database.execSQL("Alter TABLE AnswerEntity add imagesInfo TEXT NOT NULL DEFAULT ''")
}
}
val instance by lazy {
Room.databaseBuilder(HaloApp.getInstance().application, HistoryDatabase::class.java, "USER_TRACK_HISTORY_DATABASE")
.addMigrations(MIGRATION_2_3)
@ -76,6 +86,7 @@ abstract class HistoryDatabase : RoomDatabase() {
.addMigrations(MIGRATION_4_5)
.addMigrations(MIGRATION_5_6)
.addMigrations(MIGRATION_6_7)
.addMigrations(MIGRATION_7_8)
.build()
}
}

View File

@ -69,48 +69,44 @@ object HistoryHelper {
@JvmStatic
fun insertNewsEntity(newsEntity: NewsEntity) {
newsEntity.orderTag = System.currentTimeMillis()
runOnIoThread { HistoryDatabase.instance.newsDao().addNews(newsEntity) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.newsDao().addNews(newsEntity) } }
}
@JvmStatic
fun deleteNewsEntity(newsId: String) {
runOnIoThread { HistoryDatabase.instance.newsDao().deleteNews(NewsEntity().apply { id = newsId }) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.newsDao().deleteNews(NewsEntity().apply { id = newsId }) } }
}
@JvmStatic
fun deleteGameEntity(gameId: String) {
runOnIoThread { HistoryDatabase.instance.gameDao().deleteGame(HistoryGameEntity(id = gameId)) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().deleteGame(HistoryGameEntity(id = gameId)) } }
}
@JvmStatic
fun deleteArticleEntity(articleId: String) {
runOnIoThread { HistoryDatabase.instance.articleDao().deleteArticle(ArticleEntity(id = articleId)) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.articleDao().deleteArticle(ArticleEntity(id = articleId)) } }
}
@JvmStatic
fun deleteAnswerEntity(answerId: String) {
runOnIoThread { HistoryDatabase.instance.answerDao().deleteAnswer(AnswerEntity().apply { primaryKey = answerId }) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.answerDao().deleteAnswer(AnswerEntity().apply { primaryKey = answerId }) } }
}
@JvmStatic
fun deleteVideoEntity(videoId: String) {
runOnIoThread { HistoryDatabase.instance.videoHistoryDao().deleteVideo(MyVideoEntity().apply { id = videoId }) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().deleteVideo(MyVideoEntity().apply { id = videoId }) } }
}
@JvmStatic
fun emptyDatabase() {
runOnIoThread { HistoryDatabase.instance.clearAllTables() }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.clearAllTables() } }
}
private fun convertArticleDetailToArticle(articleDetailEntity: ArticleDetailEntity): ArticleEntity {
val articleEntity = ArticleEntity()
articleEntity.id = articleDetailEntity.id
articleEntity.brief = articleDetailEntity.content.
removeVideoContent().
removeInsertedContent().
clearHtmlFormatCompletely().
replace(" +".toRegex()," ")
articleEntity.brief = articleDetailEntity.content.removeVideoContent().removeInsertedContent().clearHtmlFormatCompletely().replace(" +".toRegex(), " ")
articleEntity.count = articleDetailEntity.count
articleDetailEntity.community.id = articleDetailEntity.communityId
articleEntity.community = articleDetailEntity.community
@ -118,6 +114,9 @@ object HistoryHelper {
articleEntity.title = articleDetailEntity.title
articleEntity.user = articleDetailEntity.user
articleEntity.orderTag = System.currentTimeMillis()
articleEntity.images = articleDetailEntity.images
articleEntity.imagesInfo = articleDetailEntity.imagesInfo
articleEntity.videos = articleDetailEntity.videos
return articleEntity
}
@ -132,12 +131,11 @@ object HistoryHelper {
answerEntity.vote = answerDetailEntity.vote
answerEntity.user = answerDetailEntity.user
answerEntity.orderTag = System.currentTimeMillis()
answerEntity.brief = answerDetailEntity.content.
removeVideoContent().
removeInsertedContent().
clearHtmlFormatCompletely().
replace(" +".toRegex(), " ")
answerEntity.brief = answerDetailEntity.content.removeVideoContent().removeInsertedContent().clearHtmlFormatCompletely().replace(" +".toRegex(), " ")
answerEntity.time = answerDetailEntity.time
answerEntity.images = answerDetailEntity.images
answerEntity.imagesInfo = answerDetailEntity.imagesInfo
answerEntity.videos = answerDetailEntity.videos
return answerEntity
}

View File

@ -9,7 +9,7 @@ import com.gh.common.exposure.meta.Meta
import com.gh.common.util.tryWithDefaultCatch
import com.gh.loghub.LoghubHelper
import org.json.JSONObject
import java.util.concurrent.Executors
import java.util.concurrent.ExecutorService
object LoghubUtils {
@ -17,22 +17,25 @@ object LoghubUtils {
private lateinit var mApplication: Application
private val loghubEventSet by lazy { hashSetOf<LoghubEvent>() }
private val loghubEventExecutor by lazy { Executors.newSingleThreadExecutor() }
private var loghubEventExecutor: ExecutorService? = null
private val loghubEventDao by lazy { LoghubDatabase.buildDatabase(mApplication).logHubEventDao() }
@JvmStatic
fun init(application: Application) {
fun init(application: Application, executor: ExecutorService) {
mApplication = application
loghubEventExecutor.execute {
val eventList = loghubEventDao.getAll()
loghubEventSet.addAll(eventList)
loghubEventExecutor = executor
loghubEventExecutor?.execute {
tryWithDefaultCatch {
val eventList = loghubEventDao.getAll()
loghubEventSet.addAll(eventList)
}
}
}
@JvmStatic
fun log(logJson: JSONObject, logStore: String, forcedUpload: Boolean) {
loghubEventExecutor.execute {
loghubEventExecutor?.execute {
try {
val event = LoghubEvent(time = (System.currentTimeMillis() / 1000L).toString(), content = logJson.toString(), logStore = logStore)
loghubEventSet.add(event)
@ -49,7 +52,7 @@ object LoghubUtils {
@JvmStatic
fun log(jsonString: String, logStore: String, forcedUpload: Boolean) {
loghubEventExecutor.execute {
loghubEventExecutor?.execute {
try {
val event = LoghubEvent(time = (System.currentTimeMillis() / 1000L).toString(), content = jsonString, logStore = logStore)
loghubEventSet.add(event)
@ -69,7 +72,7 @@ object LoghubUtils {
}
fun commitSavedLoghubEvents() {
loghubEventExecutor.execute {
loghubEventExecutor?.execute {
// TODO 初始化 loghubHelper 去掉这个 tryCatch 块
tryWithDefaultCatch {
if (loghubEventSet.isEmpty()) return@execute

View File

@ -20,7 +20,12 @@ class VolumeObserver(var context: Context, handler: Handler, var callback: MuteC
super.onChange(selfChange)
val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
var currentVolume = 0
tryCatchInRelease {
// 部分设备(Meizu 7.1.2 M6 Note)的 audioManager getStreamVolume 内部会触发空指针 :(
currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
}
val delta = previousVolume - currentVolume

View File

@ -7,6 +7,7 @@ import android.view.View
import android.view.Window
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.g00fy2.versioncompare.Version
@ -14,7 +15,6 @@ import com.gh.common.AppExecutor.uiExecutor
import com.gh.common.constant.Constants
import com.gh.common.dialog.TrackableDialog
import com.gh.common.util.*
import com.gh.common.util.PackageInstaller.getDownloadPath
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.ApkEntity
@ -23,6 +23,7 @@ import com.gh.gamecenter.entity.TrackableEntity
import com.halo.assistant.HaloApp
import com.lightgame.download.*
import com.lightgame.utils.Utils
import java.lang.ref.WeakReference
import java.text.DecimalFormat
class SimulatorDownloadManager private constructor() {
@ -34,6 +35,7 @@ class SimulatorDownloadManager private constructor() {
private var appProgressFilling: View? = null
private var appProgressAnchor: View? = null
private var downloadDialog: Dialog? = null
private var mContextRef: WeakReference<Context>? = null
private var simulatorLocation: SimulatorLocation? = null
private var simulator: SimulatorEntity? = null
@ -71,7 +73,10 @@ class SimulatorDownloadManager private constructor() {
val startTime = downloadEntity.getMetaExtra(Constants.SIMULATOR_DOWNLOAD_START_TIME)
LogUtils.uploadSimulatorDownload("simulator_download_complete", fileName, simulator?.id, downloadEntity.name, gameId, locationStr, downloadType, startTime)
DownloadManager.getInstance(HaloApp.getInstance().application).cancel(downloadEntity.url, false, true)
downloadDialog?.dismiss()
val activity = mContextRef?.get() as? AppCompatActivity
if (activity?.isFinishing == false) {
downloadDialog?.dismiss()
}
}
DownloadStatus.neterror == downloadEntity.status -> {
ToastUtils.showToast("网络不稳定,下载任务已暂停")
@ -94,7 +99,9 @@ class SimulatorDownloadManager private constructor() {
showDownloadDialog(context, simulator, location, "", "", null)
}
fun showDownloadDialog(context: Context, simulator: SimulatorEntity?, location: SimulatorLocation, gameId: String = "", gameName: String = "", cancelCallback: (() -> Unit)? = null) {
fun showDownloadDialog(context: Context?, simulator: SimulatorEntity?, location: SimulatorLocation, gameId: String = "", gameName: String = "", cancelCallback: (() -> Unit)? = null) {
if (context == null) return
mContextRef = WeakReference(context)
this.simulatorLocation = location
this.simulator = simulator
this.gameId = gameId
@ -117,7 +124,7 @@ class SimulatorDownloadManager private constructor() {
key = if (shouldShowUpdate && isInstalled) "更新弹窗" else "下载弹窗",
logShowEvent = true
)
DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, Gravity.LEFT, {
DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, Gravity.LEFT, false, {
if (shouldShowUpdate && isInstalled) {
cancelCallback?.invoke()
MtaHelper.onEvent(trackableEntity.event, trackableEntity.key, "点击下次再说")
@ -153,7 +160,10 @@ class SimulatorDownloadManager private constructor() {
view.findViewById<View>(R.id.app_tv_cancel).setOnClickListener {
DownloadManager.getInstance(context).pause(simulator?.apk?.url)
MtaHelper.onEvent("模拟器下载", "下载中弹窗", "点击关闭")
downloadDialog?.dismiss()
val activity = mContextRef?.get() as? AppCompatActivity
if (activity?.isFinishing == false) {
downloadDialog?.dismiss()
}
}
downloadDialog?.setOnDismissListener {
@ -184,6 +194,7 @@ class SimulatorDownloadManager private constructor() {
DownloadManager.getInstance(context).pauseAll()
val entity = DownloadManager.getInstance(context).getDownloadEntityByUrl(apkEntity.url)
HaloApp.put(simulator.name, simulator)
if (entity != null) {
when (entity.status) {
DownloadStatus.pause, DownloadStatus.subscribe,
@ -203,16 +214,18 @@ class SimulatorDownloadManager private constructor() {
private fun createDownload(context: Context, apkEntity: ApkEntity, simulator: SimulatorEntity) {
DownloadManager.getInstance(context).addObserver(dataWatcher)
val downloadId = PackageInstaller.createDownloadId(simulator.name)
val downloadEntity = DownloadEntity()
downloadEntity.url = apkEntity.url
downloadEntity.name = simulator.name
downloadEntity.path = getDownloadPath(simulator.name, apkEntity.format)
downloadEntity.path = PackageInstaller.getDownloadPathWithId(downloadId, apkEntity.format)
downloadEntity.platform = apkEntity.getPlatform()
downloadEntity.packageName = apkEntity.packageName
downloadEntity.versionName = apkEntity.version
downloadEntity.addMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE, Constants.SIMULATOR_DOWNLOAD)
downloadEntity.addMetaExtra(Constants.SIMULATOR_DOWNLOAD_START_TIME, (System.currentTimeMillis() / 1000).toString())
downloadEntity.addMetaExtra(Constants.DOWNLOAD_ID, downloadId)
uiExecutor.executeWithDelay(Runnable { DownloadManager.getInstance(context).add(downloadEntity) }, 200)
val locationStr = if (simulatorLocation == SimulatorLocation.LAUNCH) "${simulatorLocation?.value}${gameName}" else simulatorLocation?.value

View File

@ -3,6 +3,7 @@ package com.gh.common.simulator
import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.text.TextUtils
import com.g00fy2.versioncompare.Version
@ -18,9 +19,11 @@ import com.lightgame.download.DownloadDao
import com.lightgame.download.DownloadEntity
import com.lightgame.download.FileUtils
import com.lightgame.utils.AppManager
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import java.io.ByteArrayOutputStream
import java.io.File
@ -33,7 +36,7 @@ object SimulatorGameManager {
@JvmStatic
fun deleteLocalGames(names: List<String>) {
val downloadEntityList = DownloadDao.getInstance(HaloApp.getInstance().application).all
val downloadEntityList = DownloadManager.getInstance(HaloApp.getInstance().application).allDownloadEntity
names.forEach { name ->
val downloadEntity = downloadEntityList.find { it.name == name }
if (downloadEntity != null) {
@ -48,7 +51,7 @@ object SimulatorGameManager {
@JvmStatic
fun deleteLocalGame(name: String) {
val downloadEntityList = DownloadDao.getInstance(HaloApp.getInstance().application).all
val downloadEntityList = DownloadManager.getInstance(HaloApp.getInstance().application).allDownloadEntity
val downloadEntity = downloadEntityList.find { it.name == name }
if (downloadEntity != null) {
val file = File(downloadEntity.path)
@ -90,31 +93,62 @@ object SimulatorGameManager {
}
}
@SuppressLint("CheckResult")
private fun jumpToSimulator(downloadEntity: DownloadEntity, gameEntity: GameEntity) {
val intent = Intent()
intent.data = Uri.fromFile(File(downloadEntity.path))
if (gameEntity.simulatorType == "FBA") {
val apkEntity = gameEntity.getApk()[0]
intent.putExtra("rom_name", apkEntity.packageName)
}
intent.putExtra("default_path", downloadEntity.path.substring(0, downloadEntity.path.lastIndexOf('/')))
intent.putExtra("game_type", gameEntity.simulatorType)
intent.putExtra("title", downloadEntity.name)
intent.putExtra("icon", gameEntity.icon ?: "")
intent.putExtra("meta", LogUtils.getMetaObject().toString())
intent.putExtra("simulatorId", gameEntity.simulator?.id)
intent.putExtra("simulatorName", gameEntity.simulator?.name)
intent.putExtra("gameId", gameEntity.id)
Single.just(gameEntity.icon ?: "")
.flatMap {
getBitmapFormCache(it)
}.map {
BitmapUtils.compressBitmap(it, 100)
}.map {
val baos = ByteArrayOutputStream()
it.compress(Bitmap.CompressFormat.WEBP, 100, baos)
baos.toByteArray()
}
.compose(singleToMain())
.subscribe({
val intent = Intent()
intent.data = Uri.fromFile(File(downloadEntity.path))
if (gameEntity.simulatorType == "FBA") {
val apkEntity = gameEntity.getApk()[0]
intent.putExtra("rom_name", apkEntity.packageName)
}
intent.putExtra("default_path", downloadEntity.path.substring(0, downloadEntity.path.lastIndexOf('/')))
intent.putExtra("game_type", gameEntity.simulatorType)
intent.putExtra("title", downloadEntity.name)
intent.putExtra("icon", gameEntity.icon ?: "")
intent.putExtra("iconStream", it)
intent.putExtra("meta", LogUtils.getMetaObject().toString())
intent.putExtra("simulatorId", gameEntity.simulator?.id)
intent.putExtra("simulatorName", gameEntity.simulator?.name)
intent.putExtra("gameId", gameEntity.id)
val destActivity = "com.gh.emu.RequestPermissionActivity"
intent.setClassName(gameEntity.simulator?.apk?.packageName ?: "", destActivity)
try {
AppManager.getInstance().recentActiveActivity.startActivity(intent)
} catch (e: ActivityNotFoundException) {
ToastUtils.showToast("模拟器安装错误")
}
val destActivity = "com.gh.emu.RequestPermissionActivity"
intent.setClassName(gameEntity.simulator?.apk?.packageName ?: "", destActivity)
try {
AppManager.getInstance().recentActiveActivity?.startActivity(intent)
} catch (e: ActivityNotFoundException) {
ToastUtils.showToast("模拟器安装错误")
}
recordPlaySimulatorGames(gameEntity.id)
recordPlaySimulatorGames(gameEntity.id)
}, {
ToastUtils.showToast("跳转失败")
})
}
private fun getBitmapFormCache(url: String): Single<Bitmap> {
return Single.create {
ImageUtils.getBitmap(url, object : BiCallback<Bitmap, Boolean> {
override fun onFirst(first: Bitmap) {
it.onSuccess(first)
}
override fun onSecond(second: Boolean) {
it.onError(Throwable("获取bitmap失败"))
}
})
}
}

View File

@ -1,7 +1,14 @@
package com.gh.common.util
import android.annotation.SuppressLint
import androidx.lifecycle.MutableLiveData
import com.gh.common.constant.Config
import com.gh.gamecenter.entity.SettingsEntity
import com.gh.gamecenter.entity.StartupAdEntity
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
object AdHelper {
@ -12,6 +19,28 @@ object AdHelper {
const val LOCATION_DISCOVER = "discover"
const val LOCATION_SIMULATOR_GAME = "simulator_game"
@JvmField
var startupAd = MutableLiveData<StartupAdEntity>()
@JvmStatic
@SuppressLint("CheckResult")
fun getStartUpAd() {
if (!NetworkUtils.isNetworkConnected(HaloApp.getInstance())) {
startupAd.postValue(null)
return
}
RetrofitManager.getInstance(HaloApp.getInstance())
.api
.getSplashAd(HaloApp.getInstance().channel)
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<StartupAdEntity>() {
override fun onSuccess(data: StartupAdEntity) {
startupAd.postValue(data)
}
})
}
fun getAd(location: String): SettingsEntity.AD? {
val adList = Config.getSettings()?.adList ?: return null

View File

@ -333,14 +333,19 @@ public class BitmapUtils {
}
public static Bitmap compressBitmap(Bitmap bitmap) {
/**
* 压缩图片
*
* @param bitmap
* @param compressSize 压缩大小(单位k)
*/
public static Bitmap compressBitmap(Bitmap bitmap, int compressSize) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Matrix matrix = new Matrix();
Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
result.compress(Bitmap.CompressFormat.WEBP, 100, bos);
while (bos.toByteArray().length > 400 * 1024) {
System.out.println(bos.toByteArray().length);
while (bos.toByteArray().length > compressSize * 1024) {
matrix.setScale(0.9f, 0.9f);
result = Bitmap.createBitmap(result, 0, 0, result.getWidth(), result.getHeight(), matrix, true);
bos.reset();

View File

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

View File

@ -334,15 +334,16 @@ public class CommentUtils {
});
});
}
public static void voteVideoComment(final Context context,
String answerId,
String articleId,
String articleCommunityId,
String videoId,
final CommentEntity commentEntity,
final TextView commentLikeCountTv,
final ImageView commentLikeIv,
final OnVoteListener listener) {
String answerId,
String articleId,
String articleCommunityId,
String videoId,
final CommentEntity commentEntity,
final TextView commentLikeCountTv,
final ImageView commentLikeIv,
final OnVoteListener listener) {
String entrance = "视频流-评论-点赞";
CheckLoginUtils.checkLogin(context, entrance, () -> {
@ -389,10 +390,10 @@ public class CommentUtils {
}
public static void unVoteVideoComment(final Context context,
String videoId,
final CommentEntity commentEntity,
final TextView commentLikeCountTv,
final ImageView commentLikeIv) {
String videoId,
final CommentEntity commentEntity,
final TextView commentLikeCountTv,
final ImageView commentLikeIv) {
String entrance = "视频流-评论-取消点赞";
CheckLoginUtils.checkLogin(context, entrance, () -> {
RetrofitManager.getInstance(context).getApi()
@ -434,10 +435,10 @@ public class CommentUtils {
holder.commentLikeIv.setImageResource(R.drawable.comment_vote_unselect);
if (userDataEntity == null || !userDataEntity.isCommentOwner()) {
holder.replyLine.setVisibility(View.VISIBLE);
if (holder.replyLine != null) holder.replyLine.setVisibility(View.VISIBLE);
holder.commentReply.setVisibility(View.VISIBLE);
} else {
holder.replyLine.setVisibility(View.GONE);
if (holder.replyLine != null) holder.replyLine.setVisibility(View.GONE);
holder.commentReply.setVisibility(View.GONE);
}

View File

@ -35,7 +35,7 @@ public class DataCollectionUtils {
public static void uploadDownload(Context context, DownloadEntity downloadEntity, String status) {
Map<String, Object> map = new HashMap<>();
map.put("game", StringsKt.removeSuffix(downloadEntity.getName(), Constants.GAME_NAME_DECORATOR));
map.put("game_id", downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER));
map.put("game_id", downloadEntity.getGameId());
if (downloadEntity.isPluggable()) {
map.put("method", "插件化");
map.put("btn_status", "插件化");

View File

@ -52,8 +52,8 @@ public class DataLogUtils {
String user = Installation.getUUID(context);
String channel = HaloApp.getInstance().getChannel();
map.put("version", version);
map.put("user", user);
map.put("device_id", MetaUtil.getIMEI());
map.put("resu", user);
map.put("jnfj", MetaUtil.getBase64EncodedIMEI());
map.put("channel", channel);
Map<String, String> params = new HashMap<>();

View File

@ -7,6 +7,7 @@ import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import com.gh.common.AppExecutor;
import com.gh.common.constant.Constants;
import com.gh.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.BuildConfig;
@ -19,9 +20,8 @@ import com.lightgame.utils.Utils;
import java.util.HashMap;
import java.util.Map;
import io.sentry.Sentry;
import io.sentry.android.core.SentryAndroid;
import io.sentry.core.Sentry;
import io.sentry.core.protocol.User;
/**
* Created by LGT on 2016/6/15.
@ -40,34 +40,9 @@ public class DataUtils {
if (CommonDebug.IS_DEBUG) {
return;
}
SentryAndroid.init(context, options -> {
options.setDebug(BuildConfig.DEBUG);
options.setEnableSessionTracking(true);
options.setEnvironment(BuildConfig.FLAVOR);
options.setDsn("https://6b1caf0d17c1408e8680f3f73ff80bd0@sentry.ghzs.com/22");
options.setBeforeSend((event, hint) -> {
if (BuildConfig.DEBUG) {
return null;
} else {
return event;
}
});
});
Sentry.configureScope(scope -> {
User user = new User();
user.setId(HaloApp.getInstance().getGid());
scope.setUser(user);
if (BuildConfig.BUILD_TIME != 0L) {
scope.setTag("alias", "内测版" + BuildConfig.VERSION_NAME + "_" + BuildConfig.BUILD_TIME);
} else {
scope.setTag("alias", "正式版" + BuildConfig.VERSION_NAME);
scope.setTag("channel", channel);
}
});
// 初始化 Sentry 约占用 90ms这里切换到子线程初始化
AppExecutor.getIoExecutor().execute(() -> initSentry(context, channel));
//TalkingData
// try {
@ -137,6 +112,41 @@ public class DataUtils {
// }
}
private static void initSentry(Context context, String channel) {
SentryAndroid.init(context, options -> {
// Sentry 疯狂报 ANR (很大一部分还是莫名奇妙的 ANR)严重影响到其它闪退日志的收集
// 这里将它局限到只有官网渠道的包才统计 ANR
if ("GH_206".equals(channel)) {
options.setAnrEnabled(true);
options.setAnrTimeoutIntervalMillis(6000);
} else {
options.setAnrEnabled(false);
}
options.setDebug(BuildConfig.DEBUG);
options.setEnableSessionTracking(true);
options.setEnvironment(BuildConfig.FLAVOR);
options.setDsn("https://6b1caf0d17c1408e8680f3f73ff80bd0@sentry.ghzs.com/22");
options.setBeforeSend((event, hint) -> {
if (BuildConfig.DEBUG) {
return null;
} else {
return event;
}
});
});
Sentry.configureScope(scope -> {
if (BuildConfig.BUILD_TIME != 0L) {
scope.setTag("alias", "内测版" + BuildConfig.VERSION_NAME);
} else {
scope.setTag("alias", "正式版" + BuildConfig.VERSION_NAME);
scope.setTag("channel", channel);
}
});
}
// MTA ->【次数统计】Key-Value参数的事件
public static void onMtaEvent(Context context, String eventId, String... kv) {
@ -229,7 +239,7 @@ public class DataUtils {
kv.put("版本", platform);
kv.put("用户机型", Build.MODEL);
kv.put("设备IMEI", MetaUtil.getIMEI());
kv.put("设备JNFJ", MetaUtil.getBase64EncodedIMEI());
kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
kv.put("光环助手版本", BuildConfig.VERSION_NAME);
kv.put("位置", entrance);

View File

@ -41,11 +41,11 @@ public class DeviceUtils {
context = context.getApplicationContext();
JSONObject object = new JSONObject();
object.put("os", "Android");
object.put("imei", MetaUtil.getIMEI());
object.put("jnfj", MetaUtil.getBase64EncodedIMEI());
object.put("mac", getMac(context));
object.put("model", MODEL);
object.put("manufacturer", MANUFACTURER);
object.put("android_id", MetaUtil.getAndroidId());
object.put("dia", MetaUtil.getBase64EncodedAndroidId());
object.put("android_sdk", Build.VERSION.SDK_INT);
object.put("android_version", android.os.Build.VERSION.RELEASE);
object.put("ip", "");
@ -57,8 +57,8 @@ public class DeviceUtils {
public static JSONObject getUserDevice(Context context) { // 判断新老用户device数据
JSONObject object = new JSONObject();
try {
object.put("IMEI", MetaUtil.getIMEI());
object.put("ANDROID_ID", MetaUtil.getAndroidId());
object.put("JNFJ", MetaUtil.getBase64EncodedIMEI());
object.put("DIA", MetaUtil.getBase64EncodedAndroidId());
object.put("MAC", getMac(context));
// object.put("MTA_ID", StatConfig.getMid(context));
object.put("MANUFACTURER", MANUFACTURER);
@ -258,7 +258,7 @@ public class DeviceUtils {
}
}
public static long getTotalRamSizeOfDevice(Context context) {
public static long getTotalRamSizeOfDevice(Context context) {
ActivityManager actManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
if (actManager != null) {

View File

@ -3,6 +3,7 @@ package com.gh.common.util
import android.app.Dialog
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.Window
import android.widget.TextView
import com.gh.common.dialog.TrackableDialog
@ -73,6 +74,65 @@ object DialogHelper {
return dialog
}
fun showRoundedCornerDialog(
context: Context,
title: String,
content: CharSequence,
hint: String? = "",
confirmText: String,
cancelText: String,
confirmClickCallback: (() -> Unit)? = null,
cancelClickCallback: (() -> Unit)? = null,
hintClickCallback: (() -> Unit)? = null,
trackMtaEvent: Boolean = false,
mtaEvent: String = "",
mtaKey: String = ""): Dialog {
val solidContext = checkDialogContext(context)
val dialog = if (trackMtaEvent) {
TrackableDialog(solidContext, R.style.GhAlertDialog, mtaEvent, mtaKey)
} else {
Dialog(solidContext, R.style.GhAlertDialog)
}
val contentView = LayoutInflater.from(solidContext).inflate(R.layout.dialog_alert_default, null)
val contentTv = contentView.findViewById<TextView>(R.id.contentTv)
val titleTv = contentView.findViewById<TextView>(R.id.titleTv)
val hintTv = contentView.findViewById<TextView>(R.id.hintTv)
val cancelTv = contentView.findViewById<TextView>(R.id.cancelTv)
val confirmTv = contentView.findViewById<TextView>(R.id.confirmTv)
contentTv.text = content
titleTv.text = title
if (!hint.isNullOrEmpty()) {
hintTv.visibility = View.VISIBLE
hintTv.text = hint
hintTv.setOnClickListener {
hintClickCallback?.invoke()
}
}
cancelTv.text = cancelText
confirmTv.text = confirmText
cancelTv.setOnClickListener {
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击$cancelText")
cancelClickCallback?.invoke()
dialog.dismiss()
}
confirmTv.setOnClickListener {
if (trackMtaEvent) MtaHelper.onEvent(mtaEvent, mtaKey, "点击$confirmText")
confirmClickCallback?.invoke()
dialog.dismiss()
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setContentView(contentView)
dialog.show()
return dialog
}
/**
* For legacy java invocation
*/

View File

@ -1,5 +1,6 @@
package com.gh.common.util;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
@ -14,12 +15,15 @@ import android.os.CountDownTimer;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@ -33,6 +37,7 @@ import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -41,12 +46,15 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.common.AppExecutor;
import com.gh.common.constant.Config;
import com.gh.common.dialog.TrackableDialog;
import com.gh.common.view.CustomLinkMovementMethod;
import com.gh.common.view.DrawableView;
import com.gh.common.view.FixLinearLayoutManager;
import com.gh.common.view.LimitHeightLinearLayout;
@ -56,6 +64,8 @@ import com.gh.gamecenter.R;
import com.gh.gamecenter.SuggestionActivity;
import com.gh.gamecenter.adapter.viewholder.PrivacyPolicyItemViewHolder;
import com.gh.gamecenter.databinding.DialogOverseaConfirmationBinding;
import com.gh.gamecenter.databinding.DialogPackageParseErrorBinding;
import com.gh.gamecenter.databinding.DialogReportReasonBinding;
import com.gh.gamecenter.databinding.ImprintContentItemBinding;
import com.gh.gamecenter.databinding.PrivacyItemBinding;
import com.gh.gamecenter.entity.ApkEntity;
@ -64,6 +74,7 @@ import com.gh.gamecenter.entity.BadgeEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.PrivacyPolicyEntity;
import com.gh.gamecenter.entity.SettingsEntity;
import com.gh.gamecenter.entity.SimpleGameEntity;
import com.gh.gamecenter.entity.TrackableEntity;
import com.gh.gamecenter.suggest.SuggestType;
import com.halo.assistant.HaloApp;
@ -350,7 +361,7 @@ public class DialogUtils {
* @param cmListener 确认按钮监听
*/
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
, String negative, String positive, TrackableEntity trackableEntity, int gravity, final CancelListener clListener, final ConfirmListener cmListener) {
, String negative, String positive, TrackableEntity trackableEntity, int gravity, boolean shouldShowCloseBtn, final CancelListener clListener, final ConfirmListener cmListener) {
context = checkDialogContext(context);
final Dialog dialog;
if (trackableEntity != null) {
@ -373,6 +384,7 @@ public class DialogUtils {
TextView cancelBtn = contentView.findViewById(R.id.cancel);
TextView confirmBtn = contentView.findViewById(R.id.confirm);
View middleLine = contentView.findViewById(R.id.middle_line);
View closeIv = contentView.findViewById(R.id.closeIv);
titleTv.setGravity(gravity);
contentTv.setGravity(gravity);
@ -389,6 +401,8 @@ public class DialogUtils {
confirmBtn.setVisibility(View.GONE);
middleLine.setVisibility(View.GONE);
}
closeIv.setVisibility(shouldShowCloseBtn ? View.VISIBLE : View.GONE);
closeIv.setOnClickListener(v -> dialog.dismiss());
cancelBtn.setOnClickListener(v -> {
if (clListener != null) clListener.onCancel();
@ -413,7 +427,12 @@ public class DialogUtils {
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
, String negative, String positive, final CancelListener clListener, final ConfirmListener cmListener) {
return showNewAlertDialog(context, title, message, negative, positive, null, Gravity.LEFT, clListener, cmListener);
return showNewAlertDialog(context, title, message, negative, positive, null, Gravity.LEFT, false, clListener, cmListener);
}
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
, String negative, String positive, int gravity, boolean shouldShowCloseBtn, final CancelListener clListener, final ConfirmListener cmListener) {
return showNewAlertDialog(context, title, message, negative, positive, null, gravity, shouldShowCloseBtn, clListener, cmListener);
}
/**
@ -970,7 +989,7 @@ public class DialogUtils {
public static void showPrivacyPolicyDialog(Context context,
@NonNull PrivacyPolicyEntity entity,
EmptyCallback callback) {
SimpleCallback<Boolean> callback) {
final Context activityContext = checkDialogContext(context);
@ -1086,19 +1105,31 @@ public class DialogUtils {
title.setText(entity.getTitle());
linkContent.setText(skipText);
linkContent.setMovementMethod(new LinkMovementMethod());
linkContent.setMovementMethod(LinkMovementMethod.getInstance());
topContent.setText(entity.getTopContent());
bottomContent.setText(entity.getBottomContent());
bottomContent.setText(ExtensionsKt.fromHtml(entity.getBottomContent()));
bottomContent.setMovementMethod(CustomLinkMovementMethod.getInstance());
// Remove underline
Spannable sa = (Spannable) bottomContent.getText();
for (URLSpan u : sa.getSpans(0, sa.length(), URLSpan.class)) {
sa.setSpan(new UnderlineSpan() {
public void updateDrawState(TextPaint tp) {
tp.setUnderlineText(false);
}
}, sa.getSpanStart(u), sa.getSpanEnd(u), 0);
}
allowButton.setOnClickListener(view -> {
dialog.dismiss();
callback.onCallback();
callback.onCallback(true);
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击同意");
});
disallowButton.setOnClickListener(v -> {
dialog.dismiss();
showPrivacyPolicyDisallowDialog(activityContext, entity, callback);
callback.onCallback(false);
// showPrivacyPolicyDisallowDialog(activityContext, entity, callback);
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "不同意并退出App");
});
@ -1902,6 +1933,234 @@ public class DialogUtils {
dialog.show();
}
public static Dialog showCancelOrDeleteReservationDialog(Context context, String title, String message
, String positive, String negative, final ConfirmListener cmListener, final CancelListener clListener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_cancel_reservation, null);
TextView contentTv = contentView.findViewById(R.id.dialog_content);
TextView titleTv = contentView.findViewById(R.id.dialog_title);
TextView negativeTv = contentView.findViewById(R.id.dialog_negative);
TextView positiveTv = contentView.findViewById(R.id.dialog_positive);
contentTv.setText(message);
titleTv.setText(title);
negativeTv.setText(negative);
positiveTv.setText(positive);
negativeTv.setOnClickListener(view -> {
if (clListener != null) {
clListener.onCancel();
}
dialog.dismiss();
});
positiveTv.setOnClickListener(view -> {
if (cmListener != null) {
cmListener.onConfirm();
}
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
WindowManager.LayoutParams params = window.getAttributes();
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(60f);
window.setAttributes(params);
}
return dialog;
}
public static void showEnergyDialog(Context context, String userName, int energy) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_energy, null);
((TextView) contentView.findViewById(R.id.userName)).setText("\"" + userName + "\"");
((TextView) contentView.findViewById(R.id.energy)).setText(energy + "");
contentView.findViewById(R.id.dialog_positive).setOnClickListener(v -> {
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
public static void showEnergyTaskNoticeDialog(Context context, String title, String content) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_notice, null);
TextView titleTv = contentView.findViewById(R.id.dialog_title);
TextView contentTv = contentView.findViewById(R.id.dialog_content);
TextView okTv = contentView.findViewById(R.id.dialog_ok);
if (title == null) {
titleTv.setVisibility(View.GONE);
} else {
titleTv.setVisibility(View.VISIBLE);
titleTv.setText(title);
}
contentTv.setText(content);
okTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font));
okTv.setOnClickListener(v -> {
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
public static void showSimulatorParseErrorDialog(Context context, String gameId, String gameName, ConfirmListener confirmListener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
DialogPackageParseErrorBinding binding = DialogPackageParseErrorBinding.inflate(LayoutInflater.from(context), null, false);
Context finalContext = context;
SpannableStringBuilder builder = new SpanBuilder("您也可以点击提交反馈跟我们联系").click(6, 10, R.color.theme_font, true, new Function0<Unit>() {
@Override
public Unit invoke() {
SimpleGameEntity entity = new SimpleGameEntity(gameId, gameName, "");
SuggestionActivity.startSuggestionActivity(finalContext, SuggestType.gameQuestion, "notfound", "模拟器安装包解析错误", entity, "-");
dialog.dismiss();
return null;
}
}).build();
binding.feedbackTv.setText(builder);
binding.feedbackTv.setMovementMethod(new LinkMovementMethod());
binding.cancel.setOnClickListener(v -> {
dialog.dismiss();
});
binding.confirm.setOnClickListener(v -> {
confirmListener.onConfirm();
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(binding.getRoot());
dialog.show();
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
WindowManager.LayoutParams params = window.getAttributes();
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(60f);
window.setAttributes(params);
}
}
@SuppressLint("SetTextI18n")
public static void showReportReasonDialog(Context context, ReportReasonCallBack callBack) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
DialogReportReasonBinding binding = DialogReportReasonBinding.inflate(LayoutInflater.from(context));
binding.reasonOne.setOnClickListener(v -> {
dialog.dismiss();
callBack.onResponse(binding.reasonOne.getText().toString(), "");
});
binding.reasonTwo.setOnClickListener(v -> {
dialog.dismiss();
callBack.onResponse(binding.reasonTwo.getText().toString(), "");
});
binding.reasonThree.setOnClickListener(v -> {
dialog.dismiss();
callBack.onResponse(binding.reasonThree.getText().toString(), "");
});
binding.reasonFour.setOnClickListener(v -> {
dialog.dismiss();
callBack.onResponse(binding.reasonFour.getText().toString(), "");
});
binding.reasonOther.setOnClickListener(v -> {
binding.reasonTitle.setText(R.string.report_reason_other_title);
binding.normalReasonContainer.setVisibility(View.GONE);
binding.otherReasonContainer.setVisibility(View.VISIBLE);
});
binding.negativeBtn.setOnClickListener(v -> {
binding.reasonTitle.setText(R.string.report_reason_title);
binding.normalReasonContainer.setVisibility(View.VISIBLE);
binding.otherReasonContainer.setVisibility(View.GONE);
});
binding.positiveBtn.setOnClickListener(v -> {
if (TextUtils.isEmpty(binding.otherReasonEt.getText().toString().trim())) {
ToastUtils.INSTANCE.showToast("请填写举报原因");
} else {
dialog.dismiss();
callBack.onResponse("其它", binding.otherReasonEt.getText().toString());
}
});
Context finalContext = context;
ExtensionsKt.setTextChangedListener(binding.otherReasonEt, (s, start, before, count) -> {
int tvCount = s.length();
if (tvCount >= 500) {
binding.tvCount.setTextColor(ContextCompat.getColor(finalContext, R.color.text_FF4147));
}
binding.tvCount.setText(tvCount + "/500");
return null;
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(binding.getRoot());
dialog.show();
}
public static void showSignSuccessDialog(Context context, ConfirmListener listener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_sign_success, null);
ImageView signBg = contentView.findViewById(R.id.signBg);
RelativeLayout signContainer = contentView.findViewById(R.id.signContainer);
Animation animation1 = AnimationUtils.loadAnimation(context, R.anim.anim_badge_light_bg);
signBg.startAnimation(animation1);
Animation animation2 = AnimationUtils.loadAnimation(context, R.anim.anim_sign_dialog_dismiss);
signContainer.postDelayed(() -> signContainer.startAnimation(animation2), 2000);
signContainer.postDelayed(dialog::dismiss, 3000);
dialog.setOnDismissListener(dialogInterface -> listener.onConfirm());
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
public static void showSignRuleDialog(Context context) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_sign_rule, null);
contentView.findViewById(R.id.dialog_ok).setOnClickListener(v -> dialog.dismiss());
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
/**
* @param context may be is application context
* @return activity context
@ -1935,4 +2194,7 @@ public class DialogUtils {
void onResponse(boolean isSubscribe);
}
public interface ReportReasonCallBack {
void onResponse(String reason, String desc);
}
}

View File

@ -1,5 +1,6 @@
package com.gh.common.util
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
@ -39,6 +40,8 @@ import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.mygame.PlayedGameActivity
import com.gh.gamecenter.personalhome.UserHomeActivity
import com.gh.gamecenter.personalhome.background.PersonalityBackgroundActivity
import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
import com.gh.gamecenter.qa.CommunityFragment
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
import com.gh.gamecenter.qa.article.SimpleArticleListActivity
@ -48,10 +51,12 @@ import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.security.BindPhoneActivity
import com.gh.gamecenter.servers.GameServersActivity
import com.gh.gamecenter.subject.SubjectActivity
import com.gh.gamecenter.suggest.SuggestType
import com.gh.gamecenter.tag.TagsActivity
import com.gh.gamecenter.user.UserViewModel
import com.gh.gamecenter.video.data.VideoDataActivity
import com.gh.gamecenter.video.detail.VideoDetailActivity
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
@ -249,6 +254,68 @@ object DirectUtils {
"bbs_detail" -> directForumDetail(context, linkEntity.link ?: "", entrance)
"mobile_bind" -> {
CheckLoginUtils.checkLogin(context, entrance) {
context.startActivity(BindPhoneActivity.getNormalIntent(context, false))
}
}
"authentication" -> {
CheckLoginUtils.checkLogin(context, entrance) {
context.startActivity(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD))
}
}
"user_background" -> {
CheckLoginUtils.checkLogin(context, entrance) {
context.startActivity(PersonalityBackgroundActivity.getIntent(context))
}
}
"avatar_frame" -> {
CheckLoginUtils.checkLogin(context, entrance) {
context.startActivity(AvatarBorderActivity.getIntent(context))
}
}
"badge" -> {
CheckLoginUtils.checkLogin(context, entrance) {
UserManager.getInstance().userInfoEntity?.run {
directToBadgeWall(context, userId, name, icon)
}
}
}
"etiquette_exam" -> directToRegulationTestPage(context)
"setting" -> context.startActivity(SettingActivity.getIntent(context, false, entrance))
"index_page" -> directToHomeTab(context)
"video_upload" -> context.startActivity(VideoManagerActivity.getIntent(context, "", entrance))
"bbs" -> directToForum(context)
"user_page" -> directToHomeActivity(context, UserManager.getInstance().userId, "", entrance)
"video_tab" -> directToVideoTab(context)
"toolkit" -> context.startActivity(ToolBoxActivity.getIntent(context, entrance))
"toolkit_detail" -> {
linkEntity.toolkit?.run {
if (url != null && url!!.contains(Config.URL_ARTICLE)) {
val newsId = url!!.substring(url!!.lastIndexOf("/") + 1, url!!.length - 5) // 5: ".html"
val intent = NewsDetailActivity.getIntentById(context, newsId, entrance)
context.startActivity(intent)
} else {
context.startActivity(WebActivity.getWebByCollectionTools(context, this, false))
}
} ?: ""
}
"halo_tab" -> directToPersonalTab(context)
//"h5_game_center" -> directLetoGameCenter(context)
"" -> {
@ -578,12 +645,17 @@ object DirectUtils {
@JvmStatic
fun directToExternalBrowser(context: Context, url: String) {
if (url.isEmpty()) return
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(Uri.decode(url)))
if (context !is AppCompatActivity) {
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
if (url.isEmpty()) return
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(Uri.decode(url)))
if (context !is AppCompatActivity) {
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(browserIntent)
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
Utils.toast(context, "跳转地址无效")
}
context.startActivity(browserIntent)
}
// 跳转 QQqqNumber 为空选择默认客服 QQ
@ -1030,7 +1102,28 @@ object DirectUtils {
}
/**
* 到首页论坛 tab
* 到首页-首页 tab
*/
@JvmStatic
fun directToHomeTab(context: Context) {
if (RunningUtils.isRunning(context)
&& MainActivity::class.java.name == RunningUtils.getBaseActivity(context)) {
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
context.startActivity(intent)
// 这里换个线程操作是为了做一点延时
AppExecutor.ioExecutor.execute {
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_HOME))
}
} else {
jumpActivity(context, Bundle().apply { putInt(KEY_POSITION, MainWrapperFragment.INDEX_HOME) })
}
}
/**
* 到首页-论坛 tab
*/
@JvmStatic
fun directToForum(context: Context) {
@ -1049,6 +1142,46 @@ object DirectUtils {
}
}
/**
* 到首页-视频 tab
*/
@JvmStatic
fun directToVideoTab(context: Context) {
if (RunningUtils.isRunning(context)
&& MainActivity::class.java.name == RunningUtils.getBaseActivity(context)) {
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
context.startActivity(intent)
// 这里换个线程操作是为了做一点延时
AppExecutor.ioExecutor.execute {
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_VIDEO))
}
} else {
jumpActivity(context, Bundle().apply { putInt(KEY_POSITION, MainWrapperFragment.INDEX_VIDEO) })
}
}
/**
* 到首页-我的光环 tab
*/
@JvmStatic
fun directToPersonalTab(context: Context) {
if (RunningUtils.isRunning(context)
&& MainActivity::class.java.name == RunningUtils.getBaseActivity(context)) {
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
context.startActivity(intent)
// 这里换个线程操作是为了做一点延时
AppExecutor.ioExecutor.execute {
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_PERSONAL))
}
} else {
jumpActivity(context, Bundle().apply { putInt(KEY_POSITION, MainWrapperFragment.INDEX_PERSONAL) })
}
}
/**
* 跳转至使用帮助与反馈
* @param position 使用帮助:[HelpAndFeedbackActivity.HELP_ITEM],意见反馈:[HelpAndFeedbackActivity.SUGGESTION_ITEM]
@ -1060,4 +1193,95 @@ object DirectUtils {
bundle.putInt(BaseActivity_TabLayout.PAGE_INDEX, position)
jumpActivity(context, bundle)
}
/**
* 跳转至商品详情
*/
@JvmStatic
fun directToCommodityDetail(context: Context, commodityId: String) {
var url: String = if ("internal" == BuildConfig.FLAVOR) {
Constants.COMMODITY_DETAIL_ADDRESS_DEV
} else {
Constants.COMMODITY_DETAIL_ADDRESS
}
url = String.format(Locale.CHINA, "%s&shopid=%s&timestamp=%d", url, commodityId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至光能记录默认跳到光能记录第一个Tab
*/
@JvmStatic
fun directToEnergyRecord(context: Context) {
directToEnergyRecord(context, 0)
}
@JvmStatic
fun directToEnergyRecord(context: Context, position: Int) {
var url: String = if ("internal" == BuildConfig.FLAVOR) {
Constants.ENERGY_RECORD_ADDRESS_DEV
} else {
Constants.ENERGY_RECORD_ADDRESS
}
url = String.format(Locale.CHINA, "%s&position=%s&timestamp=%d", url, position, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至订单中心
*/
@JvmStatic
fun directToOrderCenter(context: Context) {
var url: String = if ("internal" == BuildConfig.FLAVOR) {
Constants.ORDER_CENTER_ADDRESS_DEV
} else {
Constants.ORDER_CENTER_ADDRESS
}
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至订单详情
*/
@JvmStatic
fun directToOrderDetail(context: Context, orderId: String) {
var url: String = if ("internal" == BuildConfig.FLAVOR) {
Constants.ORDER_DETAIL_ADDRESS_DEV
} else {
Constants.ORDER_DETAIL_ADDRESS
}
url = String.format(Locale.CHINA, "%s&order_id=%s&timestamp=%d", url, orderId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至邀请好友
*/
@JvmStatic
fun directToInviteFriends(context: Context) {
var url: String = if ("internal" == BuildConfig.FLAVOR) {
Constants.INVITE_FRIENDS_ADDRESS_DEV
} else {
Constants.INVITE_FRIENDS_ADDRESS
}
directToFullScreenWebPage(context, url, false)
}
/**
* 跳转至等级页面
*/
@JvmStatic
fun directToLevelPage(context: Context) {
var url: String = if (isPublishEnv()) {
Constants.LEVEL_ADDRESS
} else {
Constants.LEVEL_ADDRESS_DEV
}
url = String.format(Locale.CHINA, "%s?timestamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
}

View File

@ -125,16 +125,17 @@ public class DownloadItemUtils {
public static void updateItemWithReserveStatus(GameViewHolder holder, GameEntity gameEntity) {
if ("download".equals(gameEntity.getReserveStatus())) {
// 已上线
holder.gameDownloadBtn.setVisibility(View.VISIBLE);
holder.gameDownloadBtn.setText("已上线");
holder.gameDownloadBtn.setTextColor(Color.WHITE);
holder.gameDownloadBtn.setBackground(ContextCompat.getDrawable(holder.gameDes.getContext(), R.drawable.game_item_btn_pause_dn));
// holder.gameDownloadBtn.setVisibility(View.VISIBLE);
// holder.gameDownloadBtn.setText("已上线");
// holder.gameDownloadBtn.setTextColor(Color.WHITE);
// holder.gameDownloadBtn.setBackground(ContextCompat.getDrawable(holder.gameDes.getContext(), R.drawable.game_item_btn_pause_dn));
updateItem(holder.gameDes.getContext(), gameEntity, holder, false);
} else if ("appointment".equals(gameEntity.getReserveStatus())) {
// 已预约
holder.gameDownloadBtn.setVisibility(View.VISIBLE);
holder.gameDownloadBtn.setText("已预约");
holder.gameDownloadBtn.setTextColor(Color.WHITE);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_pause_dn);
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(holder.gameDes.getContext(), R.color.aaaaaa));
holder.gameDownloadBtn.setBackgroundResource(R.drawable.button_round_f5f5f5);
}
}
@ -579,7 +580,9 @@ public class DownloadItemUtils {
final String location,
@Nullable final ExposureEvent traceEvent) {
String str = downloadBtn.getText().toString();
ApkEntity apk = gameEntity.getApk().get(0);
if (gameEntity.getApk().isEmpty()) return;
ApkEntity apk = ExtensionsKt.safelyGetInRelease(gameEntity.getApk(), 0);
if (apk == null) return;
if (str.equals(context.getString(R.string.download))) {
// 先弹下载弹窗(如果需要的话)
@ -654,6 +657,8 @@ public class DownloadItemUtils {
}
DataUtils.onGameLaunchEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk().get(0).getPackageName());
EnergyTaskHelper.postEnergyTask("play_game", gameEntity.getId(), gameEntity.getApk().get(0).getPackageName());
} else if (str.equals(context.getString(R.string.update))) {
if (entrance.contains("我的游戏")) {
MtaHelper.onEvent("我的游戏_启动", "更新", gameEntity.getName());
@ -687,6 +692,8 @@ public class DownloadItemUtils {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
DeviceRemindDialog.Companion.showDeviceRemindDialog(context, gameEntity);
EnergyTaskHelper.postEnergyTask("download_game", gameEntity.getId(), gameEntity.getApk().get(0).getPackageName());
} else {
Utils.toast(context, msg);
}

View File

@ -16,6 +16,7 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.SuggestionActivity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.SimpleGameEntity
import com.gh.gamecenter.entity.SimulatorEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBShowDialog
import com.gh.gamecenter.retrofit.Response
@ -50,7 +51,7 @@ object DownloadObserver {
val xapkStatus = downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
if (!xapkStatus.isNullOrEmpty()) return
val gameId = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)
val gameId = downloadEntity.gameId
val downloadManager = DownloadManager.getInstance(HaloApp.getInstance().application)
tryCatchInRelease {
@ -111,6 +112,7 @@ object DownloadObserver {
}
if (DownloadStatus.done == downloadEntity.status) {
if (downloadEntity.name.contains(mApplication.getString(R.string.app_name))) {
statDoneEvent(downloadEntity)
MtaHelper.onEvent("软件更新", "下载完成")
// 会有 ActivityNotFoundException 异常catch 掉不管了
tryWithDefaultCatch {
@ -138,19 +140,20 @@ object DownloadObserver {
}
if (!downloadEntity.isPluggable) {
if (downloadEntity.isSimulatorGame()) {
val gameEntity = HaloApp.get(GameEntity::class.java.simpleName, true) as? GameEntity
if (gameEntity?.simulator != null) {
val isInstalled = PackageUtils.isInstalledFromAllPackage(HaloApp.getInstance().application, gameEntity.simulator!!.apk!!.packageName)
if (!isInstalled) {
val currentActivity = AppManager.getInstance().currentActivity() ?: return
val simulatorJson = downloadEntity.getMetaExtra(Constants.SIMULATOR)
val gameName = downloadEntity.getMetaExtra(Constants.GAME_NAME)
if (simulatorJson.isEmpty()) return
val simulator = GsonUtils.fromJson(simulatorJson, SimulatorEntity::class.java)
val isInstalled = PackageUtils.isInstalledFromAllPackage(HaloApp.getInstance().application, simulator.apk?.packageName)
if (!isInstalled) {
val currentActivity = AppManager.getInstance().currentActivity()
?: return
SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, gameEntity.simulator,
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.id, gameEntity.name
?: "", null)
}
SimulatorGameManager.recordDownloadSimulatorGames(gameEntity.id)
SimulatorGameManager.postPlayedGame(gameEntity.id, downloadEntity.packageName)
SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator,
SimulatorDownloadManager.SimulatorLocation.LAUNCH, downloadEntity.gameId, gameName, null)
}
SimulatorGameManager.recordDownloadSimulatorGames(downloadEntity.gameId)
SimulatorGameManager.postPlayedGame(downloadEntity.gameId, downloadEntity.packageName)
} else {
val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
// 是否是自动安装
@ -179,15 +182,33 @@ object DownloadObserver {
}
// 下载过程分析统计
// val pm = mApplication.packageManager
// val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0)
// if (packageInfo == null) {
// 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
// 这里为了让它能用就不判断是否解析包错误了
if (PackageUtils.isDeviceUnableToHandleBigApkFile(downloadEntity.path)) {
return
}
val pm = mApplication.packageManager
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0)
if (packageInfo == null) {
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析",
// "游戏名字", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
//
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误_新",
// "游戏", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
// }
val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
if (downloadType == Constants.SIMULATOR_DOWNLOAD) {
val currentActivity = AppManager.getInstance().currentActivity()
?: return
DialogUtils.showSimulatorParseErrorDialog(currentActivity, downloadEntity.gameId, downloadEntity.name) {
val simulator = HaloApp.get(downloadEntity.name, true) as? SimulatorEntity
?: return@showSimulatorParseErrorDialog
DownloadManager.getInstance(currentActivity).cancel(downloadEntity.url, true, true)
SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator, SimulatorDownloadManager.SimulatorLocation.SIMULATOR_GAME)
}
}
}
}
if (downloadEntity.status == DownloadStatus.done) {
@ -219,7 +240,7 @@ object DownloadObserver {
kv1["版本"] = platform
kv1["状态"] = "下载完成"
kv1["用户机型"] = Build.MODEL
kv1["设备IMEI"] = MetaUtil.getIMEI()
kv1["设备JNFJ"] = MetaUtil.getBase64EncodedIMEI()
kv1["网络状态"] = DeviceUtils.getNetwork(HaloApp.getInstance().application)
kv1["光环助手版本"] = BuildConfig.VERSION_NAME
if (downloadEntity.isUpdate) {
@ -257,7 +278,7 @@ object DownloadObserver {
}
ExposureUtils.logADownloadCompleteExposureEvent(
GameEntity(id = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER),
GameEntity(id = downloadEntity.gameId,
mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR),
gameVersion = downloadEntity.versionName ?: ""),
downloadEntity.platform,
@ -287,7 +308,7 @@ object DownloadObserver {
params["game"] = id
params["platform"] = platform ?: ""
val body = RequestBody.create(MediaType.parse("application/json"),
JSONObject(params).toString())
JSONObject(params as Map<*, *>).toString())
RetrofitManager.getInstance(mApplication).api.postDownload(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

View File

@ -0,0 +1,160 @@
package com.gh.common.util
import android.annotation.SuppressLint
import android.view.Gravity
import android.view.View
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import com.gh.common.constant.Constants
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.R
import com.gh.gamecenter.energy.EnergyCenterActivity
import com.gh.gamecenter.entity.EnergyTaskCompleteEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import org.json.JSONObject
/**
* 上报光能任务辅助类
*/
object EnergyTaskHelper {
@JvmStatic
fun postEnergyTask(action: String) {
postEnergyTask(action, null, null, null)
}
@JvmStatic
fun postEnergyTask(action: String, id: String) {
postEnergyTask(action, id, null, null)
}
@JvmStatic
fun postEnergyTask(action: String, id: String, packageName: String) {
postEnergyTask(action, id, packageName, null)
}
@JvmStatic
fun postEnergyTaskForWeb(action: String, url: String) {
postEnergyTask(action, null, null, url)
}
@JvmStatic
fun postEnergyTaskForShare(type: String, id: String, url: String) {
when (type) {
"游戏详情" -> postEnergyTask("share_game_detail", id)
"视频" -> postEnergyTask("share_video", id)
"资讯文章" -> postEnergyTask("share_article", id)
"问题详情" -> postEnergyTask("share_question", id)
"回答详情" -> postEnergyTask("share_answer", id)
"文章详情" -> postEnergyTask("share_community_article", id)
"工具箱" -> postEnergyTask("share_toolkit", id)
"web链接" -> postEnergyTaskForWeb("share_web", url)
}
}
@SuppressLint("CheckResult")
@JvmStatic
fun postEnergyTask(action: String, id: String? = null, packageName: String? = null, url: String? = null) {
if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0L) {
val taskParams = JSONObject()
taskParams.put("action", action)
val actionParams = JSONObject()
if (id != null) actionParams.put("_id", id)
if (packageName != null) actionParams.put("package", packageName)
if (url != null) actionParams.put("url", url)
taskParams.put("action_param", actionParams)
debugOnly { Utils.log("EnergyTaskHelper -> $taskParams") }
val body = RequestBody.create(MediaType.parse("application/json"), taskParams.toString())
RetrofitManager.getInstance(HaloApp.getInstance().application)
.api.postEnergyTask(UserManager.getInstance().userId, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<List<EnergyTaskCompleteEntity>>() {
override fun onSuccess(data: List<EnergyTaskCompleteEntity>) {
data.forEach { showCompletePopup(it) }
}
})
}
}
@SuppressLint("CheckResult")
@JvmStatic
fun postInviteCodeTask(code: String, from: String, successCallback: () -> Unit, failCallback: () -> Unit) {
if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0L) {
val taskParams = JSONObject()
taskParams.put("action", "enter_invite_code")
val actionParams = JSONObject()
actionParams.put("code", code)
actionParams.put("type", "new")
actionParams.put("from", from)
taskParams.put("action_param", actionParams)
debugOnly { Utils.log("EnergyTaskHelper -> $taskParams") }
val body = RequestBody.create(MediaType.parse("application/json"), taskParams.toString())
RetrofitManager.getInstance(HaloApp.getInstance().application)
.api.postEnergyTask(UserManager.getInstance().userId, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<List<EnergyTaskCompleteEntity>>() {
override fun onSuccess(data: List<EnergyTaskCompleteEntity>) {
SPUtils.setBoolean(Constants.SP_HAS_COMPLETE_INVITE_CODE, true)
successCallback.invoke()
data.forEach { showCompletePopup(it) }
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
failCallback.invoke()
}
})
}
}
// 完成弹窗
@JvmStatic
fun showCompletePopup(entity: EnergyTaskCompleteEntity) {
val currentActivity = AppManager.getInstance().recentActiveActivity
currentActivity?.run {
val contentView = View.inflate(this, R.layout.popup_energy_task, null)
contentView.run {
findViewById<TextView>(R.id.taskDesc).text = "恭喜你!完成任务:${entity.name}"
findViewById<TextView>(R.id.taskEnergy).text = "+${entity.energy}光能"
isFocusable = true
isFocusableInTouchMode = true
setOnClickListener {
currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity))
}
}
val popWindow = PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, 88F.dip2px())
popWindow.showAtLocation(currentActivity.window.decorView, Gravity.TOP, 0, 0)
countDownTimer(3) { finish, _ ->
if (finish && popWindow != null && popWindow.isShowing) {
popWindow.dismiss()
}
}
}
}
}

View File

@ -221,6 +221,9 @@ public class EntranceUtils {
public static final String KEY_PRIMARY_CATALOG_NAME = "primaryCatalogName";
public static final String KEY_CATALOG_TITLE = "catalog_title";
public static final String KEY_CATALOG_INIT_TITLE = "catalog_init_title";
public static final String KEY_CATEGORY_LIST = "categoty_list";
public static final String KEY_IS_FREE = "is_free";
public static final String KEY_IS_SIGN = "is_sign";
public static void jumpActivity(Context context, Bundle bundle) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);

View File

@ -6,6 +6,7 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.entity.ErrorEntity
import com.lightgame.utils.Utils
import retrofit2.HttpException
/**
* 这个类用来管理一些错误像弹窗、TOAST 什么的
@ -17,6 +18,7 @@ object ErrorHelper {
* [showHighPriorityHint] 用来标识有同样错误码可以触发两种处理时,为 true 时选择重要的
* [customizedHandler] 返回 true 为已处理该错误码false 则交由 [handleError] 处理
*/
@JvmStatic
fun handleErrorWithCustomizedHandler(context: Context,
errorString: String?,
showHighPriorityHint: Boolean = false,
@ -169,4 +171,23 @@ object ErrorHelper {
}, null)
}
@JvmStatic
fun handleLoginError(context: Context, httpException: HttpException?) {
try {
val errorEntity: ErrorEntity? = httpException?.response()?.errorBody()?.string()?.toObject()
when {
errorEntity?.code == 403099 -> {
Utils.toast(context, "当前账号正在注销,禁止登录")
}
errorEntity?.toast?.isNotEmpty() == true -> {
Utils.toast(context, errorEntity.toast)
}
else -> Utils.toast(context, R.string.login_failure)
}
} catch (e: Exception) {
e.printStackTrace()
Utils.toast(context, R.string.login_failure)
}
}
}

View File

@ -424,7 +424,7 @@ fun String.copyTextAndToast(toastText: String = "复制成功") {
val application = HaloApp.getInstance().application
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(null, this)
cmb.primaryClip = clip
cmb.setPrimaryClip(clip)
if (!TextUtils.isEmpty(toastText)) {
ToastUtils.showToast(toastText)
@ -534,6 +534,14 @@ fun Fragment.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
})
}
fun Fragment.checkCalendarPermissionBeforeAction(action: (() -> Unit)) {
PermissionHelper.checkCalendarPermissionBeforeAction(requireContext(), object : EmptyCallback {
override fun onCallback() {
action.invoke()
}
})
}
fun FragmentActivity.checkReadPhoneStateAndStoragePermissionBeforeAction(action: (() -> Unit)) {
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(this, object : EmptyCallback {
override fun onCallback() {
@ -558,6 +566,14 @@ fun FragmentActivity.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
})
}
fun FragmentActivity.checkCalendarPermissionBeforeAction(action: (() -> Unit)) {
PermissionHelper.checkCalendarPermissionBeforeAction(this, object : EmptyCallback {
override fun onCallback() {
action.invoke()
}
})
}
/**
* List related.
*/
@ -602,11 +618,11 @@ fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before
}
/**
* ArrayList related
* List related
*/
fun <T> ArrayList<T>.safelyGetInRelease(index: Int): T? {
fun <T> List<T>.safelyGetInRelease(index: Int): T? {
return if (index >= size) {
throwExceptionInDebug("这里触发了数组越界,请检查")
throwExceptionInDebug("这里触发了数组越界,请检查 (index $index >= size $size)")
toastInInternalRelease("这个操作可能触发闪退,请确定复现方式并联系开发处理")
null
} else {
@ -706,11 +722,16 @@ fun SimpleDraweeView.display(url: String) {
* DownloadEntity extension
*/
fun DownloadEntity.addMetaExtra(key: String, value: String?) {
value?.let { meta[key] = value }
value?.let {
if (meta == null) {
meta = hashMapOf()
}
meta[key] = value
}
}
fun DownloadEntity.getMetaExtra(key: String): String {
return meta[key] ?: ""
return meta?.get(key) ?: ""
}
fun DownloadEntity.isSilentUpdate(): Boolean {
@ -732,6 +753,9 @@ fun Context.doOnMainProcessOnly(callback: EmptyCallback) {
doOnMainProcessOnly { callback.onCallback() }
}
/**
* 虽然现在我们没有了友盟以后只是单进程APP但在 debug 模式下还有 whatTheStack 这个进程如果不限定主进程会出现奇奇怪怪的问题 (BroadcastReceiver相关)
*/
inline fun Context.doOnMainProcessOnly(f: () -> Unit) {
val processName = PackageUtils.obtainProcessName(this)
if (processName == null || BuildConfig.APPLICATION_ID == processName) {

View File

@ -78,6 +78,9 @@ public class GameUtils {
int pluginCount = 0; // 可插件化数量
int updateCount = 0; // 可更新数量
int installCount = 0; // 已安装数量
boolean isRelatedEmulatorInstalled = false; // 若该游戏是模拟器游戏时其对应的模拟器是否已经安装
DownloadEntity downloadEntity;
Object gh_id;
apkFor:
@ -113,7 +116,10 @@ public class GameUtils {
&& !PackageUtils.isSignedByGh(context, apkEntity.getPackageName())
&& apkEntity.isShowPlugin(pluginLocation)) {
pluginCount++;
} else if (gh_id == null || gh_id.equals(gameEntity.getId())) {
} else if (gh_id == null
|| gh_id.equals(gameEntity.getId())
// 当使用镜像时,可能会存在镜像 gh_id 与当前游戏 id 不一样的情况,这时也让它通过,避免装完还是显示`下载`
|| gameEntity.shouldUseMirrorInfo()) {
installCount++;
}
}
@ -123,20 +129,26 @@ public class GameUtils {
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(context, gameEntity.getSimulator().getApk().getPackageName());
if (isInstalled) {
installCount++;
isRelatedEmulatorInstalled = true;
} else {
doneCount++;
}
}
}
}
if (installCount != 0) {
if (isRelatedEmulatorInstalled && doneCount != 0) {
return context.getString(R.string.launch);
}
if (doneCount != 0) {
return context.getString(R.string.install);
} else if (pluginCount != 0 && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
return context.getString(R.string.pluggable);
} else if (updateCount != 0 && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
return context.getString(R.string.update);
} else if (doneCount != 0) {
return context.getString(R.string.install);
} else if (installCount != 0) {
return context.getString(R.string.launch);
} else if (gameEntity.getVersionNumber().contains("无版号") && Config.isGameDomeSwitchOpen() && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
return context.getString(R.string.attempt);
} else {

View File

@ -38,13 +38,18 @@ object HomePluggableHelper {
@JvmStatic
fun activationFilterData() {
val filterList = mHomePluggableFilterDao.getDataByActive(false)
try {
val filterList = mHomePluggableFilterDao.getDataByActive(false)
if (filterList != null) {
for (entity in filterList) {
entity.active = true
if (filterList != null) {
for (entity in filterList) {
entity.active = true
}
mHomePluggableFilterDao.addData(filterList)
}
tryCatchInRelease { mHomePluggableFilterDao.addData(filterList) }
} catch (e: Exception) {
e.printStackTrace()
toastInInternalRelease("数据库/磁盘已满,插件筛选失败")
}
}
}

View File

@ -24,6 +24,7 @@ import com.facebook.imagepipeline.image.CloseableImage
import com.facebook.imagepipeline.image.ImageInfo
import com.facebook.imagepipeline.request.ImageRequest
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.facebook.imagepipeline.request.Postprocessor
import com.gh.common.constant.Config
import com.gh.common.structure.FixedSizeLinkedHashSet
import com.gh.gamecenter.R
@ -85,8 +86,13 @@ object ImageUtils {
@JvmStatic
fun addLimitWidth(imageUrl: String?, width: Int?): String? {
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
val webpConfig = Config.getSettings()?.image?.oss?.webp ?: Config.getSettings()?.image?.oss?.gif
if (jpegConfig != null) {
return "$imageUrl$jpegConfig,w_$width"
return if (width == 0 || width == null) {
"$imageUrl$webpConfig"
} else {
"$imageUrl$jpegConfig,w_$width"
}
}
return imageUrl
}
@ -286,12 +292,13 @@ object ImageUtils {
/**
* 规则 width>0 Wifi/4G:x2 traffic:x1
* 统一加载 webp 忽略掉第二种方案
* 第一种方案:通过LayoutParams获取 可以快速(无延迟)获取宽高,但是无法获取wrap_content和match_parent的View
* 第二种方案(备用方案):有延迟,View的宽高需要在Measure过程后才能确定,能够在这里获取到正确的宽高
* ~~第二种方案(备用方案):有延迟,View的宽高需要在Measure过程后才能确定,能够在这里获取到正确的宽高~~
* @param isAutoPlayGif 是否禁止播放动图
*/
@JvmStatic
fun display(view: SimpleDraweeView?, url: String?, isAutoPlayGif: Boolean = true) {
fun display(view: SimpleDraweeView?, url: String?, isAutoPlayGif: Boolean = true, processor: Postprocessor? = null) {
if (url == null) return
val width = view?.layoutParams?.width
@ -310,40 +317,47 @@ object ImageUtils {
}
val loadImageClosure: (autoPlay: Boolean, highResUrl: String, lowResUrl: String) -> Unit = { autoPlay, hUrl, lUrl ->
view?.controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(ImageRequest.fromUri(hUrl))
val imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(hUrl))
.setPostprocessor(processor)
.build()
val controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(imageRequest)
.apply {
if (lUrl.isNotEmpty()
&& lUrl != hUrl
&& hUrl != view?.getTag(R.string.highResImageTag)) {
lowResImageRequest = ImageRequest.fromUri(lUrl)
lowResImageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(lUrl))
.setPostprocessor(processor)
.build()
}
autoPlayAnimations = autoPlay
}
.build()
view?.controller = controller
view?.setTag(R.string.highResImageTag, highResUrl)
}
val shouldLoadAsGif = url.endsWith(".gif") && isAutoPlayGif && view?.getTag(R.id.tag_show_gif) != false
// 低于 2G 运行内存的不加载 gif
val shouldLoadAsGif = url.endsWith(".gif")
&& isAutoPlayGif
&& (HaloApp.getInstance().deviceRamSize == 0L || HaloApp.getInstance().deviceRamSize > 2500)
&& view?.getTag(R.id.tag_show_gif) != false
if (shouldLoadAsGif && view?.tag == url) return
if (width != null && width > 0) {
highResUrl = if (shouldLoadAsGif) {
resizeGif(url, width, height ?: 0)
} else {
getTransformLimitUrl(url, width, view.context) ?: ""
}
if (!shouldLoadAsGif) {
highResUrl = getTransformLimitUrl(url, width ?: 0, view?.context) ?: ""
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
} else {
view?.post {
highResUrl = if (shouldLoadAsGif) {
resizeGif(url, view.width, height ?: 0)
} else {
getTransformLimitUrl(url, view.width, view.context) ?: ""
}
if (width != null && width > 0) {
highResUrl = resizeGif(url, view.width, height ?: 0)
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
} else {
view?.post {
highResUrl = resizeGif(url, view.width, height ?: 0)
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
}
}
}
view?.tag = url
@ -352,25 +366,27 @@ object ImageUtils {
// Wifi/4G:x2 traffic:x1
@JvmStatic
fun getTransformLimitUrl(url: String?, width: Int?, context: Context?): String? {
var transformUrl: String? = url
val transformUrl: String?
if (width != null && width > 0) {
// 加载大小是实际 ImageView 大小两倍的图片真的有意义吗?
val transformUrlX2 = addLimitWidth(url, width * 2)
val transformUrlX1 = addLimitWidth(url, width)
// 当网络为 WIFI 或 4G 且系统版本大于 5.0 && 手机内存大于 1G 才用高清图片
if (NetworkUtils.isWifiOr4GConnected(context)
// 当网络为 WIFI 或 4G 且系统版本大于 5.0 && 手机内存大于 2G 才用高清图片
transformUrl = if (NetworkUtils.isWifiOr4GConnected(context)
&& Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP
&& HaloApp.getInstance().deviceRamSize > 1024) {
transformUrl = transformUrlX2
&& HaloApp.getInstance().deviceRamSize > 2500) {
transformUrlX2
} else {
// 检查X2大图是否被缓存
if (Fresco.getImagePipeline().isInBitmapMemoryCache(Uri.parse(transformUrlX2)) ||
Fresco.getImagePipeline().isInDiskCacheSync(Uri.parse(transformUrlX2))) {
transformUrl = transformUrlX2
transformUrlX2
} else {
transformUrl = transformUrlX1
transformUrlX1
}
}
} else {
transformUrl = addLimitWidth(url, null)
}
addCachedUrl(transformUrl ?: "")
return transformUrl
@ -383,9 +399,7 @@ object ImageUtils {
if (width != null && width > 0) {
view.setImageURI(addLimitWidth(url, width * 2))
} else {
view?.post {
view.setImageURI(addLimitWidth(url, view.width * 2))
}
view?.setImageURI(addLimitWidth(url, view.width * 2))
}
}
@ -395,6 +409,18 @@ object ImageUtils {
}
}
/**
* 获取已缓存的图片地址,不区分质量,暂时只供查看大图页面使用
*/
fun getCachedUrl(url: String): String {
for (decoratedUrl in mImageUrlCacheSet) {
if (decoratedUrl.contains(url)) {
return decoratedUrl
}
}
return url
}
@JvmStatic
fun bmpToByteArray(bmp: Bitmap, needRecycle: Boolean): ByteArray {
val output = ByteArrayOutputStream()
@ -444,7 +470,7 @@ object ImageUtils {
}
}
public interface OnImageloadListener {
interface OnImageloadListener {
fun onLoadFinal(imageInfo: ImageInfo?)
}

View File

@ -18,11 +18,11 @@ public class Installation {
private static String sID = null;
public synchronized static String getUUID(Context context) {
String imei = MetaUtil.getIMEI();
String imei = MetaUtil.getBase64EncodedIMEI();
if (!TextUtils.isEmpty(imei)) {
return imei;
}
String android_id = MetaUtil.getAndroidId();
String android_id = MetaUtil.getBase64EncodedAndroidId();
if (!TextUtils.isEmpty(android_id)) {
return android_id;
}

View File

@ -19,6 +19,7 @@ import com.gh.gamecenter.entity.CommunityEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.ShareResultEntity;
import com.gh.gamecenter.entity.SpecialColumn;
import com.gh.gamecenter.entity.StartupAdEntity;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.qa.entity.Questions;
import com.gh.gamecenter.retrofit.EmptyResponse;
@ -235,6 +236,7 @@ public class LogUtils {
object.put("game_name", gameEntity.getName());
object.put("game_id", gameEntity.getId());
object.put("game_platform", gameEntity.getPlatform());
object.put("download_open", gameEntity.getDownloadOffStatus() == null ? "true" : "false");
} catch (JSONException e) {
e.printStackTrace();
}
@ -255,13 +257,13 @@ public class LogUtils {
try {
object.put("version", PackageUtils.getVersionName());
object.put("channel", HaloApp.getInstance().getChannel());
object.put("android_id", MetaUtil.getAndroidId());
object.put("dia", MetaUtil.getBase64EncodedAndroidId());
object.put("time", Utils.getTime(context));
object.put("network", DeviceUtils.getNetwork(context));
object.put("user_id", UserManager.getInstance().getUserId());
object.put("device_system", android.os.Build.VERSION.RELEASE);
object.put("device_model", android.os.Build.MODEL);
object.put("imei", MetaUtil.getIMEI());
object.put("jnfj", MetaUtil.getBase64EncodedIMEI());
object.put("G_ID", UserManager.getInstance().getDeviceId());
} catch (JSONException e) {
e.printStackTrace();
@ -279,13 +281,13 @@ public class LogUtils {
try {
object.put("version", PackageUtils.getVersionName());
object.put("channel", HaloApp.getInstance().getChannel());
object.put("android_id", MetaUtil.getAndroidId());
object.put("dia", MetaUtil.getBase64EncodedAndroidId());
object.put("time", Utils.getTime(context));
object.put("network", DeviceUtils.getNetwork(context));
object.put("user_id", UserManager.getInstance().getUserId());
object.put("device_system", android.os.Build.VERSION.RELEASE);
object.put("device_model", android.os.Build.MODEL);
object.put("imei", MetaUtil.getIMEI());
object.put("jnfj", MetaUtil.getBase64EncodedIMEI());
object.put("G_ID", UserManager.getInstance().getDeviceId());
} catch (JSONException e) {
e.printStackTrace();
@ -298,13 +300,13 @@ public class LogUtils {
Meta meta = MetaUtil.INSTANCE.getMeta();
JSONObject metaObject = new JSONObject();
try {
metaObject.put("android_id", meta.getAndroid_id());
metaObject.put("dia", MetaUtil.getBase64EncodedAndroidId());
metaObject.put("android_sdk", meta.getAndroid_sdk());
metaObject.put("android_version", meta.getAndroid_version());
metaObject.put("appVersion", meta.getAppVersion());
metaObject.put("channel", meta.getChannel());
metaObject.put("gid", meta.getGid());
metaObject.put("imei", meta.getImei());
metaObject.put("jnfj", MetaUtil.getBase64EncodedIMEI());
metaObject.put("mac", meta.getMac());
metaObject.put("manufacturer", meta.getManufacturer());
metaObject.put("model", meta.getModel());
@ -376,6 +378,63 @@ public class LogUtils {
uploadVideoStreaming(object);
}
public static void uploadTopVideoStreamingPlaying(String action, String videoId, String videoTitle, String gameId, String gameName, String videoModel, String videoPlayStatus, double videoSize, int videoTotalTime, int videoPlayTs, int progress) {
JSONObject object = new JSONObject();
JSONObject payloadObject = new JSONObject();
try {
object.put("event", "TOP_VIDEO_PLAYING");
object.put("action", action);
payloadObject.put("video_mode", videoModel);//视频播放方式 ["自动播放"/"点击播放"/"全屏播放"]
payloadObject.put("video_id", videoId);
payloadObject.put("video_title", videoTitle);
payloadObject.put("game_id", gameId);
payloadObject.put("game_name", gameName);
payloadObject.put("video_size", videoSize);
payloadObject.put("video_total_time", videoTotalTime);
payloadObject.put("progress", progress);
payloadObject.put("video_play_ts", videoPlayTs);
payloadObject.put("video_play_status", videoPlayStatus);
object.put("payload", payloadObject);
object.put("meta", getMetaObject());
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "video_streaming", false);
}
public static void uploadHomeVideoStreamingPlaying(String action, boolean videoShade, String videoId, String videoTitle, String gameId, String gameName, double videoSize, int videoTotalTime, int videoPlayTs, int progress) {
JSONObject object = new JSONObject();
JSONObject payloadObject = new JSONObject();
try {
object.put("event", "HOME_VIDEO_PLAYING");
object.put("action", action);
payloadObject.put("video_id", videoId);
payloadObject.put("video_title", videoTitle);
payloadObject.put("game_id", gameId);
payloadObject.put("game_name", gameName);
payloadObject.put("video_size", videoSize);
payloadObject.put("video_total_time", videoTotalTime);
payloadObject.put("progress", progress);
payloadObject.put("video_play_ts", videoPlayTs);
payloadObject.put("video_shade", String.valueOf(videoShade));//["true"/"false"]是否存在引导遮罩
object.put("payload", payloadObject);
object.put("meta", getMetaObject());
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "video_streaming", false);
}
public static void uploadWelcomeDialog(String action, String dialogId, String linkTitle) {
ExposureEntity payload = new ExposureEntity();
payload.setWelcomeDialogId(dialogId);
@ -429,13 +488,13 @@ public class LogUtils {
Meta meta = MetaUtil.INSTANCE.getMeta();
JSONObject metaObject = new JSONObject();
try {
metaObject.put("android_id", meta.getAndroid_id());
metaObject.put("dia", MetaUtil.getBase64EncodedAndroidId());
metaObject.put("android_sdk", meta.getAndroid_sdk());
metaObject.put("android_version", meta.getAndroid_version());
metaObject.put("appVersion", meta.getAppVersion());
metaObject.put("channel", meta.getChannel());
metaObject.put("gid", meta.getGid());
metaObject.put("imei", meta.getImei());
metaObject.put("jnfj", MetaUtil.getBase64EncodedIMEI());
metaObject.put("mac", meta.getMac());
metaObject.put("manufacturer", meta.getManufacturer());
metaObject.put("model", meta.getModel());
@ -523,13 +582,13 @@ public class LogUtils {
Meta meta = MetaUtil.INSTANCE.getMeta();
JSONObject metaObject = new JSONObject();
try {
metaObject.put("android_id", meta.getAndroid_id());
metaObject.put("dia", MetaUtil.getBase64EncodedAndroidId());
metaObject.put("android_sdk", meta.getAndroid_sdk());
metaObject.put("android_version", meta.getAndroid_version());
metaObject.put("appVersion", meta.getAppVersion());
metaObject.put("channel", meta.getChannel());
metaObject.put("gid", meta.getGid());
metaObject.put("imei", meta.getImei());
metaObject.put("jnfj", MetaUtil.getBase64EncodedIMEI());
metaObject.put("mac", meta.getMac());
metaObject.put("manufacturer", meta.getManufacturer());
metaObject.put("model", meta.getModel());
@ -612,10 +671,16 @@ public class LogUtils {
}
public static void uploadSearchGame(String event, String location, String key, String searchType) {
uploadSearchClick(event, location, key, searchType, "", "");
uploadSearchClick(event, location, key, searchType, "", "", false);
}
public static void uploadSearchClick(String event, String location, String key, String searchType, String gameId, String gameName) {
public static void uploadSearchClick(String event,
String location,
String key,
String searchType,
String gameId,
String gameName,
Boolean isMirrorData) {
JSONObject object = new JSONObject();
JSONObject payload = new JSONObject();
try {
@ -628,6 +693,7 @@ public class LogUtils {
payload.put("search_type", searchType); //搜索类型, 有四种取值 默认搜索/历史搜索/自动搜索/主动搜索
payload.put("game_id", gameId); //event为search_click才取值
payload.put("game_name", gameName); //event为search_click才取值
payload.put("is_mirror_data", isMirrorData);
object.put("payload", payload);
} catch (JSONException e) {
e.printStackTrace();
@ -659,6 +725,25 @@ public class LogUtils {
logCatalogEvent("click_content_list", entrance, key, seq1, -1, seqContent, seqContentList);
}
public static void logSpecialCatalogBannerClickEvent(String key, int seq) {
JSONObject object = new JSONObject();
try {
object.put("event", "category_lunbo_click");
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
object.put("key", key);
object.put("sequence", seq);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
private static void logCatalogEvent(String event, String entrance, String key, int seq1, int seq2, int seqContent, int seqContentList) {
JSONObject object = new JSONObject();
JSONObject payload = new JSONObject();
@ -683,4 +768,48 @@ public class LogUtils {
}
LoghubUtils.log(object, "event", false);
}
public static void uploadPackageSkip(String event, String action, String gameId, String gameName) {
JSONObject object = new JSONObject();
try {
object.put("event", event);//external_jump/external_show
object.put("action", action);
if (!TextUtils.isEmpty(gameId) && !TextUtils.isEmpty(gameName)) {
object.put("game_id", gameId);
object.put("game_name", gameName);
}
object.put("meta", getMetaObject());
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void logStartAd(String event, StartupAdEntity adEntity) {
JSONObject object = new JSONObject();
try {
object.put("event", event);
object.put("timestamp", System.currentTimeMillis() / 1000);
object.put("meta", getMetaObject());
if (adEntity != null) {
object.put("abs_id", adEntity.getId());
object.put("abs_text", adEntity.getDesc());
if (adEntity.getButton()) {
object.put("abs_type", adEntity.getJump().getType());
object.put("abs_link", adEntity.getJump().getLink());
object.put("abs_link_title", adEntity.getJump().getText());
}
}
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
}

View File

@ -29,7 +29,10 @@ import android.widget.TextView;
import com.gh.common.Base64ImageHolder;
import com.gh.common.constant.Config;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WeiBoShareActivity;
import com.lightgame.utils.Utils;
import com.sina.weibo.sdk.WbSdk;
import com.sina.weibo.sdk.auth.AuthInfo;
import com.tencent.connect.auth.QQToken;
import com.tencent.connect.share.QQShare;
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX;
@ -48,7 +51,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Date;
import java.util.List;
import static com.gh.common.util.LoginHelper.WEIBO_SCOPE;
/**
* Created by khy on 2016/11/8.
@ -86,13 +90,17 @@ public class MessageShareUtils {
@Override
public void onError(UiError uiError) {
// 单分享图片不支持显示未安装弹窗,手动调出
Activity activity = mActivity.get();
if (activity != null && !ShareUtils.isQQClientAvailable(activity.getApplication())) {
new TDialog(activity,
"",
"http://openmobile.qq.com/oauth2.0/m_jump_by_version",
null,
new QQToken("")).show();
if (mActivity != null) {
Activity activity = mActivity.get();
if (activity != null && !ShareUtils.isQQClientAvailable(activity.getApplication())) {
new TDialog(activity,
"",
"http://openmobile.qq.com/oauth2.0/m_jump_by_version",
null,
new QQToken("")).show();
} else {
Utils.toast(mContext, "分享失败");
}
} else {
Utils.toast(mContext, "分享失败");
}
@ -207,49 +215,54 @@ public class MessageShareUtils {
}
public void shareFromWeb(Activity activity, String type) {
// base64转bitmap
byte[] decode = Base64.decode(Base64ImageHolder.INSTANCE.getImage(), Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(decode, 0, decode.length);
// 转完后重新置位
Base64ImageHolder.INSTANCE.setImage("");
this.picName = "shareImgPic.jpg";
this.mActivity = new WeakReference<>(activity);
this.shareBm = bitmap;
// 保存图片
File file = new File(activity.getExternalCacheDir().getPath() + "/ShareImg");
if (!file.isDirectory()) {
file.delete();
file.mkdirs();
}
if (!file.exists()) {
file.mkdirs();
}
writeBitmap(file.getPath(), picName, bitmap, false);
if ("weibo".equals(type)) {
weiboShare();
} else {
// base64转bitmap
byte[] decode = Base64.decode(Base64ImageHolder.INSTANCE.getImage(), Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(decode, 0, decode.length);
// 转完后重新置位
Base64ImageHolder.INSTANCE.setImage("");
this.picName = "shareImgPic.jpg";
this.shareBm = bitmap;
// 分享
switch (type) {
case "qq" :
qqSahre();
break;
case "qq_zone" :
qZoneSahre();
break;
case "wechat" :
wechatSahre();
break;
case "wechat_moments" :
wechatMomentsSahre();
case "save" :
String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/ghzhushou/";
writeBitmap(savePath, "gh-" + new Date().getTime() + ".jpg", shareBm, true);
break;
// 保存图片
File file = new File(activity.getExternalCacheDir().getPath() + "/ShareImg");
if (!file.isDirectory()) {
file.delete();
file.mkdirs();
}
if (!file.exists()) {
file.mkdirs();
}
writeBitmap(file.getPath(), picName, bitmap, false);
// 分享
switch (type) {
case "qq" :
qqShare();
break;
case "qq_zone" :
qZoneShare();
break;
case "wechat" :
wechatShare();
break;
case "wechat_moments" :
wechatMomentsShare();
break;
case "save" :
String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/ghzhushou/";
writeBitmap(savePath, "gh-" + new Date().getTime() + ".jpg", shareBm, true);
break;
}
}
}
//QQ分享
private void qqSahre() {
private void qqShare() {
Utils.toast(mContext, "分享跳转中...");
Bundle params = new Bundle();
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE,
@ -269,7 +282,7 @@ public class MessageShareUtils {
}
//QQ空间分享
private void qZoneSahre() {
private void qZoneShare() {
Utils.toast(mContext, "分享跳转中...");
Bundle params = new Bundle();
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE,
@ -289,7 +302,7 @@ public class MessageShareUtils {
}
//微信好友分享
private void wechatSahre() {
private void wechatShare() {
Utils.toast(mContext, "分享跳转中...");
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
@ -325,7 +338,7 @@ public class MessageShareUtils {
}
//微信朋友圈分享
private void wechatMomentsSahre() {
private void wechatMomentsShare() {
Utils.toast(mContext, "分享跳转中...");
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
@ -352,6 +365,20 @@ public class MessageShareUtils {
mPopupWindow.dismiss();
}
//新浪微博分享
public void weiboShare() {
WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
Activity activity = mActivity.get();
if (activity != null) {
Intent intent = WeiBoShareActivity.getWeiboImageShareIntent(activity);
activity.startActivity(intent);
}
if (mPopupWindow == null) return;
mPopupWindow.dismiss();
}
private String buildTransaction(final String type) {
return (type == null) ? String.valueOf(System.currentTimeMillis()) : type + System.currentTimeMillis();
}
@ -474,22 +501,22 @@ public class MessageShareUtils {
holder.itemView.setOnClickListener(v -> {
switch (holder.getPosition()) {
case 0:
wechatSahre();
wechatShare();
if (shareType != 2) {
// activity.finish();
}
break;
case 1:
wechatMomentsSahre();
wechatMomentsShare();
if (shareType != 2) {
// activity.finish();
}
break;
case 2:
qqSahre();
qqShare();
break;
case 3:
qZoneSahre();
qZoneShare();
break;
case 4:
String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/ghzhushou/";

View File

@ -37,4 +37,15 @@ object NumberUtils {
val minute = Math.round((totalMinute - hour * 60).toFloat())
return hour.toString() + "小时" + if (minute == 0) "" else minute.toString() + "分钟"
}
@JvmStatic
fun findMax(lastPositions: IntArray): Int {
var max = lastPositions[0]
for (value in lastPositions) {
if (value > max) {
max = value
}
}
return max
}
}

View File

@ -26,8 +26,8 @@ object PackageInstaller {
* 为了兼容java代码
*/
@JvmStatic
fun install(context: Context, downloadEntity: DownloadEntity) {
install(context, downloadEntity, true)
fun install(context: Context, downloadEntity: DownloadEntity?) {
downloadEntity?.let { install(context, downloadEntity, true) }
}
/**
@ -44,15 +44,19 @@ object PackageInstaller {
val currentActivity = AppManager.getInstance().currentActivity() ?: return
InstallPermissionDialogFragment.show(currentActivity as AppCompatActivity, downloadEntity) {
// 取消状态栏下载完成的通知,若存在
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
// TODO 此处可能遇到 activity 是 WXEntryActivity
// TODO 当 activity 全部出栈,但是应用还在下载游戏,下载完会唤不起安装!
if (currentActivity is AppCompatActivity) {
InstallPermissionDialogFragment.show(currentActivity, downloadEntity) {
// 取消状态栏下载完成的通知,若存在
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
if (isXapk) {
XapkInstaller.install(context, downloadEntity, showUnzipToast)
} else {
install(context, downloadEntity.path)
if (isXapk) {
XapkInstaller.install(context, downloadEntity, showUnzipToast)
} else {
install(context, downloadEntity.path)
}
}
}
}
@ -67,6 +71,8 @@ object PackageInstaller {
fun install(context: Context, pkgPath: String) {
try {
if (PackageUtils.isCanLaunchSetup(context, pkgPath)) {
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
val installIntent = getInstallIntent(context, pkgPath)
context.startActivity(installIntent)
} else {
@ -115,28 +121,43 @@ object PackageInstaller {
*/
@JvmStatic
fun uninstall(context: Context, path: String) {
val packageName = PackageUtils.getPackageNameByPath(context, path)
uninstallForPackageName(context, packageName)
}
/**
* 根据包名卸载应用
*/
@JvmStatic
fun uninstallForPackageName(context: Context, pkn: String) {
if (pkn.isBlank()) return
val uninstallIntent = Intent()
uninstallIntent.action = Intent.ACTION_DELETE
uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT)
if (context !is Activity) {
uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
val packageName = PackageUtils.getPackageNameByPath(context, path)
uninstallIntent.data = Uri.parse("package:$packageName")
InstallUtils.getInstance(context).addUninstall(packageName)
uninstallIntent.data = Uri.parse("package:$pkn")
InstallUtils.getInstance(context).addUninstall(pkn)
context.startActivity(uninstallIntent)
}
@JvmStatic
fun getDownloadPath(gameName: String?, format: String?): String {
return FileUtils.getDownloadPath(HaloApp.getInstance().application, getDownloadFileName(gameName, format))
fun getDownloadPathWithId(id: String, format: String?): String {
return FileUtils.getDownloadPath(HaloApp.getInstance().application, id + "." + getFileSuffixByFormat(format))
}
private fun getDownloadFileName(gameName: String?, format: String?): String {
var fileExtension = "apk"
if (format == XapkInstaller.XAPK_EXTENSION_NAME) {
fileExtension = XapkInstaller.XAPK_EXTENSION_NAME
private fun getFileSuffixByFormat(format: String?): String {
return if (format == XapkInstaller.XAPK_EXTENSION_NAME) {
XapkInstaller.XAPK_EXTENSION_NAME
} else {
"apk"
}
return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis()) + "." + fileExtension
}
@JvmStatic
fun createDownloadId(gameName: String?): String {
return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis())
}
}

View File

@ -18,6 +18,7 @@ import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.g00fy2.versioncompare.Version;
import com.gh.common.xapk.XapkInstaller;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
@ -26,12 +27,16 @@ import com.gh.gamecenter.manager.PackagesManager;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
import net.dongliu.apk.parser.ApkFile;
import net.dongliu.apk.parser.bean.ApkMeta;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@ -183,16 +188,13 @@ public class PackageUtils {
return null;
}
// TODO 找一个更好的办法来比较签名并且不触发 ANR
public static boolean compareSignatureBetweenInstalledAppWithApk(Context context, String packageName, String apkFilePath) {
try {
// 统计签名比较使用的频率 (大文件会触发 ANR)
SentryHelper.INSTANCE.onEvent(
"SIGNATURE_COMPARE",
"packageName", packageName);
// 据 Sentry 统计,刚上架一个周末的包里对这个方法有 700+ 次调用,然后其中一部分会造成 ANR
Signature sig = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures[0];
// Fuck HUAWEI, 华为系统调用 getPackageArchiveInfo 获取魔羯 apk 的签名时会耗时超过5秒造成 ANR没有找到解决方法
// 调用 getPackageArchiveInfo 获取较大的 apk 的签名时会耗时超过5秒造成 ANR没有找到解决方法
// 如果可以的话尽量避免调用 getPackageArchiveInfo 方法
Signature releaseSig = context.getPackageManager().getPackageArchiveInfo(apkFilePath, PackageManager.GET_SIGNATURES).signatures[0];
return sig.hashCode() == releaseSig.hashCode();
@ -293,14 +295,69 @@ public class PackageUtils {
* 根据路径获取apk的包名
*/
public static String getPackageNameByPath(Context context, String path) {
// 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
// 大于 1G 的 APK 就走另类方法
if (isDeviceUnableToHandleBigApkFile(path)) {
// XAPK 不存在 AndroidManifest
if (path.contains(XapkInstaller.XAPK_EXTENSION_NAME)) {
return null;
}
return getPackageNameByPathAlternative(path);
}
PackageManager packageManager = context.getApplicationContext().getPackageManager();
PackageInfo info = packageManager.getPackageArchiveInfo(path, 0);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
return appInfo.packageName;
}
return null;
}
/**
* 此设备是否不能调用 packageManager.getPackageArchiveInfo 来获取 APK 信息
*
* 部分设备 (已知 vivo 5.1.1 及 5.0.1 的设备) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
*/
public static boolean isDeviceUnableToHandleBigApkFile(String path) {
if ("vivo".equals(Build.MANUFACTURER)
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
File file = new File(path);
if (file != null && file.length() > 1024 * 1024 * 1024) {
return true;
}
}
return false;
}
/**
* 从 APK 文件里读包名的另类方法
* 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
*
* 令人迷惑的点:
* 1. 同样的代码,同样的 APK 在 demo 包里调用 packageManager.getPackageArchiveInfo 并不会 ANR
* 2. 把 packageManager.getPackageArchiveInfo 放在子线程调用一样会出现 ANR
* 3. demo 里 manifest 中 application 配置和 targetSdk 也改成与光环一样也不会出现 ANR
*
* 大概是光环的某个配置触发了系统的 bug ?
*
*/
private static String getPackageNameByPathAlternative(String path) {
ApkFile apkParser = null;
try {
apkParser = new ApkFile(new File(path));
ApkMeta apkMeta = apkParser.getApkMeta();
apkParser.close();
return apkMeta.getPackageName();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/*
* 根据包名,判断是否已安装该游戏
@ -485,9 +542,14 @@ public class PackageUtils {
if (gh_version != null && apkEntity.getGhVersion() != null && gh_id != null) {
gh_version = gh_version.substring(2);
return Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion())
&& apkEntity.getForce()
&& gh_id.equals(gameId);
try {
return Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion()) && apkEntity
.getForce() && gh_id.equals(gameId);
} catch (NumberFormatException exception) {
// gh_id 可能出錯
exception.printStackTrace();
return false;
}
}
return false;
}
@ -519,15 +581,21 @@ public class PackageUtils {
* @return 进程名
*/
public static String obtainProcessName(Context context) {
final int pid = android.os.Process.myPid();
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> listTaskInfo = am.getRunningAppProcesses();
if (listTaskInfo != null && !listTaskInfo.isEmpty()) {
for (ActivityManager.RunningAppProcessInfo info : listTaskInfo) {
if (info != null && info.pid == pid) {
return info.processName;
try {
final int pid = android.os.Process.myPid();
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> listTaskInfo = am.getRunningAppProcesses();
if (listTaskInfo != null && !listTaskInfo.isEmpty()) {
for (ActivityManager.RunningAppProcessInfo info : listTaskInfo) {
if (info != null && info.pid == pid) {
return info.processName;
}
}
}
} catch (Exception e) {
// 遇到异常了让这次调用正常执行
e.printStackTrace();
return BuildConfig.APPLICATION_ID;
}
return null;
}
@ -553,6 +621,13 @@ public class PackageUtils {
if (!pm.isScreenOn()) return false;
}
// 上面的判断逻辑可能还是不够用,还是有少部分
// Not allowed to start service Intent: app is in background 错误
// 这里补充个自有的规则
if (!HaloApp.getInstance().isRunningForeground) {
return false;
}
String packageName = context.getApplicationContext().getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
// The name of the process that this object is associated with.

View File

@ -5,10 +5,12 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.fragment.app.FragmentActivity
import com.gh.common.constant.Constants
import com.tbruyelle.rxpermissions2.RxPermissions
object PermissionHelper {
@ -59,41 +61,41 @@ object PermissionHelper {
@JvmStatic
fun checkStoragePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
if (context is FragmentActivity) {
val rxPermission = RxPermissions(context)
if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& context.checkCallingOrSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
emptyCallback.onCallback()
SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, false)
} else {
showDialogBeforeRequestingStorageDialog(context, emptyCallback)
}
}
}
tryWithDefaultCatch {
rxPermission
.requestEachCombined(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
.subscribe { permission ->
when {
permission.granted -> {
emptyCallback.onCallback()
}
permission.shouldShowRequestPermissionRationale -> {
DialogUtils.showPermissionDialog(context,
"权限申请",
"光环助手需要存储权限,以保证能正常使用相关功能",
"重试",
"放弃",
{ checkStoragePermissionBeforeAction(context, emptyCallback) },
null)
}
else -> {
DialogUtils.showPermissionDialog(context,
"权限申请",
"在设置-应用-光环助手-权限中开启存储权限,以保证能正常使用相关功能",
"去设置",
"放弃",
{
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:" + context.getPackageName())
context.startActivity(intent)
},
null)
private fun checkStoragePermissionBeforeAction(context: FragmentActivity, emptyCallback: EmptyCallback) {
tryWithDefaultCatch {
val rxPermission = RxPermissions(context)
rxPermission
.requestEachCombined(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
.subscribe { permission ->
when {
permission.granted -> {
emptyCallback.onCallback()
SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, false)
}
permission.shouldShowRequestPermissionRationale -> {
// do nothing
}
else -> {
if (SPUtils.getBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION)) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:" + context.packageName)
context.startActivity(intent)
} else {
SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, true)
}
}
}
}
}
}
}
@ -101,39 +103,37 @@ object PermissionHelper {
@JvmStatic
fun checkReadPhoneStateAndStoragePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
if (context is FragmentActivity) {
val rxPermission = RxPermissions(context)
if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& context.checkCallingOrSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
emptyCallback.onCallback()
} else {
val rxPermission = RxPermissions(context)
tryWithDefaultCatch {
rxPermission
.requestEachCombined(
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE)
.subscribe { permission ->
when {
permission.granted -> {
emptyCallback.onCallback()
tryWithDefaultCatch {
rxPermission
.requestEachCombined(
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE)
.subscribe { permission ->
when {
permission.granted -> {
emptyCallback.onCallback()
ActivationHelper.sendActivationInfo()
}
permission.shouldShowRequestPermissionRationale -> {
DialogUtils.showPermissionDialog(context, "权限申请",
"光环助手需要获取存储权限和手机信息权限,以保证能正常使用相关功能", "重试", "放弃",
{ checkStoragePermissionBeforeAction(context, emptyCallback) }, null)
}
else -> {
DialogUtils.showPermissionDialog(context, "权限申请",
"在设置-应用-光环助手-权限中开启获取存储权限和手机信息,以保证能正常使用相关功能",
"去设置",
"放弃",
{
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:" + context.getPackageName())
context.startActivity(intent)
}, null)
ActivationHelper.sendActivationInfo()
}
permission.shouldShowRequestPermissionRationale -> {
// do nothing
}
else -> {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:" + context.getPackageName())
context.startActivity(intent)
}
}
}
}
}
}
}
}
@ -141,34 +141,73 @@ object PermissionHelper {
@SuppressLint("CheckResult")
@JvmStatic
fun checkReadPhoneStatePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
if (context is FragmentActivity) {
if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
emptyCallback.onCallback()
} else {
val rxPermission = RxPermissions(context)
tryWithDefaultCatch {
rxPermission
.requestEachCombined(Manifest.permission.READ_PHONE_STATE)
.subscribe { permission ->
when {
permission.granted -> {
emptyCallback.onCallback()
ActivationHelper.sendActivationInfo()
}
permission.shouldShowRequestPermissionRationale -> {
// do nothing
}
else -> {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:" + context.getPackageName())
context.startActivity(intent)
}
}
}
}
}
}
}
@SuppressLint("CheckResult")
@JvmStatic
fun checkCalendarPermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
if (context is FragmentActivity) {
val rxPermission = RxPermissions(context)
tryWithDefaultCatch {
rxPermission
.requestEachCombined(Manifest.permission.READ_PHONE_STATE)
.requestEachCombined(Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CALENDAR)
.subscribe { permission ->
when {
permission.granted -> {
emptyCallback.onCallback()
ActivationHelper.sendActivationInfo()
}
permission.shouldShowRequestPermissionRationale -> {
DialogUtils.showPermissionDialog(context, "权限申请",
"光环助手需要获取手机信息权限,以保证能正常使用相关功能", "重试", "放弃",
{ checkStoragePermissionBeforeAction(context, emptyCallback) }, null)
DialogUtils.showPermissionDialog(context,
"权限申请",
"光环助手需要日历权限,以保证能正常使用相关功能",
"重试",
"放弃",
{ checkCalendarPermissionBeforeAction(context, emptyCallback) },
null)
}
else -> {
DialogUtils.showPermissionDialog(context, "权限申请",
"在设置-应用-光环助手-权限中开启获取手机信息,以保证能正常使用相关功能",
DialogUtils.showPermissionDialog(context,
"权限申请",
"在设置-应用-光环助手-权限中开启日历权限,以保证能正常使用相关功能",
"去设置",
"放弃",
{
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:" + context.getPackageName())
context.startActivity(intent)
}, null)
},
null)
}
}
}
@ -220,7 +259,24 @@ object PermissionHelper {
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun showDialogBeforeRequestingStorageDialog(context: FragmentActivity, emptyCallback: EmptyCallback) {
DialogHelper.showRoundedCornerDialog(
context,
title = "权限申请",
content = "光环助手将向您申请开启设备的存储权限,以保证能正常使用相关功能。拒绝授权将无法正常使用部分功能。",
hint = "查看权限应用场景",
cancelText = "放弃",
confirmText = "去授权",
hintClickCallback = {
DirectUtils.directToWebView(context, Constants.PERMISSION_SCENARIO_ADDRESS, "(权限弹窗)")
},
cancelClickCallback = null,
confirmClickCallback = {
checkStoragePermissionBeforeAction(context, emptyCallback)
}
)
}
/**
@ -236,5 +292,4 @@ object PermissionHelper {
}
}
}

View File

@ -64,34 +64,24 @@ object ReservationHelper {
@JvmStatic
fun showDeleteReservationDialog(context: Context, emptyCallback: EmptyCallback) {
DialogHelper.showDialog(
context,
DialogUtils.showCancelOrDeleteReservationDialog(context,
"删除预约",
"游戏已上线,你可以删除此预约记录,确定删除吗?",
"确定删除",
"暂不删除",
{ emptyCallback.onCallback() },
null,
trackMtaEvent = true
// , mtaEvent = "预约游戏",
// mtaKey = "删除预约弹窗"
)
"暂不删除", {
emptyCallback.onCallback()
}, null)
}
@JvmStatic
fun showCancelReservationDialog(context: Context, emptyCallback: EmptyCallback) {
DialogHelper.showDialog(
context,
DialogUtils.showCancelOrDeleteReservationDialog(context,
"取消预约",
"取消之后你将无法收到游戏上线的通知,确定取消预约吗?",
"确定取消",
"暂不取消",
{ emptyCallback.onCallback() },
null,
trackMtaEvent = true
// , mtaEvent = "预约游戏",
// mtaKey = "取消预约弹窗"
)
"暂不取消", {
emptyCallback.onCallback()
}, null)
}

View File

@ -2,10 +2,10 @@ package com.gh.common.util
import android.text.TextUtils
import com.lightgame.utils.Utils
import io.sentry.core.Sentry
import io.sentry.core.SentryEvent
import io.sentry.core.SentryLevel
import io.sentry.core.protocol.Message
import io.sentry.Sentry
import io.sentry.SentryEvent
import io.sentry.SentryLevel
import io.sentry.protocol.Message
object SentryHelper {
@ -17,7 +17,7 @@ object SentryHelper {
val message = Message()
message.message = eventId
sentryEvent.message = message
sentryEvent.level = SentryLevel.LOG
sentryEvent.level = SentryLevel.INFO
for (i in kv.indices) {
if (i % 2 != 0) {

View File

@ -90,7 +90,8 @@ public class ShareUtils {
video("视频"),
web("web链接"),
userHome("个人主页"),
qaDetail("QA内容详情");
qaDetail("QA内容详情"),
inviteFriends("邀请好友");
private String name;
@ -124,6 +125,7 @@ public class ShareUtils {
EventBus.getDefault().post(new EBShare(ShareUtils.shareEntrance));
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "success",
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
EnergyTaskHelper.postEnergyTaskForShare(ShareUtils.shareEntrance.getName(), ShareUtils.resourceId, ShareUtils.shareEntity.getShareUrl());
}
@Override
@ -169,6 +171,40 @@ public class ShareUtils {
return false;
}
// 邀请好友(专属链接)
public void shareInviteFriends(Activity activity, String url, String way) {
if (activity.isFinishing()) return;
this.mActivity = new WeakReference<>(activity);
this.shareIcon = activity.getString(R.string.gh_icon_url);
this.shareUrl = url;
this.mSummary = "卡牌神器,海量游戏下载,积分大礼,等你尝鲜";
this.mTitle = "推荐一款好玩的游戏下载APP【光环助手】";
this.mShareEntrance = ShareEntrance.inviteFriends;
ShareUtils.shareEntrance = mShareEntrance;
ShareUtils.resourceId = "";
ShareUtils.shareEntity = new ShareEntity(shareUrl, mTitle, mSummary);
LogUtils.uploadShareEnter(mShareEntrance.getName(), shareUrl, mTitle, mSummary, "");
// 分享
switch (way) {
case "qq" :
qqShare();
break;
case "qq_zone" :
qZoneShare();
break;
case "wechat" :
wechatShare();
break;
case "wechat_moments" :
wechatMomentsShare();
break;
case "weibo" :
sinaWeiboShare();
break;
}
}
public void showShareUserHomeWindows(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareEntrance shareEntrance, String id, ShareCallBack callBack) {
if (activity.isFinishing()) return;
this.mActivity = new WeakReference<>(activity);
@ -318,13 +354,27 @@ public class ShareUtils {
});
}
public void shareParamsDetail(Activity activity, String url, String icon, String shareTitle, String shareSummary, ShareEntrance shareEntrance, String id, ShareCallBack callBack) {
if (activity.isFinishing()) return;
this.mActivity = new WeakReference<>(activity);
this.shareIcon = icon;
this.shareUrl = url;
this.mSummary = shareSummary;
this.mTitle = shareTitle;
this.mShareEntrance = shareEntrance;
ShareUtils.shareEntrance = mShareEntrance;
ShareUtils.resourceId = id;
ShareUtils.shareEntity = new ShareEntity(shareUrl, mTitle, mSummary);
LogUtils.uploadShareEnter(mShareEntrance.getName(), shareUrl, mTitle, mSummary, id);
}
public void showShareWindows(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareEntrance shareEntrance, String id) {
showShareWindowsCallback(activity, view, url, icon, shareTitle, shareSummary, shareEntrance, id, null);
}
//QQ分享
private void qqShare() {
public void qqShare() {
Utils.toast(mContext, R.string.share_skip);
Bundle params = new Bundle();
@ -359,7 +409,7 @@ public class ShareUtils {
}
//微信好友分享
private void wechatShare() {
public void wechatShare() {
Utils.toast(mContext, R.string.share_skip);
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
@ -476,7 +526,7 @@ public class ShareUtils {
}
//QQ空间分享
private void qZoneShare() {
public void qZoneShare() {
Utils.toast(mContext, R.string.share_skip);
Bundle params = new Bundle();
@ -515,7 +565,7 @@ public class ShareUtils {
}
//微信朋友圈分享
private void wechatMomentsShare() {
public void wechatMomentsShare() {
Utils.toast(mContext, R.string.share_skip);
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
@ -558,7 +608,7 @@ public class ShareUtils {
}
//新浪微博分享
private void sinaWeiboShare() {
public void sinaWeiboShare() {
WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
if (mShareEntrance == ShareEntrance.qaDetail) {
@ -567,7 +617,7 @@ public class ShareUtils {
}
Activity activity = mActivity.get();
if (activity != null) {
Intent intent = WeiBoShareActivity.getWeiboshareIntent(
Intent intent = WeiBoShareActivity.getWeiboShareIntent(
activity,
shareUrl,
shareIcon,
@ -584,7 +634,7 @@ public class ShareUtils {
}
//短信分享
private void shortMessageShare() {
public void shortMessageShare() {
String smsBody;
switch (mShareEntrance) {
case news:
@ -628,7 +678,7 @@ public class ShareUtils {
}
//复制文字链接
private void copyLink(String copyContent) {
public void copyLink(String copyContent) {
shareType = "copy_link";
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
if (mShareEntrance != ShareEntrance.shareGh) {
@ -639,6 +689,10 @@ public class ShareUtils {
}
}
public String getTitle() {
return mTitle;
}
private class ShareRecyclerViewAdapter extends RecyclerView.Adapter<ShareRecyclerViewAdapter.ViewHolder> {
private OnItemClickListener listener;
@ -664,6 +718,7 @@ public class ShareUtils {
if (listener != null) {
listener.onItemClick(holder.getAdapterPosition());
}
switch (holder.getPosition()) {
case 0:
shareType = "wechat_friend";
@ -749,7 +804,7 @@ public class ShareUtils {
}
private void safelyDismiss() {
if (popupWindow.get() != null) {
if (popupWindow != null && popupWindow.get() != null) {
popupWindow.get().dismiss();
}
}

View File

@ -23,7 +23,7 @@ object SPUtils {
@JvmStatic
fun getString(key: String): String {
return sp.getString(key, "")
return sp.getString(key, "")?:""
}
@JvmStatic

View File

@ -71,7 +71,7 @@ object SyncDataBetweenPageHelper {
val fields = syncData::class.java.declaredFields
var isNeedNotify = false
for (field in fields) {
if (field.getAnnotation(Synchronize::class.java) != null) {
if (field.getAnnotation(Synchronize::class.java) != null && resultData != null) {
// 同步数据
val resultField = resultData::class.java.getDeclaredField(field.name)
resultField.isAccessible = true

View File

@ -88,6 +88,17 @@ object TimeUtils {
return String.format(Locale.CHINA, "%02d:%02d", minute, second)
}
/**
* 格式化时长将秒数转化为HH:mm:ss格式
*/
@JvmStatic
fun formatDuration(seconds: Long): String {
val hour = seconds / 3600
val minute = seconds % 3600 / 60
val second = seconds % 60
return String.format(Locale.CHINA, "%02d:%02d:%02d", hour, minute, second)
}
@JvmStatic
fun getDayString(date: Long): String {
val offSet = Calendar.getInstance().timeZone.rawOffset
@ -117,6 +128,20 @@ object TimeUtils {
return calendar.timeInMillis
}
@JvmStatic
fun getTimeOfToday(hour: Int) = getTimeOfToday(hour, 0)
@JvmStatic
fun getTimeOfToday(hour: Int, minute: Int): Long {
val calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"))
calendar.timeInMillis = getJavaTimestamp(System.currentTimeMillis())
calendar.set(Calendar.HOUR_OF_DAY, hour)
calendar.set(Calendar.MINUTE, minute)
calendar.set(Calendar.SECOND, 0)
calendar.set(Calendar.MILLISECOND, 0)
return calendar.timeInMillis
}
@JvmStatic
fun getJavaTimestamp(timestamp: Long): Long {
return if ((log10(timestamp.toDouble()) + 1).toInt() == 10) {

View File

@ -6,6 +6,7 @@ import com.gh.common.constant.Constants;
import com.gh.gamecenter.BuildConfig;
import com.halo.assistant.HaloApp;
import java.util.ArrayList;
import java.util.regex.Pattern;
import androidx.collection.ArrayMap;
@ -17,10 +18,12 @@ public class TimestampUtils {
private static ArrayMap<String, Integer> intervalMap; // 间隔
private static ArrayMap<String, Integer> cdMap; // cd
private static ArrayList<String> whiteList; // 白名单
public static void initMap() {
initIntervalMap();
initCDMap();
initWhiteList();
}
private static void initIntervalMap() {
@ -43,11 +46,25 @@ public class TimestampUtils {
cdMap.put(".*packages.*", Constants.PACKAGES_CD);
}
private static void initWhiteList() {
whiteList = new ArrayList<>();
whiteList.add(".*tasks:check.*");
whiteList.add(".*novice_tasks.*");
whiteList.add(".*daily_tasks.*");
whiteList.add(".*energies.*");
}
/*
* 为url添加timestamp
*/
public static String addTimestamp(String url) {
for (String key : whiteList) {
if (Pattern.matches(key, url)) {
return url;
}
}
if (BuildConfig.DEBUG || "GH_REFRESH".equals(HaloApp.getInstance().getChannel())) {
if (TextUtils.isEmpty(url)) {
return url;

View File

@ -1,65 +1,23 @@
package com.gh.common.util
import android.widget.Toast
import com.halo.assistant.HaloApp
import com.lightgame.utils.toast.ToastHandler
import com.lightgame.utils.toast.ToastHelper
object ToastUtils {
/** 之前显示的内容 */
private var mOldMsg: String? = null
/** Toast对象 */
private var mToast: Toast? = null
/** 第一次时间 */
private var mOneTime: Long = 0
/** 第二次时间 */
private var mTwoTime: Long = 0
/**
* 显示Toast
* @param message
*/
fun showToast(message: String) {
showToast(message, -1)
}
/**
* 显示Toast
* @param message
* @param gravity
*/
fun showToast(message: String, gravity: Int = -1, yOffset: Int = 0) {
if (mToast == null) {
mToast = ToastHandler.INSTANCE.getToastInstance(HaloApp.getInstance().application, message, Toast.LENGTH_SHORT)
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
mToast!!.show()
mOneTime = System.currentTimeMillis()
} else {
mTwoTime = System.currentTimeMillis()
if (message == mOldMsg) {
if (mTwoTime - mOneTime > Toast.LENGTH_SHORT) {
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
mToast!!.show()
}
} else {
mOldMsg = message
mToast!!.setText(message)
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
mToast!!.show()
}
}
mOneTime = mTwoTime
}
@JvmStatic
fun toast(message: String) {
if (mToast != null) mToast?.cancel()
mToast = ToastHandler.INSTANCE.getToastInstance(HaloApp.getInstance().application, message, Toast.LENGTH_SHORT)
mToast?.show()
showToast(message)
}
@JvmStatic
fun showToast(message: String) {
ToastHelper.showToast(HaloApp.getInstance(), message)
}
@JvmStatic
fun showToast(message: String, gravity: Int = -1, yOffset: Int = 0) {
ToastHelper.showToast(HaloApp.getInstance(), message, gravity, yOffset)
}
}

View File

@ -0,0 +1,21 @@
package com.gh.common.util
import android.graphics.Bitmap
import android.graphics.Matrix
import com.facebook.common.references.CloseableReference
import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory
import com.facebook.imagepipeline.request.BasePostprocessor
class TopCutProcess(private val cutRatio: Float) : BasePostprocessor() {
override fun process(sourceBitmap: Bitmap, bitmapFactory: PlatformBitmapFactory): CloseableReference<Bitmap>? {
val viewWidth = sourceBitmap.width
val viewHeight = sourceBitmap.height.toFloat()
var newHeight = viewWidth / cutRatio
if (newHeight > viewHeight) {
newHeight = viewHeight
}
val bitmapRef = bitmapFactory.createBitmap(sourceBitmap, 0, 0, viewWidth, (newHeight).toInt())
return CloseableReference.cloneOrNull(bitmapRef)
}
}

View File

@ -116,6 +116,7 @@ object UploadImageUtils {
Observable.create(ObservableOnSubscribe<Map<String, String>> {
val compressList = compressImageList(imgs, compressGif)
listener.onCompressSuccess(compressList.map { file -> file.absolutePath }.toList())
var listTotal = 0L // 总大小
var listProgress = 0L // 已上传的大小
for (img in compressList) {
@ -274,7 +275,7 @@ object UploadImageUtils {
}
// 防止GIF图片文件后缀不是GIF这个FileName只是告诉服务端后缀格式没有其他用处
fun getFileName(file: File): String {
fun getFileName(file: File): String {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.absolutePath, options)
@ -292,6 +293,7 @@ object UploadImageUtils {
interface OnUploadImageListListener {
fun onSuccess(imageUrl: LinkedHashMap<String, String>, errorMap: Map<String, Exception>) // key:sourceImage value:compressImage
fun onCompressSuccess(imageUrls: List<String>) {}
fun onError(errorMap: Map<String, Exception>) // 全部上传失败时回调
fun onProgress(total: Long, progress: Long)
}

View File

@ -1,127 +0,0 @@
package com.gh.common.util;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
public class UriUtils {
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
private static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}

View File

@ -10,6 +10,7 @@ import android.app.AppOpsManager.MODE_ALLOWED
import android.app.AppOpsManager.OPSTR_GET_USAGE_STATS
import android.app.usage.UsageEvents
import android.app.usage.UsageStatsManager
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.os.Build
@ -24,7 +25,6 @@ import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
@ -173,8 +173,6 @@ object UsageStatsHelper {
val body = RequestBody.create(MediaType.parse("application/json"), postBody.toString())
mApi.postUsageStatus(body, UserManager.getInstance().userId)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
debugOnly {
@ -221,8 +219,6 @@ object UsageStatsHelper {
}
mApi.getUsageStatusUpdateTime(HaloApp.getInstance().gid)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
val body = JSONObject(data.string())
@ -257,10 +253,15 @@ object UsageStatsHelper {
@JvmStatic
fun skipToUsageStats(context: Context, requestCode: Int = -1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (context is Activity && requestCode != -1) {
context.startActivityForResult(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS), requestCode)
} else {
context.startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
try {
if (context is Activity && requestCode != -1) {
context.startActivityForResult(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS), requestCode)
} else {
context.startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
}
} catch (e: ActivityNotFoundException) {
Utils.toast(context, "当前设备不支持直接跳转查看应用使用情况页面,请手动进入并打开")
e.printStackTrace()
}
} else {
Utils.toast(context, "当前设备不支持查看应用使用情况")

View File

@ -2,7 +2,10 @@ package com.gh.common.videolog
import android.annotation.SuppressLint
import android.app.Application
import android.database.sqlite.SQLiteFullException
import com.gh.common.util.toRequestBody
import com.gh.common.util.toastInInternalRelease
import com.gh.common.util.tryWithDefaultCatch
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
@ -11,34 +14,40 @@ import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import java.util.concurrent.Executors
import java.util.concurrent.ExecutorService
object VideoRecordUtils {
private const val STORE_SIZE = 20
private lateinit var mApplication: Application
private val videoRecordSet by lazy { hashSetOf<VideoRecordEntity>() }
private val videoRecordExecutor by lazy { Executors.newSingleThreadExecutor() }
private var videoRecordExecutor: ExecutorService? = null
private val videoRecordDao by lazy { AppDatabase.getInstance(mApplication).videoRecordDao() }
@JvmStatic
fun init(application: Application) {
fun init(application: Application, executor : ExecutorService) {
mApplication = application
videoRecordExecutor.execute {
val recordList = videoRecordDao.getAll()
videoRecordSet.addAll(recordList)
videoRecordExecutor = executor
videoRecordExecutor?.execute {
tryWithDefaultCatch {
val recordList = videoRecordDao.getAll()
videoRecordSet.addAll(recordList)
}
}
}
fun log(videoId: String) {
videoRecordExecutor.execute {
videoRecordExecutor?.execute {
try {
val entity = VideoRecordEntity(videoId = videoId, time = System.currentTimeMillis() / 1000L)
videoRecordSet.add(entity)
videoRecordDao.insert(entity)
} catch (e: Exception) {
e.printStackTrace()
if (e is SQLiteFullException) {
toastInInternalRelease("数据库/磁盘已满,写入视频新日志失败")
}
}
if (videoRecordSet.size >= STORE_SIZE) {
commitVideoRecord()
@ -48,11 +57,15 @@ object VideoRecordUtils {
fun commitVideoRecord() {
if (videoRecordSet.isEmpty() || !::mApplication.isInitialized) return
videoRecordExecutor.execute {
videoRecordExecutor?.execute {
uploadVideoRecord()
val exposureList = videoRecordSet.toList()
videoRecordSet.removeAll(exposureList)
videoRecordDao.deleteMany(exposureList)
try {
videoRecordDao.deleteMany(exposureList)
} catch (e: SQLiteFullException) {
toastInInternalRelease("数据库/磁盘已满,删除视频日志失败")
}
}
}

View File

@ -99,4 +99,4 @@ class AutoScrollRecyclerViewContainerView(context: Context, @Nullable attrs: Att
}
}
}
}
}

View File

@ -0,0 +1,108 @@
//package com.gh.common.view
//
//import android.content.Context
//import android.util.AttributeSet
//import android.view.MotionEvent
//import android.widget.LinearLayout
//import androidx.annotation.Nullable
//import androidx.core.view.children
//import androidx.lifecycle.Lifecycle
//import androidx.lifecycle.LifecycleObserver
//import androidx.lifecycle.OnLifecycleEvent
//import androidx.recyclerview.widget.RecyclerView
//import com.gh.common.AppExecutor
//import java.lang.ref.WeakReference
//
// TODO 多页面会出现问题
//class AutoScrollRecyclerViewContainerView(context: Context, @Nullable attrs: AttributeSet?)
// : LinearLayout(context, attrs), LifecycleObserver {
//
// var autoScrollTask: AutoScrollTask?
//
// private var mIsScrolling = false
// private var mIsScrollable = false
// private var mLastScrollTime = 0L
//
// private var mOnItemTouchListener: RecyclerView.OnItemTouchListener? = null
//
// init {
// autoScrollTask = AutoScrollTask(this)
// }
//
// override fun onAttachedToWindow() {
// super.onAttachedToWindow()
//
// if (mOnItemTouchListener == null) {
// mOnItemTouchListener = object : RecyclerView.OnItemTouchListener {
// override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}
// override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent) = rv.scrollState == RecyclerView.SCROLL_STATE_DRAGGING
// override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
// }
// }
//
// for (child in children) {
// if (child is RecyclerView) {
// child.removeOnItemTouchListener(mOnItemTouchListener!!)
// child.addOnItemTouchListener(mOnItemTouchListener!!)
// }
// }
//
// resumeScrolling()
// }
//
// override fun onDetachedFromWindow() {
// super.onDetachedFromWindow()
//
// pauseScrolling()
// }
//
// @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
// fun resumeScrolling() {
// if (mIsScrolling) return
//
// mIsScrollable = true
// mIsScrolling = true
//
// AppExecutor.lightWeightIoExecutor.execute {
// while (mIsScrolling && autoScrollTask != null) {
// if (System.currentTimeMillis() - mLastScrollTime >= AUTO_SCROLL_INTERVAL) {
// mLastScrollTime = System.currentTimeMillis()
// AppExecutor.uiExecutor.execute(autoScrollTask!!)
// }
// }
// }
// }
//
// @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
// fun pauseScrolling() {
// mIsScrolling = false
// }
//
// fun setLifeCycleOwner(lifeCycleOwner: Lifecycle) {
// lifeCycleOwner.addObserver(this)
// }
//
// companion object {
// private const val AUTO_SCROLL_INTERVAL: Long = 16
// private const val SCROLL_SLOP = 1
// }
//
// class AutoScrollTask(reference: AutoScrollRecyclerViewContainerView?) : Runnable {
// private val mReference: WeakReference<AutoScrollRecyclerViewContainerView?>?
//
// init {
// mReference = WeakReference(reference)
// }
//
// override fun run() {
// val containerView: AutoScrollRecyclerViewContainerView? = mReference?.get()
// if (containerView != null && containerView.mIsScrolling && containerView.mIsScrollable) {
// for (child in containerView.children) {
// if (child is RecyclerView) {
// child.scrollBy(SCROLL_SLOP, SCROLL_SLOP)
// }
// }
// }
// }
// }
//}

View File

@ -5,7 +5,7 @@ import android.graphics.drawable.PaintDrawable
import android.view.View
import android.widget.PopupWindow
class BugFixedPopupWindow @JvmOverloads constructor(contentView: View? = null, width: Int = 0, height: Int = 0)
open class BugFixedPopupWindow @JvmOverloads constructor(contentView: View? = null, width: Int = 0, height: Int = 0)
: PopupWindow(contentView, width, height) {
init {

View File

@ -1,6 +1,7 @@
package com.gh.common.view
import android.content.Context
import android.graphics.RectF
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.ViewConfiguration
@ -37,7 +38,9 @@ class DraggableBigImageView @JvmOverloads constructor(context: Context, attrs: A
MotionEvent.ACTION_DOWN -> if (mInitScale == null || mInitScale == 0F) mInitScale = ssiv?.scale
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> up()
MotionEvent.ACTION_MOVE -> {
if (mSingleTouch && mInitScale != 0F && ssiv?.scale == mInitScale) {
val rectF = RectF()
ssiv?.getPanRemaining(rectF)
if (mSingleTouch && mInitScale != 0F && (rectF.top == 0f || rectF.bottom == 0f)) {
if (mLastX == 0F) mLastX = event.rawX
if (mLastY == 0F) mLastY = event.rawY
val offsetX = event.rawX - mLastX

View File

@ -2,24 +2,21 @@ package com.gh.common.view
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Shader
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import com.gh.common.util.DisplayUtils
import com.halo.assistant.HaloApp
import android.graphics.drawable.StateListDrawable
import android.widget.TextView
import androidx.annotation.DrawableRes
import com.gh.common.util.dip2px
import com.j256.ormlite.stmt.query.In
import android.graphics.Shader
import android.graphics.LinearGradient
import android.graphics.drawable.shapes.RectShape
import android.graphics.drawable.ShapeDrawable
import android.opengl.ETC1.getHeight
import com.gh.gamecenter.R
import com.lightgame.utils.Utils
import android.graphics.drawable.StateListDrawable
import android.graphics.drawable.shapes.RectShape
import android.widget.TextView
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.gh.common.databind.DrawablesBindingAdapter
import com.gh.common.util.DisplayUtils
import com.gh.common.util.dip2px
import com.halo.assistant.HaloApp
object DrawableView {
@ -97,6 +94,17 @@ object DrawableView {
return drawable
}
@JvmStatic
fun getCornerDrawable(color: Int, radiusLT: Float, radiusRT: Float, radiusRB: Float, radiusLB: Float):Drawable{
val drawable = GradientDrawable()
drawable.shape = GradientDrawable.RECTANGLE
drawable.setColor(color)
val radiusEach = floatArrayOf(radiusLT.dip2px().toFloat(), radiusLT.dip2px().toFloat(), radiusRT.dip2px().toFloat(), radiusRT.dip2px().toFloat(),
radiusRB.dip2px().toFloat(), radiusRB.dip2px().toFloat(), radiusLB.dip2px().toFloat(), radiusLB.dip2px().toFloat())
drawable.cornerRadii = radiusEach
return drawable
}
@JvmStatic
fun getCornerGradientDrawable(startColor: Int, endColor: Int, radius: Float = 999F): Drawable {
val drawable = GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, intArrayOf(startColor, endColor))

View File

@ -100,7 +100,8 @@ public class ExpandTextView extends AppCompatTextView {
/**
* 适用于不使用 maxLines 而是整段收起时的文字来确定“...更多”的位置的样式
* @param shrankText 收起时的文字 (“...更多”跟在 shrankText 后)
*
* @param shrankText 收起时的文字 (“...更多”跟在 shrankText 后)
* @param expandedText 展开时的文字
*/
public void setShrankTextAndExpandedText(CharSequence shrankText, CharSequence expandedText) {
@ -122,6 +123,11 @@ public class ExpandTextView extends AppCompatTextView {
}
private void showExpandButton() {
// 避免二次生成展开按钮 (有点粗暴,但是为了满足 recyclerView 复用后没问题,还是每次都用当前文字来判断比较好)
if (getText().toString().endsWith(mExpandText)) {
return;
}
String finalEndText = "";
TextPaint paint = getPaint();
@ -160,6 +166,10 @@ public class ExpandTextView extends AppCompatTextView {
float subSequenceWidth;
for (int i = lastLineText.length() - 1; i > 0; i--) {
if (mUseGradientAlphaEndText) {
// 避免 additionalEntTextCount 大于 i 造成数组越界 (TODO 代码太多,有时间再检查)
if (additionalEndTextCount > i) return;
subSequence = lastLineText.subSequence(0, i - additionalEndTextCount);
subSequenceWidth = paint.measureText(subSequence.toString());

View File

@ -0,0 +1,33 @@
package com.gh.common.view;
import android.content.Context;
import android.util.AttributeSet;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class FixGridLayoutManager extends GridLayoutManager {
public FixGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public FixGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
}
public FixGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.ScrollView
import java.lang.IllegalArgumentException
/**
* 不能滑动的 ScrollView
@ -11,10 +12,16 @@ import android.widget.ScrollView
class FixedScrollView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : ScrollView(context, attrs) {
override fun onTouchEvent(ev: MotionEvent?): Boolean {
return when (ev?.action) {
MotionEvent.ACTION_DOWN -> true
else -> super.onTouchEvent(ev)
// super.onTouchEvent may cause IllegalArgumentException which is crazy!
try {
return when (ev?.action) {
MotionEvent.ACTION_DOWN -> true
else -> super.onTouchEvent(ev)
}
} catch (e: IllegalArgumentException) {
e.printStackTrace()
}
return false
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {

View File

@ -0,0 +1,102 @@
package com.gh.common.view
import android.content.Context
import android.graphics.Color
import android.graphics.Paint
import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.gh.common.util.DisplayUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.TagStyleEntity
import kotlin.math.ceil
/**
* 首页游戏标签,最多显示三个,实际显示个数由控件宽度决定
*/
class GameTagFlexLinearLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) {
private var mTotalCount = 0
private var mTags = ArrayList<TagStyleEntity>()
private var mItemHeight = DisplayUtils.dip2px(13F)
private var mPadding = DisplayUtils.dip2px(4F)
private var mMargin = DisplayUtils.dip2px(4F)
private var mTextSize = 9F
private var mTotalWidth = 0
private val mMaxCount = 3
init {
gravity = Gravity.CENTER_VERTICAL
}
fun setTags(datas: ArrayList<TagStyleEntity>) {
val tags = datas.take(mMaxCount)
mTags.clear()
mTotalCount = tags.size
mTotalWidth = measuredWidth
val paint = Paint()
paint.textSize = DisplayUtils.sp2px(context, mTextSize).toFloat()
var currentWidth = 0f
tags.forEach {
val strWidth = getTextWidth(paint, it.name)
if (currentWidth + strWidth + mPadding * 2 + mMargin <= mTotalWidth) {
currentWidth += strWidth + mPadding * 2 + mMargin
mTags.add(it)
}
}
if (mTags.isNotEmpty()) {
addTags()
}
}
private fun getTextWidth(paint: Paint, str: String?): Int {
var width = 0
if (str != null && str.isNotEmpty()) {
val len = str.length
val widths = FloatArray(len)
paint.getTextWidths(str, widths)
for (i in 0 until len) {
width += ceil(widths[i].toDouble()).toInt()
}
}
return width
}
private fun addTags() {
removeAllViews()
mTags.forEach {
addView(createView(it))
}
}
private fun createView(tag: TagStyleEntity): View {
return TextView(context).apply {
text = tag.name
includeFontPadding = false
textSize = mTextSize
gravity = Gravity.CENTER
setTextColor(Color.parseColor("#666666"))
val params = LayoutParams(LayoutParams.WRAP_CONTENT, mItemHeight)
params.setMargins(0, 0, mMargin, 0)
setPadding(mPadding, 0, mPadding, 0)
layoutParams = params
val gradientDrawable = createBackgroundDrawable()
background = gradientDrawable
}
}
private fun createBackgroundDrawable(): GradientDrawable {
val gradientDrawable = GradientDrawable()
gradientDrawable.setColor(Color.TRANSPARENT)
gradientDrawable.setStroke(DisplayUtils.dip2px(context, 0.5f), Color.parseColor("#CCCCCC"))
gradientDrawable.cornerRadius = DisplayUtils.dip2px(2f).toFloat()
return gradientDrawable
}
}

View File

@ -20,7 +20,7 @@ class GradientAlphaTextSpan(var textColor: Int) : ReplacementSpan() {
originalColor, originalColorWithAlphaChanged, Shader.TileMode.CLAMP)
paint.shader = mShader
canvas.drawText(text, start, end, x, y.toFloat(), paint)
canvas.drawText(text ?: "", start, end, x, y.toFloat(), paint)
paint.shader = null
}

View File

@ -3,6 +3,7 @@ package com.gh.common.view
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
class GridSpacingItemDecoration(private val mSpanCount: Int,
@ -19,7 +20,16 @@ class GridSpacingItemDecoration(private val mSpanCount: Int,
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val position = parent.getChildAdapterPosition(view)
val isStaggeredGridLayout = parent.layoutManager is StaggeredGridLayoutManager
val position = if (!isStaggeredGridLayout) {
parent.getChildAdapterPosition(view)
} else {
val params = view.layoutParams as (StaggeredGridLayoutManager.LayoutParams)
// 当前位置
params.spanIndex
}
val column = position % mSpanCount
if (mIncludeEdge) {
@ -29,6 +39,8 @@ class GridSpacingItemDecoration(private val mSpanCount: Int,
if (position < mSpanCount) {
outRect.top = mSpacing
} else if (isStaggeredGridLayout) {
outRect.top = mSpacing
}
outRect.bottom = mSpacing
@ -37,6 +49,8 @@ class GridSpacingItemDecoration(private val mSpanCount: Int,
outRect.right = mSpacing - (column + 1) * mSpacing / mSpanCount
if (position >= mSpanCount) {
outRect.top = mSpacing
} else if (isStaggeredGridLayout) {
outRect.top = mSpacing
}
}

View File

@ -0,0 +1,221 @@
package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import com.facebook.drawee.drawable.ScalingUtils
import com.gh.common.util.*
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.ItemCommunityImageBinding
import com.gh.gamecenter.qa.entity.AnswerEntity
import com.gh.gamecenter.qa.entity.CommunityVideoEntity
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
import java.util.ArrayList
class ImageContainerView : LinearLayout {
private var mAnswerEntity: AnswerEntity? = null
//三图默认宽度
private var mDefaultWidth = 0f
//单图固定宽度
private var mFixdWidth = 0f
//最小比例
private var mMinRatio = 3 / 4f
//最大比例
private var mMaxRatio = 3 / 2f
//长图比例
private var mLongPictureRatio = 9 / 18f
private var mEntrance = ""
private var mPath = ""
//图片之间的间距
private val mItemSpace = 4f.dip2px()
private var index = 0
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initView(attrs)
}
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
ta.recycle()
}
fun bindData(entity: AnswerEntity, entrance: String = "", path: String = "") {
mAnswerEntity = entity
mEntrance = entrance
mPath = path
index = 0
removeAllViews()
if (entity.getPassVideos().isNullOrEmpty() && entity.images.isNullOrEmpty()) {
visibility = View.GONE
return
}
visibility = View.VISIBLE
if (mAnswerEntity?.type == "community_article") {
//若文章内容含有图片及视频,则信息流卡片,仅展示图片,且标题后带有‘有视频’标签
//若文章内容仅含有图片,则信息流卡片,仅展示图片,无标签
//若文章内容仅含有视频,则信息流卡片,仅展示视频,无标签
when {
entity.images.isNotEmpty() -> {
val imagesInfo = entity.imagesInfo
val images = entity.images.take(3)
images.forEachIndexed { index, url ->
val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0
val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0
bindImage(url, width, height, images.size == 1)
}
}
entity.getPassVideos().isNotEmpty() -> {
val video = entity.getPassVideos()[0]
bindVideo(video, video.width, video.height, true)
}
else -> {
// do noting
}
}
} else {
//若问答内容含有图片及视频,则信息流卡片,同时展示图片及视频,且参考以往排序逻辑(视频优先放置第一位),无标签
//若问答内容仅含有图片,则信息流卡片,仅展示图片,无标签
//若问答内容仅含有视频,则信息流卡片,仅展示视频,无标签
if (entity.getPassVideos().isNotEmpty()) {
val video = entity.getPassVideos()[0]
bindVideo(video, video.width, video.height, mAnswerEntity?.images.isNullOrEmpty())
entity.images.take(2).forEachIndexed { index, url ->
val imagesInfo = entity.imagesInfo
val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0
val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0
bindImage(url, width, height, false)
}
} else {
val images = entity.images.take(3)
images.forEachIndexed { index, url ->
val imagesInfo = entity.imagesInfo
val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0
val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0
bindImage(url, width, height, images.size == 1)
}
}
}
}
private fun bindVideo(video: CommunityVideoEntity, width: Int, height: Int, isChangeRatio: Boolean) {
val binding = ItemCommunityImageBinding.inflate(LayoutInflater.from(context), null, false)
addView(binding.root)
binding.durationOrNumTv.visibility = View.VISIBLE
binding.videoPlay.visibility = View.VISIBLE
binding.labelIcon.visibility = View.GONE
binding.durationOrNumTv.text = video.duration
displayImage(binding, video.poster, width.toFloat(), height.toFloat(), isChangeRatio, true)
binding.root.setOnClickListener {
debounceActionWithInterval(it.id, 1000) {
if (mAnswerEntity == null) return@debounceActionWithInterval
val videoEntity = mAnswerEntity!!.getPassVideos()[0]
DirectUtils.directToVideoDetail(context,
videoEntity.id,
VideoDetailContainerViewModel.Location.VIDEO_HOT.value,
showComment = false,
entrance = mEntrance,
path = mPath)
}
}
index++
}
private fun bindImage(url: String, width: Int, height: Int, isChangeRatio: Boolean) {
val binding = ItemCommunityImageBinding.inflate(LayoutInflater.from(context), null, false)
binding.root.tag = index
addView(binding.root)
binding.durationOrNumTv.visibility = View.GONE
binding.videoPlay.visibility = View.GONE
displayImage(binding, url, width.toFloat(), height.toFloat(), isChangeRatio)
binding.root.setOnClickListener {
debounceActionWithInterval(it.id, 1000) {
if (mAnswerEntity == null) return@debounceActionWithInterval
val position = if (mAnswerEntity?.type == "community_article") {
binding.root.tag as Int
} else {
if (mAnswerEntity!!.getPassVideos().isNullOrEmpty()) binding.root.tag as Int else (binding.root.tag as Int) - 1
}
val intent = ImageViewerActivity.getIntent(context, mAnswerEntity!!.images as ArrayList<String>, position, binding.root,
if (mAnswerEntity?.type == "community_article") mAnswerEntity else null, mEntrance)
context.startActivity(intent)
}
}
index++
}
private fun displayImage(binding: ItemCommunityImageBinding, url: String, width: Float, height: Float, isChangeRatio: Boolean, isVideo: Boolean = false) {
val params = binding.root.layoutParams as LayoutParams
val hierarchy = binding.image.hierarchy
binding.labelIcon.visibility = View.GONE
if (width != 0f && height != 0f) {
val picRatio = width / height
if (isChangeRatio) {
when {
picRatio <= mMinRatio -> {
params.height = (mFixdWidth / mMinRatio).toInt()
ImageUtils.display(binding.image, url, false, TopCutProcess(mMinRatio))
}
picRatio >= mMaxRatio -> {
params.height = (mFixdWidth / mMaxRatio).toInt()
ImageUtils.display(binding.image, url, false)
}
else -> {
params.height = (mFixdWidth / picRatio).toInt()
ImageUtils.display(binding.image, url, false)
}
}
params.width = mFixdWidth.toInt()
} else {
params.width = mDefaultWidth.toInt()
params.height = mDefaultWidth.toInt()
ImageUtils.display(binding.image, url, false)
}
//长图
if (!isVideo && picRatio <= mLongPictureRatio) {
binding.labelIcon.visibility = View.VISIBLE
binding.labelIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_long_pic_label))
}
} else {
params.width = mDefaultWidth.toInt()
params.height = mDefaultWidth.toInt()
ImageUtils.display(binding.image, url, false)
}
if (url.endsWith(".gif")) {
binding.labelIcon.visibility = View.VISIBLE
binding.labelIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_gif_label))
}
val mediaCount = if (mAnswerEntity?.type == "community_article") {
mAnswerEntity?.images?.size ?: 0
} else {
(mAnswerEntity?.images?.size ?: 0) + (mAnswerEntity?.getPassVideos()?.size ?: 0)
}
if (!isVideo && index == 2 && mediaCount > 3) {
binding.labelIcon.visibility = View.GONE
binding.durationOrNumTv.visibility = View.VISIBLE
binding.durationOrNumTv.text = "+${mAnswerEntity?.images?.size}"
}
hierarchy.actualImageScaleType = ScalingUtils.ScaleType.CENTER_CROP
if (index != 0) params.leftMargin = mItemSpace
binding.root.layoutParams = params
}
}

View File

@ -2,6 +2,7 @@ package com.gh.common.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Html;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
@ -31,6 +32,7 @@ public class MarqueeView extends ViewFlipper {
private int textSize = 14;
private int textColor = 0xffffffff;
private boolean useSingleLineText = false;
private boolean isHtmlText = false;
public MarqueeView(Context context, AttributeSet attrs) {
super(context, attrs);
@ -121,9 +123,13 @@ public class MarqueeView extends ViewFlipper {
tv.setEllipsize(TextUtils.TruncateAt.END);
}
tv.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
tv.setText(text);
tv.setTextColor(textColor);
tv.setTextSize(textSize);
tv.setTextColor(textColor);
if (isHtmlText) {
tv.setText(Html.fromHtml(text));
} else {
tv.setText(text);
}
return tv;
}
@ -133,6 +139,12 @@ public class MarqueeView extends ViewFlipper {
start();
}
public void startWithListForHtmlText(List<String> notices) {
isHtmlText = true;
setNotices(notices);
start();
}
public void enableSingleLineText() {
useSingleLineText = true;
}

View File

@ -0,0 +1,54 @@
package com.gh.common.view
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.graphics.drawable.ColorDrawable
import android.util.AttributeSet
import androidx.cardview.widget.CardView
import com.gh.common.util.dip2px
import com.gh.gamecenter.R
class RadiusCardView : CardView {
var topLeftRadius = 0f
var topRightRadius = 0f
var bottomLeftRadius = 0f
var bottomRightRadius = 0f
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
radius = 0f
val array = context.obtainStyledAttributes(attrs, R.styleable.RadiusCardView)
topLeftRadius = array.getDimensionPixelSize(R.styleable.RadiusCardView_topLeftRadius, 0).toFloat()
topRightRadius = array.getDimensionPixelSize(R.styleable.RadiusCardView_topRightRadius, 0).toFloat()
bottomLeftRadius = array.getDimensionPixelSize(R.styleable.RadiusCardView_bottomLeftRadius, 0).toFloat()
bottomRightRadius = array.getDimensionPixelSize(R.styleable.RadiusCardView_bottomRightRadius, 0).toFloat()
background = ColorDrawable()
array.recycle()
}
@SuppressLint("DrawAllocation")
override fun onDraw(canvas: Canvas?) {
val path = Path()
val rectF: RectF = getRectF()
val radius = floatArrayOf(topLeftRadius, topLeftRadius, topRightRadius, topRightRadius, bottomLeftRadius, bottomLeftRadius, bottomLeftRadius, bottomLeftRadius)
path.addRoundRect(rectF, radius, Path.Direction.CW)
canvas?.clipPath(path, Region.Op.INTERSECT)
super.onDraw(canvas)
}
fun setRadius(tLRadius: Float, tRRadius: Float, bLRadius: Float, bRRadius: Float) {
topLeftRadius = tLRadius.dip2px().toFloat()
topRightRadius = tRRadius.dip2px().toFloat()
bottomLeftRadius = bLRadius.dip2px().toFloat()
bottomRightRadius = bRRadius.dip2px().toFloat()
invalidate()
}
private fun getRectF(): RectF {
val rect = Rect()
getDrawingRect(rect)
return RectF(rect)
}
}

View File

@ -25,6 +25,9 @@ class ReserveDialog : BaseDialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val binding: DialogReserveBinding = DataBindingUtil.inflate(inflater, R.layout.dialog_reserve, container, false)
mReserveList = arguments?.getParcelableArrayList(RESERVE_LIST) ?: arrayListOf()
binding.title.text = resources.getString(R.string.dialog_reserve_title, mReserveList.size).fromHtml()
binding.more.visibility = if (mReserveList.size > 4) {
View.VISIBLE
@ -74,8 +77,13 @@ class ReserveDialog : BaseDialogFragment() {
}
companion object {
const val RESERVE_LIST = "reserve_list"
@JvmStatic
fun getInstance(reserveList: List<SimpleGameEntity>) = ReserveDialog().apply { mReserveList = reserveList }
fun getInstance(reserveList: List<SimpleGameEntity>) = ReserveDialog().apply {
arguments = Bundle()
arguments?.putParcelableArrayList(RESERVE_LIST, ArrayList(reserveList))
}
}
}

View File

@ -24,6 +24,7 @@ import com.gh.common.util.HtmlUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.RichEditorUtils;
import com.gh.common.util.SPUtils;
import com.gh.gamecenter.BuildConfig;
@ -119,6 +120,7 @@ public class RichEditor extends WebView {
private OnDecorationStateListener mDecorationStateListener;
private AfterInitialLoadListener mLoadListener;
private WebChromeClientListener mChromeClientListener;
private PageFinishedListener mPageFinishedListener;
public RichEditor(Context context) {
this(context, null);
@ -177,6 +179,10 @@ public class RichEditor extends WebView {
mChromeClientListener = chromeClientListener;
}
public void setPageFinishedListener(PageFinishedListener pageFinishedListener) {
mPageFinishedListener = pageFinishedListener;
}
public void setLayoutCallback(EmptyCallback layoutCallback) {
mInitialLayoutCallback = layoutCallback;
}
@ -321,6 +327,10 @@ public class RichEditor extends WebView {
exec("javascript:RE.setBaseFontSize('" + px + "px');");
}
public boolean hasPlaceholderImage() {
return getHtml().contains("placeholder-image-container");
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
@ -444,6 +454,15 @@ public class RichEditor extends WebView {
exec("javascript:RE.setTextColor('" + hex + "');");
}
public void insertPlaceholderImage(String id) {
exec("javascript:RE.prepareInsert();");
exec("javascript:RE.insertPlaceholderImage('" + id + "');");
}
public void replacePlaceholderImage(String list) {
exec("javascript:RE.replacePlaceholderImage('" + list + "');");
}
public void removeFormat() {
exec("javascript:RE.removeFormat();");
}
@ -612,6 +631,10 @@ public class RichEditor extends WebView {
boolean shouldOverrideUrlLoading(WebView view, String url);
}
public interface PageFinishedListener {
void onPageFinished();
}
class NativeCallBack {
/**
@ -649,6 +672,21 @@ public class RichEditor extends WebView {
return DeviceUtils.getNetwork(HaloApp.getInstance().getApplication());
}
@JavascriptInterface
public void onPageFinished() {
mPageFinishedListener.onPageFinished();
}
@JavascriptInterface
public String getAppVersion() {
return BuildConfig.VERSION_NAME;
}
@JavascriptInterface
public int getAppVersionCode() {
return PackageUtils.getVersionCode();
}
/**
* 显示toast
*
@ -737,7 +775,7 @@ public class RichEditor extends WebView {
public void invalidate() {
super.invalidate();
if (mInitialLayoutCallback != null &&getHeight() > 0) {
if (mInitialLayoutCallback != null && getHeight() > 0) {
// 仅初次 layout 完成会有回调
mInitialLayoutCallback.onCallback();
mInitialLayoutCallback = null;

View File

@ -23,30 +23,31 @@ import androidx.viewpager.widget.ViewPager;
*/
public class TabIndicatorView extends View implements ViewPager.OnPageChangeListener {
private TabLayout mTabLayout;
private int mIndicatorSpace;
private int mIndicatorHeight;
private int mIndicatorWidth;
private int mIndicatorColor = 0;
private GradientDrawable mGradientDrawable;
private Drawable mCustomDrawable;
public TabIndicatorView(Context context) {
this(context, null);
}
public TabIndicatorView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TabIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabIndicatorView);
if (a.hasValue(R.styleable.TabIndicatorView_indicatorColor)) {
mIndicatorColor = a.getColor(R.styleable.TabIndicatorView_indicatorColor, 0);
@ -55,45 +56,48 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
mGradientDrawable.setColor(mIndicatorColor);
mGradientDrawable.setCornerRadius(Integer.MAX_VALUE);
}
if (a.hasValue(R.styleable.TabIndicatorView_indicatorDrawable)) {
mCustomDrawable = a.getDrawable(R.styleable.TabIndicatorView_indicatorDrawable);
}
a.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mIndicatorHeight = MeasureSpec.getSize(heightMeasureSpec);
}
public void setupWithTabLayout(final TabLayout tableLayout) {
mTabLayout = tableLayout;
tableLayout.setSelectedTabIndicatorColor(Color.TRANSPARENT);
tableLayout.getViewTreeObserver().addOnScrollChangedListener(() -> {
if (mTabLayout.getScrollX() != getScrollX())
scrollTo(mTabLayout.getScrollX(), mTabLayout.getScrollY());
});
ViewCompat.setElevation(this, ViewCompat.getElevation(mTabLayout));
//清除Tab background
for (int tab = 0; tab < tableLayout.getTabCount(); tab++) {
View tabView = getTabViewByPosition(tab);
if (tabView != null) tabView.setBackgroundResource(0);
}
}
public void setupWithViewPager(ViewPager viewPager) {
viewPager.addOnPageChangeListener(this);
}
public void setIndicatorWidth(int width) {
if (width > 0) this.mIndicatorWidth = DisplayUtils.dip2px(getContext(), width);
}
public void setIndicatorSpace(int space) {
this.mIndicatorSpace = DisplayUtils.dip2px(getContext(), space);
}
private int getIndicatorSpace() {
if (mIndicatorSpace != 0) return mIndicatorSpace;
if (mIndicatorWidth != 0) {
@ -102,13 +106,15 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
}
return 0;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Drawable drawable;
if (mGradientDrawable != null) {
if (mCustomDrawable != null) {
drawable = mCustomDrawable;
} else if (mGradientDrawable != null) {
drawable = mGradientDrawable;
} else {
drawable = getResources().getDrawable(R.drawable.ask_tab_indicator_bg); // 固定Indicator背景 有需要可以自行更改
@ -116,77 +122,77 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
drawable.setBounds(l, t, r, b);
drawable.draw(canvas);
}
int l;
int t;
int r;
int b;
public void generatePath(int position, float positionOffset) {
RectF range = new RectF();
View tabView = getTabViewByPosition(position);
if (tabView == null) return;
int left, top, right, bottom;
left = top = right = bottom = 0;
if (positionOffset > 0.f && position < mTabLayout.getTabCount() - 1) {
View nextTabView = getTabViewByPosition(position + 1);
if (nextTabView != null) {
left += (int) (nextTabView.getLeft() * positionOffset + tabView.getLeft() * (1.f - positionOffset));
right += (int) (nextTabView.getRight() * positionOffset + tabView.getRight() * (1.f - positionOffset));
}
left += getIndicatorSpace();
right -= getIndicatorSpace();
top = tabView.getTop() + getPaddingTop();
bottom = tabView.getBottom() - getPaddingBottom();
range.set(left, top, right, bottom);
} else {
left = tabView.getLeft() + getIndicatorSpace();
right = tabView.getRight() - getIndicatorSpace();
top = tabView.getTop() + getPaddingTop();
bottom = tabView.getBottom() - getPaddingBottom();
range.set(left, top, right, bottom);
if (range.isEmpty()) return;
}
r = right;
l = left;
t = top;
b = top + mIndicatorHeight;
invalidate();
}
private View getTabViewByPosition(int position) {
if (mTabLayout != null && mTabLayout.getTabCount() > 0) {
ViewGroup tabStrip = (ViewGroup) mTabLayout.getChildAt(0);
return tabStrip != null ? tabStrip.getChildAt(position) : null;
}
return null;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
generatePath(position, positionOffset);
}
@Override
public void onPageSelected(int position) {
if (mTabLayout.getSelectedTabPosition() != position) {
TabLayout.Tab tab = mTabLayout.getTabAt(position);
if (tab != null) tab.select();
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
}

View File

@ -15,6 +15,7 @@ import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.InflateException;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.ConsoleMessage;
@ -34,6 +35,7 @@ import android.widget.FrameLayout;
import androidx.annotation.Keep;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import org.json.JSONArray;
import org.json.JSONException;
@ -284,6 +286,12 @@ public class DWebView extends WebView {
// add dsbridge tag in lower android version
settings.setUserAgentString(settings.getUserAgentString() + " _dsbridge");
}
if (Build.VERSION.SDK_INT < 19) {
removeJavascriptInterface("searchBoxJavaBridge_");
removeJavascriptInterface("accessibility");
removeJavascriptInterface("accessibilityTraversal");
}
}
@ -414,7 +422,7 @@ public class DWebView extends WebView {
e.printStackTrace();
try {
super.loadUrl("javascript:" + script);
} catch (Exception ignored){
} catch (Exception ignored) {
}
}
@ -716,6 +724,8 @@ public class DWebView extends WebView {
return true;
}
}
Activity activity = (AppCompatActivity) getContext();
if (activity.isFinishing()) return true;
Dialog alertDialog = new AlertDialog.Builder(getContext()).
setMessage(message).
setCancelable(false).
@ -742,6 +752,8 @@ public class DWebView extends WebView {
if (webChromeClient != null && webChromeClient.onJsConfirm(view, url, message, result)) {
return true;
} else {
Activity activity = (AppCompatActivity) getContext();
if (activity.isFinishing()) return true;
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
@ -784,6 +796,8 @@ public class DWebView extends WebView {
if (webChromeClient != null && webChromeClient.onJsPrompt(view, url, message, defaultValue, result)) {
return true;
} else {
Activity activity = (AppCompatActivity) getContext();
if (activity.isFinishing()) return true;
final EditText editText = new EditText(getContext());
editText.setText(defaultValue);
if (defaultValue != null) {
@ -1023,4 +1037,12 @@ public class DWebView extends WebView {
mainHandler.post(runnable);
}
@Override
public void setOverScrollMode(int mode) {
try {
super.setOverScrollMode(mode);
} catch (Throwable e) {
e.printStackTrace();
}
}
}

View File

@ -163,7 +163,13 @@ public class PagerLayoutManager extends LinearLayoutManager {
return 0;
}
this.mDrift = dy;
return super.scrollVerticallyBy(dy, recycler, state);
//fix for `java.lang.IndexOutOfBoundsException: Inconsistency detected.`
try {
return super.scrollVerticallyBy(dy, recycler, state);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
/**

View File

@ -18,7 +18,7 @@ import java.util.*
* 目前检验是否已解压的根据是存在相同文件名且大小一致(暂时想不到校验MD5值的方法)
*
* obb文件直接解压至根目录即可,无需操作文件
* apk文件这解压的gh-download文件夹中
* apk文件这解压的gh-files文件夹中
*/
object XapkInstaller : IXapkUnzipListener {
private const val XAPK_PACKAGE_PATH_TAG = "xapk_package_path"

View File

@ -1,7 +1,9 @@
package com.gh.download
import android.content.pm.PackageManager
import android.content.pm.PackageInfo
import android.text.TextUtils
import com.gh.common.constant.Constants
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.exposure.meta.MetaUtil.getMeta
import com.gh.common.loghub.LoghubUtils
import com.gh.common.util.*
@ -52,11 +54,15 @@ object DownloadDataHelper {
} else if (status == DownloadStatus.subscribe || status == DownloadStatus.neterror || status == DownloadStatus.timeout) {
"暂停下载-连上WiFi自动下载"
} else if (status == DownloadStatus.done) {
if(downloadEntity.isSimulatorGame()){
if (downloadEntity.isSimulatorGame()) {
return "下载完成"
}
val pm = HaloApp.getInstance().application.applicationContext.packageManager
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0)
val packageInfo = if (PackageUtils.isDeviceUnableToHandleBigApkFile(downloadEntity.path)) {
PackageInfo()
} else {
val pm = HaloApp.getInstance().application.applicationContext.packageManager
pm.getPackageArchiveInfo(downloadEntity.path, 0)
}
if (packageInfo == null && XapkInstaller.PACKAGE_EXTENSION_NAME == downloadEntity.path.getExtension()) {
"解析包错误"
} else {
@ -100,7 +106,7 @@ object DownloadDataHelper {
payloadObject.put("gameName", downloadEntity.name)
payloadObject.put("platform", downloadEntity.platform)
payloadObject.put("package", downloadEntity.packageName)
payloadObject.put("filename", downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1))
payloadObject.put("filename", getFileName(downloadEntity))
jsonObject.put("payload", payloadObject)
} catch (e: Exception) {
e.printStackTrace()
@ -182,7 +188,7 @@ object DownloadDataHelper {
payloadObject.put("gameName", downloadEntity.name)
payloadObject.put("platform", downloadEntity.platform)
payloadObject.put("package", downloadEntity.packageName)
payloadObject.put("filename", downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1))
payloadObject.put("filename", getFileName(downloadEntity))
payloadObject.put("launch_ms", startupTime)
jsonObject.put("payload", payloadObject)
} catch (e: Exception) {
@ -213,7 +219,7 @@ object DownloadDataHelper {
payloadObject.put("gameName", downloadEntity.name)
payloadObject.put("platform", downloadEntity.platform)
payloadObject.put("package", downloadEntity.packageName)
payloadObject.put("filename", downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1))
payloadObject.put("filename", getFileName(downloadEntity))
payloadObject.put("total_size", downloadEntity.size / 1024 / 1024)
payloadObject.put("completed_size", downloadEntity.progress / 1024 / 1024)
if (downloadEntity.status == DownloadStatus.resume) {
@ -257,7 +263,7 @@ object DownloadDataHelper {
payloadObject.put("gameName", downloadEntity.name)
payloadObject.put("platform", downloadEntity.platform)
payloadObject.put("package", downloadEntity.packageName)
payloadObject.put("filename", downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1))
payloadObject.put("filename", getFileName(downloadEntity))
payloadObject.put("speed_progress", JSONArray(averageSpeedList))
payloadObject.put("is_finished", downloadEntity.status == DownloadStatus.done)
jsonObject.put("payload", payloadObject)
@ -292,7 +298,7 @@ object DownloadDataHelper {
sheet.put("game_id", downloadEntity.gameId)
sheet.put("platform", downloadEntity.platform)
sheet.put("package", downloadEntity.packageName)
sheet.put("filename", downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1))
sheet.put("filename", getFileName(downloadEntity))
sheet.put("total_size", downloadEntity.size / 1024 / 1024)
sheet.put("current_progress_size", downloadEntity.progress / 1024)
mDownloadHeartbeatSheet[downloadEntity.url] = sheet
@ -339,13 +345,13 @@ object DownloadDataHelper {
val meta = getMeta()
// meta
val metaObject = JSONObject()
metaObject.put("android_id", meta.android_id)
metaObject.put("dia", MetaUtil.getBase64EncodedAndroidId())
metaObject.put("android_sdk", meta.android_sdk)
metaObject.put("android_version", meta.android_version)
metaObject.put("appVersion", meta.appVersion)
metaObject.put("channel", meta.channel)
metaObject.put("gid", meta.gid)
metaObject.put("imei", meta.imei)
metaObject.put("jnfj", MetaUtil.getBase64EncodedIMEI())
metaObject.put("mac", meta.mac)
metaObject.put("manufacturer", meta.manufacturer)
metaObject.put("model", meta.model)
@ -355,4 +361,13 @@ object DownloadDataHelper {
metaObject.put("userId", meta.userId)
return metaObject
}
private fun getFileName(downloadEntity: DownloadEntity): String {
val downloadId = downloadEntity.getMetaExtra(Constants.DOWNLOAD_ID)
return if (!TextUtils.isEmpty(downloadId)) {
downloadId + downloadEntity.path.substring(downloadEntity.path.lastIndexOf("."))
} else {
downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1)
}
}
}

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