Compare commits

...

282 Commits

Author SHA1 Message Date
5a826234d0 fix 2020-12-03 14:55:02 +08:00
9f5ffb084a 修复APP更新逻辑,以VersionName为准
修复App更新无法下载安装包问题
2020-11-23 18:38:01 +08:00
b5d4cbe718 更新启动弹窗隐私协议和用户协议内容 2020-11-20 14:20:49 +08:00
b39a47c0bd 光环马甲包4.3.8修改 2020-11-20 14:18:39 +08:00
5ea6647bf7 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into video_only
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/LoginActivity.java
#	app/src/main/java/com/gh/gamecenter/MainActivity.java
#	app/src/main/java/com/gh/gamecenter/SplashScreenActivity.java
#	app/src/main/java/com/gh/gamecenter/collection/CollectionWrapperFragment.java
#	app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java
#	app/src/main/java/com/gh/gamecenter/history/HistoryWrapperFragment.kt
#	app/src/main/java/com/gh/gamecenter/personal/PersonalViewModel.kt
#	app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt
#	app/src/main/res/layout/fragment_home.xml
#	app/src/main/res/layout/fragment_login.xml
#	app/src/main/res/layout/fragment_personal.xml
2020-11-13 16:04:36 +08:00
lyr
6fcd8397b6 修复"模拟器游戏创建桌面快捷方式时,由于图片过大而闪退"的Bug 2020-11-04 17:34:53 +08:00
3478aaba2f Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-11-04 10:24:53 +08:00
1f0b9a95e2 尝试修复后台开启前台服务闪退 https://gitlab.ghzs.com/halo/assistant-android/-/issues/7 2020-11-04 10:15:16 +08:00
5cdc1635ca 正式环境接口改为 4.4 2020-11-03 18:11:18 +08:00
3db784509b 更新依赖库 hash 2020-11-02 10:46:50 +08:00
e8f63ea99f 调整 jenkins 打包脚本 2020-11-02 10:46:30 +08:00
97ac4b03a3 处理合并异常 2020-11-02 10:27:30 +08:00
883a948b7b Merge branch 'feature-sdk-free' into dev
# Conflicts:
#	app/src/main/java/com/gh/common/LocalBroadcastReceiver.kt
#	app/src/main/java/com/gh/common/im/ImManager.kt
#	app/src/main/java/com/gh/common/im/ImReceiver.kt
#	app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameDetailCustomColumnAdapter.kt
#	app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingCommentItemViewHolder.kt
#	app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyAdapter.kt
#	app/src/main/java/com/gh/gamecenter/personalhome/background/PersonalityBackgroundViewModel.kt
#	app/src/main/java/com/gh/gamecenter/user/UserRepository.java
#	app/src/main/java/com/halo/assistant/HaloApp.java
#	dependencies.gradle
2020-11-02 10:03:28 +08:00
ebb279c42f 移除大部分第三方SDK 2020-11-02 09:45:24 +08:00
lyr
261e0cc45a 搜索页-未登录状态点击预约按钮也上传"search_click"点击事件 2020-10-30 15:01:21 +08:00
0357a0a71e 处理跳转模拟器传递meta格式错误 2020-10-30 10:30:04 +08:00
lyr
d87de59427 光环助手V4.4.0-个人主页优化(第2期)-> 1029 UI反馈 -> 第2点 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1037#note_74645 2020-10-29 22:37:11 +08:00
lyr
d5ee01a2e1 光环助手V4.4.0-游戏搜索功能强化(第6期)-> 20201028测试问题/搜索快捷按钮交互优化 2020-10-29 22:08:30 +08:00
lyr
3563637919 光环助手V4.4.0-游戏搜索数据 -> 20201029测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1035#note_74631 2020-10-29 21:32:34 +08:00
lyr
d881e08aee 光环助手V4.4.0-我的光环-新增[模拟器游戏] -> 1029测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1031 2020-10-29 21:24:32 +08:00
f5ff838d2f 更换背景默认透明度改为1 2020-10-29 20:57:26 +08:00
52c1b08e59 修复自动搜索曝光统计问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1035 2020-10-29 17:42:44 +08:00
lyr
652972f49d 光环助手V4.4.0-我的光环-新增[模拟器游戏] -> 1028测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1031 2020-10-29 16:16:02 +08:00
0d122cf8ba 光环助手V4.4.0-单机模拟器1028测试(4) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1030 2020-10-29 09:27:01 +08:00
lyr
2b115c4058 第一次打开App删除所有模拟器游戏记录 2020-10-28 18:17:52 +08:00
lyr
cfca7db4ef 补充游戏搜索页-"搜索-点击"事件的埋点数据 2020-10-28 15:41:05 +08:00
lyr
5f66c029fb 光环助手V4.4.0-游戏搜索数据 —> 20201028测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1035#note_74338 2020-10-28 14:52:39 +08:00
lyr
8635652fe2 优化"个人主页"代码逻辑 2020-10-28 11:22:57 +08:00
lyr
a890ad532c 光环助手V4.4.0-游戏搜索功能强化(第6期)-> 20201027测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1025#note_74281 2020-10-28 11:18:03 +08:00
lyr
65c9d2be2a 光环助手V4.4.0-我的光环-新增[模拟器游戏] -> 1027测试/201027UI反馈 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1031 2020-10-27 18:22:49 +08:00
9620e26f6a 删除模拟器游戏时上传记录 2020-10-27 16:57:34 +08:00
e4ca1d8406 光环助手V4.4.0-单机模拟器 1027测试(6,7,8,10) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1030 2020-10-27 16:19:00 +08:00
74ebaa592b 修改模拟器下载完成埋点 2020-10-27 11:09:35 +08:00
f9b689efdb 更新 LGLibrary 2020-10-27 10:13:42 +08:00
ed458f08ad debug mode 接入简单的闪退日志显示插件 2020-10-27 10:06:26 +08:00
lyr
9822646acc 光环助手V4.4.0-游戏搜索数据->前端埋点 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1035 2020-10-26 18:38:56 +08:00
4259078420 完成光环前端优化汇总(2020年10月第1周)(10,11) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1028 2020-10-26 18:21:13 +08:00
3b9db4e964 恢复模拟器游戏保存路径 2020-10-26 18:11:42 +08:00
b7e6cd08fd 修改通知弹窗闪退问题 2020-10-26 16:49:12 +08:00
bba1e6f10c 处理一些闪退异常 2020-10-26 14:23:44 +08:00
3fe2973968 修改模拟器下载日志 2020-10-26 14:15:37 +08:00
b16d33d9fa Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-10-26 09:22:18 +08:00
e1a7ed9049 修改更换背景获取bitmap方式 2020-10-26 09:21:59 +08:00
lyr
11354030e8 光环助手V4.4.0-游戏搜索功能强化(第6期)三 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1025 2020-10-26 09:21:42 +08:00
ee109060fc 更改首页横向自滚动专题的实现 2020-10-23 18:19:49 +08:00
lyr
eebc0c1096 提交遗漏代码 2020-10-23 17:09:28 +08:00
lyr
4ec45e2a27 Merge remote-tracking branch 'origin/dev' into dev 2020-10-23 17:08:10 +08:00
lyr
12143f7f95 优化"模拟器游戏"模块代码逻辑 2020-10-23 17:06:19 +08:00
7025dc45bd 优化获取图片 bitmap 的逻辑 2020-10-23 17:05:13 +08:00
772e7861e2 更换模拟器游戏文件夹名 2020-10-23 15:58:25 +08:00
ff71c9a3e8 优化模拟器下载 2020-10-23 11:50:52 +08:00
b7001cc996 Merge branch 'dev_4.4.0' into dev
# Conflicts:
#	app/src/main/java/com/gh/base/GHActivityLifecycleCallbacksImpl.java
#	app/src/main/java/com/gh/common/util/DownloadObserver.kt
#	app/src/main/java/com/gh/gamecenter/user/UserRepository.java
#	app/src/main/java/com/halo/assistant/HaloApp.java
2020-10-23 10:47:40 +08:00
83658e47f8 特殊渠道隐藏首页视频tab https://gitlab.ghzs.com/pm/issues-Inbox/-/issues/3090 2020-10-23 10:21:05 +08:00
lyr
0699d3ccc4 调整"模拟器游戏"列表-下载按钮UI 2020-10-22 18:19:11 +08:00
f80b998e98 处理当前链接没有下载记录并且文件已经存在下载异常问题 2020-10-22 17:26:04 +08:00
91e84be708 尝试排除分片检测下载进度数据上传的无用数据 2020-10-22 17:07:54 +08:00
f589c286c6 提交LGLibrary 2020-10-22 16:42:20 +08:00
379650a0f5 Merge branch 'emulator' into dev_4.4.0
# Conflicts:
#	app/src/main/java/com/gh/common/util/EntranceUtils.java
#	app/src/main/java/com/gh/common/util/LogUtils.java
#	app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java
#	app/src/main/java/com/halo/assistant/HaloApp.java
#	app/src/main/res/values/colors.xml
2020-10-22 16:12:24 +08:00
3796eb46bd 启动模拟器游戏 2020-10-22 15:46:49 +08:00
c240048c5e 处理延迟初始化视频播放闪退 2020-10-22 14:52:13 +08:00
lyr
2f81c9240d 完善"模拟器游戏"快捷方式的处理逻辑 2020-10-22 10:58:40 +08:00
lyr
da0dc3df97 完成"模拟器游戏"模块UI 2020-10-21 17:45:47 +08:00
d73c0f2044 Merge branch 'emulator' of gitlab.ghzs.com:halo/assistant-android into emulator
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorGameFragment.kt
2020-10-21 17:18:58 +08:00
a6f9e12082 光环助手V4.4.0-数据统计需求(单机模拟器)(一、1,二) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1033 2020-10-21 17:16:24 +08:00
20f8ba0de5 补充处理部分数据收集代码 2020-10-21 16:53:10 +08:00
f7342a944e 更新 talkingdata SDK 规避频繁获取 IMEI 2020-10-21 16:45:39 +08:00
lyr
1086574b33 "模拟器游戏"空数据页面增加广告位链接 2020-10-21 16:21:41 +08:00
59e30d432d Merge branch 'privacy_free' into dev
# Conflicts:
#	app/src/main/java/com/halo/assistant/HaloApp.java
2020-10-21 15:26:56 +08:00
lyr
58631d540c "模拟器游戏"顶部Tab增加筛选,增加无数据显示页面 2020-10-21 15:25:28 +08:00
lyr
08763aeb2d 上传遗漏代码 2020-10-21 11:36:46 +08:00
lyr
039d0ca06c 去掉多余代码 2020-10-21 11:31:45 +08:00
lyr
f39574c8b3 大致完成"模拟器游戏"模块UI 2020-10-21 11:26:44 +08:00
6067a52fb1 光环助手V4.4.0-数据统计需求(单机模拟器)(二、2) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1033 2020-10-21 10:01:36 +08:00
a1298547d1 版本号升级为4.4.0 2020-10-20 18:38:14 +08:00
49d5514a25 回退下载防劫持敏感度调整代码 2020-10-20 15:53:16 +08:00
09c414a02c 降低下载劫持判断的敏感度 2020-10-20 09:26:39 +08:00
6a6378f635 【光环助手V4.4.0】论坛数据埋点需求 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1019 2020-10-20 09:16:34 +08:00
920050efc8 Merge dev_4.4.0 into dev_4.4.0 2020-10-19 18:35:25 +08:00
103ecc10d3 完成游戏下载状态新增"更新中" https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1021 2020-10-19 18:30:05 +08:00
f90e9a8085 视频流支持下载、启动模拟器游戏 2020-10-19 16:46:17 +08:00
caa37ead4b 光环助手V4.4.0-个人主页优化(第2期)(2-⑦、3) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1037 2020-10-19 15:07:42 +08:00
d18eeaf346 已下载的模拟器游戏显示在 已安装、玩过的游戏 等位置 2020-10-19 10:35:04 +08:00
lyr
b98d287843 光环助手V4.4.0-个人主页优化(第2期)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1037#note_73008 2020-10-18 16:36:27 +08:00
66fb57f708 记录模拟器游戏下载完成、启动 2020-10-16 18:19:50 +08:00
3911c10827 修复因为线程冲突导致重定向回调无法触发的问题 2020-10-16 17:52:16 +08:00
c29972df50 修复因为线程冲突导致重定向回调无法触发的问题 2020-10-16 17:17:27 +08:00
8001ce2603 大致完成模拟器游戏下载、模拟器下载与安装 2020-10-16 17:16:24 +08:00
b1079e84d8 大致完成模拟器游戏下载、模拟器下载与安装 2020-10-16 17:15:51 +08:00
c6cf8aab1c 修复因延迟获取用户数据造成的下载误报劫持问题 2020-10-16 16:51:21 +08:00
4d7718e3af 修复因延迟获取用户数据造成的闪退 2020-10-16 11:08:25 +08:00
9cdbcd4935 补充延迟操作备忘说明 2020-10-15 16:12:09 +08:00
d396ebda44 延迟一些与隐私政策相关的操作 2020-10-15 16:09:12 +08:00
6ab8bdc422 修复因为延迟收据收集代码而造成的闪退问题 2020-10-15 09:29:20 +08:00
15352bb379 调整隐私弹窗文案 2020-10-15 09:29:19 +08:00
b68536b561 调整隐私弹窗文案 2020-10-15 09:29:19 +08:00
762ee8d300 添加第三方SDK接入声明跳转 2020-10-15 09:29:19 +08:00
8dfda56586 避免用户同意隐私协议前获取IMEI和MAC,缓存IMEI避免频繁获取 2020-10-15 09:29:17 +08:00
93126517b6 模拟器游戏下载记录使用本地数据库保存 2020-10-14 19:53:24 +08:00
04a8f5772c 补充游戏详情大家都在玩的页面路径 2020-10-14 14:53:41 +08:00
9687ddcd54 光环前端优化汇总(2020年10月第1周)(7) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1028 2020-10-14 09:24:54 +08:00
04c49cbad7 测试环境api更新为v4d4d0 2020-10-13 18:12:08 +08:00
6addea7d73 处理下载网络错误空指针异常 2020-10-13 17:48:49 +08:00
lyr
229eaa0859 光环前端优化汇总(2020年10月第1周)第4/5点 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1028 2020-10-13 17:48:42 +08:00
3876096f52 处理webview调用更改标题方法报错的问题 2020-10-13 17:24:02 +08:00
bad3ab19c6 修复下载任务因耗时/超时变动引起的状态变更问题 2020-10-13 17:22:29 +08:00
b2100fe0e5 修改模拟器游戏保存路径 2020-10-13 17:18:08 +08:00
5998bb9d4a 光环助手V4.3.0-RELEASE 20201012-1500 测试汇总(3) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1034 2020-10-13 09:42:23 +08:00
fefe29a0b8 模拟器下载弹窗(未完) 2020-10-13 09:21:34 +08:00
a16554da21 光环助手V4.3.0-RELEASE 20201012-1500 测试汇总(1,2) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1034 2020-10-12 16:33:48 +08:00
6efc1e06bb 下载模拟器游戏 2020-10-12 16:21:11 +08:00
e51439d584 完成光环前端优化汇总(10月第一周第8点删掉七陌客服) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1028 2020-10-12 15:52:51 +08:00
907bad48bc 修复横向列表指示线错位的问题 2020-10-12 15:10:33 +08:00
582df7da58 Merge remote-tracking branch 'origin/dev' into dev 2020-10-12 14:21:23 +08:00
28f18a558c 补充JS方法用于更新内嵌WebView标题 2020-10-12 14:21:00 +08:00
lyr
658fb8579c 光环前端优化汇总(2020年10月第1周)第9点 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1028 2020-10-12 14:14:14 +08:00
45632052e5 Merge remote-tracking branch 'origin/dev' into dev 2020-10-12 10:42:00 +08:00
311211747a 广点通根据帐号细分至渠道 https://gitlab.ghzs.com/pm/yunying/-/issues/1271 2020-10-12 10:40:09 +08:00
010995b16d 曝光下载完成补充 host 和 path 信息 https://gitlab.ghzs.com/stats/stats-issues/-/issues/188 2020-10-12 10:26:48 +08:00
c82e981f4e 尝试修复前台服务闪退 2020-10-12 10:04:43 +08:00
f9803fa244 调整防劫持判断逻辑 https://wiki.ghzs.com/pages/viewpage.action?pageId=2754298 2020-10-12 10:03:17 +08:00
f21d86c8a7 光环前端优化汇总(2020年10月第1周)(3) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1028 2020-10-10 16:24:17 +08:00
8db525542e 修复多层嵌套列表因未完全显示而没能统计曝光的问题 2020-09-29 17:36:01 +08:00
lyr
49cf093a44 他人主页-点击个性签名不能跳转到个性签名编辑页 2020-09-29 15:43:18 +08:00
lyr
f2302ffc50 补充方法供网页跳转绑定手机页面 2020-09-29 14:47:27 +08:00
f85685fd52 更新 chucker 版本 2020-09-28 15:06:19 +08:00
a80419e4bd 修复横向大图滑动列表的滑动闪退 2020-09-28 12:53:00 +08:00
0e7b6bb097 回退chucker库 2020-09-28 10:19:35 +08:00
b795df2de8 正式环境切换到4.3.0 2020-09-28 09:47:27 +08:00
e99e8328ab 降低自滚动栏目在MUMU模拟器上的速率 2020-09-28 09:30:51 +08:00
500c77d6ed 修复横向滑动列表会有自然偏移的问题 2020-09-27 22:31:42 +08:00
3c13431bd3 Merge remote-tracking branch 'origin/dev' into dev 2020-09-27 21:37:01 +08:00
d5e426a7f0 调整详情页初始化顺序 2020-09-27 21:36:51 +08:00
8a37e0bdf4 调整自滚动栏目滚动速度 2020-09-27 21:36:07 +08:00
lyr
230eec78c1 光环助手V4.3.0-个人主页优化-2020.09.27ui反馈-2/4/5 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1004 2020-09-27 21:35:54 +08:00
8bb74461e6 调整首页专题样式 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/998 2020-09-27 21:08:27 +08:00
b0d0d3ca45 Merge remote-tracking branch 'origin/dev' into dev 2020-09-27 20:48:57 +08:00
356c9432ec 优化图片加载逻辑 2020-09-27 20:48:49 +08:00
31e14fd47b 上传背景后回到个人主页 2020-09-27 20:47:46 +08:00
c0644dc705 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-27 19:52:55 +08:00
1a43589bb1 光环助手V4.3.0-个人主页优化2020.09.27ui反馈(1,3) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1004 2020-09-27 19:52:50 +08:00
defd6d9a14 回退图片加载优化 2020-09-27 19:36:36 +08:00
lyr
77b4e8f73d 光环助手V4.3.0-徽章中心优化-测试问题14 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1003 2020-09-27 18:37:44 +08:00
61ef40f9b5 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-27 18:29:38 +08:00
13dd5c9892 修改选择挂件逻辑 2020-09-27 18:29:32 +08:00
d20aef7107 优化自滚动栏目的滚动状态 2020-09-27 17:45:46 +08:00
8c9cd6e0ec 调整首页/版块专题样式 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/999 2020-09-27 17:42:53 +08:00
lyr
487c2fd0a5 Merge remote-tracking branch 'origin/dev' into dev 2020-09-27 17:14:46 +08:00
lyr
0ffdef080b 光环助手V4.3.0-徽章中心优化-20200925UI测试-图4 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1003 2020-09-27 17:14:25 +08:00
ba76dbbd15 修改视频上传UI 2020-09-27 17:13:47 +08:00
7cfe82af47 修复自定义栏目和系统通知图标的复用显示问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/993 2020-09-27 15:36:06 +08:00
567977089a Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-27 14:44:36 +08:00
a258fe1d20 调整视频上传UI 2020-09-27 14:44:32 +08:00
lyr
28cf1ab114 光环前端优化汇总-0924测试-游戏评分-评论回复,点赞和取消点赞也需要改成论坛的形式 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/993 2020-09-27 14:43:02 +08:00
0e49c074ec 调整全局图片加载机制 2020-09-27 11:51:32 +08:00
85249f1d94 调整首页专题样式 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/998 2020-09-27 11:46:58 +08:00
38bda5ec02 QA增加0923补充MTA事件 2020-09-27 10:26:38 +08:00
0cc24956e0 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-27 09:27:56 +08:00
c17bcd9765 修改视频流下拉刷新成功提示UI 2020-09-27 09:27:51 +08:00
9f1642f577 修复自滚动栏目点击无响应的问题 2020-09-27 09:23:45 +08:00
lyr
9c01f75e8b 光环助手V4.3.0-徽章中心优化-0925测试问题-10/11/12 和 20200925UI测试-图4 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1003 2020-09-26 15:16:32 +08:00
a460722ae5 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-25 17:56:43 +08:00
37330c2ab2 增加刷新视频成功动画提示 2020-09-25 17:56:39 +08:00
lyr
5db25f966e 光环助手V4.3.0-个人主页优化0925测试问题10 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1004 2020-09-25 17:56:10 +08:00
4749c743e9 光环助手V4.3.0-个人主页优化0925测试问题11 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1004 2020-09-25 17:31:20 +08:00
f5b614cc63 发布问题增加防抖机制 2020-09-25 17:30:34 +08:00
34b8b00cb2 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-25 16:19:12 +08:00
6af86d871c 处理快速点击内存泄漏问题 2020-09-25 16:19:07 +08:00
0b7fade38b 优化 gif 加载 2020-09-25 16:07:09 +08:00
lyr
3237834f9a 修改徽章弹窗-动画旋转速度 2020-09-25 16:03:02 +08:00
53e9554f08 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-25 15:55:07 +08:00
70ee3001c2 光环助手V4.3.0-论坛功能优化(第一期)0924测试反馈(1) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1002 2020-09-25 15:55:03 +08:00
lyr
d7ae2b2aa4 修改"领取徽章弹窗显示的徽章图片不对"的问题 2020-09-25 14:54:05 +08:00
9c9dbfb105 修改视频流下拉刷新没有清除上个视频的动效 2020-09-25 14:39:10 +08:00
c633c228db 更换论坛tab动效文件 2020-09-25 14:15:18 +08:00
ad82005881 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-25 11:47:13 +08:00
815a0d0600 光环助手V4.3.0-论坛功能优化(第一期)优化/bug(1,2) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1002 2020-09-25 11:47:08 +08:00
e02f9db81d 修复专题头图出现额外空白区域的问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/998 2020-09-25 11:09:48 +08:00
c422b96da4 Merge remote-tracking branch 'origin/dev' into dev 2020-09-25 11:08:56 +08:00
lyr
40a64996d7 增加个人主页和个性签名的点击范围 2020-09-25 11:00:34 +08:00
cbfca66d51 修复版块加载到底后列表刷新失效的问题 2020-09-25 10:42:54 +08:00
f4a110c94d Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-25 10:34:58 +08:00
f601fd2339 光环助手V4.3.0-论坛功能优化(第一期)0904需求测试(1,2) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1002 2020-09-25 10:34:53 +08:00
e3217eaf22 调整专题图片显示样式 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/999 2020-09-25 10:24:13 +08:00
540515ab41 调整首页/版块的样式间距 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/998 2020-09-25 10:07:28 +08:00
lyr
e1c02a6138 完成徽章中心优化-20200924UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1003 2020-09-25 09:46:44 +08:00
lyr
a508576785 修改"个人主页没有与我的光环同步显示徽章数量"问题 2020-09-25 09:31:06 +08:00
lyr
84e57d5c91 评论点赞/取消点赞增加Toast 2020-09-25 09:28:19 +08:00
62b1005dbf 光环助手V4.3.0-视频优化与新增功能汇总20200924测试(4) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/983 2020-09-25 09:03:04 +08:00
04a5450a41 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-24 18:24:46 +08:00
2ac4dd6c5a 光环助手V4.3.0-视频优化与新增功能汇总20200924测试(5,6,7) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/983 2020-09-24 18:24:41 +08:00
lyr
441a569f30 优化"我的关注"UI 2020-09-24 18:19:23 +08:00
lyr
f319201e74 完成前端优化汇总-0924测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/993#note_70940 2020-09-24 17:58:47 +08:00
lyr
47b2fa60d8 完成个人主页-0924测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1004 2020-09-24 16:48:43 +08:00
4d15c15b2d 光环助手V4.3.0-个人主页优化0924测试(7) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1004 2020-09-24 16:14:20 +08:00
3702094d98 使用官方的chucker库 2020-09-24 15:45:19 +08:00
6185ca595d 光环助手V4.3.0-个人主页优化0924测试(1,6) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1004 2020-09-24 15:00:29 +08:00
358b93029b 光环助手V4.3.0-论坛功能优化(第一期)UI测试汇总 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1002 2020-09-24 14:22:23 +08:00
38044b1d2b 光环助手V4.3.0-视频优化与新增功能汇总 UI测试汇总 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/983 2020-09-24 11:38:38 +08:00
lyr
90877738b3 优化个人主页-游戏评论Tab 2020-09-24 09:33:03 +08:00
477613d21f 修改预览图背景没有对齐 2020-09-23 18:23:35 +08:00
lyr
a77ee0fa70 完成徽章中心优化-20200922UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1003#note_70670 2020-09-23 18:07:34 +08:00
036fa444c6 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-23 18:05:12 +08:00
d83e1e413f 光环助手V4.3.0-个人主页优化2020.09.23ui反馈(5,7) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1004 2020-09-23 18:05:07 +08:00
19986099ff 补充新专题样式的MTA点击事件 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1001 2020-09-23 17:57:23 +08:00
lyr
f23dd6a662 完成个人主页-2020.09.23ui反馈问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1004 2020-09-23 17:29:18 +08:00
951d306765 修复搜索相关的数据统计问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1015 2020-09-23 17:19:52 +08:00
8adfaa88a3 延迟加载游戏库 2020-09-23 16:37:03 +08:00
lyr
fcb76e71e5 优化个人主页-游戏评论 2020-09-23 15:39:20 +08:00
lyr
2da536f667 登录页UI优化 2020-09-23 15:36:40 +08:00
2034b1c587 类原生系统的通知ICON换为与普通推送通知一样 2020-09-23 15:30:04 +08:00
ea2e169199 完成首页和版块的项目间距调整 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/999, https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/998 2020-09-23 15:10:55 +08:00
2cf6c2747c Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-23 15:08:05 +08:00
dd24b6243a 光环助手V4.3.0-引导设置“安装权限” 0922测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1011 2020-09-23 15:07:59 +08:00
lyr
81fc6aa6cb 完成光环前端优化汇总(2020年9月第1周)第8点 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/993#note_67726 2020-09-23 11:28:25 +08:00
lyr
8e3bcf6b5b 完成光环前端优化汇总(2020年9月第1周)第4点 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/993#note_67726 2020-09-23 10:00:22 +08:00
8e181c9846 处理帖子删除评论后数据同步问题 2020-09-23 09:46:51 +08:00
lyr
7a737da328 优化个人主页UI以及逻辑 2020-09-22 19:23:00 +08:00
5545c112b7 完成前端优化汇总的5 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/993 2020-09-22 18:21:57 +08:00
a6f187d444 光环助手V4.3.0-Q&A管理优化需求 20200922UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/992 2020-09-22 17:46:33 +08:00
3ad72ee1f8 处理帖子列表删除评论后评论数错误问题 2020-09-22 17:32:52 +08:00
2cc100b887 处理消息中心图片不显示问题 2020-09-22 17:15:52 +08:00
761c5dc0bf Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-09-22 17:08:14 +08:00
80d3f140f4 处理网页中含有地图导致时间冲突问题 2020-09-22 17:08:09 +08:00
b72621ee2b 修复自滚动栏目偶发不能滚动的问题,调整首页/版块专题复用的偏移量 2020-09-22 15:41:28 +08:00
7896f3ee46 增加我的光环查看背景操作 2020-09-22 15:13:04 +08:00
d33c15e47b 删除多余代码 2020-09-22 14:51:05 +08:00
ddcd3f8169 增加帖子评论删除功能 2020-09-22 14:48:27 +08:00
lyr
42f66cd543 个人主页增加礼仪测试通过弹窗 2020-09-22 14:15:45 +08:00
c0efd4a8e4 完成专题功能优化20200919测试问题的(6/7/8/9) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/998 2020-09-22 12:07:09 +08:00
lyr
a4df780a8b 优化个人主页UI 2020-09-22 11:55:46 +08:00
lyr
e8ac144454 添加分享个人主页网址 2020-09-22 11:10:13 +08:00
lyr
d543181b92 退出登录"我的光环"设置为默认背景 2020-09-22 10:46:23 +08:00
lyr
02cfb7515b 基本完成光环助手V4.3.0-个人主页优化https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1004 2020-09-22 10:40:12 +08:00
4b71e44c51 修改个人主页挂件不显示 2020-09-21 16:39:08 +08:00
68f7e1fa58 用户头像添加挂件 2020-09-21 16:25:00 +08:00
2f66588455 补充插件反馈跳转 urlScheme https://gitlab.ghzs.com/pm/halo-plugin-issues/-/issues/164 2020-09-21 09:34:05 +08:00
f39cf38313 完成首页新增专题以及热门搜索的曝光上报 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1001, https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1015 2020-09-18 18:32:06 +08:00
1141604d20 修改头像挂件控件 2020-09-18 18:23:59 +08:00
6b575f0169 光环助手V4.3.0-Q&A管理优化需求(7,8) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/992 2020-09-18 11:52:30 +08:00
6428179c54 修复测试环境上传大图会闪退的问题 2020-09-18 11:40:03 +08:00
44445e6e34 修复自适应图片的展开问题 2020-09-18 11:18:14 +08:00
fb48316069 添加跳转帮助与反馈页面协议 2020-09-18 11:00:26 +08:00
ea5312d606 处理编译问题 2020-09-18 10:15:32 +08:00
5cb6f9e296 Merge branch 'dev_4.3.0' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/fragment/SearchToolWrapperFragment.java
#	app/src/main/java/com/gh/gamecenter/security/SecurityFragment.kt
#	dependencies.gradle
2020-09-18 10:08:37 +08:00
fdb1d255ba Merge branch 'dev_4.3.0' of gitlab.ghzs.com:halo/assistant-android into dev_4.3.0 2020-09-18 10:03:04 +08:00
153b19c966 跳转使用帮助内容详情 2020-09-18 10:02:59 +08:00
ba79d009e6 优化一般静态图片的加载显示逻辑 2020-09-18 09:56:44 +08:00
47f9c967b1 Merge branch 'dev_4.3.0' of gitlab.ghzs.com:halo/assistant-android into dev_4.3.0
# Conflicts:
#	app/src/main/res/values/colors.xml
2020-09-17 18:10:28 +08:00
97ab6108cf 完成粗略的头像挂件和更换背景页面 2020-09-17 18:08:01 +08:00
8e9da6e1f5 完成游戏专题功能优化的14,15 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/998 2020-09-17 16:35:53 +08:00
aca29abde6 完成9月第一周前端优化汇总的5,10 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/993 2020-09-17 15:28:59 +08:00
lyr
dac3f7e2d7 分享截图过程中,base64转bitmap后释放base64 2020-09-17 11:27:05 +08:00
lyr
9f9254a835 上传遗漏代码 2020-09-17 10:02:31 +08:00
lyr
58e3ef83e0 上传遗漏资源文件 2020-09-17 09:59:09 +08:00
lyr
76bb5d1052 基本完成"光环助手V4.3.0-徽章中心优化"前端部分https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1003 2020-09-17 09:52:07 +08:00
afff3446c4 修改视频流评论投诉 2020-09-16 14:23:29 +08:00
2fa6e9c549 光环助手V4.3.0-Q&A管理优化需求(5) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/992 2020-09-16 14:20:58 +08:00
cb4bcedba7 去掉游戏详情专区网页地址的timestamp后缀 2020-09-16 10:19:55 +08:00
5dbe10a8a8 完成游戏专题功能优化的样式增加 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/998 2020-09-15 15:55:25 +08:00
13ca69c569 光环助手V4.3.0-视频优化与新增功能汇总(4) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/983 2020-09-15 09:39:56 +08:00
19e18226bd 完成粗糙的首页专题样式增加 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/998 2020-09-14 18:39:01 +08:00
6b51a198c2 光环助手V4.3.0-版块管理功能优化(三) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/999 2020-09-14 17:25:06 +08:00
5ad38457af 光环前端优化汇总(2020年9月第1周)(9) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/993 2020-09-14 16:42:23 +08:00
ee3043875a 光环助手V4.3.0-引导设置“安装权限” https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1011 2020-09-14 11:40:37 +08:00
92c8a698f3 jenkins脚本去掉中文 2020-09-11 18:11:55 +08:00
41f78c365b 版本号更新至4.3.0 2020-09-11 18:09:40 +08:00
lyr
4b8053beee 光环助手V4.3.0-优化登录功能(第二期)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1006 2020-09-10 18:09:59 +08:00
lyr
8008266389 手机号绑定冲突页UI优化 2020-09-10 11:06:56 +08:00
a37701f148 调整问题详情、回答详情更多按钮 2020-09-08 17:00:49 +08:00
add1339f4a 调整帖子详情更多按钮 2020-09-08 14:49:51 +08:00
859a2a5672 光环前端优化汇总(2020年9月第1周)(2) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/993 2020-09-07 17:46:01 +08:00
a7a48ccf77 光环助手V4.3.0-视频优化与新增功能汇总 (5,7-9) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/983 2020-09-07 14:36:20 +08:00
e9583284d0 Merge branch 'dev_fragment' into dev_4.3.0
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/fragment/SearchToolWrapperFragment.java
#	app/src/main/java/com/gh/gamecenter/video/game/GameVideoActivity.kt
2020-09-04 15:25:00 +08:00
b670a9c1c4 光环助手V4.3.0-视频优化与新增功能汇总(10) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/983 2020-09-04 15:12:04 +08:00
33d86a7995 处理页面重建后DialogFragment重复创建 2020-09-02 16:28:01 +08:00
80ce5052d9 整理 Fragment 实例化代码 https://gitlab.ghzs.com/halo/assistant-android/-/issues/20 2020-09-01 10:05:20 +08:00
ec805653bb 大致完成 整理 Fragment 实例化代码 https://gitlab.ghzs.com/halo/assistant-android/-/issues/20 2020-08-31 18:31:55 +08:00
798c4a2089 update 2020-04-29 10:59:39 +08:00
0686f70df6 更新到3.7.6 2020-04-29 10:51:28 +08:00
3c30564ab6 update 2020-04-10 19:10:11 +08:00
f04070e846 update 2020-04-02 18:39:01 +08:00
fc279839fa 光环助手马甲包——视频 https://gitlab.ghzs.com/pm/yunying/issues/1051 2020-04-02 15:07:11 +08:00
599 changed files with 17071 additions and 4713 deletions

View File

@ -6,7 +6,7 @@ apply plugin: 'kotlin-kapt'
// apkChannelPackage
apply plugin: 'channel'
apply from: 'tinker-support.gradle'
//apply from: 'tinker-support.gradle'
android {
@ -45,6 +45,9 @@ android {
abiFilters "armeabi-v7a"
}
renderscriptTargetApi 18
renderscriptSupportModeEnabled true
// 由于app只针对中文用户所以仅保留zh资源其他删掉
resConfigs "zh"
@ -189,6 +192,7 @@ dependencies {
debugImplementation "com.facebook.stetho:stetho-okhttp3:${stetho}"
debugImplementation "com.squareup.okhttp3:logging-interceptor:${okHttp}"
debugImplementation "com.gu.android:toolargetool:${toolargetool}"
debugImplementation "com.github.nichbar:WhatTheStack:$whatTheStack"
implementation "androidx.core:core:${core}"
implementation "androidx.fragment:fragment:${fragment}"
@ -245,7 +249,7 @@ dependencies {
implementation "com.sina.weibo.sdk:core:${weiboSDK}"
// bugly with tinker support
implementation "com.tencent.bugly:crashreport_upgrade:${buglyTinkerSupport}"
// implementation "com.tencent.bugly:crashreport_upgrade:${buglyTinkerSupport}"
implementation "com.google.android:flexbox:${flexbox}"
@ -285,9 +289,9 @@ dependencies {
debugImplementation "com.github.nichbar.chucker:library:$chucker"
releaseImplementation "com.github.nichbar.chucker:library-no-op:$chucker"
implementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog"
implementation "com.bytedance.ies.ugc.aweme:opensdk-china-external:$bytedanceAweme"
implementation "com.bytedance.ies.ugc.aweme:opensdk-common:$bytedanceAweme"
// implementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog"
// implementation "com.bytedance.ies.ugc.aweme:opensdk-china-external:$bytedanceAweme"
// implementation "com.bytedance.ies.ugc.aweme:opensdk-common:$bytedanceAweme"
implementation "com.aliyun.dpa:oss-android-sdk:${oss}"
@ -303,12 +307,12 @@ dependencies {
implementation "com.github.PhilJay:MPAndroidChart:${chart}"
implementation project(':libraries:LGLibrary')
implementation project(':libraries:MTA')
// implementation project(':libraries:MTA')
implementation project(':libraries:QQShare')
implementation project(':libraries:TalkingData')
implementation project(':libraries:UmengPush')
// implementation project(':libraries:TalkingData')
// implementation project(':libraries:UmengPush')
// implementation project(':libraries:WechatShare')
implementation project(':libraries:im')
// implementation project(':libraries:im')
implementation project(':libraries:Matisse')
}
File propFile = file('sign.properties')

Binary file not shown.

Binary file not shown.

BIN
app/libs/gid-1.3.jar Normal file

Binary file not shown.

View File

@ -254,4 +254,8 @@
-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.wireless.security.**{*;}
-keep class com.alibaba.sdk.android.**{*;}
-keep class com.ut.**{*;}
-keep class com.ta.**{*;}

View File

@ -27,6 +27,8 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 修改系统设置的权限 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- 创建快捷方式的权限 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
@ -36,8 +38,6 @@
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--可选,穿山甲提供“获取地理位置权限”和“不给予地理位置权限,开发者传入地理位置参数”两种方式上报用户位置,两种方式均可不选,添加位置权限或参数将帮助投放定位广告-->
<!--请注意:无论通过何种方式提供给穿山甲用户地理位置,均需向用户声明地理位置权限将应用于穿山甲广告投放,穿山甲不强制获取地理位置信息-->
<!--<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />-->
@ -47,13 +47,13 @@
<uses-sdk tools:overrideLibrary="com.shuyu.gsyvideoplayer,
com.shuyu.gsyvideoplayer.lib,
com.haroldadmin.whatthestack,
com.shuyu.gsyvideoplayer.armv7a,
com.shuyu.gsyvideoplayer.x86,
com.shuyu.gsy.base,
com.google.android.exoplayer2,
tv.danmaku.ijk.media.exo2,
pl.droidsonroids.gif,
com.donkingliang.consecutivescroller" />
pl.droidsonroids.gif" />
<!-- 去掉 SDK 一些流氓权限 -->
<uses-permission
@ -69,7 +69,7 @@
<!--android:largeHeap = "true"-->
<application
android:name="com.halo.assistant.TinkerApp"
android:name="com.halo.assistant.HaloApp"
android:allowBackup="true"
android:icon="@mipmap/logo"
android:label="@string/app_name"
@ -562,6 +562,35 @@
android:name=".video.label.VideoLabelActivity"
android:screenOrientation="portrait" />
<activity
android:name=".personalhome.border.AvatarBorderActivity"
android:screenOrientation="portrait" />
<activity
android:name=".personalhome.background.PersonalityBackgroundActivity"
android:screenOrientation="portrait" />
<activity
android:name=".personalhome.background.BackgroundPreviewActivity"
android:screenOrientation="portrait" />
<activity
android:name=".personalhome.background.BackgroundClipActivity"
android:screenOrientation="portrait"
android:theme="@style/TransparentStatusBarAndNavigationBar"/>
<activity
android:name=".personalhome.excellentcomments.ExcellentCommentsActivity"
android:screenOrientation="portrait" />
<activity
android:name=".simulatorgame.SimulatorGameActivity"
android:screenOrientation="portrait" />
<activity
android:name=".simulatorgame.SimulatorManagementActivity"
android:screenOrientation="portrait" />
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
<activity
android:name="com.gh.gamecenter.PushProxyActivity"
@ -589,11 +618,11 @@
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity>
<activity
android:name="${applicationId}.douyinapi.DouYinEntryActivity"
android:launchMode="singleTask"
android:taskAffinity="${applicationId}"
android:exported="true" />
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
<!-- android:launchMode="singleTask"-->
<!-- android:taskAffinity="${applicationId}"-->
<!-- android:exported="true" />-->
<provider
android:name="androidx.core.content.FileProvider"
@ -628,45 +657,45 @@
</intent-filter>
</receiver>
<receiver android:name="com.gh.gamecenter.receiver.UmengMessageReceiver">
<intent-filter>
<action android:name="com.gh.gamecenter.UMENG" />
</intent-filter>
</receiver>
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMessageReceiver">-->
<!-- <intent-filter>-->
<!-- <action android:name="com.gh.gamecenter.UMENG" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<!--魅族push应用定义消息receiver声明 -->
<receiver android:name="com.gh.gamecenter.receiver.UmengMeizuPushReceiver">
<intent-filter>
<!-- 接收push消息 -->
<action android:name="com.meizu.flyme.push.intent.MESSAGE" />
<!-- 接收register消息 -->
<action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />
<!-- 接收unregister消息-->
<action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />
<!-- 兼容低版本Flyme3推送服务配置 -->
<action android:name="com.meizu.c2dm.intent.REGISTRATION" />
<action android:name="com.meizu.c2dm.intent.RECEIVE" />
<!-- &lt;!&ndash;魅族push应用定义消息receiver声明 &ndash;&gt;-->
<!-- <receiver android:name="com.gh.gamecenter.receiver.UmengMeizuPushReceiver">-->
<!-- <intent-filter>-->
<!-- &lt;!&ndash; 接收push消息 &ndash;&gt;-->
<!-- <action android:name="com.meizu.flyme.push.intent.MESSAGE" />-->
<!-- &lt;!&ndash; 接收register消息 &ndash;&gt;-->
<!-- <action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />-->
<!-- &lt;!&ndash; 接收unregister消息&ndash;&gt;-->
<!-- <action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />-->
<!-- &lt;!&ndash; 兼容低版本Flyme3推送服务配置 &ndash;&gt;-->
<!-- <action android:name="com.meizu.c2dm.intent.REGISTRATION" />-->
<!-- <action android:name="com.meizu.c2dm.intent.RECEIVE" />-->
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
<!-- <category android:name="${applicationId}" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<receiver
android:name="com.gh.common.im.ImReceiver"
android:enabled="true">
<intent-filter android:priority="2147483647">
<action android:name="com.gh.im" />
<action android:name="action_finish" />
</intent-filter>
</receiver>
<!-- <receiver-->
<!-- android:name="com.gh.common.im.ImReceiver"-->
<!-- android:enabled="true">-->
<!-- <intent-filter android:priority="2147483647">-->
<!-- <action android:name="com.gh.im" />-->
<!-- <action android:name="action_finish" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<meta-data
android:name="com.huawei.hms.client.appid"
android:value="@string/huawei_push_appid" />
<!-- <meta-data-->
<!-- android:name="com.huawei.hms.client.appid"-->
<!-- android:value="@string/huawei_push_appid" />-->
<service
android:name="com.gh.base.GHUmengNotificationService"
android:permission="android.permission.BIND_JOB_SERVICE" />
<!-- <service-->
<!-- android:name="com.gh.base.GHUmengNotificationService"-->
<!-- android:permission="android.permission.BIND_JOB_SERVICE" />-->
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"v":"5.6.9","fr":30,"ip":0,"op":20,"w":66,"h":66,"nm":"bottom bar tab/论坛/选中/E","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"矩形","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":4,"s":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":9,"s":[110,110,100]},{"t":13,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":0,"s":[{"i":[[-0.55,0],[0,0],[0,-0.55],[0,0],[1.38,0],[0,1.38],[0,0]],"o":[[0,0],[0.55,0],[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.55]],"v":[[-1.5,-2.5],[1.5,-2.5],[2.5,-1.5],[2.5,0],[0,2.5],[-2.5,0],[-2.5,-1.5]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":4,"s":[{"i":[[-0.55,0],[0,0],[0,-0.55],[0,0],[1.38,0],[0,1.38],[0,0]],"o":[[0,0],[0.55,0],[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.55]],"v":[[-1.5,-1.25],[1.5,-1.25],[2.5,-0.25],[2.5,0],[0,1.896],[-2.5,0],[-2.5,-0.25]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":9,"s":[{"i":[[-0.55,0],[0,0],[0,-0.55],[0,0],[1.38,0],[0,1.38],[0,0]],"o":[[0,0],[0.55,0],[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.55]],"v":[[-1.5,-2.938],[1.5,-2.938],[2.5,-1.938],[2.5,0],[0,2.833],[-2.5,0],[-2.5,-1.938]],"c":true}]},{"t":13,"s":[{"i":[[-0.55,0],[0,0],[0,-0.55],[0,0],[1.38,0],[0,1.38],[0,0]],"o":[[0,0],[0.55,0],[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.55]],"v":[[-1.5,-2.5],[1.5,-2.5],[2.5,-1.5],[2.5,0],[0,2.5],[-2.5,0],[-2.5,-1.5]],"c":true}]}],"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":20,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"路径 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,34.599,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.2,0],[2.19,-0.35],[0,-1.82],[0,0],[0,0],[-1.98,0],[0,0],[0,0],[0,0],[-0.72,0.53],[0,0],[0,0],[0,2.05],[0,0],[1.8,0.28]],"o":[[-2.19,0],[-1.8,0.28],[0,0],[0,0],[0.1,1.96],[0,0],[0,0],[0,0],[0.58,0.65],[0,0],[0,0],[2.05,0],[0,0],[0,-1.82],[-2.2,-0.35]],"v":[[-0.003,-9.745],[-6.583,-9.215],[-9.712,-5.555],[-9.712,3.465],[-9.702,3.665],[-6.003,7.175],[-3.383,7.175],[-2.122,9.065],[-2.023,9.185],[0.277,9.405],[3.238,7.175],[5.997,7.175],[9.717,3.465],[9.717,-5.555],[6.587,-9.215]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.266,0.638,1,0.5,0.242,0.595,1,1,0.217,0.552,1],"ix":9}},"s":{"a":0,"k":[-9.712,-9.745],"ix":5},"e":{"a":0,"k":[9.712,9.745],"ix":6},"t":1,"nm":"color","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"路径","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"预合成 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2},"a":{"a":0,"k":[33,33,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[70,70,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":9,"s":[110,110,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[90,90,100]},{"t":16,"s":[100,100,100]}],"ix":6}},"ao":0,"w":66,"h":66,"ip":0,"op":20,"st":0,"bm":0}],"markers":[]}
{"v":"5.6.9","fr":30,"ip":0,"op":20,"w":66,"h":66,"nm":"bottom bar tab/论坛/选中/E","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"白-修正","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":4,"s":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":9,"s":[110,110,100]},{"t":13,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":0,"s":[{"i":[[0,-0.66],[0,0],[1.38,0],[0,1.38],[0,0],[-0.66,0],[0,0]],"o":[[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.66],[0,0],[0.66,0]],"v":[[2.5,-1.3],[2.5,0],[0,2.5],[-2.5,0],[-2.5,-1.3],[-1.3,-2.5],[1.3,-2.5]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":4,"s":[{"i":[[0,-0.66],[0,0],[1.38,0],[0,1.38],[0,0],[-0.66,0],[0,0]],"o":[[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.66],[0,0],[0.66,0]],"v":[[2.5,-0.102],[2.5,0],[0,2.109],[-2.5,0],[-2.5,-0.102],[-1.3,-1.302],[1.3,-1.302]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":9,"s":[{"i":[[0,-0.66],[0,0],[1.38,0],[0,1.38],[0,0],[-0.66,0],[0,0]],"o":[[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.66],[0,0],[0.66,0]],"v":[[2.498,-1.845],[2.5,0],[0,2.734],[-2.5,0],[-2.502,-1.845],[-1.302,-3.045],[1.298,-3.045]],"c":true}]},{"t":13,"s":[{"i":[[0,-0.66],[0,0],[1.38,0],[0,1.38],[0,0],[-0.66,0],[0,0]],"o":[[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.66],[0,0],[0.66,0]],"v":[[2.5,-1.3],[2.5,0],[0,2.5],[-2.5,0],[-2.5,-1.3],[-1.3,-2.5],[1.3,-2.5]],"c":true}]}],"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33.76,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.8,0.42],[-3.44,-0.79],[-0.09,-1.71],[0,0],[0,0],[1.98,-0.1],[0,0],[0,0],[0,0],[0.62,0.57],[0,0],[0,0],[0,0],[0,0],[0,0],[0.2,1.89],[0,0],[0,0],[0,0]],"o":[[3.44,-0.79],[1.74,0.41],[0,0],[0,0],[0,2],[0,0],[0,0],[0,0],[-0.69,0.52],[0,0],[0,0],[0,0],[0,0],[0,0],[-1.94,0],[0,0],[0,0],[0,0],[0,-1.8]],"v":[[-6.39,-8.971],[6.39,-8.971],[9.49,-5.471],[9.5,-5.271],[9.5,3.249],[5.95,6.989],[5.75,6.999],[3.25,6.999],[0.3,9.209],[-1.95,9.089],[-2.06,8.969],[-2.17,8.849],[-2.21,8.779],[-3.4,6.999],[-5.75,6.999],[-9.48,3.639],[-9.49,3.449],[-9.5,3.249],[-9.5,-5.271]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.266,0.638,1,0.5,0.242,0.595,1,1,0.217,0.552,1],"ix":9}},"s":{"a":0,"k":[-9.5,-9.561],"ix":5},"e":{"a":0,"k":[9.5,9.561],"ix":6},"t":1,"nm":"color","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"路径","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"预合成 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2},"a":{"a":0,"k":[33,33,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[70,70,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":9,"s":[110,110,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[90,90,100]},{"t":16,"s":[100,100,100]}],"ix":6}},"ao":0,"w":66,"h":66,"ip":0,"op":20,"st":0,"bm":0}],"markers":[]}

View File

@ -0,0 +1,360 @@
<html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>隐私政策</title>
<style>
* {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
font-size: 16px;
}
</style>
</head>
<body>
<div class="content-area">
<p>
<b>欢迎您使用光环game</b>
<br>
</p>
<p>更新日期2020年11月20日</p>
<p>生效日期2020年11月30日</p>
<p>
当您使用或开启相关功能或使用服务时,为了实现功能、服务所必需,受制于手机系统限制,我们会申请您的设备信息权限;除非是为实现基本业务服务功能或根据法律法规要求所必需的必要信息,您均可以拒绝提供且不影响其他功能或服务。
</p>
<p>
为了让您正常观看视频和记录浏览账户登录功能,我们会申请您的储存权限;
</p>
<p>以下为完整《隐私权限政策》</p>
<p>
光环game简称“我们”深知个人信息对您的重要性我们将依据《中华人民共和国网络安全法》、《信息安全技术
个人信息安全规范》GB/T
35273-2017以及其他相关法律法规和技术规范收集和使用您的个人信息以帮助我们向您提供更优质的产品和/或服务,
保护您的个人信息及隐私安全。我们制定本“隐私指引”并特别提示希望您在使用光环game及相关服务前仔细阅读并理解本隐私政策以便做出适当的选择。
</p>
<p>
下文将帮您详细了解我们如何收集、使用、存储、传输、共享、转让(如适用)与保护个人信息;帮您了解查询、访问、删除、更正、撤回授权个人信息的方式。其中,
<b>
有关您个人信息权益的条款重要内容我们已用加粗形式提示,请特别关注。
</b>
</p>
<p><b>1.我们处理个人信息的法律依据</b></p>
<p><b>2.我们如何共享、转让、公开披露个人信息</b></p>
<p><b>3.我们如何收集和使用个人信息</b></p>
<p><b>4.我们如何存储个人信息</b></p>
<p><b>5.我们如何保护个人信息的安全</b></p>
<p><b>6.管理您的个人信息</b></p>
<p><b>7.未成年人使用条款</b></p>
<p><b>8.隐私政策的修订和通知</b></p>
<p><b>9.联系我们</b></p>
<p><b>1.我们处理个人信息的法律依据</b></p>
<p>
如果您是中华人民共和国大陆地区的用户我们将依据《中华人民共和国网络安全法》、《信息安全技术个人信息安全规范》GB/T
35273-2017以及其他相关法律法规收集和使用您的个人信息为您提供产品或服务。
</p>
<p>
我们通常只会在征得您同意的情况下收集您的个人信息。在某些情况下,我们可能还会基于法律义务或者履行合同之必需向您收集个人信息,或者可能需要个人信息来保护您的重要利益或其他人的利益。
</p>
<p><b>2.我们如何共享、转让、公开披露个人信息</b></p>
<p>
<b>2.</b>
<b>1</b>
<b>共享您的个人信息</b>
</p>
<p>
1我们不会与任何公司、组织和个人共享您的个人信息但以下情况除外
</p>
<p>
2事先获得您的明确授权或同意
获得您的明确同意后,我们会与其他方共享您的个人信息;
</p>
<p>
3在法定情形下的共享
根据适用的法律法规、法律程序、政府的强制命令或司法裁定而需共享您的个人信息;
</p>
<p>
4在法律要求或允许的范围内为了保护光环game及其用户或社会公众的利益、财产或安全免遭损害而有必要提供您的个人信息给第三方
</p>
<p>
5与我们的关联公司共享
您的个人信息可能会在我们的关联公司之间共享。我们会对共享的个人信息进行匿名化处理,且这种共享受本指引所声明目的的约束。关联公司如要改变个人信息的处理目的,将再次征求您的授权同意。
</p>
<p>
<b>2.</b>
<b>2</b>
<b>转让</b>
</p>
<p>
1我们不会转让您的个人信息给任何其他第三方除非征得您的明确同意。
</p>
<p>
2随着我们业务的持续发展我们将有可能进行合并、收购、资产转让您的个人信息有可能因此而被转移。在发生前述变更时我们将按照法律法规及不低于本隐私政策所载明的安全标准要求继受方保护您的个人信息否则我们将要求继受方重新征得您的授权同意。
</p>
<p>
<b>2.</b>
<b>3</b>
<b>披露</b>
</p>
<p>
1我们不会公开披露您的信息除非遵循国家法律法规规定或者获得您的同意。我们公开披露您的个人信息会采用符合行业内标准的安全保护措施。
</p>
<p>
2基于法律、法律程序、诉讼或政府主管部门强制性要求的情况下我们可能会向有权机关披露您的个人信息。但我们保证在上述情况发生时我们会要求披露请求方必须出具与之相应的有效法律文件并对被披露的信息采取符合法律和业界标准的安全防护措施。
</p>
<p>3对违规账号、欺诈行为进行处罚公告时我们会披露相关账号的信息。</p>
<p>
<b>2.</b>
<b>4</b>
<b>依法豁免征得同意共享、转让、公开披露的个人信息</b>
</p>
<p>
请您理解,在下列情形中,根据法律法规及国家标准,我们共享、转让、公开披露您的个人信息无需征得您的授权同意:
</p>
<p>1与国家安全、国防安全直接相关的</p>
<p>2与公共安全、公共卫生、重大公共利益直接相关的</p>
<p>3与犯罪侦查、起诉、审判和判决执行等直接相关的</p>
<p>
4出于维护您或其他个人的生命、财产等重大合法权益但又很难得到本人同意的
</p>
<p>5您自行向社会公众公开的个人信息</p>
<p>
6从合法公开披露的信息中收集个人信息的如合法的新闻报道、政府信息公开等渠道。
</p>
<p><b>3.我们如何收集和使用个人信息</b></p>
<p>
我们会遵循正当、合法、必要的原则,出于本指引所述的以下目的,收集和使用您在使用服务过程中主动提供或因使用产品或服务而产生的个人信息。
</p>
<p>
我们收集和使用的您的个人信息类型包括两种:第一种:我们产品或服务的核心业务功能所必需的信息:此类信息为产品或服务正常运行的必备信息,您须授权我们收集。如您拒绝提供,您将无法正常使用我们的功能,以"仅浏览(游客身份)"
的状态体验;第二种:我们产品或服务的附加业务功能可能需要收集的信息:此信息为非核心业务功能所需的信息,您可以选择是否授权我们收集。如您拒绝提供,将导致附加业务功能无法实现或无法达到我们拟达到的效果,但不影响您对核心业务功能的正常使用。
</p>
<p>
如果我们要将您的个人信息用于本指引未载明的其它用途,或基于特定目的将收集而来的信息用于其他目的,我们将以合理的方式向您告知,并在使用前再次征得您的同意。
</p>
<p><b>3.1实现产品或服务的基本功能</b></p>
<p>
1手机管理和内容资源下载功能。为实现手机管理及手机内容资源下载的基本功能我们会通过手机系统的公用接口收集经过MD5算法加密的国际移动设备身份码IMEI和网络设备地址MAC以及手机型号、手机系统版本号、系统编号、系统ID号、屏幕分辨率、上网类型、手机中软件的名称、版本号、版本名、包名、软件使用时间和频率、软件崩溃信息、设备和软件相关的信息。这些信息是提供服务所必须收集的基础信息如您拒绝提供上述权限将可能导致您无法使用我们的服务。
</p>
<p>
2软件升级管理功能。为实现手机软件下载、安装、升级、卸载软件管理功能在您使用产品时我们会采集您手机中已安装软件的软件名称、版本号、版本名、软件包名信息并上传到我们的服务器进行软件版本比对。发现有更新的版本我们会提示您升级相应的软件。上述软件信息为实现此功能所必需不涉及您个人身份敏感信息。
</p>
<p>
3过滤无法使用的软件功能。为了过滤您手机无法使用的软件我们会收集您手机的手机型号、手机系统版本号、系统版本号、屏幕分辨率信息并依据这些信息排除您手机无法使用的软件以保证您在光环game下载的软件都可安装使用。
</p>
<p><b>3.2关于获取手机设备信息的说明</b></p>
<p>
1为方便区分每个用户的个人信息等本软件需获取用户的手机设备信息。2为了保障软件与服务的安全运行我们会收集您的硬件型号、操作系统版本号、国际移动设备识别码、唯一设备标识符、网络设备硬件地址、IP
地址、WLAN接入点、蓝牙、基站、软件版本号、网络接入方式、类型、状态、网络质量数据、操作、使用、服务日志。
</p>
<p>
3为了预防恶意程序及安全运营所必需我们会收集安装的应用信息或正在运行的进程信息、应用程序的总体运行、使用情况与频率、应用崩溃情况、总体安装使用情况、性能数据、应用来源。
</p>
<p>
4我们可能使用您的账户信息、设备信息、服务日志信息以及我们关联公司、合作方在获得您授权或依法可以共享的信息用于判断账户安全、进行身份验证、检测及防范安全事件。
</p>
<p>5具体会发生获取手机设备信息场景如下说明</p>
<p>
&nbsp;&nbsp;①首次启动光环game&nbsp;②评论详情-发送评论功能&nbsp;③视频投稿-上传视频功能&nbsp;④视频详情-关注up主功能&nbsp;
</p>
<p><b>3.3帮助您成为我们的在线用户</b></p>
<p>1注册账号/登录账号</p>
<p>
a.当您注册、登录我们相关服务时,您可以通过手机号创建账号,并且您可以完善相关的网络身份识别信息(头像、昵称、密码),收集这些信息是为了帮助您完成注册。您还可以根据自身需求选择填写性别、生日、地区及个人介绍来完善您的信息。
</p>
<p>2认证用户</p>
<p>
a.在您使用身份认证的功能或服务时,根据相关法律法规,您可能需要提供您的真实身份信息(真实姓名、身份证号码、电话号码)以完成实名验证。
</p>
<p>
b.这些信息属于个人敏感信息,您可以拒绝提供,但您将可能无法获得相关服务,但不影响其他功能与服务的正常使用。
</p>
<p>
<b>3.</b>
<b>4</b>
<b>信息发布功能</b>
</p>
<p>
1注册成为光环game用户后可在光环game平台上发布评论、视频还可以对别人的视频评论作出回复、赞同、感谢。
</p>
<p>
2上述功能基于相册图片库/视频库)的图片/视频访问及上传的附加服务,我们会请求您授权相机、照片、麦克风权限,您可以使用该功能上传您的照片/图片/视频,以实现发布照片/图片/视频的功能、与其他用户进行照片/图片分享等功能。如您拒绝提供该权限和内容的,仅会使您无法使用该功能,但并不影响您正常使用产品与/或服务的其他功能。
</p>
<p>
3您发布视频内容或回答时我们将收集您发布的信息并展示您的昵称、头像、发布内容。
</p>
<p>
4用户因使用我们的产品或者服务而被我们收集的信息例如其他用户发布的信息中可能含有您的部分信息在评论、留言、发布图文、音视频中涉及到与您相关的信息
</p>
<p>
<b>3.</b>
<b>5</b>
<b>浏览、关注与收藏功能</b>
</p>
<p>1您可浏览的内容包括视频、评论。</p>
<p>
2在浏览的过程中您还可以关注您感兴趣的用户、收藏并收藏上述内容。
</p>
<p>
3为此
我们可能会收集您使用时的设备信息,如设备型号、唯一设备标识符、操作系统、分辨率、电信运营商等软硬件信息。
我们还可能收集您的浏览器类型,以此来为您提供信息展示的最优方案。
</p>
<p>
4此外在您使用浏览和收藏功能的过程中我们会自动收集您使用的详细情况并作为有关的
网络日志保存。
</p>
<p>
5您浏览和发布的内容及评论信息您上传的视频作品、您使用的语言、访问的日期和时间、及您的操作系统、软件版本号、登录IP
信息。
</p>
<p>
6在此过程中
我们会收集您的浏览记录,浏览记录包括您浏览的视频、评论,您可以自主清楚浏览缓存。
</p>
<p>
<b>3.</b>
<b>6</b>
<b>互动交流</b>
</p>
<p>
1您主动关注您感兴趣的up主、视频并与之进行互动进行浏览、评论、收藏、点赞或分享内容时我们会收集您关注的账号并向您展示您关注账号发布内容。
</p>
<p>
2您使用推荐通讯录好友功能时我们会请求通讯录权限并将通讯录中的信息进行高强度加密算法处理后用于向您推荐通信录中的好友。通讯录信息属于个人敏感信息拒绝提供该信息仅会使您无法使用上述功能但不影响您正常使用“光环game”及相关服务的其他功能。
</p>
<p>
<b>3.</b>
<b>7</b>
<b>收集、使用个人信息目的变更</b>
</p>
<p>
1请您了解随着我们业务的发展可能会对“光环game”的功能和提供的服务有所调整变化。
</p>
<p>
2原则上当新功能或服务与我们当前提供的功能或服务相关时收集与使用的个人信息将与原处理目的具有直接或合理关联。
</p>
<p>
3在与原处理目的无直接或合理关联的场景下我们收集、使用您的个人信息会再次进行告知并征得您的同意。
</p>
<p>
<b>3.</b>
<b>8</b>
<b>依法豁免征得同意收集和使用的个人信息</b>
</p>
<p>
请您理解,在下列情形中,根据法律法规及相关国家标准,我们收集和使用您的个人信息无需征得您的授权同意:
</p>
<p>1与国家安全、国防安全直接相关的</p>
<p>2与公共安全、公共卫生、重大公共利益直接相关的</p>
<p>3与犯罪侦查、起诉、审判和判决执行等直接相关的</p>
<p>
4出于维护个人信息主体或其他个人的生命、财产等重大合法权益但又很难得到本人同意的
</p>
<p>5所收集的您的个人信息是您自行向社会公众公开的</p>
<p>
6从合法公开披露的信息中收集的您的个人信息的如合法的新闻报道、政府信息公开等渠道
</p>
<p>7根据您的要求签订或履行合同所必需的</p>
<p>
8用于维护软件及相关服务的安全稳定运行所必需的例如发现、处置软件及相关服务的故障
</p>
<p>9为合法的新闻报道所必需的</p>
<p>
10学术研究机构基于公共利益开展统计或学术研究所必要且对外提供学术研究或描述的结果时对结果中所包含的个人信息进行去标识化处理的。
</p>
<p>11法律法规规定的其他情形。</p>
<p>
特别提示您注意,如信息无法单独或结合其他信息识别到您的个人身份,其不属于法律意义上您的个人信息;当您的信息可以单独或结合其他信息识别到您的个人身份时或我们将无法与任何特定个人信息建立联系的数据与其他您的个人信息结合使用时,这些信息在结合使用期间,将作为您的个人信息按照本隐私政策处理与保护。
</p>
<p><b>4.我们如何存储个人信息</b></p>
<p><b>4.1 存储地点</b></p>
<p>
1我们依照法律法规的规定将在境内运营过程中收集和产生的您的个人信息存储于中华人民共和国境内。
</p>
<p>
2目前我们不会将上述信息传输至境外如果我们向境外传输我们将会遵循相关国家规定或者征求您的同意。
</p>
<p><b>4.2存储期限</b></p>
<p>
1我们仅在为提供“光环game”及服务之目的所必需的期间内保留您的个人信息您发布的视频、评论、点赞及相关信息在您未撤回、删除或未注销账号期间我们会保留相关信息。
</p>
<p>
2超出必要期限后我们将对您的个人信息进行删除或匿名化处理但法律法规另有规定的除外。
</p>
<p><b>5.我们如何保护个人信息的安全</b></p>
<p>
1我们非常重视您个人信息的安全将努力采取合理的安全措施包括技术方面和管理方面来保护您的个人信息防止您提供的个人信息被不当使用或未经授权的情况下被访问、公开披露、使用、修改、损坏、丢失或泄漏。
</p>
<p>
2我们会使用不低于行业同行的加密技术、匿名化处理及相关合理可行的手段保护您的个人信息并使用安全保护机制防止您的个人信息遭到恶意攻击。
</p>
<p>
3我们会建立专门的安全部门、安全管理制度、数据安全流程保障您的个人信息安全。我们采取严格的数据使用和访问制度确保只有授权人员才可访问您的个人信息并适时对数据和技术进行安全审计。
</p>
<p>
4尽管已经采取了上述合理有效措施并已经遵守了相关法律规定要求的标准但请您理解由于技术的限制以及可能存在的各种恶意手段在互联网行业即便竭尽所能加强安全措施也不可能始终保证信息百分之百的安全我们将尽力确保您提供给我们的个人信息的安全性。
</p>
<p>
5您知悉并理解您接入我们的服务所用的系统和通讯网络有可能因我们可控范围外的因素而出现问题。因此我们强烈建议您采取积极措施保护个人信息的安全包括但不限于使用复杂密码、定期修改密码、不将自己的账号密码及相关个人信息透露给他人。
</p>
<p>
6我们会制定应急处理预案并在发生用户信息安全事件时立即启动应急预案努力阻止这些安全事件的影响和后果扩大。一旦发生用户信息安全事件泄露、丢失我们将按照法律法规的要求及时向您告知安全事件的基本情况和可能的影响、我们已经采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施。我们将及时将事件相关情况以推送通知、邮件、信函、短信及相关形式告知您难以逐一告知时我们会采取合理、有效的方式发布公告。同时我们还将按照相关监管部门要求上报用户信息安全事件的处置情况。
</p>
<p>
7您一旦离开“光环game”及相关服务浏览或使用其他网站、服务及内容资源我们将没有能力和直接义务保护您在光环game及相关服务之外的软件、网站提交的任何个人信息无论您登录、浏览或使用上述软件、网站是否基于“光环game”的链接或引导。
</p>
<p><b>6.管理您的个人信息</b></p>
<p>
我们非常重视您对个人信息的管理,并尽全力保护您的隐私,对于您个人信息的查询、访问、修改、删除、撤回同意授权、注销账号、投诉举报以及设置隐私功能的相关权利,以使您有能力保障您的隐私和信息安全。
</p>
<p><b>6.1 访问、删除、更正您的个人信息</b></p>
<p>1访问个人账号信息</p>
<p>a. 您可以查询、访问您的头像、用户名、简介、性别、生日、地区</p>
<p>b.您可以在光环game的“个人主页”中进行查询、访问。</p>
<p>2查询访问、更正、取消您关注账号、查询访问粉丝</p>
<p>a.进入“关注”在关注列表中查询、访问、取消关注您关注的账号。</p>
<p>b.您可以通过点击“设置”—点击“清理缓存”。</p>
<p>3访问隐私政策</p>
<p>
a.您可以在注册页面,或者在登录个人账号“设置”—“关于”查看本隐私政策的全部内容
</p>
<p>
b.请您了解本隐私政策中所述的“光环game”及相关服务可能会根据您所使用的手机型号、系统版本、软件应用程序版本、移动客户端等因素而有所不同。最终的产品和服务以您所使用的“光环game”软件及相关服务为准。
</p>
<p>6停止运营向您告知</p>
<p>
a.如我们停止运营,我们将及时停止收集您个人信息的活动,将停止运营的通知以逐一送达或公告的形式通知您,并对所持有的您的个人信息进行删除或匿名化处理。
</p>
<p><b>7.未成年人条款</b></p>
<p>
a.若您是未满18周岁的未成年人在使用“光环game”及相关服务前应在您的父母或其他监护人监护、指导下共同阅读并同意本隐私政策。
</p>
<p>
b.我们根据国家相关法律法规的规定保护未成年人的个人信息,只会在法律允许、父母或其他监护人明确同意或保护未成年人所必要的情况下收集、使用、储存、共享、转让或披露未成年人的个人信息;如果我们发现在未事先获得可证实的父母同意的情况下收集了未成年人的个人信息,则会设法尽快删除相关信息。
</p>
<p>
c.若您是未成年人的监护人,当您对您所监护的未成年人的个人信息有相关疑问时,请通过公司本隐私政策公示的联系方式与我们联系。
</p>
<p><b>8.隐私政策的修订和通知</b></p>
<p>
1为了给您提供更好的服务光环game及相关服务将不时更新与变化我们会适时对本隐私政策进行修订这些修订构成本隐私政策的一部分并具有等同于本隐私政策的效力未经您明确同意我们不会削减您依据当前生效的本隐私政策所应享受的权利。
</p>
<p>
2本隐私政策更新后我们会在光环game发出更新版本并在更新后的条款生效前通过公告或其他适当的方式提醒您更新的内容以便您及时了解本隐私政策的最新版本。
</p>
<p><b>9.联系我们</b></p>
<p>
如果您对我们的隐私政策及对您个人信息的处理有任何疑问、意见、建议、或投诉,请通过以下方式与我们联系
</p>
<p>
广州市来特悦游信息科技有限公司注册地址广州市天河区中山大道建工路13、15号3-6层5楼512房仅限办公用途
</p>
<p>在线客服QQ3624425003</p>
<p>信息保护事务联系电话020-85526920</p>
<p>在一般情况下我们会在15个工作日内对您的请求予以答复</p>
</div>
</body></html>

View File

@ -0,0 +1,161 @@
<html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>光环助手软件许可及服务协议</title>
<style>
* {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
font-size: 16px;
}
</style>
</head>
<body>
<div class="content-area">
<p><b></b></p>
<p>
<b>光环</b>
<b>game</b>
<b>软件许可及服务协议</b>
</p>
<p><b>更新日期2020年11月20日</b></p>
<p><b>生效日期2020年11月30日</b></p>
<p><b>首部及导言</b></p>
<p>欢迎使用光环game软件许可及服务</p>
<p>
各位用户在使用光环game前请您务必审慎阅读、并充分理解本协议中的各项条款
<b>
特别是免除或者限制责任的条款,以及开通或使用某项服务的单独协议,并选择接受或不接受。
</b>
除非您已阅读并接受本协议所有条款,否则您无权下载、安装或使用本软件及相关服务。您的下载、安装、使用、登录等行为即视为您已阅读并同意上述协议的约束。
</p>
<p>如果您未满18周岁请在法定监护人的陪同下阅读本协议及其他上述协议。</p>
<p><b>一、权利声明</b></p>
<p>
“光环game”的一切知识产权以及与“光环game”相关的所有信息内容包括但不限于文字表述及其组合、图标、图饰、图像、图表、色彩、界面设计、版面框架、有关数据、附加程序、印刷材料或电子文档等均为光环game所有受著作权法和国际著作权条约以及其他知识产权法律法规的保护。
</p>
<p><b>二、软件使用规范</b></p>
<p>
2.1
本软件是基于Android安卓系统手机、平板电脑(PAD)等设备开发的一款软件,提供注册登录、观看视频、视频投稿等功能
</p>
<p>2.2 软件的下载、安装和使用</p>
<p>
本软件为免费软件用户可以非商业性、无限制数量地从光环game授权的渠道下载、安装及使用本软件。
</p>
<p>
<b>如果您从未经光环</b>
<b>game</b>
<b>授权的第三方获取本软件或与本软件名称相同的安装程序,光环</b>
<b>game</b>
<b>无法保证该软件能够正常使用,并对因此给您造成的损失不予负责。</b>
</p>
<p>2.3 软件的复制、分发和传播</p>
<p>
本产品以研究交流为目的。用户可以非商业性、无限制数量地复制、分发和传播本软件产品。但必须保证每一份复制、分发和传播都是完整和真实的,
包括所有有关本软件产品的软件、电子文档, 版权和商标,亦包括本协议。
</p>
<p>2.4 软件的更新</p>
<p>
为了改善用户体验、完善服务内容光环game将不断努力开发新的服务并为您不时提供软件更新这些更新可能会采取软件替换、修改、功能强化、版本升级等形式。为了保证本软件及服务的安全性和功能的一致性光环game有权不经向您特别通知而对软件进行更新或者对软件的部分功能效果进行改变或限制。本软件新版本发布后旧版本的软件可能无法使用。光环game不保证旧版本软件继续可用及相应的客户服务请您随时核对并下载最新版本。
</p>
<p><b>三、用户使用须知</b></p>
<p>3.1 您理解并同意:</p>
<p>
为了向您提供有效的服务,本软件会利用您移动通讯终端的处理器和带宽等资源。本软件使用过程中可能产生数据流量的费用,用户需自行向运营商了解相关资费信息,并自行承担相关费用.
</p>
<p>3.2您理解并同意:</p>
<p>
<b>
如果因您不正当使用本软件造成了不良影响,或因使用本软件造成的包括但不限于数据异常等问题,均由使用者自行承担,光环团队不对任意类型的使用结果承担责任;
</b>
</p>
<p>3.3您理解并同意:</p>
<p>
本软件不含任何破坏用户移动通讯设备数据和获取用户隐私信息的恶意代码,不会泄露用户的个人信息和隐私;
</p>
<p>3.4您理解并同意:</p>
<p>
<b>
对于包括但不限于互联网网络故障、计算机故障、手机故障或病毒、信息损坏或丢失、计算机系统问题,或其它任何基于不可抗力原因而产生的损失,光环团队不承担任何责任。
</b>
</p>
<p>3.5您理解并同意:</p>
<p>光环game发布、收录的视频均不代表光环立场。</p>
<p>3.6您理解并同意:</p>
<p>
用户应在遵守法律及本协议的前提下使用本软件。用户无权实施包括但不限于下列行为:
</p>
<p>3.6.1 不得删除或者改变本软件上的所有权利管理电子信息</p>
<p>
3.6.2
不得故意避开或者破坏著作权人为保护本软件著作权而采取的技术措施;&nbsp;
</p>
<p>3.6.3 用户不得利用本软件误导、欺骗他人;&nbsp;</p>
<p>
3.6.4
违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机信息系统不能正常运行;&nbsp;
</p>
<p>3.6.5 未经允许,进入计算机信息网络或者使用计算机信息网络资源;&nbsp;</p>
<p>3.6.6 未经允许,对计算机信息网络功能进行删除、修改或者增加;&nbsp;</p>
<p>
3.6.7
未经允许,对计算机信息网络中存储、处理或者传输的数据和应用程序进行删除、修改或者增加;&nbsp;
</p>
<p>
3.6.8
破坏本软件系统或网站的正常运行,故意传播计算机病毒等破坏性程序;&nbsp;
</p>
<p>3.6.9 其他任何危害计算机信息网络安全的行为。&nbsp;</p>
<p>3.7 您理解并同意:</p>
<p>
本软件经过详细的测试,但不能保证与所有的软硬件系统完全兼容,不能保证本软件完全没有错误。如果出现不兼容及软件错误的情况,用户可通过各反馈途径将情况告知光环团队,获得技术支持。如果无法解决兼容性问题,用户可以删除本软件。
</p>
<p><b>四、争议解决处理</b></p>
<p>
本《协议》的解释、效力及纠纷的解决适用于中华人民共和国法律。若用户和光环game之间发生任何纠纷或争议首先应友好协商解决协商不成的用户在此完全同意将纠纷或争议提交光环game所在地法院管辖
</p>
<p>
<b></b>
<b>、关于获取手机设备信息的说明</b>
</p>
<p>
1为方便区分每个用户的个人信息等本软件需获取用户的手机设备信息用于用户登录、视频评论互动交流等用户相关的行为
</p>
<p>
2为了保障软件与服务的安全运行我们会收集您的硬件型号、操作系统版本号、国际移动设备识别码、唯一设备标识符、网络设备硬件地址、IP
地址、WLAN接入点、蓝牙、基站、软件版本号、网络接入方式、类型、状态、网络质量数据、操作、使用、服务日志。
</p>
<p>
3为了预防恶意程序及安全运营所必需我们会收集安装的应用信息或正在运行的进程信息、应用程序的总体运行、使用情况与频率、应用崩溃情况、总体安装使用情况、性能数据、应用来源。
</p>
<p>
4我们可能使用您的账户信息、设备信息、服务日志信息以及我们关联公司、合作方在获得您授权或依法可以共享的信息用于判断账户安全、进行身份验证、检测及防范安全事件。
</p>
<p>5具体会发生获取手机设备信息场景如下说明</p>
<p>
&nbsp;&nbsp;1) 首次启动光环game&nbsp;2) 评论详情-发送评论功能&nbsp;3)
视频投稿-上传视频功能&nbsp;4) 视频详情-关注up主功能
</p>
<p><b>七、其他</b></p>
<p>
7.1
本协议所有条款的标题仅为阅读方便,本身并无实际涵义,不能作为本协议涵义解释的依据。
</p>
<p>
&nbsp;7.2
如果本协议中的任何条款无论因何种原因完全或部分无效或不具有执行力,或违反任何适用的法律,则该条款被视为删除,但本协议的其余条款仍应有效并且有约束力。
</p>
<p>
&nbsp;7.3
光环有权随时根据有关法律、法规的变化以及公司经营状况和经营策略的调整等修改本协议。修改后的协议会在软件设置内发布。
当发生有关争议时,以最新的协议文本为准。如果不同意改动的内容,用户可以自行删除本软件。如果用户继续使用本软件,则视为您接受本协议的变动。
</p>
<p>&nbsp;7.4 光环在法律允许的最大范围内对本协议拥有解释权与修改权。</p>
</div>
</body></html>

View File

@ -4,10 +4,6 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import com.gh.base.adapter.FragmentAdapter;
import com.gh.base.fragment.BaseFragment_TabLayout;
import com.gh.common.view.TabIndicatorView;
@ -18,6 +14,9 @@ import com.lightgame.view.NoScrollableViewPager;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import butterknife.BindView;
/**
@ -73,10 +72,13 @@ public abstract class BaseActivity_TabLayout extends ToolBarActivity implements
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getIntent() != null) mCheckedIndex = getIntent().getIntExtra(PAGE_INDEX, 0);
mFragmentsList = new ArrayList<>();
initFragmentList(mFragmentsList);
mTabTitleList = new ArrayList<>();
initTabTitleList(mTabTitleList);
mFragmentsList = new ArrayList<>(restoreFragments());
if (mFragmentsList.isEmpty() || mFragmentsList.size() != mTabTitleList.size()) {
mFragmentsList.clear();
initFragmentList(mFragmentsList);
}
mViewPager.setOffscreenPageLimit(mFragmentsList.size());
mViewPager.addOnPageChangeListener(this);
@ -100,6 +102,20 @@ public abstract class BaseActivity_TabLayout extends ToolBarActivity implements
BaseFragment_TabLayout.initTabStyle(mTabLayout, mCheckedIndex);
}
private ArrayList<Fragment> restoreFragments() {
String tag = "android:switcher:" + mViewPager.getId() + ":";
ArrayList<Fragment> fragments = new ArrayList<>();
int childCount = mTabTitleList.size();
for (int index = 0; index < childCount; index++) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag + index);
if (fragment != null) {
fragments.add(fragment);
}
}
return fragments;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

View File

@ -4,10 +4,10 @@ import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;
import com.gh.common.im.ImManager;
import com.gh.common.notifier.Notifier;
import com.gh.common.util.DataUtils;
import com.gh.download.DownloadManager;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.AppManager;
/**
@ -34,23 +34,27 @@ public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallba
@Override
public void onActivityResumed(Activity activity) {
DataUtils.onResume(activity);
CurrentActivityHolder.getActivitySet().add(activity);
ImManager.updateFloatingWindow();
//FIXME 这里应该只是部分Activity需要
try {
// 初始化gameMap
DownloadManager.getInstance(activity).initGameMap();
} catch (Exception e) {
e.printStackTrace();
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
DataUtils.onResume(activity);
//FIXME 这里应该只是部分Activity需要
try {
// 初始化gameMap
DownloadManager.getInstance(activity).initGameMap();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onActivityPaused(Activity activity) {
DataUtils.onPause(activity);
CurrentActivityHolder.getActivitySet().remove(activity);
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
DataUtils.onPause(activity);
}
}
@Override

View File

@ -1,229 +1,229 @@
package com.gh.base
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.preference.PreferenceManager
import android.text.TextUtils
import android.view.View
import androidx.core.app.NotificationCompat
import androidx.core.text.htmlEncode
import com.gh.common.notifier.Notifier
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.PushEntity
import com.gh.gamecenter.entity.PushMessageEntity
import com.gh.gamecenter.entity.PushMessageUnreadEntity
import com.gh.gamecenter.entity.PushNotificationEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.message.MessageUnreadRepository
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
import com.gh.gamecenter.receiver.UmengMessageReceiver
import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_CLICK
import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_REMOVE
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.google.gson.Gson
import com.umeng.message.UmengMessageService
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.android.agoo.common.AgooConstants
import org.json.JSONObject
import retrofit2.HttpException
import java.util.*
class GHUmengNotificationService : UmengMessageService() {
companion object {
const val ACTION_UMENG = "com.gh.gamecenter.UMENG"
const val MESSAGE_FROM_SYSTEM = "message_from_system"
const val HALO_MESSAGE_DIALOG = "HALO_MESSAGE_DIALOG"
const val HALO_MESSAGE_CENTER = "HALO_MESSAGE_CENTER"
const val ANSWER = "answer"
const val FOLLOW_QUESTION = "follow_question"
const val NOTIFICATION_ID = 2015
const val DISPLAY_TYPE_NOTIFICATION = "notification"
const val DISPLAY_TYPE_CUSTOM = "custom"
const val MESSAGE_ID = "message_id"
const val NOTIFICATION_MESSAGE_ID = "notification_message_id" // 通知中心消息 ID
const val PUSH_ID = "push_id"
}
val notificationTags = arrayOf("GH_UMENG_TAG_1", "GH_UMENG_TAG_2", "GH_UMENG_TAG_3")
val gson = Gson()
override fun onMessage(context: Context, intent: Intent) {
val message = intent.getStringExtra(AgooConstants.MESSAGE_BODY)
val isMessageFromSystem = intent.getBooleanExtra(MESSAGE_FROM_SYSTEM, false)
try {
val pushData = message.toObject<PushEntity>()
pushData?.let { handlePushData(context, it, message, isMessageFromSystem) }
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun handlePushData(context: Context, pushData: PushEntity, message: String, isMessageFromSystem: Boolean) {
val notificationManager = context.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (pushData.displayType == DISPLAY_TYPE_NOTIFICATION) {
// 其它类型的透传信息
// 显示到通知栏
val msg = message.toObject<PushNotificationEntity>()
val data = msg?.extra?.data
// 系统推送(非自定义信息),直接处理跳转
if (isMessageFromSystem) {
val intent = Intent()
intent.setClass(context, UmengMessageReceiver::class.java)
intent.putExtra(EntranceUtils.KEY_DATA, data?.link)
intent.putExtra(EntranceUtils.KEY_TYPE, UmengMessageReceiver.DIRECT_ONLY)
intent.putExtra(EntranceUtils.KEY_MESSAGE, message)
intent.putExtra(NOTIFICATION_MESSAGE_ID, data?.messageId)
context.sendBroadcast(intent)
return
}
// 用户未登录的情况下不生成消息中心通知,避免用户掉登录了还收到跳转至消息中心的通知
if (data != null
&& data.link?.link == "system"
&& !UserManager.getInstance().isLoggedIn) {
return
}
val clickIntent = Intent()
val removeIntent = Intent()
clickIntent.setClass(context, UmengMessageReceiver::class.java)
clickIntent.putExtra(EntranceUtils.KEY_DATA, data?.link)
clickIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
clickIntent.putExtra(MESSAGE_ID, msg?.msgId)
clickIntent.putExtra(PUSH_ID, data?.pushId)
clickIntent.putExtra(NOTIFICATION_MESSAGE_ID, data?.messageId)
clickIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_CLICK)
removeIntent.setClass(context, UmengMessageReceiver::class.java)
removeIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_REMOVE)
removeIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
val clickPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(),
clickIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val deletePendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt() + 1,
removeIntent, PendingIntent.FLAG_UPDATE_CURRENT)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("Halo_Push", "Halo_Push", NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
val notification = NotificationCompat.Builder(context, "Halo_Push")
.setSmallIcon(R.drawable.ic_notification)
.setTicker(pushData.body?.ticker)
.setContentTitle(pushData.body?.title)
.setContentText(pushData.body?.text?.fromHtml())
.setContentIntent(clickPendingIntent)
.setDeleteIntent(deletePendingIntent)
.build()
notification.flags = notification.flags or Notification.FLAG_AUTO_CANCEL
notificationManager.notify(getNotificationTag(context), NOTIFICATION_ID, notification)
} else {
if (UserManager.getInstance().isLoggedIn &&
HALO_MESSAGE_DIALOG == pushData.body?.custom &&
MessageUnreadRepository.unreadLiveData.value != null) {
// 回答了问题或者关注了问题的消息
val msg = gson.fromJson(message, PushMessageEntity::class.java)
val data = msg?.extra?.data
val type = if (ANSWER == data?.type) {
"回答了你的问题"
} else {
"回答了你关注的问题"
}
val userName = StringUtils.shrinkStringWithDot(data?.userEntity?.name, 8)
val displayText = userName + type
if (Notifier.isActivityValid(CurrentActivityHolder.getCurrentActivity()) &&
Notifier.shouldShowNotifier(data?.answer?.id + displayText)) {
Notifier.create(CurrentActivityHolder.getCurrentActivity())
.setText(displayText)
.setDuration(5000)
.setIcon(data?.userEntity?.icon)
.setOnClickListener(View.OnClickListener {
val bundle = Bundle()
bundle.putString(EntranceUtils.KEY_ANSWER_ID, data?.answer?.id)
bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG)
bundle.putString(EntranceUtils.KEY_TO, AnswerDetailActivity::class.java.name)
EntranceUtils.jumpActivity(context, bundle)
MtaHelper.onEvent("消息弹窗", type, "Does not contains any parameter.")
// 标记已读
val jsonObject = JSONObject()
jsonObject.put("type", type)
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
RetrofitManager.getInstance(application).api.postMessageRead(UserManager.getInstance().userId, data?.id, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
MessageUnreadRepository.loadMessageUnreadData()
}
override fun onFailure(e: HttpException?) {
e?.printStackTrace()
}
})
Notifier.hide()
})
.show(false)
Notifier.tagNotifierAsShowed(data?.answer?.id + displayText)
}
} else if (HALO_MESSAGE_CENTER == pushData.body?.custom) {
// 消息中心逻辑
val msg = gson.fromJson(message, PushMessageUnreadEntity::class.java)
val data = msg?.extra?.data
data?.let { MessageUnreadRepository.loadMessageUnreadData() }
}
}
}
/**
* 规则:最多三条消息,以旧换新
*
* @return NotificationTag
*/
private fun getNotificationTag(context: Context): String {
val sp = PreferenceManager.getDefaultSharedPreferences(context)
val edit = sp.edit()
val timeTagMap = HashMap<Long, String>()
for (tag in notificationTags) {
val time = sp.getLong(tag, 0)
if (time == 0L) {
edit.putLong(tag, System.currentTimeMillis()).apply()
return tag
} else {
timeTagMap[time] = tag
}
}
val minTime = Collections.min(timeTagMap.keys)
val tag = timeTagMap[minTime]
edit.putLong(tag, System.currentTimeMillis()).apply()
return if (TextUtils.isEmpty(tag)) notificationTags[0] else tag!!
}
}
//package com.gh.base
//
//import android.app.Notification
//import android.app.NotificationChannel
//import android.app.NotificationManager
//import android.app.PendingIntent
//import android.content.Context
//import android.content.Intent
//import android.os.Build
//import android.os.Bundle
//import android.preference.PreferenceManager
//import android.text.TextUtils
//import android.view.View
//import androidx.core.app.NotificationCompat
//import androidx.core.text.htmlEncode
//import com.gh.common.notifier.Notifier
//import com.gh.common.util.*
//import com.gh.gamecenter.R
//import com.gh.gamecenter.entity.PushEntity
//import com.gh.gamecenter.entity.PushMessageEntity
//import com.gh.gamecenter.entity.PushMessageUnreadEntity
//import com.gh.gamecenter.entity.PushNotificationEntity
//import com.gh.gamecenter.manager.UserManager
//import com.gh.gamecenter.message.MessageUnreadRepository
//import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
//import com.gh.gamecenter.receiver.UmengMessageReceiver
//import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_CLICK
//import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_REMOVE
//import com.gh.gamecenter.retrofit.Response
//import com.gh.gamecenter.retrofit.RetrofitManager
//import com.google.gson.Gson
//import com.umeng.message.UmengMessageService
//import io.reactivex.android.schedulers.AndroidSchedulers
//import io.reactivex.schedulers.Schedulers
//import okhttp3.MediaType
//import okhttp3.RequestBody
//import okhttp3.ResponseBody
//import org.android.agoo.common.AgooConstants
//import org.json.JSONObject
//import retrofit2.HttpException
//import java.util.*
//
//class GHUmengNotificationService : UmengMessageService() {
//
// companion object {
// const val ACTION_UMENG = "com.gh.gamecenter.UMENG"
// const val MESSAGE_FROM_SYSTEM = "message_from_system"
// const val HALO_MESSAGE_DIALOG = "HALO_MESSAGE_DIALOG"
// const val HALO_MESSAGE_CENTER = "HALO_MESSAGE_CENTER"
// const val ANSWER = "answer"
// const val FOLLOW_QUESTION = "follow_question"
// const val NOTIFICATION_ID = 2015
// const val DISPLAY_TYPE_NOTIFICATION = "notification"
// const val DISPLAY_TYPE_CUSTOM = "custom"
// const val MESSAGE_ID = "message_id"
// const val NOTIFICATION_MESSAGE_ID = "notification_message_id" // 通知中心消息 ID
// const val PUSH_ID = "push_id"
// }
//
// val notificationTags = arrayOf("GH_UMENG_TAG_1", "GH_UMENG_TAG_2", "GH_UMENG_TAG_3")
// val gson = Gson()
//
// override fun onMessage(context: Context, intent: Intent) {
// val message = intent.getStringExtra(AgooConstants.MESSAGE_BODY)
// val isMessageFromSystem = intent.getBooleanExtra(MESSAGE_FROM_SYSTEM, false)
//
// try {
// val pushData = message.toObject<PushEntity>()
// pushData?.let { handlePushData(context, it, message, isMessageFromSystem) }
// } catch (e: Exception) {
// e.printStackTrace()
// }
// }
//
// private fun handlePushData(context: Context, pushData: PushEntity, message: String, isMessageFromSystem: Boolean) {
// val notificationManager = context.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//
// if (pushData.displayType == DISPLAY_TYPE_NOTIFICATION) {
// // 其它类型的透传信息
// // 显示到通知栏
// val msg = message.toObject<PushNotificationEntity>()
// val data = msg?.extra?.data
//
// // 系统推送(非自定义信息),直接处理跳转
// if (isMessageFromSystem) {
// val intent = Intent()
// intent.setClass(context, UmengMessageReceiver::class.java)
// intent.putExtra(EntranceUtils.KEY_DATA, data?.link)
// intent.putExtra(EntranceUtils.KEY_TYPE, UmengMessageReceiver.DIRECT_ONLY)
// intent.putExtra(EntranceUtils.KEY_MESSAGE, message)
// intent.putExtra(NOTIFICATION_MESSAGE_ID, data?.messageId)
// context.sendBroadcast(intent)
// return
// }
//
// // 用户未登录的情况下不生成消息中心通知,避免用户掉登录了还收到跳转至消息中心的通知
// if (data != null
// && data.link?.link == "system"
// && !UserManager.getInstance().isLoggedIn) {
// return
// }
//
// val clickIntent = Intent()
// val removeIntent = Intent()
//
// clickIntent.setClass(context, UmengMessageReceiver::class.java)
// clickIntent.putExtra(EntranceUtils.KEY_DATA, data?.link)
// clickIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
// clickIntent.putExtra(MESSAGE_ID, msg?.msgId)
// clickIntent.putExtra(PUSH_ID, data?.pushId)
// clickIntent.putExtra(NOTIFICATION_MESSAGE_ID, data?.messageId)
// clickIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_CLICK)
//
// removeIntent.setClass(context, UmengMessageReceiver::class.java)
// removeIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_REMOVE)
// removeIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
//
// val clickPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(),
// clickIntent, PendingIntent.FLAG_UPDATE_CURRENT)
//
// val deletePendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt() + 1,
// removeIntent, PendingIntent.FLAG_UPDATE_CURRENT)
//
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// val channel = NotificationChannel("Halo_Push", "Halo_Push", NotificationManager.IMPORTANCE_DEFAULT)
// notificationManager.createNotificationChannel(channel)
// }
//
// val notification = NotificationCompat.Builder(context, "Halo_Push")
// .setSmallIcon(R.drawable.ic_notification)
// .setTicker(pushData.body?.ticker)
// .setContentTitle(pushData.body?.title)
// .setContentText(pushData.body?.text?.fromHtml())
// .setContentIntent(clickPendingIntent)
// .setDeleteIntent(deletePendingIntent)
// .build()
// notification.flags = notification.flags or Notification.FLAG_AUTO_CANCEL
//
// notificationManager.notify(getNotificationTag(context), NOTIFICATION_ID, notification)
// } else {
// if (UserManager.getInstance().isLoggedIn &&
// HALO_MESSAGE_DIALOG == pushData.body?.custom &&
// MessageUnreadRepository.unreadLiveData.value != null) {
// // 回答了问题或者关注了问题的消息
// val msg = gson.fromJson(message, PushMessageEntity::class.java)
// val data = msg?.extra?.data
//
// val type = if (ANSWER == data?.type) {
// "回答了你的问题"
// } else {
// "回答了你关注的问题"
// }
//
// val userName = StringUtils.shrinkStringWithDot(data?.userEntity?.name, 8)
// val displayText = userName + type
//
// if (Notifier.isActivityValid(CurrentActivityHolder.getCurrentActivity()) &&
// Notifier.shouldShowNotifier(data?.answer?.id + displayText)) {
// Notifier.create(CurrentActivityHolder.getCurrentActivity())
// .setText(displayText)
// .setDuration(5000)
// .setIcon(data?.userEntity?.icon)
// .setOnClickListener(View.OnClickListener {
// val bundle = Bundle()
// bundle.putString(EntranceUtils.KEY_ANSWER_ID, data?.answer?.id)
// bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG)
// bundle.putString(EntranceUtils.KEY_TO, AnswerDetailActivity::class.java.name)
// EntranceUtils.jumpActivity(context, bundle)
//
// MtaHelper.onEvent("消息弹窗", type, "Does not contains any parameter.")
//
// // 标记已读
// val jsonObject = JSONObject()
// jsonObject.put("type", type)
// val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
//
// RetrofitManager.getInstance(application).api.postMessageRead(UserManager.getInstance().userId, data?.id, body)
// .subscribeOn(Schedulers.io())
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe(object : Response<ResponseBody>() {
// override fun onResponse(response: ResponseBody?) {
// super.onResponse(response)
// MessageUnreadRepository.loadMessageUnreadData()
// }
//
// override fun onFailure(e: HttpException?) {
// e?.printStackTrace()
// }
// })
// Notifier.hide()
// })
// .show(false)
// Notifier.tagNotifierAsShowed(data?.answer?.id + displayText)
// }
// } else if (HALO_MESSAGE_CENTER == pushData.body?.custom) {
// // 消息中心逻辑
// val msg = gson.fromJson(message, PushMessageUnreadEntity::class.java)
// val data = msg?.extra?.data
// data?.let { MessageUnreadRepository.loadMessageUnreadData() }
// }
// }
// }
//
// /**
// * 规则:最多三条消息,以旧换新
// *
// * @return NotificationTag
// */
// private fun getNotificationTag(context: Context): String {
// val sp = PreferenceManager.getDefaultSharedPreferences(context)
// val edit = sp.edit()
//
// val timeTagMap = HashMap<Long, String>()
// for (tag in notificationTags) {
// val time = sp.getLong(tag, 0)
// if (time == 0L) {
// edit.putLong(tag, System.currentTimeMillis()).apply()
// return tag
// } else {
// timeTagMap[time] = tag
// }
// }
//
// val minTime = Collections.min(timeTagMap.keys)
// val tag = timeTagMap[minTime]
// edit.putLong(tag, System.currentTimeMillis()).apply()
// return if (TextUtils.isEmpty(tag)) notificationTags[0] else tag!!
// }
//}

View File

@ -4,16 +4,20 @@ import android.app.Dialog;
import android.os.Bundle;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.Lifecycle;
import com.gh.common.util.ClickUtils;
import com.gh.gamecenter.R;
import com.lightgame.utils.RuntimeUtils;
import com.lightgame.utils.Utils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Lifecycle;
/**
* @author CsHeng
* @Date 17/05/2017
@ -58,6 +62,18 @@ public class BaseDialogFragment extends DialogFragment {
public boolean onBack() {
return false;
}
@Override
public void show(@NonNull FragmentManager manager, @Nullable String tag) {
Fragment fragment = manager.findFragmentByTag(tag);
if (fragment != null) {
FragmentTransaction transaction = manager.beginTransaction();
transaction.show(fragment);
transaction.commit();
} else {
super.show(manager, tag);
}
}
}

View File

@ -3,15 +3,6 @@ package com.gh.base.fragment;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.tabs.TabLayout;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckedTextView;
@ -21,6 +12,7 @@ import com.gh.base.adapter.FragmentAdapter;
import com.gh.common.view.TabIndicatorView;
import com.gh.gamecenter.R;
import com.gh.gamecenter.normal.NormalFragment;
import com.google.android.material.tabs.TabLayout;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
import com.lightgame.view.NoScrollableViewPager;
@ -28,6 +20,10 @@ import com.lightgame.view.NoScrollableViewPager;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import butterknife.BindView;
/**
@ -83,10 +79,27 @@ public abstract class BaseFragment_TabLayout extends NormalFragment implements V
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) mCheckedIndex = getArguments().getInt(PAGE_INDEX, 0);
mFragmentsList = new ArrayList<>();
initFragmentList(mFragmentsList);
mTabTitleList = new ArrayList<>();
initTabTitleList(mTabTitleList);
mFragmentsList = new ArrayList<>(restoreFragments());
if (mFragmentsList.isEmpty() || mFragmentsList.size() != mTabTitleList.size()) {
mFragmentsList.clear();
initFragmentList(mFragmentsList);
}
}
private ArrayList<Fragment> restoreFragments() {
String tag = "android:switcher:" + mViewPager.getId() + ":";
ArrayList<Fragment> fragments = new ArrayList<>();
int childCount = mTabTitleList.size();
for (int index = 0; index < childCount; index++) {
Fragment fragment = getChildFragmentManager().findFragmentByTag(tag + index);
if (fragment != null) {
fragments.add(fragment);
}
}
return fragments;
}
@Override

View File

@ -1,10 +1,8 @@
package com.gh.base.fragment
import android.content.Intent
import android.graphics.Typeface
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager
@ -13,9 +11,8 @@ import com.gh.base.adapter.FragmentAdapter
import com.gh.common.view.TabIndicatorView
import com.gh.gamecenter.R
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.lightgame.utils.Utils
import com.lightgame.view.NoScrollableViewPager
import java.util.*
abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeListener {
@ -72,9 +69,15 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
mTabTitleList.clear()
mFragmentsList.clear()
initFragmentList(mFragmentsList)
initTabTitleList(mTabTitleList)
mFragmentsList.addAll(restoreFragments())
if (mFragmentsList.isEmpty() || mFragmentsList.size != mTabTitleList.size) {
mFragmentsList.clear()
initFragmentList(mFragmentsList)
}
mViewPager.offscreenPageLimit = mFragmentsList.size
mViewPager.addOnPageChangeListener(this)
@ -95,6 +98,19 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
BaseFragment_TabLayout.initTabStyle(mTabLayout, mCheckedIndex)
}
private fun restoreFragments(): ArrayList<Fragment> {
val tag = "android:switcher:${mViewPager.id}:"
val fragments = ArrayList<Fragment>()
val childCount = mTabTitleList.size
for (index in 0 until childCount) {
val fragment = childFragmentManager.findFragmentByTag("$tag$index")
if (fragment != null) {
fragments.add(fragment)
}
}
return fragments
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {}

View File

@ -13,13 +13,16 @@ import com.gh.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.LoginActivity
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.entity.Badge
import com.gh.gamecenter.entity.MtaEvent
import com.gh.gamecenter.entity.NotificationUgc
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.security.BindPhoneActivity
import com.gh.gamecenter.user.LoginTag
import com.gh.gamecenter.user.UserRepository
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
@ -215,7 +218,44 @@ class DefaultJsApi(var context: Context) {
DialogUtils.showLowVersionDialog(context)
}
@JavascriptInterface
fun shareBase64Image(event: Any) {
val imageShareEvent = event.toString().toObject() ?: ImageShareEvent()
val context = CurrentActivityHolder.getCurrentActivity()
Base64ImageHolder.image = imageShareEvent.image.run {
if (this.startsWith("data:image/png;base64")) this.split(",")[1] else this
}
MessageShareUtils.getInstance(context).shareFromWeb(context, imageShareEvent.type)
}
@JavascriptInterface
fun bindPhone(msg: Any) {
val intent = BindPhoneActivity.getNormalIntent(context, false)
context.startActivity(intent)
}
@JavascriptInterface
fun updateTitle(msg: Any) {
if (context is WebActivity) {
runOnUiThread { (context as WebActivity).setNavigationTitle(msg.toString()) }
}
}
@JavascriptInterface
fun logoutExitWebViewAndRedirectToLogin() {
UserRepository.getInstance(context).logout()
if (context is Activity) {
AppExecutor.uiExecutor.executeWithDelay(Runnable {
context.ifLogin("内部网页")
(context as Activity).finish()
}, 100)
}
}
@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 = "")
}

View File

@ -6,10 +6,12 @@ import android.net.Uri
import android.text.TextUtils
import android.util.Base64
import com.gh.common.util.*
import com.gh.common.util.DirectUtils.directToFeedback
import com.gh.common.util.DirectUtils.directToGameDetailVideoStreaming
import com.gh.common.util.DirectUtils.directToGameServerCalendar
import com.gh.common.util.DirectUtils.directToGameVideo
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.common.util.DirectUtils.directToQa
import com.gh.common.util.DirectUtils.directToVideoDetail
import com.gh.common.util.GsonUtils.gson
import com.gh.gamecenter.LibaoDetailActivity
@ -277,7 +279,33 @@ object DefaultUrlHandler {
}
EntranceUtils.HOST_FORUM -> {
DirectUtils.directToForum(context);
DirectUtils.directToForum(context)
}
EntranceUtils.HOST_SUGGESTION -> {
val platform = uri.getQueryParameter(EntranceUtils.KEY_PLATFORM)
val platformName = PlatformUtils.getInstance(context).getPlatformName(platform)
val gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID)
val packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5)
val content = if (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) String.format("%s-%s-V%s",
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
if (TextUtils.isEmpty(platformName)) platform else platformName,
uri.getQueryParameter(EntranceUtils.KEY_VERSION)) else String.format("%s-%s-V%s\n游戏ID%s\n游戏包MD5%s\n",
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
if (TextUtils.isEmpty(platformName)) platform else platformName,
uri.getQueryParameter(EntranceUtils.KEY_VERSION), gameId, packageMd5)
val qaId = uri.getQueryParameter("qa_id") ?: ""
val qaTitle = uri.getQueryParameter(EntranceUtils.KEY_QA_TITLE)
if (!TextUtils.isEmpty(qaId)) {
directToQa(context, qaTitle, qaId)
} else {
directToFeedback(context, content, EntranceUtils.ENTRANCE_BROWSER)
}
}
EntranceUtils.HOST_HELP_AND_FEEDBACK -> {
val position = uri.getQueryParameter("position") ?: ""
DirectUtils.directToHelpAndFeedback(context, position.toInt())
}
else -> DialogUtils.showLowVersionDialog(context)
}

View File

@ -64,7 +64,9 @@ object FixedRateJobHelper {
// 更新游戏屏蔽信息
if ((mExecuteCount * CHECKER_PERIOD) % REGION_SETTING_PERIOD == 0L) {
RegionSettingHelper.getRegionSetting()
if (HaloApp.getInstance().isRunningForeground) {
RegionSettingHelper.getRegionSetting()
}
}
// 提交视频浏览记录数据

View File

@ -1,39 +1,39 @@
package com.gh.common
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.gh.common.im.ImManager
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.m7.imkfsdk.chat.ChatActivity
import io.reactivex.schedulers.Schedulers
/**
* 可使用 [LocalBroadcastManager] 来进行简单的模块间消息通知
*/
class LocalBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
intent?.let {
when (intent.action) {
ChatActivity.ACTION_DISMISS_FLOATING_WINDOW -> {
ImManager.dismissFloatingWindow()
RetrofitManager.getInstance(HaloApp.getInstance().application).api.postImEnding(UserManager.getInstance().userId)
.subscribeOn(Schedulers.io())
.subscribe()
}
ChatActivity.ACTION_HIDE_UNREAD_DOT -> {
ImManager.updateShouldShowFloatingWindowDot(false)
}
else -> return
}
}
}
}
//package com.gh.common
//
//import android.content.BroadcastReceiver
//import android.content.Context
//import android.content.Intent
//import com.gh.common.im.ImManager
//import com.gh.gamecenter.manager.UserManager
//import com.gh.gamecenter.retrofit.RetrofitManager
//import com.halo.assistant.HaloApp
//import com.m7.imkfsdk.chat.ChatActivity
//import io.reactivex.schedulers.Schedulers
//
///**
// * 可使用 [LocalBroadcastManager] 来进行简单的模块间消息通知
// */
//
//class LocalBroadcastReceiver : BroadcastReceiver() {
//
// override fun onReceive(context: Context?, intent: Intent?) {
// intent?.let {
// when (intent.action) {
// ChatActivity.ACTION_DISMISS_FLOATING_WINDOW -> {
// ImManager.dismissFloatingWindow()
//
// RetrofitManager.getInstance(HaloApp.getInstance().application).api.postImEnding(UserManager.getInstance().userId)
// .subscribeOn(Schedulers.io())
// .subscribe()
// }
//
// ChatActivity.ACTION_HIDE_UNREAD_DOT -> {
// ImManager.updateShouldShowFloatingWindowDot(false)
// }
//
// else -> return
// }
// }
// }
//
//}

View File

@ -1,29 +1,8 @@
package com.gh.common
import android.annotation.SuppressLint
import android.preference.PreferenceManager
import com.gh.base.GHUmengNotificationService
import com.gh.common.constant.Config
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.util.edit
import com.gh.common.util.toJson
import com.gh.common.util.toObject
import com.gh.common.util.tryWithDefaultCatch
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.entity.AliasEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import com.umeng.commonsdk.UMConfigure
import com.umeng.message.IUmengRegisterCallback
import com.umeng.message.PushAgent
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import org.android.agoo.huawei.HuaWeiRegister
import org.android.agoo.mezu.MeizuRegister
import org.android.agoo.xiaomi.MiPushRegistar
import org.json.JSONObject
object PushManager {
@ -36,103 +15,103 @@ object PushManager {
@JvmStatic
fun init(channel: String) {
tryWithDefaultCatch {
//初始化友盟推送
UMConfigure.init(mApplication, Config.UMENG_APPKEY, channel, UMConfigure.DEVICE_TYPE_PHONE, Config.UMENG_MESSAGE_SECRET)
val pushAgent = PushAgent.getInstance(mApplication)
runOnIoThread { registerDevice() }
// 注册小米、华为和魅族通道
MiPushRegistar.register(mApplication, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY)
HuaWeiRegister.register(mApplication)
MeizuRegister.register(mApplication, BuildConfig.MEIZUPUSH_APPID, BuildConfig.MEIZUPUSH_APPKEY)
val aliasInSp = PreferenceManager.getDefaultSharedPreferences(mApplication).getString(SP_PUSH_ALIAS, "")
mPreviousAlias = aliasInSp?.toObject()
if (mPreviousAlias == null) {
getAndSetAlias()
}
// 完全自定义处理(透传)
pushAgent.setPushIntentServiceClass(GHUmengNotificationService::class.java)
}
// tryWithDefaultCatch {
// //初始化友盟推送
// UMConfigure.init(mApplication, Config.UMENG_APPKEY, channel, UMConfigure.DEVICE_TYPE_PHONE, Config.UMENG_MESSAGE_SECRET)
//
// val pushAgent = PushAgent.getInstance(mApplication)
//
// runOnIoThread { registerDevice() }
//
// // 注册小米、华为和魅族通道
// MiPushRegistar.register(mApplication, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY)
// HuaWeiRegister.register(mApplication)
// MeizuRegister.register(mApplication, BuildConfig.MEIZUPUSH_APPID, BuildConfig.MEIZUPUSH_APPKEY)
//
// val aliasInSp = PreferenceManager.getDefaultSharedPreferences(mApplication).getString(SP_PUSH_ALIAS, "")
// mPreviousAlias = aliasInSp?.toObject()
//
// if (mPreviousAlias == null) {
// getAndSetAlias()
// }
//
// // 完全自定义处理(透传)
// pushAgent.setPushIntentServiceClass(GHUmengNotificationService::class.java)
// }
}
private fun registerDevice() {
PushAgent.getInstance(mApplication).register(object : IUmengRegisterCallback {
override fun onSuccess(dToken: String) {
//注册成功会返回device token
deviceToken = dToken
getAndSetAlias()
Utils.log("deviceToken::$dToken")
}
override fun onFailure(s: String, s1: String) {
Utils.log("deviceToken::" + "注册失败")
}
})
// PushAgent.getInstance(mApplication).register(object : IUmengRegisterCallback {
// override fun onSuccess(dToken: String) {
// //注册成功会返回device token
// deviceToken = dToken
// getAndSetAlias()
// Utils.log("deviceToken::$dToken")
// }
//
// override fun onFailure(s: String, s1: String) {
// Utils.log("deviceToken::" + "注册失败")
// }
// })
}
@SuppressLint("CheckResult")
@JvmStatic
fun getAndSetAlias() {
if (deviceToken.isNullOrEmpty()) {
registerDevice()
return
}
val meta = MetaUtil.getMeta()
val jsonObject = JSONObject()
jsonObject.put("device_token", deviceToken)
jsonObject.put("imei", meta.imei)
jsonObject.put("android_id", meta.android_id)
jsonObject.put("model", meta.model)
jsonObject.put("manufacturer", meta.manufacturer)
jsonObject.put("os", meta.os)
jsonObject.put("os_version", meta.android_version)
jsonObject.put("mac", meta.mac)
jsonObject.put("gid", meta.gid)
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
RetrofitManager.getInstance(mApplication).api.getAlias(body)
.subscribeOn(Schedulers.io())
.subscribe(
{ setAlias(it) },
{ it.printStackTrace() }
)
// if (deviceToken.isNullOrEmpty()) {
// registerDevice()
// return
// }
//
// val meta = MetaUtil.getMeta()
//
// val jsonObject = JSONObject()
// jsonObject.put("device_token", deviceToken)
// jsonObject.put("imei", meta.imei)
// jsonObject.put("android_id", meta.android_id)
// jsonObject.put("model", meta.model)
// jsonObject.put("manufacturer", meta.manufacturer)
// jsonObject.put("os", meta.os)
// jsonObject.put("os_version", meta.android_version)
// jsonObject.put("mac", meta.mac)
// jsonObject.put("gid", meta.gid)
//
// val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
//
// RetrofitManager.getInstance(mApplication).api.getAlias(body)
// .subscribeOn(Schedulers.io())
// .subscribe(
// { setAlias(it) },
// { it.printStackTrace() }
// )
}
@JvmStatic
fun setAlias(alias: AliasEntity) {
val pushAgent = PushAgent.getInstance(mApplication)
mPreviousAlias = alias
PreferenceManager.getDefaultSharedPreferences(mApplication).edit {
putString(SP_PUSH_ALIAS, mPreviousAlias?.toJson())
}
pushAgent.setAlias(alias.alias, alias.aliasType) { b, s ->
Utils.log("注册别名 $b + $s")
}
// val pushAgent = PushAgent.getInstance(mApplication)
//
// mPreviousAlias = alias
// PreferenceManager.getDefaultSharedPreferences(mApplication).edit {
// putString(SP_PUSH_ALIAS, mPreviousAlias?.toJson())
// }
//
// pushAgent.setAlias(alias.alias, alias.aliasType) { b, s ->
// Utils.log("注册别名 $b + $s")
// }
}
@JvmStatic
fun deleteAlias() {
val pushAgent = PushAgent.getInstance(mApplication)
mPreviousAlias?.let {
pushAgent.deleteAlias(it.alias, it.aliasType) { b, s ->
Utils.log("删除别名 $b + $s")
}
}
PreferenceManager.getDefaultSharedPreferences(mApplication).edit {
putString(SP_PUSH_ALIAS, "")
}
mPreviousAlias = null
// val pushAgent = PushAgent.getInstance(mApplication)
//
// mPreviousAlias?.let {
// pushAgent.deleteAlias(it.alias, it.aliasType) { b, s ->
// Utils.log("删除别名 $b + $s")
// }
// }
// PreferenceManager.getDefaultSharedPreferences(mApplication).edit {
// putString(SP_PUSH_ALIAS, "")
// }
// mPreviousAlias = null
}
}

View File

@ -0,0 +1,3 @@
package com.gh.common
typealias OnFastClickListener = (isSuccess: Boolean) -> Unit

View File

@ -5,8 +5,6 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.gh.common.util.GsonUtils;
import com.gh.common.util.PackageHelper;
import com.gh.common.util.PackageUtils;
@ -25,6 +23,7 @@ import org.greenrobot.eventbus.EventBus;
import java.util.List;
import androidx.annotation.Nullable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@ -241,6 +240,9 @@ public class Config {
public static boolean isGameDomeSwitchOpen() {
return getSettings() != null && getSettings().getGameDomeSwitch().equals("on");
}
public static boolean isPermissionPopupSwitchOpen() {
return getSettings() != null && getSettings().getPermissionPopupSwitch().equals("on");
}
public static void fixHideFunction() {
SharedPreferences preferences = PreferenceManager.

View File

@ -51,11 +51,17 @@ public class Constants {
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_DOWNLOAD_START_TIME = "simulator_download_start_time";
public static final String LAST_GHZS_UPDATE_FILE_SIZE = "last_ghzs_update_file_size";
// 新用户首次启动光环的时间
public static final String SP_INITIAL_USAGE_TIME = "initial_usage_time";
public static final String SP_IMEI = "imei";
public static final String SP_ANDROID_ID = "android_id";
//引导设置 “通知管理” 引导弹窗
public static final String SP_SHOWED_NOTIFICATION_LOGIN = "show_notification_login_hint";
public static final String SP_SHOWED_NOTIFICATION_QUESTION = "show_notification_question_hint";
@ -115,6 +121,14 @@ public class Constants {
public static final String SP_WECHAT_SHOW_BIND_PHONE_TIME = "wechat_show_bind_phone_time" + HaloApp.getInstance().getGid();
public static final String SP_WEIBO_SHOW_BIND_PHONE_TIME = "weibo_show_bind_phone_time" + HaloApp.getInstance().getGid();
public static final String SP_DOUYIN_SHOW_BIND_PHONE_TIME = "douyin_show_bind_phone_time" + HaloApp.getInstance().getGid();
//隐私政策是否有更新
public static final String SP_PRIVACY_CURRENT_MD5 = "sp_privacy_current_md5";
public static final String SP_PRIVACY_MINE_MD5 = "sp_privacy_mine_md5";
public static final String SP_PRIVACY_SETTING_MD5 = "sp_privacy_setting_md5";
public static final String SP_PRIVACY_MD5 = "sp_privacy_md5";
public static final String SP_IS_USER_ACCEPTED_PRIVACY_STATEMENT = "has_user_accepted_privacy_statement";
public static final String SP_BRAND_NEW_USER = "brand_new_user";
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
@ -132,16 +146,32 @@ public class Constants {
public static final String REGULATION_TEST_ADDRESS_DEV = "https://static-web.ghzs.com/etiquette-dev/index.html#/";
public static final String REGULATION_TEST_ADDRESS = "https://static-web.ghzs.com/etiquette/index.html#/";
// 徽章
public static final String BADGE_ADDRESS_DEV = "http://resource.ghzs.com/page/badge_dev/index.html#/";
public static final String BADGE_ADDRESS = "http://resource.ghzs.com/page/badge_pro/index.html#/";
// 徽章中心
public static final String BADGE_ADDRESS_DEV = "https://static-web.ghzs.com/badge-dev/index.html#/";
public static final String BADGE_ADDRESS = "https://static-web.ghzs.com/badge/index.html#/";
// 徽章详情
public static final String BADGE_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/badge-dev/index.html#/badgedetail";
public static final String BADGE_DETAIL_ADDRESS = "https://static-web.ghzs.com/badge/index.html#/badgedetail";
// 分享个人主页地址
public static final String SHARE_USER_HOME_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs-userhome-dev/index.html#/";
public static final String SHARE_USER_HOME_ADDRESS = "https://static-web.ghzs.com/ghzs-userhome/index.html#/";
// 腾讯企点地址
public static final String TENCENT_QIDIAN_ADDRESS = "https://url.cn/D80iyMVV?_type=wpa&qidian=true";
public static final String TENCENT_QIDIAN_ADDRESS = "https://admin.qidian.qq.com/template/blue/mp/menu/qr-code-jump.html?linkType=0&env=ol&kfuin=2355094296&fid=457&key=c76dcb2e3d582b6ffbfb5bb22cde85ff&cate=1&source=&isLBS=&isCustomEntry=&type=16&ftype=1&_type=wpa&qidian=true";
//版规声明
public static final String FORUM_REGULATIONS_NEWS_ID = "5f4db9cc34d44d01b92fd670";
//帮助内容详情
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=";
// 注销页面
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 int DATA_AMOUNT = 20;

View File

@ -32,6 +32,9 @@ public class ItemViewType {
public static final int IMAGE_SLIDE_ITEM = 23;
public static final int VERTICAL_SLIDE_ITEM = 24;
public static final int COLUMN_COLLECTION = 25;
public static final int GALLERY_SLIDE = 27; // 首页自动滚动画廊专题
public static final int GALLERY = 28; // 首页倾斜画廊专题
public static final int BLANK_DIVIDER = 29; // 空白补充区域
/**
* 普通列表

View File

@ -14,12 +14,6 @@ import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.base.OnViewClickListener;
import com.gh.common.constant.Config;
@ -28,6 +22,8 @@ import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.history.HistoryHelper;
import com.gh.common.repository.ReservationRepository;
import com.gh.common.simulator.SimulatorDownloadManager;
import com.gh.common.simulator.SimulatorGameManager;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DialogUtils;
@ -72,11 +68,18 @@ import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
/**
* Created by khy on 12/02/18.
*/
@ -436,6 +439,15 @@ public class BindingAdapters {
case PLUGIN:
if (gameEntity.getApk().size() == 1) {
ApkEntity apk = gameEntity.getApk().get(0);
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(apk.getUrl());
if (gameEntity.getSimulator() != null) {
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(v.getContext(), gameEntity.getSimulator().getApk().getPackageName());
if (downloadEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity) && !isInstalled) {
SimulatorDownloadManager.getInstance().showDownloadDialog(v.getContext(), gameEntity.getSimulator(),
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(), null);
return;
}
}
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
@ -461,6 +473,20 @@ public class BindingAdapters {
break;
case LAUNCH_OR_OPEN:
if (gameEntity.getApk().size() == 1) {
//启动模拟器游戏
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
if (downloadEntity != null) {
File file = new File(downloadEntity.getPath());
if (!file.exists()) {
download(progressBar, gameEntity, traceEvent, false, entrance, location);
return;
}
SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity);
}
return;
}
DataUtils.onGameLaunchEvent(v.getContext(), gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
PackageUtils.launchApplicationByPackageName(v.getContext(), gameEntity.getApk().get(0).getPackageName());
} else {
@ -516,9 +542,12 @@ public class BindingAdapters {
HistoryHelper.insertGameEntity(gameEntity);
}
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), isPlay,linkEntity.getCloseButton()));
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton()));
progressBar.getContext().startActivity(i);
break;
case UPDATING:
Utils.toast(progressBar.getContext(), "正在加急更新版本,敬请后续留意");
break;
}
});
@ -548,10 +577,14 @@ public class BindingAdapters {
} else {
if (offStatus != null && "dialog".equals(offStatus)) {
progressBar.setText("查看");
progressBar.setDownloadType(DownloadProgressBar.DownloadType.NONE);
} else if ("updating".equals(offStatus)) {
progressBar.setText("更新中");
progressBar.setDownloadType(DownloadProgressBar.DownloadType.UPDATING);
} else {
progressBar.setText("暂无");
progressBar.setDownloadType(DownloadProgressBar.DownloadType.NONE);
}
progressBar.setDownloadType(DownloadProgressBar.DownloadType.NONE);
}
} else {

View File

@ -26,21 +26,12 @@ import com.gh.gamecenter.UserInfoEditActivity
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.entity.AuthDialogEntity
import com.gh.gamecenter.entity.AuthDialogLevel
import com.gh.gamecenter.entity.DeviceDialogEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.user.UserViewModel
import com.google.gson.reflect.TypeToken
import com.halo.assistant.fragment.user.UserInfoEditFragment
import com.lightgame.utils.AppManager
import com.tencent.bugly.beta.tinker.TinkerManager.getApplication
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import retrofit2.HttpException
class CertificationDialog(context: Context, private val authDialogEntity: AuthDialogEntity, val gameId: String, val listener: DialogUtils.ConfirmListener) :
Dialog(context, R.style.GhAlertDialog) {

View File

@ -0,0 +1,103 @@
package com.gh.common.dialog
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentTransaction
import com.airbnb.lottie.LottieAnimationView
import com.gh.common.constant.Config
import com.gh.common.util.MtaHelper
import com.gh.common.util.PermissionHelper
import com.gh.common.util.PermissionHelper.INSTALL_PERMISS_CODE
import com.gh.common.util.goneIf
import com.gh.gamecenter.R
import kotlin.random.Random
class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
lateinit var mView: View
var mCallBack: (() -> Unit)? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mView = inflater.inflate(R.layout.dialog_install_permission, null, false)
return mView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val closeTv = mView.findViewById<TextView>(R.id.closeTv)
val closeIv = mView.findViewById<ImageView>(R.id.closeIv)
val activateTv = mView.findViewById<TextView>(R.id.activateTv)
val switchLottie = mView.findViewById<LottieAnimationView>(R.id.switchLottie)
switchLottie.setAnimation("lottie/install_permission_switch.json")
switchLottie.playAnimation()
val randomNumber = Random.nextInt(2)
closeTv.goneIf(randomNumber == 0)
closeIv.goneIf(randomNumber != 0)
closeTv.setOnClickListener {
MtaHelper.onEvent(getEvent(), getKey(), "文案样式_点击以后再说")
dismiss()
}
closeIv.setOnClickListener {
MtaHelper.onEvent(getEvent(), getKey(), "图标样式_点击关闭")
dismiss()
}
activateTv.setOnClickListener {
MtaHelper.onEvent(getEvent(), getKey(), if (randomNumber == 0) "文案样式_点击立即开启" else "图标样式_点击立即开启")
PermissionHelper.toInstallPermissionSetting(requireActivity())
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISS_CODE) {
mCallBack?.invoke()
dismiss()
}
}
override fun getEvent(): String = "安装引导弹窗"
override fun getKey(): String = "引导弹窗"
companion object {
@JvmStatic
fun show(activity: AppCompatActivity, callBack: (() -> Unit)?) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
callBack?.invoke()
return
}
if (!Config.isPermissionPopupSwitchOpen()) {
callBack?.invoke()
return
}
val haveInstallPermission = activity.packageManager.canRequestPackageInstalls();
if (haveInstallPermission) {
callBack?.invoke()
return
}
var installPermissionDialogFragment = activity.supportFragmentManager.findFragmentByTag(InstallPermissionDialogFragment::class.java.simpleName) as? InstallPermissionDialogFragment
if (installPermissionDialogFragment != null) {
installPermissionDialogFragment.mCallBack = callBack
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
transaction.show(installPermissionDialogFragment)
transaction.commit()
} else {
installPermissionDialogFragment = InstallPermissionDialogFragment().apply {
mCallBack = callBack
}
installPermissionDialogFragment.show(activity.supportFragmentManager, InstallPermissionDialogFragment::class.java.simpleName)
}
}
}
}

View File

@ -2,7 +2,6 @@ package com.gh.common.dialog
import android.annotation.SuppressLint
import android.content.Intent
import android.content.res.AssetManager
import android.os.Build
import android.os.Bundle
import android.provider.Settings

View File

@ -0,0 +1,154 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.DialogInterface
import android.os.Build
import android.os.Bundle
import android.view.*
import android.webkit.WebSettings
import android.webkit.WebView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentTransaction
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.util.dip2px
import com.gh.gamecenter.R
class PrivacyDialogFragment : BaseDialogFragment() {
private val mLocalPrivacyHtml = "file:///android_asset/privacy_policies.html"
private val mLocalRegulationHtml = "file:///android_asset/user_regulation.html"
var containerView: View? = null
var mCallBack: ((isSuccess: Boolean) -> Unit)? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
containerView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_privacy_protocol, null, false)
return containerView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
val mWebViewRegulation = containerView?.findViewById<WebView>(R.id.webView2)
mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
mWebViewRegulation?.isHorizontalScrollBarEnabled = false
val mTitlePrivacyTv = containerView?.findViewById<TextView>(R.id.privacyTitleTv)
val mTitleRegulationTv = containerView?.findViewById<TextView>(R.id.userRegulationTitleTv)
val settingsArrayList = arrayListOf(mWebViewPrivacy?.settings, mWebViewRegulation?.settings)
for (settings in settingsArrayList) {
settings?.javaScriptEnabled = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
}
// 避免提示网页有害信息不能访问
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
settings?.safeBrowsingEnabled = false
}
// 适配大于屏幕宽度的页面
settings?.useWideViewPort = true
settings?.loadWithOverviewMode = true
settings?.domStorageEnabled = true
// 自适应屏幕
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
settings?.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING
}
}
// if (NetworkUtils.isNetworkConnected(requireContext())) {
// mWebViewPrivacy?.loadUrl(requireContext().getString(R.string.privacy_policy_url))
// mWebViewRegulation?.loadUrl(requireContext().getString(R.string.user_regulation_url))
// } else {
mWebViewPrivacy?.loadUrl(mLocalPrivacyHtml)
mWebViewRegulation?.loadUrl(mLocalRegulationHtml)
// }
// val client = object : WebViewClient() {
// override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
// super.onReceivedError(view, request, error)
// if (view == mWebViewPrivacy) {
// view?.loadUrl(mLocalPrivacyHtml)
// } else {
// view?.loadUrl(mLocalRegulationHtml)
// }
// }
// }
// mWebViewPrivacy?.webViewClient = client
// mWebViewRegulation?.webViewClient = client
mTitlePrivacyTv?.setOnClickListener {
mTitlePrivacyTv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
mTitleRegulationTv?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_F5F5F5))
mWebViewPrivacy?.visibility = View.VISIBLE
mWebViewRegulation?.visibility = View.GONE
}
mTitleRegulationTv?.setOnClickListener {
mTitlePrivacyTv?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_F5F5F5))
mTitleRegulationTv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
mWebViewPrivacy?.visibility = View.GONE
mWebViewRegulation?.visibility = View.VISIBLE
}
containerView?.findViewById<View>(R.id.refuseTv)?.setOnClickListener {
mCallBack?.invoke(false)
dismiss()
}
containerView?.findViewById<View>(R.id.agreeTv)?.setOnClickListener {
mCallBack?.invoke(true)
dismiss()
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val createDialog = super.onCreateDialog(savedInstanceState)
createDialog.setCanceledOnTouchOutside(false)
createDialog.setOnKeyListener(object : DialogInterface.OnKeyListener {
override fun onKey(dialog: DialogInterface?, keyCode: Int, event: KeyEvent?): Boolean {
if (keyCode == KeyEvent.KEYCODE_BACK) {
return true
}
return false
}
})
val window = createDialog.window
window?.setGravity(Gravity.CENTER)
return createDialog
}
override fun onStart() {
super.onStart()
val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
val height = ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
}
companion object {
@JvmStatic
fun show(activity: AppCompatActivity, callBack: ((isSuccess: Boolean) -> Unit)?) {
var privacyDialogFragment = activity.supportFragmentManager.findFragmentByTag(PrivacyDialogFragment::class.java.simpleName) as? PrivacyDialogFragment
if (privacyDialogFragment != null) {
privacyDialogFragment.mCallBack = callBack
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
transaction.show(privacyDialogFragment)
transaction.commit()
} else {
privacyDialogFragment = PrivacyDialogFragment().apply {
mCallBack = callBack
}
privacyDialogFragment.show(activity.supportFragmentManager, PrivacyDialogFragment::class.java.simpleName)
}
}
}
}

View File

@ -17,6 +17,10 @@ data class ExposureEntity(
val downloadType: String? = "",
val downloadCompleteType: String? = "",
// 下载地址的 host 和 path
var host: String? = "",
var path: String? = "",
// 统计启动弹窗相关数据用的 (ugly)
@SerializedName("dialog_id")
var welcomeDialogId: String? = "",

View File

@ -26,6 +26,8 @@ data class ExposureEvent(
@PrimaryKey
val id: String = UUID.randomUUID().toString()) : Parcelable {
companion object {
// TODO 建一个 exposureEvent 池规避反复生成对象
@JvmStatic
fun createEvent(gameEntity: GameEntity?, source: List<ExposureSource>, eTrace: List<ExposureEvent>? = null, event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
if (gameEntity?.getApk()?.size == 1) {

View File

@ -43,7 +43,7 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
if (layoutManager == null) layoutManager = recyclerView.layoutManager as LinearLayoutManager
layoutManager?.run {
visibleState = ExposureThrottleBus.VisibleState(findFirstCompletelyVisibleItemPosition(), findLastCompletelyVisibleItemPosition())
visibleState = ExposureThrottleBus.VisibleState(findFirstVisibleItemPosition(), findLastVisibleItemPosition())
throttleBus?.postVisibleState(visibleState!!)
}
}
@ -55,7 +55,7 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
val eventList = arrayListOf<ExposureEvent>()
for (pos in visibleState.firstCompletelyVisible..visibleState.lastCompletelyVisible) {
for (pos in visibleState.firstVisiblePosition..visibleState.lastVisiblePosition) {
try {
exposable.getEventByPosition(pos)?.let { eventList.add(it) }
exposable.getEventListByPosition(pos)?.let { eventList.addAll(it) }

View File

@ -3,6 +3,7 @@ package com.gh.common.exposure
import com.aliyun.sls.android.sdk.model.LogGroup
import com.gh.common.exposure.time.TimeUtil
import com.gh.common.util.toJson
import com.gh.common.util.tryWithDefaultCatch
import com.gh.gamecenter.BuildConfig
import com.gh.loghub.LgLOG
import com.gh.loghub.LoghubHelper
@ -94,15 +95,18 @@ object ExposureManager {
*/
fun commitSavedExposureEvents(forced: Boolean = false) {
exposureExecutor.execute {
if (exposureSet.size < STORE_SIZE && !forced || exposureSet.size == 0) return@execute
tryWithDefaultCatch {
// TODO 初始化 loghubHelper 去掉这个 tryCatch 块
if (exposureSet.size < STORE_SIZE && !forced || exposureSet.size == 0) return@execute
val exposureList = exposureSet.toList()
// uploadLogGroup 是一个异步方法LoghubHelper 里面实现了重传功能,所以这里交给它就好了
loghubHelper.uploadLogGroup(buildLogGroup(exposureList))
val exposureList = exposureSet.toList()
// uploadLogGroup 是一个异步方法LoghubHelper 里面实现了重传功能,所以这里交给它就好了
loghubHelper.uploadLogGroup(buildLogGroup(exposureList))
Utils.log("Exposure", "提交了${exposureList.size}条曝光记录")
exposureSet.removeAll(exposureList)
exposureDao.deleteMany(exposureList)
Utils.log("Exposure", "提交了${exposureList.size}条曝光记录")
exposureSet.removeAll(exposureList)
exposureDao.deleteMany(exposureList)
}
}
}

View File

@ -38,21 +38,21 @@ class ExposureThrottleBus(var onSuccess: Consumer<VisibleState>, var onError: Co
mPublishSubject.onNext(visibleState)
}
class VisibleState(val firstCompletelyVisible: Int, val lastCompletelyVisible: Int) {
class VisibleState(val firstVisiblePosition: Int, val lastVisiblePosition: Int) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
val that = other as VisibleState
if (firstCompletelyVisible != that.firstCompletelyVisible) return false
if (firstVisiblePosition != that.firstVisiblePosition) return false
return lastCompletelyVisible == that.lastCompletelyVisible
return lastVisiblePosition == that.lastVisiblePosition
}
override fun hashCode(): Int {
var result = firstCompletelyVisible
result = 31 * result + lastCompletelyVisible
var result = firstVisiblePosition
result = 31 * result + lastVisiblePosition
return result
}
}

View File

@ -38,6 +38,8 @@ object ExposureUtils {
fun logADownloadCompleteExposureEvent(entity: GameEntity,
platform: String?,
trace: String?,
host: String? = "unknown",
path: String? = "unknown",
downloadType: DownloadType) {
val gameEntity = entity.clone()
gameEntity.platform = platform
@ -47,6 +49,8 @@ object ExposureUtils {
source = traceEvent?.source ?: ArrayList(),
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
event = ExposureType.DOWNLOAD_COMPLETE)
exposureEvent.payload.host = host
exposureEvent.payload.path = path
ExposureManager.log(exposureEvent)
ExposureManager.commitSavedExposureEvents(forced = true)
}

View File

@ -5,17 +5,17 @@ import android.app.Application
import android.content.Context
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.wifi.WifiManager
import android.os.Build
import android.provider.Settings
import android.telephony.TelephonyManager
import android.text.TextUtils
import com.gh.common.constant.Constants
import com.gh.common.util.SPUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.manager.UserManager
import com.halo.assistant.HaloApp
import com.leon.channel.helper.ChannelReaderUtil
import com.walkud.rom.checker.RomIdentifier
import java.io.File
object MetaUtil {
@ -23,9 +23,11 @@ object MetaUtil {
private var channel = ""
private var m: Meta? = null
private var imei: String? = null
private var androidId: String? = null
fun refreshMeta() {
m = Meta(mac = getMac(),
m = Meta(mac = "",
imei = getIMEI(),
model = getModel(),
manufacturer = getManufacturer(),
@ -57,57 +59,48 @@ object MetaUtil {
return channel
}
/**
* Get MAC address
* TODO check > 6.0 results
*/
fun getMac(): String? {
var mac: String = ""
//Plan A
try {
mac = File("/sys/class/net/wlan0/address").inputStream().bufferedReader().use { it.readText() }
if (!TextUtils.isEmpty(mac)) return mac.trim()
} catch (e: Exception) {
// e.printStackTrace()
}
// Plan B
try {
mac = File("/sys/class/net/eth0/address").inputStream().bufferedReader().use { it.readText() }
if (!TextUtils.isEmpty(mac)) return mac.trim()
} catch (e: Exception) {
// e.printStackTrace()
}
// Plan C
val wifiManager = application.getSystemService(Context.WIFI_SERVICE) as WifiManager
try {
mac = wifiManager.connectionInfo.macAddress
} catch (e: Exception) {
// e.printStackTrace()
}
return mac.trim()
}
/**
* Get IMEI
*/
fun getIMEI(): String? {
@JvmStatic
fun getIMEI(): String {
if (application.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED)
if (!HaloApp.isUserAcceptPrivacyPolicy(HaloApp.getInstance().application)) {
return ""
}
if (imei != null) {
return imei ?: ""
}
imei = SPUtils.getString(Constants.SP_IMEI)
if (!TextUtils.isEmpty(imei)) {
return imei ?: ""
}
if (application.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
return ""
}
val telephonyManager = application.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
if (Build.VERSION.SDK_INT >= 26) {
return telephonyManager.imei
if (Build.VERSION.SDK_INT >= 29) {
return "".apply {
imei = this
SPUtils.setString(Constants.SP_IMEI, this)
}
} else if (Build.VERSION.SDK_INT >= 26) {
return (telephonyManager.imei ?: "").apply {
imei = this
SPUtils.setString(Constants.SP_IMEI, this)
}
}
return telephonyManager.getDeviceId()
return (telephonyManager.getDeviceId() ?: "").apply {
imei = this
SPUtils.setString(Constants.SP_IMEI, this)
}
}
@ -119,14 +112,35 @@ object MetaUtil {
return Build.MANUFACTURER
}
fun getAndroidId(): String? {
var android_id: String = ""
try {
android_id = Settings.Secure.getString(application.contentResolver, Settings.Secure.ANDROID_ID)
@JvmStatic
fun getAndroidId(): String {
if (!HaloApp.isUserAcceptPrivacyPolicy(HaloApp.getInstance().application)) {
return ""
}
if (androidId != null) {
return androidId ?: ""
}
androidId = SPUtils.getString(Constants.SP_ANDROID_ID)
if (!TextUtils.isEmpty(androidId)) {
return androidId ?: ""
}
return try {
Settings.Secure.getString(application.contentResolver, Settings.Secure.ANDROID_ID).apply {
androidId = this
SPUtils.setString(Constants.SP_ANDROID_ID, this)
}
} catch (e: Exception) {
e.printStackTrace()
androidId = ""
SPUtils.setString(Constants.SP_ANDROID_ID, "")
""
}
return android_id
}
fun getAndroidSDK(): Int? {

View File

@ -62,7 +62,7 @@ object RegionSettingHelper {
@SuppressLint("CheckResult")
@JvmStatic
fun getRegionSetting() {
debounceActionWithInterval(R.string.name, 3000) {
debounceActionWithInterval(R.string.app_name, 3000) {
// 使用默认的 Schdulers.io() 可能会触发 OOM
RetrofitManager.getInstance(HaloApp.getInstance().application)
.sensitiveApi

View File

@ -0,0 +1,10 @@
package com.gh.common.iinterface
@Suppress("SpellCheckingInspection")
interface IOffsetable {
fun getOffset(position: Int): Int
fun updateOffset(position: Int, offset: Int)
fun resetOffset()
}

View File

@ -1,67 +1,67 @@
package com.gh.common.im
import android.app.Activity
import androidx.core.view.ViewCompat
import android.view.View
import android.view.ViewGroup
object ImHintHelper {
@JvmStatic
fun show(activity: Activity?) {
activity?.let {
var hintView = retrieveHintViewFromActivity(it)
if (hintView == null) {
hintView = ImHintView(it)
hintView.showDot(ImManager.shouldShowFloatingWindowDot)
val decorView = it.window.decorView as ViewGroup
it.runOnUiThread {
decorView.addView(hintView)
}
} else {
hintView.showDot(ImManager.shouldShowFloatingWindowDot)
}
}
}
@JvmStatic
fun dismiss(activity: Activity?) {
activity?.let {
clearCurrent(it)
}
}
private fun retrieveHintViewFromActivity(activity: Activity?) : ImHintView? {
(activity?.window?.decorView as? ViewGroup)?.let {
for (i in 0..it.childCount) {
val childView = if (it.getChildAt(i) is ImHintView) it.getChildAt(i) as ImHintView else null
if (childView != null && childView.windowToken != null) {
return childView
}
}
return null
}
return null
}
private fun clearCurrent(activity: Activity?) {
(activity?.window?.decorView as? ViewGroup)?.let {
for (i in 0..it.childCount) {
val childView = if (it.getChildAt(i) is ImHintView) it.getChildAt(i) as ImHintView else null
if (childView != null && childView.windowToken != null) {
ViewCompat.animate(childView).alpha(0f).withEndAction(getRemoveViewRunnable(childView))
}
}
}
}
private fun getRemoveViewRunnable(childView: View?): Runnable {
return Runnable {
childView?.let {
(childView.parent as? ViewGroup)?.removeView(childView)
}
}
}
}
//package com.gh.common.im
//
//import android.app.Activity
//import androidx.core.view.ViewCompat
//import android.view.View
//import android.view.ViewGroup
//
//object ImHintHelper {
//
// @JvmStatic
// fun show(activity: Activity?) {
// activity?.let {
// var hintView = retrieveHintViewFromActivity(it)
// if (hintView == null) {
// hintView = ImHintView(it)
// hintView.showDot(ImManager.shouldShowFloatingWindowDot)
//
// val decorView = it.window.decorView as ViewGroup
// it.runOnUiThread {
// decorView.addView(hintView)
// }
// } else {
// hintView.showDot(ImManager.shouldShowFloatingWindowDot)
// }
// }
// }
//
// @JvmStatic
// fun dismiss(activity: Activity?) {
// activity?.let {
// clearCurrent(it)
// }
// }
//
// private fun retrieveHintViewFromActivity(activity: Activity?) : ImHintView? {
// (activity?.window?.decorView as? ViewGroup)?.let {
// for (i in 0..it.childCount) {
// val childView = if (it.getChildAt(i) is ImHintView) it.getChildAt(i) as ImHintView else null
// if (childView != null && childView.windowToken != null) {
// return childView
// }
// }
// return null
// }
// return null
// }
//
// private fun clearCurrent(activity: Activity?) {
// (activity?.window?.decorView as? ViewGroup)?.let {
// for (i in 0..it.childCount) {
// val childView = if (it.getChildAt(i) is ImHintView) it.getChildAt(i) as ImHintView else null
// if (childView != null && childView.windowToken != null) {
// ViewCompat.animate(childView).alpha(0f).withEndAction(getRemoveViewRunnable(childView))
// }
// }
// }
// }
//
// private fun getRemoveViewRunnable(childView: View?): Runnable {
// return Runnable {
// childView?.let {
// (childView.parent as? ViewGroup)?.removeView(childView)
// }
// }
// }
//
//}

View File

@ -1,45 +1,45 @@
package com.gh.common.im
import android.app.Activity
import android.content.Context
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import android.widget.RelativeLayout
import androidx.core.view.ViewCompat
import com.gh.common.util.DisplayUtils
import com.gh.gamecenter.R
import kotlinx.android.synthetic.main.view_im_hint.view.*
class ImHintView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
: RelativeLayout(context, attrs, defStyle) {
init {
inflate(context, R.layout.view_im_hint, this)
ViewCompat.setTranslationZ(this, Integer.MAX_VALUE.toFloat() - 1)
ivContainer.setOnClickListener {
if (context is Activity) {
ImManager.startChatActivity(context)
ImManager.removeNotification()
}
}
val lp = ivContainer.layoutParams as RelativeLayout.LayoutParams
lp.setMargins(0, 0, dp2px(30f), dp2px(106f) + DisplayUtils.retrieveNavigationHeight(context))
}
fun showDot(show: Boolean) {
if (show) {
unreadDot.visibility = View.VISIBLE
} else {
unreadDot.visibility = View.GONE
}
}
private fun dp2px(dp: Float): Int {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.applicationContext.resources.displayMetrics).toInt()
}
}
//package com.gh.common.im
//
//import android.app.Activity
//import android.content.Context
//import android.util.AttributeSet
//import android.util.TypedValue
//import android.view.View
//import android.widget.RelativeLayout
//import androidx.core.view.ViewCompat
//import com.gh.common.util.DisplayUtils
//import com.gh.gamecenter.R
//import kotlinx.android.synthetic.main.view_im_hint.view.*
//
//class ImHintView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
// : RelativeLayout(context, attrs, defStyle) {
//
// init {
// inflate(context, R.layout.view_im_hint, this)
//
// ViewCompat.setTranslationZ(this, Integer.MAX_VALUE.toFloat() - 1)
//
// ivContainer.setOnClickListener {
// if (context is Activity) {
// ImManager.startChatActivity(context)
// ImManager.removeNotification()
// }
// }
//
// val lp = ivContainer.layoutParams as RelativeLayout.LayoutParams
//
// lp.setMargins(0, 0, dp2px(30f), dp2px(106f) + DisplayUtils.retrieveNavigationHeight(context))
// }
//
// fun showDot(show: Boolean) {
// if (show) {
// unreadDot.visibility = View.VISIBLE
// } else {
// unreadDot.visibility = View.GONE
// }
// }
//
// private fun dp2px(dp: Float): Int {
// return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.applicationContext.resources.displayMetrics).toInt()
// }
//}

View File

@ -1,25 +1,9 @@
package com.gh.common.im
import android.app.Activity
import android.app.NotificationManager
import android.content.Context
import com.gh.base.CurrentActivityHolder
import com.gh.common.runOnIoThread
import com.gh.common.util.SPUtils
import com.gh.common.util.tryWithDefaultCatch
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.HelpAndFeedbackActivity
import com.gh.gamecenter.MainActivity
import com.gh.gamecenter.MessageActivity
import com.gh.gamecenter.manager.UserManager
import com.halo.assistant.HaloApp
import com.m7.imkfsdk.KfStartHelper
import com.m7.imkfsdk.utils.Utils
import com.moor.imkf.ChatListener
import com.moor.imkf.IMChat
import com.moor.imkf.IMChatManager
import com.moor.imkf.IMMessage
import com.moor.imkf.utils.MoorUtils
object ImManager {
@ -35,57 +19,57 @@ object ImManager {
@JvmStatic
fun attachIm() {
try {
if (UserManager.getInstance().userInfoEntity != null &&
currentUserId != UserManager.getInstance().userId) {
currentUserId = UserManager.getInstance().userId
MoorUtils.init(HaloApp.getInstance().application)
Utils.init(HaloApp.getInstance().application)
IMChatManager.getInstance().init(
HaloApp.getInstance().application,
ImReceiver.UNIQUE_BROADCAST_ACTION,
IM_KEY,
UserManager.getInstance().userInfoEntity?.name + "(" + UserManager.getInstance().userId + ")",
UserManager.getInstance().userId)
shouldShowFloatingWindow = SPUtils.getBoolean(SP_FLOATING_WINDOW_KEY + UserManager.getInstance().userId)
shouldShowFloatingWindowDot = SPUtils.getBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId)
updateFloatingWindow()
}
} catch (e: Exception) {
e.printStackTrace()
}
// try {
// if (UserManager.getInstance().userInfoEntity != null &&
// currentUserId != UserManager.getInstance().userId) {
// currentUserId = UserManager.getInstance().userId
// MoorUtils.init(HaloApp.getInstance().application)
// Utils.init(HaloApp.getInstance().application)
// IMChatManager.getInstance().init(
// HaloApp.getInstance().application,
// ImReceiver.UNIQUE_BROADCAST_ACTION,
// IM_KEY,
// UserManager.getInstance().userInfoEntity?.name + "(" + UserManager.getInstance().userId + ")",
// UserManager.getInstance().userId)
//
// shouldShowFloatingWindow = SPUtils.getBoolean(SP_FLOATING_WINDOW_KEY + UserManager.getInstance().userId)
// shouldShowFloatingWindowDot = SPUtils.getBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId)
// updateFloatingWindow()
// }
// } catch (e: Exception) {
// e.printStackTrace()
// }
}
@JvmStatic
fun detachIm() {
try {
IMChatManager.getInstance().quitSDk()
shouldShowFloatingWindow = false
updateFloatingWindow()
removeNotification()
} catch (e: Exception) {
e.printStackTrace()
}
// try {
// IMChatManager.getInstance().quitSDk()
// shouldShowFloatingWindow = false
// updateFloatingWindow()
// removeNotification()
// } catch (e: Exception) {
// e.printStackTrace()
// }
}
@JvmStatic
fun startChatActivity(activity: Activity, inputContent: String? = "", requestCode: Int? = null) {
if (!UserManager.getInstance().userId.isNullOrEmpty()) {
try {
SPUtils.setBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId, false)
shouldShowFloatingWindowDot = false
val chatHelper = KfStartHelper(activity, UserManager.getInstance().userInfoEntity?.icon, inputContent, requestCode)
chatHelper.initSdkChat(
ImReceiver.UNIQUE_BROADCAST_ACTION,
IM_KEY,
UserManager.getInstance().userInfoEntity?.name + "(" + UserManager.getInstance().userId + ")"
+ "[" + BuildConfig.VERSION_NAME + "]",
UserManager.getInstance().userId)
} catch (e: Exception) {
e.printStackTrace()
}
}
// if (!UserManager.getInstance().userId.isNullOrEmpty()) {
// try {
// SPUtils.setBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId, false)
// shouldShowFloatingWindowDot = false
// val chatHelper = KfStartHelper(activity, UserManager.getInstance().userInfoEntity?.icon, inputContent, requestCode)
// chatHelper.initSdkChat(
// ImReceiver.UNIQUE_BROADCAST_ACTION,
// IM_KEY,
// UserManager.getInstance().userInfoEntity?.name + "(" + UserManager.getInstance().userId + ")"
// + "[" + BuildConfig.VERSION_NAME + "]",
// UserManager.getInstance().userId)
// } catch (e: Exception) {
// e.printStackTrace()
// }
// }
}
@JvmStatic
@ -104,50 +88,50 @@ object ImManager {
@JvmStatic
fun removeNotification() {
val notificationManager = HaloApp.getInstance().application?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(ImReceiver.NOTIFICATION_ID)
// val notificationManager = HaloApp.getInstance().application?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// notificationManager.cancel(ImReceiver.NOTIFICATION_ID)
}
@JvmStatic
fun updateFloatingWindow() {
try {
CurrentActivityHolder.getCurrentActivity()?.let {
if (isActivityValid(it)) {
if (shouldShowFloatingWindow) {
ImHintHelper.show(it)
} else {
ImHintHelper.dismiss(it)
removeNotification()
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
// try {
// CurrentActivityHolder.getCurrentActivity()?.let {
// if (isActivityValid(it)) {
// if (shouldShowFloatingWindow) {
// ImHintHelper.show(it)
// } else {
// ImHintHelper.dismiss(it)
// removeNotification()
// }
// }
// }
// } catch (e: Exception) {
// e.printStackTrace()
// }
}
@JvmStatic
fun sendFeedbackMessage(message: String) {
val fromToMessage = IMMessage.createTxtMessage(message)
runOnIoThread {
tryWithDefaultCatch {
IMChat.getInstance().sendMessage(fromToMessage, object : ChatListener {
override fun onProgress(p0: Int) {}
override fun onSuccess() {}
override fun onFailed() {}
})
}
}
// val fromToMessage = IMMessage.createTxtMessage(message)
// runOnIoThread {
// tryWithDefaultCatch {
// IMChat.getInstance().sendMessage(fromToMessage, object : ChatListener {
// override fun onProgress(p0: Int) {}
// override fun onSuccess() {}
// override fun onFailed() {}
// })
// }
// }
}
fun updateShouldShowFloatingWindow(show: Boolean) {
SPUtils.setBoolean(SP_FLOATING_WINDOW_KEY + UserManager.getInstance().userId, show)
shouldShowFloatingWindow = show
// SPUtils.setBoolean(SP_FLOATING_WINDOW_KEY + UserManager.getInstance().userId, show)
// shouldShowFloatingWindow = show
}
fun updateShouldShowFloatingWindowDot(show: Boolean) {
SPUtils.setBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId, show)
shouldShowFloatingWindowDot = show
// SPUtils.setBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId, show)
// shouldShowFloatingWindowDot = show
}
private fun isActivityValid(activity: Activity): Boolean {

View File

@ -1,20 +1,9 @@
package com.gh.common.im
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import com.gh.base.CurrentActivityHolder
import com.gh.common.util.doOnMainProcessOnly
import com.gh.gamecenter.R
import com.m7.imkfsdk.chat.ChatActivity
import com.m7.imkfsdk.utils.Utils
import com.moor.imkf.IMChatManager
class ImReceiver : BroadcastReceiver() {
@ -26,54 +15,54 @@ class ImReceiver : BroadcastReceiver() {
var notificationManager: NotificationManager? = null
override fun onReceive(context: Context?, intent: Intent?) {
context?.doOnMainProcessOnly {
intent?.let {
if (intent.action == IMChatManager.NEW_MSG_ACTION) {
notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// 判断 ImActivity 是否在最顶端
if (CurrentActivityHolder.getCurrentActivity() is ChatActivity) {
ImManager.showFloatingWindow()
ImManager.updateShouldShowFloatingWindowDot(false)
} else {
val contentIntent = Intent(Utils.getApp(), ChatActivity::class.java)
contentIntent.putExtra("PeerId", "")
contentIntent.putExtra("type", "peedId")
contentIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
val resultPendingIntent = PendingIntent.getActivity(
Utils.getApp(),
0,
contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
// 新的通知
val builder = NotificationCompat.Builder(Utils.getApp(), "Halo_IM")
val notification = builder.setTicker("您有新的消息")
.setDefaults(Notification.DEFAULT_ALL)
.setSmallIcon(R.drawable.ic_notification)
.setWhen(System.currentTimeMillis())
.setContentIntent(resultPendingIntent)
.setContentTitle("光环助手客服回复")
.setContentText("您有新的消息")
.setAutoCancel(true)
.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("Halo_IM", "Halo_IM", NotificationManager.IMPORTANCE_DEFAULT)
notificationManager?.createNotificationChannel(channel)
}
if (notification != null) {
notificationManager?.notify(NOTIFICATION_ID, notification)
ImManager.showFloatingWindow()
}
}
} else if (intent.action == IMChatManager.FINISH_ACTION) {
ImManager.dismissFloatingWindow()
}
}
}
// context?.doOnMainProcessOnly {
// intent?.let {
// if (intent.action == IMChatManager.NEW_MSG_ACTION) {
// notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// // 判断 ImActivity 是否在最顶端
// if (CurrentActivityHolder.getCurrentActivity() is ChatActivity) {
// ImManager.showFloatingWindow()
// ImManager.updateShouldShowFloatingWindowDot(false)
// } else {
// val contentIntent = Intent(Utils.getApp(), ChatActivity::class.java)
//
// contentIntent.putExtra("PeerId", "")
// contentIntent.putExtra("type", "peedId")
//
// contentIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
// val resultPendingIntent = PendingIntent.getActivity(
// Utils.getApp(),
// 0,
// contentIntent,
// PendingIntent.FLAG_UPDATE_CURRENT
// )
//
// // 新的通知
// val builder = NotificationCompat.Builder(Utils.getApp(), "Halo_IM")
// val notification = builder.setTicker("您有新的消息")
// .setDefaults(Notification.DEFAULT_ALL)
// .setSmallIcon(R.drawable.ic_notification)
// .setWhen(System.currentTimeMillis())
// .setContentIntent(resultPendingIntent)
// .setContentTitle("光环助手客服回复")
// .setContentText("您有新的消息")
// .setAutoCancel(true)
// .build()
//
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// val channel = NotificationChannel("Halo_IM", "Halo_IM", NotificationManager.IMPORTANCE_DEFAULT)
// notificationManager?.createNotificationChannel(channel)
// }
//
// if (notification != null) {
// notificationManager?.notify(NOTIFICATION_ID, notification)
// ImManager.showFloatingWindow()
// }
// }
// } else if (intent.action == IMChatManager.FINISH_ACTION) {
// ImManager.dismissFloatingWindow()
// }
// }
// }
}
}

View File

@ -6,6 +6,7 @@ import com.aliyun.sls.android.sdk.model.Log
import com.aliyun.sls.android.sdk.model.LogGroup
import com.gh.common.exposure.ExposureEntity
import com.gh.common.exposure.meta.Meta
import com.gh.common.util.tryWithDefaultCatch
import com.gh.loghub.LoghubHelper
import org.json.JSONObject
import java.util.concurrent.Executors
@ -69,13 +70,16 @@ object LoghubUtils {
fun commitSavedLoghubEvents() {
loghubEventExecutor.execute {
if (loghubEventSet.isEmpty()) return@execute
// TODO 初始化 loghubHelper 去掉这个 tryCatch 块
tryWithDefaultCatch {
if (loghubEventSet.isEmpty()) return@execute
val exposureList = loghubEventSet.toList()
val exposureList = loghubEventSet.toList()
createLogGroupAndUpload()
loghubEventSet.removeAll(exposureList)
loghubEventDao.deleteMany(exposureList)
createLogGroupAndUpload()
loghubEventSet.removeAll(exposureList)
loghubEventDao.deleteMany(exposureList)
}
}
}

View File

@ -5,7 +5,7 @@ import com.gh.common.util.ApkActiveUtils
import com.gh.common.util.RandomUtils
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.tencent.bugly.beta.tinker.TinkerManager.getApplication
import com.halo.assistant.HaloApp
import io.reactivex.Observable
// 热门卡牌的仓库
@ -16,7 +16,7 @@ object RemenkapaiRepository {
@JvmStatic
fun getRemenkapai(size: Int): Observable<List<GameEntity>> {
return if (remenkapaiList.isEmpty()) {
RetrofitManager.getInstance(getApplication()).sensitiveApi.remenkapai
RetrofitManager.getInstance(HaloApp.getInstance().application).sensitiveApi.remenkapai
.map(RegionSettingHelper.filterGame)
.map { gameList -> filterEntityWithoutApk(gameList) }
.map { pickRandomSizeEntity(size) }

View File

@ -0,0 +1,243 @@
package com.gh.common.simulator
import android.app.Dialog
import android.content.Context
import android.view.View
import android.view.Window
import android.widget.ProgressBar
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.g00fy2.versioncompare.Version
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
import com.gh.gamecenter.entity.SimulatorEntity
import com.gh.gamecenter.entity.TrackableEntity
import com.halo.assistant.HaloApp
import com.lightgame.download.*
import com.lightgame.utils.Utils
import java.text.DecimalFormat
class SimulatorDownloadManager private constructor() {
private var app_pb_progress: ProgressBar? = null
private var appProgressSize: TextView? = null
private var appProgressRemain: TextView? = null
private var appProgressPercent: TextView? = null
private var appProgressFilling: View? = null
private var appProgressAnchor: View? = null
private var downloadDialog: Dialog? = null
private var simulatorLocation: SimulatorLocation? = null
private var simulator: SimulatorEntity? = null
private var gameId: String = ""
private var gameName: String = ""
private var downloadType: String = ""
private val dataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity?) {
if (downloadEntity?.isSimulatorDownload() == true) {
val size = downloadEntity.progress.toFloat() / 1024 / 1024
val df = DecimalFormat("0.00")
appProgressSize!!.text = "${df.format(size.toDouble())}MB"
appProgressRemain!!.text = String.format("剩余%s", SpeedUtils.getRemainSecondTime(downloadEntity.size,
downloadEntity.progress, downloadEntity.speed * 1024))
app_pb_progress!!.progress = (downloadEntity.percent * 10).toInt()
val width = app_pb_progress!!.width
val marLeft = (downloadEntity.percent / 100 * width).toInt()
val anchorLp = appProgressAnchor!!.layoutParams
if (anchorLp is ConstraintLayout.LayoutParams) {
anchorLp.leftMargin = marLeft
appProgressAnchor!!.layoutParams = anchorLp
}
val fillingLp = appProgressFilling!!.layoutParams
fillingLp.width = marLeft + DisplayUtils.dip2px(5f)
appProgressFilling!!.layoutParams = fillingLp
appProgressPercent?.text = if (downloadEntity.percent != 100.0) "${downloadEntity.percent}%" else "100%"
when {
DownloadStatus.done == downloadEntity.status -> {
val locationStr = if (simulatorLocation == SimulatorLocation.LAUNCH) "${simulatorLocation?.value}${gameName}" else simulatorLocation?.value
val fileName = downloadEntity.path.substring(downloadEntity.path.lastIndexOf('/') + 1).removeSuffix(".apk")
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()
}
DownloadStatus.neterror == downloadEntity.status -> {
ToastUtils.showToast("网络不稳定,下载任务已暂停")
}
DownloadStatus.timeout == downloadEntity.status -> {
ToastUtils.showToast("网络不稳定,下载任务已暂停")
}
DownloadStatus.notfound == downloadEntity.status -> {
ToastUtils.showToast("下载链接异常,请稍后重试")
}
DownloadStatus.hijack == downloadEntity.status -> {
ToastUtils.showToast("网络劫持,请稍后重试")
}
}
}
}
}
fun showDownloadDialog(context: Context, simulator: SimulatorEntity?, location: SimulatorLocation) {
showDownloadDialog(context, simulator, location, "", "", null)
}
fun showDownloadDialog(context: Context, simulator: SimulatorEntity?, location: SimulatorLocation, gameId: String = "", gameName: String = "", cancelCallback: (() -> Unit)? = null) {
this.simulatorLocation = location
this.simulator = simulator
this.gameId = gameId
this.gameName = gameName
//判断是否隐藏
if (simulator?.active == false) {
showNoneEmulatorDialog(context)
return
}
val isInstalled = PackageUtils.isInstalledFromAllPackage(context, simulator?.apk?.packageName)
val versionFromInstalledApp = PackageUtils.getVersionByPackage(simulator?.apk?.packageName)
val shouldShowUpdate = Version(simulator?.apk?.version).isHigherThan(versionFromInstalledApp)
val title = if (shouldShowUpdate && isInstalled) "更新模拟器" else "安装模拟器"
val message = if (shouldShowUpdate && isInstalled) "检测到模拟器存在更高版本,是否前往更新" else "模拟器游戏需要先下载安装对应的模拟器,才可以运行"
val positiveText = if (shouldShowUpdate && isInstalled) "更新(${simulator?.apk?.size}" else "下载(${simulator?.apk?.size}"
val negativeText = if (shouldShowUpdate && isInstalled) "下次再说" else "取消"
downloadType = if (shouldShowUpdate && isInstalled) "update" else "download"
val trackableEntity = TrackableEntity("模拟器下载",
key = if (shouldShowUpdate && isInstalled) "更新弹窗" else "下载弹窗",
logShowEvent = true
)
DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, {
if (shouldShowUpdate && isInstalled){
cancelCallback?.invoke()
MtaHelper.onEvent(trackableEntity.event, trackableEntity.key, "点击下次再说")
}
}, {
showDownloadingDialog(context, simulator)
MtaHelper.onEvent(trackableEntity.event, trackableEntity.key, if (shouldShowUpdate && isInstalled) "点击更新" else "点击下载")
})
}
private fun showDownloadingDialog(context: Context, simulator: SimulatorEntity?) {
val msg = FileUtils.isCanDownload(context, simulator?.apk?.size)
if (!msg.isNullOrEmpty()) {
Utils.toast(context, msg)
return
}
if (NetworkUtils.isMobileConnected(context)) {
Utils.toast(context, "当前使用移动数据进行下载")
}
downloadDialog = TrackableDialog(context, R.style.GhAlertDialog, "模拟器下载", "下载中弹窗")
downloadDialog?.window?.setBackgroundDrawableResource(R.color.transparent)
val view = View.inflate(context, R.layout.download_simulator_dialog, null)
app_pb_progress = view.findViewById(R.id.progress)
appProgressSize = view.findViewById(R.id.size)
appProgressRemain = view.findViewById(R.id.remain)
appProgressAnchor = view.findViewById(R.id.progress_anchor)
appProgressPercent = view.findViewById(R.id.percent)
appProgressFilling = view.findViewById(R.id.progress_filling)
view.findViewById<View>(R.id.app_tv_cancel).setOnClickListener {
DownloadManager.getInstance(context).pause(simulator?.apk?.url)
MtaHelper.onEvent("模拟器下载", "下载中弹窗", "点击关闭")
downloadDialog?.dismiss()
}
downloadDialog?.setOnDismissListener {
DownloadManager.getInstance(context).removeObserver(dataWatcher)
}
downloadDialog?.setCanceledOnTouchOutside(false)
downloadDialog?.setCancelable(false)
downloadDialog?.closeOptionsMenu()
downloadDialog?.requestWindowFeature(Window.FEATURE_NO_TITLE)
downloadDialog?.setContentView(view)
val params = downloadDialog?.window?.attributes
params?.width = context.resources.displayMetrics.widthPixels - DisplayUtils.dip2px(60f)
downloadDialog?.window?.attributes = params
download(context, simulator)
}
private fun showNoneEmulatorDialog(context: Context) {
val dialog = DialogUtils.showNewAlertDialog(context, "安装模拟器", "模拟器游戏需要先下载安装对应的模拟器,才可以运行", "取消", "暂无下载", null, {
ToastUtils.showToast("该模拟器暂未提供下载")
})
dialog?.window?.findViewById<TextView>(R.id.confirm)?.setTextColor(ContextCompat.getColor(context, R.color.text_cccccc))
}
private fun download(context: Context, simulator: SimulatorEntity?) {
val apkEntity = simulator?.apk ?: return
DownloadManager.getInstance(context).pauseAll()
val entity = DownloadManager.getInstance(context).getDownloadEntityByUrl(apkEntity.url)
if (entity != null) {
when (entity.status) {
DownloadStatus.pause, DownloadStatus.subscribe,
DownloadStatus.neterror, DownloadStatus.timeout -> {
DownloadManager.getInstance(context).addObserver(dataWatcher)
uiExecutor.executeWithDelay(Runnable { DownloadManager.getInstance(context).resume(entity, true) }, 200)
downloadDialog?.show()
}
DownloadStatus.done -> DataChanger.notifyDataChanged(entity)
else -> createDownload(context, apkEntity, simulator)
}
} else {
createDownload(context, apkEntity, simulator)
}
}
private fun createDownload(context: Context, apkEntity: ApkEntity, simulator: SimulatorEntity) {
DownloadManager.getInstance(context).addObserver(dataWatcher)
val downloadEntity = DownloadEntity()
downloadEntity.url = apkEntity.url
downloadEntity.name = simulator.name
downloadEntity.path = getDownloadPath(simulator.name, 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())
uiExecutor.executeWithDelay(Runnable { DownloadManager.getInstance(context).add(downloadEntity) }, 200)
val locationStr = if (simulatorLocation == SimulatorLocation.LAUNCH) "${simulatorLocation?.value}${gameName}" else simulatorLocation?.value
val fileName = downloadEntity.path.substring(downloadEntity.path.lastIndexOf('/') + 1).removeSuffix(".apk")
LogUtils.uploadSimulatorDownload("simulator_download", fileName, simulator.id, simulator.name, gameId, locationStr, downloadType, "")
downloadDialog?.show()
}
companion object {
@Volatile
private var instance: SimulatorDownloadManager? = null
@JvmStatic
fun getInstance(): SimulatorDownloadManager {
return instance ?: synchronized(this) {
instance ?: SimulatorDownloadManager().also { instance = it }
}
}
}
enum class SimulatorLocation(val value: String) {
LAUNCH("启动"),
SIMULATOR_GAME("模拟器游戏"),
SIMULATOR_MANAGE("模拟器游戏-模拟器管理")
}
}

View File

@ -0,0 +1,219 @@
package com.gh.common.simulator
import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import android.content.Intent
import android.net.Uri
import android.text.TextUtils
import com.g00fy2.versioncompare.Version
import com.gh.common.util.*
import com.gh.download.DownloadManager
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.EmptyResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadDao
import com.lightgame.download.DownloadEntity
import com.lightgame.download.FileUtils
import com.lightgame.utils.AppManager
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import java.io.File
object SimulatorGameManager {
private val gamePath = FileUtils.getDownloadPath(HaloApp.getInstance().application, "emulator_game")
@JvmStatic
fun getPathByType(type: String) = "${gamePath}/${type}"
@JvmStatic
fun deleteLocalGames(names: List<String>) {
val downloadEntityList = DownloadDao.getInstance(HaloApp.getInstance().application).all
names.forEach { name ->
val downloadEntity = downloadEntityList.find { it.name == name }
if (downloadEntity != null) {
val file = File(downloadEntity.path)
if (file.exists()) {
file.delete()
DownloadDao.getInstance(HaloApp.getInstance().application).delete(downloadEntity.url)
}
}
}
}
@JvmStatic
fun deleteLocalGame(name: String) {
val downloadEntityList = DownloadDao.getInstance(HaloApp.getInstance().application).all
val downloadEntity = downloadEntityList.find { it.name == name }
if (downloadEntity != null) {
val file = File(downloadEntity.path)
if (file.exists()) {
file.delete()
DownloadDao.getInstance(HaloApp.getInstance().application).delete(downloadEntity.url)
}
}
}
@JvmStatic
fun findDownloadEntityByUrl(url: String?): DownloadEntity? {
val downloadEntity = DownloadDao.getInstance(HaloApp.getInstance().application).get(url)
if (downloadEntity != null) {
val isFileCompleted = DownloadManager.getInstance(HaloApp.getInstance().application).isFileCompleted(url)
if (downloadEntity.isSimulatorGame() && isFileCompleted) {
return downloadEntity
}
}
return null
}
@JvmStatic
fun isSimulatorGame(gameEntity: GameEntity) = gameEntity.category == "simulator"
@JvmStatic
fun launchSimulatorGame(downloadEntity: DownloadEntity, gameEntity: GameEntity) {
val versionFromInstalledApp = PackageUtils.getVersionByPackage(gameEntity.simulator?.apk?.packageName)
val shouldShowUpdate = Version(gameEntity.simulator?.apk?.version).isHigherThan(versionFromInstalledApp)
if (shouldShowUpdate) {
SimulatorDownloadManager.getInstance().showDownloadDialog(AppManager.getInstance().recentActiveActivity, gameEntity.simulator,
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.id, gameEntity.name
?: "") {
jumpToSimulator(downloadEntity, gameEntity)
}
} else {
jumpToSimulator(downloadEntity, gameEntity)
}
}
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)
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)
}
/**
* 记录设备下载的模拟器游戏
*/
@SuppressLint("CheckResult")
@JvmStatic
fun recordDownloadSimulatorGames(gameId: String) {
val requestMap = hashMapOf<String, Any>()
requestMap["game_id"] = gameId
requestMap["package"] = "-"
val body = requestMap.createRequestBodyAny()
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.downloadSimulatorGames(HaloApp.getInstance().gid, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(EmptyResponse())
}
/**
* 标记已玩过
*/
@SuppressLint("CheckResult")
fun postPlayedGame(gameId: String, packageName: String) {
if (!TextUtils.isEmpty(gameId) && UserManager.getInstance().isLoggedIn) {
val requestMap = hashMapOf<String, Any>()
requestMap["game_id"] = gameId
requestMap["package"] = packageName
val body = requestMap.toRequestBody()
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.postPlayedGame(UserManager.getInstance().userId, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(EmptyResponse())
}
}
/**
* 记录启动设备上的模拟器游戏
*/
@SuppressLint("CheckResult")
fun recordPlaySimulatorGames(gameId: String) {
val requestMap = hashMapOf<String, Any>()
requestMap["game_id"] = gameId
requestMap["package"] = "-"
val body = requestMap.createRequestBodyAny()
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.playedSimulatorGames(HaloApp.getInstance().gid, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(EmptyResponse())
}
/**
* 删除设备下载模拟器游戏的记录
*/
@SuppressLint("CheckResult")
fun deleteSimulatorGame(gameId: String, callback: () -> Unit) {
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.deleteSimulatorGame(HaloApp.getInstance().gid, gameId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
callback.invoke()
}
})
}
/**
* 批量删除设备下载模拟器游戏的记录
*/
@SuppressLint("CheckResult")
fun deleteSimulatorGames(gameIds: List<String>, callback: () -> Unit) {
val requestMap = hashMapOf<String, Any>()
requestMap["game_ids"] = gameIds
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.deleteSimulatorGames(HaloApp.getInstance().gid, requestMap.toRequestBody())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
callback.invoke()
}
})
}
/**
* 批量删除设备下载模拟器游戏的记录
*/
@JvmStatic
@SuppressLint("CheckResult")
fun deleteAllSimulatorGame() {
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.deleteAllSimulatorGame(HaloApp.getInstance().gid)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(EmptyResponse())
}
}

View File

@ -0,0 +1,16 @@
package com.gh.common.structure
class FixedSizeLinkedHashSet<T>(var maxSize: Int) : LinkedHashSet<T>() {
override fun add(element: T): Boolean {
if (size == maxSize) {
pop()
}
return super.add(element);
}
private fun pop() {
if (size > 0) {
remove(iterator().next())
}
}
}

View File

@ -5,11 +5,12 @@ import com.gh.gamecenter.entity.SettingsEntity
object AdHelper {
// 搜索为空/求版本/意见反馈-功能收录/发现
// 搜索为空/求版本/意见反馈-功能收录/发现/模拟器游戏
const val LOCATION_SEARCH_EMPTY = "search_empty"
const val LOCATION_GAME_REQUEST_VERSION = "game_request_version"
const val LOCATION_SUGGESTION_FUNCTION = "suggestion_function"
const val LOCATION_DISCOVER = "discover"
const val LOCATION_SIMULATOR_GAME = "simulator_game"
fun getAd(location: String): SettingsEntity.AD? {
val adList = Config.getSettings()?.adList ?: return null
@ -34,4 +35,19 @@ object AdHelper {
return discoverAdList
}
fun getAdForLocation(location: String): SettingsEntity.AD? {
val adList = Config.getSettings()?.adList ?: return null
var result: SettingsEntity.AD? = null
run outside@ {
for (ad in adList) {
if (ad.location == location) {
result = ad
return@outside
}
}
}
return result
}
}

View File

@ -1,14 +1,10 @@
package com.gh.common.util
import com.alibaba.wireless.security.jaq.avmp.IJAQAVMPSignComponent
import com.alibaba.wireless.security.open.SecurityGuardManager
import com.halo.assistant.HaloApp
object AntiBotHelper {
@JvmStatic
val manager by lazy {
SecurityGuardManager.getInstance(HaloApp.getInstance().application).getInterface(IJAQAVMPSignComponent::class.java).apply {
this.initialize()
}
}
// @JvmStatic
// val manager by lazy {
// SecurityGuardManager.getInstance(HaloApp.getInstance().application).getInterface(IJAQAVMPSignComponent::class.java).apply {
// this.initialize()
// }
// }
}

View File

@ -1,5 +1,6 @@
package com.gh.common.util;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@ -14,9 +15,17 @@ import com.halo.assistant.HaloApp;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import androidx.annotation.IntRange;
import androidx.annotation.RequiresApi;
import androidx.renderscript.Allocation;
import androidx.renderscript.Element;
import androidx.renderscript.RenderScript;
import androidx.renderscript.ScriptIntrinsicBlur;
/**
* Created by LGT on 2016/10/21.
*/
@ -114,6 +123,14 @@ public class BitmapUtils {
return true;
}
public static Bitmap getBitmapByFile(String filepath, int w, int h) {
return getBitmapByFile(filepath, w, h, Bitmap.Config.RGB_565);
}
public static Bitmap getBitmapByFile(String filepath, Bitmap.Config config) {
return getBitmapByFile(filepath, 0, 0, config);
}
/**
* 根据文件路径返回bitmap
*
@ -122,12 +139,12 @@ public class BitmapUtils {
* @param h 高
* @return bitmap
*/
public static Bitmap getBitmapByFile(String filepath, int w, int h) {
public static Bitmap getBitmapByFile(String filepath, int w, int h, Bitmap.Config config) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
// 设置为ture只获取图片大小
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inPreferredConfig = config;
// 返回为空
BitmapFactory.decodeFile(filepath, options);
int width = options.outWidth;
@ -135,8 +152,8 @@ public class BitmapUtils {
float scaleWidth = 0.f, scaleHeight = 0.f;
if (width > w || height > h) {
// 缩放
scaleWidth = ((float) width) / w;
scaleHeight = ((float) height) / h;
if (w > 0) scaleWidth = ((float) width) / w;
if (h > 0) scaleHeight = ((float) height) / h;
}
options.inJustDecodeBounds = false;
int scale = (int) Math.ceil(Math.max(scaleWidth, scaleHeight));
@ -189,6 +206,7 @@ public class BitmapUtils {
/**
* Drawable转Bitmap
*
* @param isSquare 是否是正方形
*/
public static Bitmap drawableToBitmap(Drawable drawable, boolean isSquare) {
@ -196,7 +214,7 @@ public class BitmapUtils {
return null;
}
int w,h;
int w, h;
// 取 drawable 的长宽
w = drawable.getIntrinsicWidth();
@ -227,4 +245,108 @@ public class BitmapUtils {
return bitmap;
}
/**
* 修改bitmap透明度
*
* @param sourceImg
* @param config
* @param number
* @return
*/
public static Bitmap getTransparentBitmap(Bitmap sourceImg, Bitmap.Config config, int number) {
int[] argb = new int[sourceImg.getWidth() * sourceImg.getHeight()];
sourceImg.getPixels(argb, 0, sourceImg.getWidth(), 0, 0, sourceImg
.getWidth(), sourceImg.getHeight());// 获得图片的ARGB值
number = number * 255 / 100;
for (int i = 0; i < argb.length; i++) {
argb[i] = (number << 24) | (argb[i] & 0x00FFFFFF);
}
sourceImg = Bitmap.createBitmap(argb, sourceImg.getWidth(), sourceImg
.getHeight(), config);
return sourceImg;
}
/**
* 高斯模糊
*
* @param context
* @param image
* @param radius
* @return
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public static Bitmap getBlurBitmap(Context context, Bitmap image, @IntRange(from = 1, to = 25) int radius) {
// 计算图片缩小后的长宽
int width = Math.round(image.getWidth() * 0.8f);
int height = Math.round(image.getHeight() * 0.8f);
// 将缩小后的图片做为预渲染的图片。
Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
// 创建一张渲染后的输出图片。
Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
// 创建RenderScript内核对象
RenderScript rs = RenderScript.create(context);
// 创建一个模糊效果的RenderScript的工具对象
ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
// 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间。
// 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去。
Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
Allocation tmpOut = Allocation.createTyped(rs, tmpIn.getType());
// 设置渲染的模糊程度, 25f是最大模糊度
blurScript.setRadius(radius);
// 设置blurScript对象的输入内存
blurScript.setInput(tmpIn);
// 将输出数据保存到输出内存中
blurScript.forEach(tmpOut);
// 将数据填充到Allocation中
tmpOut.copyTo(outputBitmap);
return outputBitmap;
}
/**
* 保存图片
*
* @param bitmap
* @param path
*/
public static void saveBitmap(Bitmap bitmap, String path) {
File file = new File(path);
if (file.exists()) {
file.delete();
}
FileOutputStream out;
try {
out = new FileOutputStream(file);
if (bitmap.compress(Bitmap.CompressFormat.PNG, 80, out)) {
out.flush();
out.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static Bitmap compressBitmap(Bitmap bitmap) {
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);
matrix.setScale(0.9f, 0.9f);
result = Bitmap.createBitmap(result, 0, 0, result.getWidth(), result.getHeight(), matrix, true);
bos.reset();
result.compress(Bitmap.CompressFormat.WEBP, 100, bos);
}
return result;
}
}

View File

@ -16,8 +16,8 @@ import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.comment.OnCommentOptionClickListener
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import com.tencent.bugly.beta.tinker.TinkerManager.getApplication
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
@ -84,11 +84,16 @@ object CommentHelper {
listener: OnCommentOptionClickListener? = null) {
val context = view.context
val dialogOptions = ArrayList<String>()
dialogOptions.add("复制")
if (commentEntity.user.id != UserManager.getInstance().userId) {
dialogOptions.add("投诉")
}
if (isVideoAuthor || (videoId != null && commentEntity.user.id == UserManager.getInstance().userId)) {
dialogOptions.add("删除评论")
} else if (articleId != null && (commentEntity.user.id == UserManager.getInstance().userId ||
commentEntity.me?.isModerator == true || commentEntity.me?.isArticleOrAnswerAuthor == true)) {
dialogOptions.add("删除评论")
}
dialogOptions.add("复制")
dialogOptions.add("投诉")
commentEntity.me?.let {
if (ignoreModerator) return@let
@ -128,7 +133,7 @@ object CommentHelper {
"投诉" -> {
context.ifLogin("回答详情-评论-投诉") {
showReportTypeDialog(context) { reportType ->
showReportTypeDialog(context, !videoId.isNullOrEmpty()) { reportType ->
val commentListener = object : PostCommentUtils.PostCommentListener {
override fun postSuccess(response: JSONObject?) {
@ -189,7 +194,7 @@ object CommentHelper {
var canHighlightCommentDirectly = false
var canHideCommentDirectly = false
if (me.moderatorPermissions.topAnswerComment > Permissions.GUEST
if (me.isModerator || me.moderatorPermissions.topAnswerComment > Permissions.GUEST
|| me.moderatorPermissions.topCommunityArticleComment > Permissions.GUEST) {
dialogOptions.add(highlight)
if (me.moderatorPermissions.topAnswerComment > Permissions.REPORTER
@ -198,7 +203,7 @@ object CommentHelper {
}
}
if (me.moderatorPermissions.hideAnswerComment > Permissions.GUEST
if (me.isModerator || me.moderatorPermissions.hideAnswerComment > Permissions.GUEST
|| me.moderatorPermissions.hideCommunityArticleComment > Permissions.GUEST) {
dialogOptions.add(hide)
if (me.moderatorPermissions.hideAnswerComment > Permissions.REPORTER
@ -263,10 +268,10 @@ object CommentHelper {
val errorJson = JSONObject(string)
val errorCode = errorJson.getInt("code")
if (errorCode == 403059) {
Utils.toast(getApplication(), "权限错误,请刷新后重试")
Utils.toast(HaloApp.getInstance().application, "权限错误,请刷新后重试")
return
} else {
Utils.toast(getApplication(), e.message())
Utils.toast(HaloApp.getInstance().application, e.message())
}
}
}
@ -312,10 +317,10 @@ object CommentHelper {
val errorJson = JSONObject(string)
val errorCode = errorJson.getInt("code")
if (errorCode == 403059) {
Utils.toast(getApplication(), "权限错误,请刷新后重试")
Utils.toast(HaloApp.getInstance().application, "权限错误,请刷新后重试")
return
} else {
Utils.toast(getApplication(), e.message())
Utils.toast(HaloApp.getInstance().application, e.message())
}
}
}
@ -346,16 +351,22 @@ object CommentHelper {
}
}
private fun showReportTypeDialog(context: Context, reportCallback: (reportType: String) -> Unit) {
private fun showReportTypeDialog(context: Context, isVideoComment: Boolean, reportCallback: (reportType: String) -> Unit) {
val reportTypes = arrayListOf("垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息", "违法有害信息", "其它")
DialogUtils.showListDialog(context, reportTypes, null) { text ->
val jsonObject = JSONObject()
try {
jsonObject.put("reason", text)
reportCallback.invoke(jsonObject.toString())
} catch (e: JSONException) {
e.printStackTrace()
if (!isVideoComment) {
DialogUtils.showListDialog(context, reportTypes, null) { text ->
val jsonObject = JSONObject()
try {
jsonObject.put("reason", text)
reportCallback.invoke(jsonObject.toString())
} catch (e: JSONException) {
e.printStackTrace()
}
}
} else {
DialogUtils.showVideoComplaintDialog(context, reportTypes, null) { text ->
reportCallback.invoke(text)
}
}
}

View File

@ -12,8 +12,6 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.gh.gamecenter.CommentDetailActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
@ -22,6 +20,7 @@ import com.gh.gamecenter.entity.MeEntity;
import com.gh.gamecenter.entity.UserInfoEntity;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.retrofit.BiResponse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
@ -40,6 +39,8 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
@ -279,6 +280,9 @@ public class CommentUtils {
if (TextUtils.isEmpty(articleId)) {
entrance = "社区文章详情-评论-点赞";
}
if (TextUtils.isEmpty(videoId)) {
entrance = "视频流-评论-点赞";
}
CheckLoginUtils.checkLogin(context, entrance, () -> {
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme_font)) {
ToastUtils.INSTANCE.showToast("已经点过赞啦!");
@ -330,6 +334,97 @@ 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 entrance = "视频流-评论-点赞";
CheckLoginUtils.checkLogin(context, entrance, () -> {
PostCommentUtils.likeComment(context, answerId, articleId, articleCommunityId, videoId, commentEntity.getId(),
new PostCommentUtils.PostCommentListener() {
@Override
public void postSuccess(JSONObject response) {
if (listener != null) {
listener.onVote();
}
}
@Override
public void postFailed(Throwable e) {
commentEntity.setVote(commentEntity.getVote() - 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint));
commentLikeIv.setImageResource(R.drawable.comment_vote_unselect);
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
if (commentEntity.getVote() == 0) {
commentLikeCountTv.setVisibility(View.GONE);
} else {
commentLikeCountTv.setVisibility(View.VISIBLE);
}
if (e instanceof HttpException) {
HttpException exception = (HttpException) e;
if (exception.code() == 403) {
try {
String detail = new JSONObject(exception.response().errorBody().string()).getString("detail");
if ("voted".equals(detail)) {
ToastUtils.INSTANCE.showToast("已经点过赞啦!");
}
} catch (Exception ex) {
ex.printStackTrace();
}
return;
}
}
Utils.toast(context, "网络异常,点赞失败");
}
});
});
}
public static void unVoteVideoComment(final Context context,
String videoId,
final CommentEntity commentEntity,
final TextView commentLikeCountTv,
final ImageView commentLikeIv) {
String entrance = "视频流-评论-取消点赞";
CheckLoginUtils.checkLogin(context, entrance, () -> {
RetrofitManager.getInstance(context).getApi()
.unVoteVideoComment(videoId, commentEntity.getId())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(@Nullable ResponseBody response) {
super.onResponse(response);
}
@Override
public void onFailure(@Nullable HttpException e) {
super.onFailure(e);
commentEntity.setVote(commentEntity.getVote() + 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font));
commentLikeIv.setImageResource(R.drawable.comment_vote_select);
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
commentLikeCountTv.setVisibility(View.VISIBLE);
try {
if (e != null && e.response().errorBody() != null) {
ErrorHelper.handleError(context, e.response().errorBody().string(), false);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
});
}
// 设置评论item 用户相关的view(点赞/头像/用户名)

View File

@ -2,10 +2,10 @@ package com.gh.common.util;
import android.content.Context;
import com.gh.common.exposure.meta.MetaUtil;
import com.gh.common.loghub.LoghubUtils;
import com.halo.assistant.HaloApp;
import com.lightgame.download.DownloadEntity;
import com.lightgame.utils.Util_System_Phone_State;
import com.lightgame.utils.Utils;
import org.json.JSONObject;
@ -53,10 +53,13 @@ public class DataLogUtils {
String channel = HaloApp.getInstance().getChannel();
map.put("version", version);
map.put("user", user);
map.put("device_id", Util_System_Phone_State.getDeviceId(context));
map.put("device_id", MetaUtil.getIMEI());
map.put("channel", channel);
Map<String, String> params = new HashMap<>();
if ("search-hot-tag".equals(topic) || "game".equals(topic) || "slide".equals(topic)) {
params.put("meta", LogUtils.getMetaObject().toString());
}
params.put("topic", topic);
params.put("source", "GH-ASSIST-Client");
params.put("time", String.valueOf(Utils.getTime(context)));

View File

@ -6,7 +6,6 @@ import android.content.Context;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import com.gh.common.constant.Config;
import com.gh.common.constant.Constants;
import com.gh.common.exposure.meta.MetaUtil;
import com.gh.gid.GidCallback;
@ -14,13 +13,6 @@ import com.gh.gid.GidHelper;
import com.halo.assistant.HaloApp;
import com.lightgame.config.CommonDebug;
import com.lightgame.utils.Utils;
import com.tencent.bugly.crashreport.CrashReport;
import com.tencent.stat.MtaSDkException;
import com.tencent.stat.StatConfig;
import com.tencent.stat.StatCrashReporter;
import com.tencent.stat.StatReportStrategy;
import com.tencent.stat.StatService;
import com.tendcloud.tenddata.TCAgent;
import java.util.HashMap;
import java.util.Map;
@ -44,71 +36,71 @@ public class DataUtils {
return;
}
//TalkingData
try {
TCAgent.LOG_ON = false;
TCAgent.init(context, Config.TALKINGDATA_APPID, channel);
/**
*
* 不要启用!!!!不要启用,全部由{@link com.gh.base.AppUncaughtHandler}处理
*/
TCAgent.setReportUncaughtExceptions(false);
} catch (Exception e) {
e.printStackTrace();
}
// try {
// TCAgent.LOG_ON = false;
// TCAgent.init(context, Config.TALKINGDATA_APPID, channel);
// /**
// *
// * 不要启用!!!!不要启用,全部由{@link com.gh.base.AppUncaughtHandler}处理
// */
// TCAgent.setReportUncaughtExceptions(false);
// } catch (Exception e) {
// e.printStackTrace();
// }
//MTA
try {
/**
*
* 不要启用!!!!全部由{@link com.gh.base.AppUncaughtHandler}处理
*/
StatConfig.setAutoExceptionCaught(false);
StatCrashReporter crashReporter = StatCrashReporter.getStatCrashReporter(context);
crashReporter.setJavaCrashHandlerStatus(false);
// crashReporter.setEnableInstantReporting(true);
StatConfig.setDebugEnable(false);
// 设置数据上报策略
// 测试渠道的时候即时上传,方便查看日志
if (Config.DEFAULT_CHANNEL.equals(HaloApp.getInstance().getChannel())) {
StatConfig.setStatSendStrategy(StatReportStrategy.INSTANT);
} else {
StatConfig.setStatSendStrategy(StatReportStrategy.PERIOD);
StatConfig.setSendPeriodMinutes(5);
}
// 设置启用Tlink
StatConfig.setTLinkStatus(true);
StatConfig.init(context);
StatConfig.setInstallChannel(channel);
StatConfig.setAntoActivityLifecycleStat(true);
StatConfig.setAppVersion(PackageUtils.getVersionName());
// 开启收集服务
StatService.startStatService(context, Config.MTA_APPKEY, com.tencent.stat.common.StatConstants.VERSION);
StatService.registerActivityLifecycleCallbacks(context);
} catch (MtaSDkException e) {
e.printStackTrace();
}
// try {
// /**
// *
// * 不要启用!!!!全部由{@link com.gh.base.AppUncaughtHandler}处理
// */
// StatConfig.setAutoExceptionCaught(false);
//
// StatCrashReporter crashReporter = StatCrashReporter.getStatCrashReporter(context);
// crashReporter.setJavaCrashHandlerStatus(false);
//// crashReporter.setEnableInstantReporting(true);
//
// StatConfig.setDebugEnable(false);
//
// // 设置数据上报策略
// // 测试渠道的时候即时上传,方便查看日志
// if (Config.DEFAULT_CHANNEL.equals(HaloApp.getInstance().getChannel())) {
// StatConfig.setStatSendStrategy(StatReportStrategy.INSTANT);
// } else {
// StatConfig.setStatSendStrategy(StatReportStrategy.PERIOD);
// StatConfig.setSendPeriodMinutes(5);
// }
//
// // 设置启用Tlink
// StatConfig.setTLinkStatus(true);
//
// StatConfig.init(context);
// StatConfig.setInstallChannel(channel);
// StatConfig.setAntoActivityLifecycleStat(true);
// StatConfig.setAppVersion(PackageUtils.getVersionName());
//
// // 开启收集服务
// StatService.startStatService(context, Config.MTA_APPKEY, com.tencent.stat.common.StatConstants.VERSION);
// StatService.registerActivityLifecycleCallbacks(context);
// } catch (MtaSDkException e) {
// e.printStackTrace();
// }
// init bugly
try {
CrashReport.setIsDevelopmentDevice(context, Config.DEFAULT_CHANNEL.equals(channel));
CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(context);
strategy.setEnableANRCrashMonitor(false);
strategy.setEnableNativeCrashMonitor(false);
strategy.setAppChannel(channel);
strategy.setAppVersion(PackageUtils.getVersionName());
CrashReport.initCrashReport(context, Config.BUGLY_APPID, false, strategy);
} catch (Exception e) {
e.printStackTrace();
}
// try {
// CrashReport.setIsDevelopmentDevice(context, Config.DEFAULT_CHANNEL.equals(channel));
//
// CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(context);
// strategy.setEnableANRCrashMonitor(false);
// strategy.setEnableNativeCrashMonitor(false);
// strategy.setAppChannel(channel);
// strategy.setAppVersion(PackageUtils.getVersionName());
//
// CrashReport.initCrashReport(context, Config.BUGLY_APPID, false, strategy);
//
// } catch (Exception e) {
// e.printStackTrace();
// }
}
@ -121,7 +113,7 @@ public class DataUtils {
}
public static void getGid() {
GidHelper.getInstance().registerDevice(new GidCallback() {
GidHelper.getInstance().registerDevice(HaloApp.getInstance().getApplication(), new GidCallback() {
@Override
public void onSuccess(String gid) {
Utils.log("Gid", gid);
@ -147,20 +139,17 @@ public class DataUtils {
}
public static void onEvent(Context var0, String var1, String var2) {
TCAgent.onEvent(var0, var1, var2);
Properties prop = new Properties();
prop.setProperty(var1, var2);
StatService.trackCustomKVEvent(var0, var1, prop);
// StatService.trackCustomKVEvent(var0, var1, prop);
}
public static void onPause(Activity var0) {
TCAgent.onPageEnd(var0, var0.getClass().getSimpleName());
StatService.onPause(var0);
// StatService.onPause(var0);
}
public static void onResume(Activity var0) {
TCAgent.onPageStart(var0, var0.getClass().getSimpleName());
StatService.onResume(var0);
// StatService.onResume(var0);
}
// 游戏启动
@ -172,13 +161,12 @@ public class DataUtils {
}
public static void onEvent(Context var0, String var1, String var2, Map<String, Object> var3) {
TCAgent.onEvent(var0, var1, var2, var3);
Properties prop = new Properties();
prop.setProperty("label", var2);
for (String key : var3.keySet()) {
prop.setProperty(key, var3.get(key) + "");
}
StatService.trackCustomKVEvent(var0, var1, prop);
// StatService.trackCustomKVEvent(var0, var1, prop);
}
public static void trackTimeEvent(Context context, String eventId, int costTime, String... kv) {
@ -196,7 +184,7 @@ public class DataUtils {
if (prop.size() == 0) return;
StatService.trackCustomKVTimeIntervalEvent(context, costTime, eventId, prop);
// StatService.trackCustomKVTimeIntervalEvent(context, costTime, eventId, prop);
}
// 游戏下载
@ -244,13 +232,13 @@ public class DataUtils {
public static void onError(Context context, Throwable throwable) {
//bugly 作为默认处理异常的类库,已经上报了,此处不重复上报
try {
CrashReport.postCatchedException(throwable);
// CrashReport.postCatchedException(throwable);
} catch (Exception e) {
}
//talkingdata
try {
TCAgent.onError(context, throwable);
// TCAgent.onError(context, throwable);
} catch (Exception e) {
}
}

View File

@ -5,6 +5,7 @@ import android.view.View;
import com.gh.common.constant.Config;
import com.gh.common.repository.ReservationRepository;
import com.gh.common.simulator.SimulatorGameManager;
import com.gh.common.view.DownloadProgressBar;
import com.gh.common.xapk.XapkInstaller;
import com.gh.common.xapk.XapkUnzipStatus;
@ -66,6 +67,9 @@ public class DetailDownloadUtils {
if ("dialog".equals(viewHolder.gameEntity.getDownloadOffStatus())) {
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(viewHolder.gameEntity.getDownloadOffText()) ? "查看详情" : viewHolder.gameEntity.getDownloadOffText());
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NONE_WITH_HINT);
} else if ("updating".equals(viewHolder.gameEntity.getDownloadOffStatus())) {
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(viewHolder.gameEntity.getDownloadOffText()) ? "更新中" : viewHolder.gameEntity.getDownloadOffText());
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.UPDATING);
} else {
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(viewHolder.gameEntity.getDownloadOffText()) ? "暂无下载" : viewHolder.gameEntity.getDownloadOffText());
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NONE);
@ -148,13 +152,25 @@ public class DetailDownloadUtils {
}
break;
case done:
viewHolder.mDownloadPb.setText(R.string.install);
if (downloadEntity.isPluggable()
&& PackagesManager.isInstalled(downloadEntity.getPackageName())) {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_PLUGIN);
} else {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
if (SimulatorGameManager.isSimulatorGame(viewHolder.gameEntity)){
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(viewHolder.context, viewHolder.gameEntity.getSimulator().getApk().getPackageName());
if (isInstalled){
viewHolder.mDownloadPb.setText(R.string.launch);
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN);
}else{
viewHolder.mDownloadPb.setText(R.string.install);
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
}
}else{
viewHolder.mDownloadPb.setText(R.string.install);
if (downloadEntity.isPluggable()
&& PackagesManager.isInstalled(downloadEntity.getPackageName())) {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_PLUGIN);
} else {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
}
}
break;
case cancel:
case hijack:

View File

@ -3,12 +3,12 @@ package com.gh.common.util
import android.content.Context
import android.os.Environment
import android.preference.PreferenceManager
import com.gh.common.exposure.meta.MetaUtil
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.entity.TimeEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_Phone_State
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
@ -60,7 +60,7 @@ object DeviceTokenUtils {
lunchType = LunchType.FIRST
}
// 保存deviceId
var deviceId = Util_System_Phone_State.getDeviceId(HaloApp.getInstance().application)
var deviceId = MetaUtil.getIMEI()
if (deviceId.isNullOrEmpty()) {
deviceId = Utils.getTime(HaloApp.getInstance().application).toString()
}

View File

@ -6,26 +6,21 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import com.gh.common.exposure.meta.MetaUtil;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Util_System_Phone_State;
import com.tencent.stat.StatConfig;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import java.net.Inet4Address;
import java.net.InetAddress;
@ -46,14 +41,14 @@ public class DeviceUtils {
context = context.getApplicationContext();
JSONObject object = new JSONObject();
object.put("os", "Android");
object.put("imei", Util_System_Phone_State.getDeviceId(context));
object.put("imei", MetaUtil.getIMEI());
object.put("mac", getMac(context));
object.put("model", MODEL);
object.put("manufacturer", MANUFACTURER);
object.put("android_id", Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID));
object.put("android_id", MetaUtil.getAndroidId());
object.put("android_sdk", Build.VERSION.SDK_INT);
object.put("android_version", android.os.Build.VERSION.RELEASE);
object.put("ip", getIPAddress(context));
object.put("ip", "");
object.put("network", getNetwork(context));
return object;
}
@ -62,10 +57,10 @@ public class DeviceUtils {
public static JSONObject getUserDevice(Context context) { // 判断新老用户device数据
JSONObject object = new JSONObject();
try {
object.put("IMEI", Util_System_Phone_State.getDeviceId(context));
object.put("ANDROID_ID", Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID));
object.put("IMEI", MetaUtil.getIMEI());
object.put("ANDROID_ID", MetaUtil.getAndroidId());
object.put("MAC", getMac(context));
object.put("MTA_ID", StatConfig.getMid(context));
// object.put("MTA_ID", StatConfig.getMid(context));
object.put("MANUFACTURER", MANUFACTURER);
object.put("MODEL", MODEL);
object.put("ANDROID_SDK", Build.VERSION.SDK_INT);
@ -78,39 +73,39 @@ public class DeviceUtils {
}
public static String getMac(Context context) {
String str = "";
String macSerial = "";
try {
Process pp = Runtime.getRuntime().exec(
"cat /sys/class/net/wlan0/address ");
InputStreamReader ir = new InputStreamReader(pp.getInputStream());
LineNumberReader input = new LineNumberReader(ir);
while (null != str) {
str = input.readLine();
if (str != null) {
macSerial = str.trim();// 去空格
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
if ("".equals(macSerial)) {
try {
return loadFileAsString("/sys/class/net/eth0/address")
.toUpperCase().substring(0, 17);
} catch (FileNotFoundException e) {
// do nothing
} catch (Exception e) {
e.printStackTrace();
}
}
if (TextUtils.isEmpty(macSerial)) { // 备用方案
macSerial = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE)).getConnectionInfo().getMacAddress();
}
return macSerial;
// String str = "";
// String macSerial = "";
// try {
// Process pp = Runtime.getRuntime().exec(
// "cat /sys/class/net/wlan0/address ");
// InputStreamReader ir = new InputStreamReader(pp.getInputStream());
// LineNumberReader input = new LineNumberReader(ir);
//
// while (null != str) {
// str = input.readLine();
// if (str != null) {
// macSerial = str.trim();// 去空格
// break;
// }
// }
// } catch (Exception ex) {
// ex.printStackTrace();
// }
// if ("".equals(macSerial)) {
// try {
// return loadFileAsString("/sys/class/net/eth0/address")
// .toUpperCase().substring(0, 17);
// } catch (FileNotFoundException e) {
// // do nothing
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// }
// if (TextUtils.isEmpty(macSerial)) { // 备用方案
// macSerial = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE)).getConnectionInfo().getMacAddress();
// }
return "";
}
private static String loadFileAsString(String fileName) throws Exception {
@ -242,8 +237,7 @@ public class DeviceUtils {
@Nullable
public static String getTelephonySubscriberId(Context context) {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return tm.getSubscriberId();
return "";
}
// ping domain
@ -273,7 +267,6 @@ public class DeviceUtils {
return memInfo.totalMem / (1024 * 1024);
}
// 只能获取WiFi的IpAddress
public static String getCurrentIpAddress() {
String ipAddress = "0.0.0.0";

View File

@ -8,8 +8,11 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.CountDownTimer;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
@ -24,18 +27,23 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
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;
@ -46,12 +54,13 @@ import com.gh.common.view.MaxHeightNestedScrollView;
import com.gh.gamecenter.AboutActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SuggestionActivity;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.adapter.viewholder.PrivacyPolicyItemViewHolder;
import com.gh.gamecenter.databinding.DialogOverseaConfirmationBinding;
import com.gh.gamecenter.databinding.ImprintContentItemBinding;
import com.gh.gamecenter.databinding.PrivacyItemBinding;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.Badge;
import com.gh.gamecenter.entity.BadgeEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.PrivacyPolicyEntity;
import com.gh.gamecenter.entity.SettingsEntity;
@ -65,6 +74,9 @@ import com.lightgame.utils.AppManager;
import com.lightgame.utils.Util_System_Keyboard;
import com.lightgame.utils.Utils;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@ -326,6 +338,82 @@ public class DialogUtils {
dialog.show();
}
/**
* ios 风格弹窗
*
* @param context
* @param title 标题
* @param message 内容
* @param negative 取消按钮文本
* @param positive 确认按钮文本
* @param clListener 取消按钮监听
* @param cmListener 确认按钮监听
*/
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
, String negative, String positive, TrackableEntity trackableEntity, final CancelListener clListener, final ConfirmListener cmListener) {
context = checkDialogContext(context);
final Dialog dialog;
if (trackableEntity != null) {
dialog = new TrackableDialog(context,
R.style.GhAlertDialog,
trackableEntity.getEvent(),
trackableEntity.getKey(),
trackableEntity.getValue(),
trackableEntity.getCancelValue(),
trackableEntity.getKeyBackValue(),
trackableEntity.getLogShowEvent());
} else {
dialog = new Dialog(context, R.style.GhAlertDialog);
}
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_new_alert, null);
TextView titleTv = contentView.findViewById(R.id.title);
TextView contentTv = contentView.findViewById(R.id.content);
TextView cancelBtn = contentView.findViewById(R.id.cancel);
TextView confirmBtn = contentView.findViewById(R.id.confirm);
View middleLine = contentView.findViewById(R.id.middle_line);
titleTv.setText(title);
contentTv.setText(message);
cancelBtn.setText(negative);
confirmBtn.setText(positive);
if (negative.isEmpty()) {
cancelBtn.setVisibility(View.GONE);
middleLine.setVisibility(View.GONE);
confirmBtn.setTextColor(ContextCompat.getColor(context, R.color.text_333333));
}
if (positive.isEmpty()) {
confirmBtn.setVisibility(View.GONE);
middleLine.setVisibility(View.GONE);
}
cancelBtn.setOnClickListener(v -> {
if (clListener != null) clListener.onCancel();
dialog.dismiss();
});
confirmBtn.setOnClickListener(v -> {
if (cmListener != null) cmListener.onConfirm();
dialog.dismiss();
});
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
return dialog;
}
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
, String negative, String positive, final CancelListener clListener, final ConfirmListener cmListener) {
return showNewAlertDialog(context, title, message, negative, positive, null, clListener, cmListener);
}
/**
* Material Design 风格弹窗
*
@ -899,7 +987,7 @@ public class DialogUtils {
params.horizontalMargin = 0;
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(40);
int height = context.getResources().getDisplayMetrics().heightPixels - DisplayUtils.dip2px(120);
int maxHeight = DisplayUtils.dip2px(546);
int maxHeight = DisplayUtils.dip2px(446);
if (height > maxHeight) {
params.height = maxHeight;
} else {
@ -935,8 +1023,10 @@ public class DialogUtils {
if (hierarchy != null) {
if (position == 0) {
hierarchy.setPlaceholderImage(R.drawable.permission_storage);
} else {
} else if (position == 1) {
hierarchy.setPlaceholderImage(R.drawable.permission_phone_state);
} else {
hierarchy.setPlaceholderImage(R.drawable.permission_sdk);
}
}
}
@ -959,9 +1049,8 @@ public class DialogUtils {
@Override
public void onClick(@NonNull View widget) {
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击隐私政策");
Intent intent = WebActivity.getPrivacyPolicyIntent(activityContext);
activityContext.startActivity(intent);
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击隐私政策");
DirectUtils.directToExternalBrowser(context, context.getString(R.string.privacy_policy_url));
}
}, skipText.length() - 9, skipText.length() - 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@ -975,11 +1064,26 @@ public class DialogUtils {
@Override
public void onClick(@NonNull View widget) {
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击用户协议");
activityContext.startActivity(WebActivity.getWebIntent(activityContext));
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击用户协议");
DirectUtils.directToExternalBrowser(context, context.getString(R.string.disclaimer_url));
}
}, skipText.length() - 4, skipText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
/*skipText.setSpan(new ClickableSpan() {
@Override
public void updateDrawState(@NonNull TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(ContextCompat.getColor(activityContext, R.color.theme_font));
ds.setUnderlineText(false);
}
@Override
public void onClick(@NonNull View widget) {
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击第三方SDK接入说明");
activityContext.startActivity(WebActivity.getThirdPartySdkStatementIntent(activityContext));
}
}, skipText.length() - 10, skipText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);*/
title.setText(entity.getTitle());
linkContent.setText(skipText);
linkContent.setMovementMethod(new LinkMovementMethod());
@ -989,30 +1093,30 @@ public class DialogUtils {
allowButton.setOnClickListener(view -> {
dialog.dismiss();
callback.onCallback();
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击同意");
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击同意");
});
disallowButton.setOnClickListener(v -> {
dialog.dismiss();
showPrivacyPolicyDisallowDialog(activityContext, entity, callback);
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "不同意并退出App");
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "不同意并退出App");
});
dialog.setOnCancelListener(cd -> {
if (isCanceledByClickOutsideOfDialog.get()) {
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击空白");
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击空白");
}
});
dialog.setOnKeyListener((dialog1, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
isCanceledByClickOutsideOfDialog.set(false);
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击返回");
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击返回");
}
return false;
});
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "出现弹窗");
// 用户未同意隐私策略不应该触发 MTA 事件
// MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "出现弹窗");
try {
dialog.setCancelable(false);
@ -1033,14 +1137,16 @@ public class DialogUtils {
View reviewButton = contentView.findViewById(R.id.review_button);
backButton.setOnClickListener(v -> {
MtaHelper.onEvent("隐私政策弹窗", "退出提示弹窗", "退出应用");
// 用户未同意隐私策略不应该触发 MTA 事件
// MtaHelper.onEvent("隐私政策弹窗", "退出提示弹窗", "退出应用");
dialog.dismiss();
AppManager.getInstance().appExit(activityContext);
});
reviewButton.setOnClickListener(v -> {
MtaHelper.onEvent("隐私政策弹窗", "退出提示弹窗", "再次查看");
// MtaHelper.onEvent("隐私政策弹窗", "退出提示弹窗", "再次查看");
callback.onCallback();
dialog.dismiss();
showPrivacyPolicyDialog(activityContext, entity, callback);
//showPrivacyPolicyDialog(activityContext, entity, callback);
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
@ -1574,29 +1680,222 @@ public class DialogUtils {
dialog.show();
}
public static void showUploadVideoChangeLabelDialog(Context context, @NonNull ConfirmListener confirmListener) {
public static void showVideoComplaintDialog(Context context,
List<String> options,
List<String> disabledOptions,
OptionCallback callback) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
Dialog dialog = new Dialog(context);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_upload_video_change_label, null);
View view = LayoutInflater.from(context).inflate(R.layout.dialog_video_complaint, null, false);
LinearLayout complaintContainer = view.findViewById(R.id.complaintContainer);
ConstraintLayout otherComplaintContainer = view.findViewById(R.id.otherComplaintContainer);
EditText complaintCommentEt = view.findViewById(R.id.complaintCommentEt);
TextView backTv = view.findViewById(R.id.backTv);
TextView commitTv = view.findViewById(R.id.commitTv);
Context finalContext = context;
//添加透明阴影,实现类似 clipPadding=false 效果
complaintCommentEt.setShadowLayer(complaintCommentEt.getExtendedPaddingBottom(), 0f, 0f, Color.TRANSPARENT);
View cancelBtn = contentView.findViewById(R.id.cancel);
View confirmBtn = contentView.findViewById(R.id.confirm);
cancelBtn.setOnClickListener(v -> {
dialog.dismiss();
ExtensionsKt.setTextChangedListener(complaintCommentEt, (s, start, before, count) -> {
commitTv.setTextColor(ContextCompat.getColor(finalContext, s.toString().trim().isEmpty() ? R.color.text_999999 : R.color.theme_font));
return null;
});
confirmBtn.setOnClickListener(v -> {
confirmListener.onConfirm();
dialog.dismiss();
for (String option : options) {
TextView reportTv = new TextView(context);
reportTv.setText(option);
reportTv.setTextSize(16f);
if (disabledOptions != null && disabledOptions.contains(option)) {
reportTv.setTextColor(ContextCompat.getColor(context, R.color.btn_gray));
} else {
reportTv.setTextColor(ContextCompat.getColor(context, R.color.title));
reportTv.setBackgroundResource(R.drawable.textview_white_style);
}
reportTv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTv.setPadding(DisplayUtils.dip2px(context, 20f), DisplayUtils.dip2px(context, 17f),
DisplayUtils.dip2px(context, 20f), DisplayUtils.dip2px(context, 17f));
if (option.equals("其它")) {
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.ic_complaint_arrow_right);
drawable.setBounds(0, 0, DisplayUtils.dip2px(6f), DisplayUtils.dip2px(10f));
reportTv.setCompoundDrawables(null, null, drawable, null);
}
complaintContainer.addView(reportTv);
reportTv.setOnClickListener(v -> {
if (option.equals("其它")) {
complaintContainer.setVisibility(View.GONE);
otherComplaintContainer.setVisibility(View.VISIBLE);
complaintCommentEt.requestFocus();
Util_System_Keyboard.showSoftKeyboard(finalContext, complaintCommentEt);
} else {
dialog.cancel();
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("reason", reportTv.getText().toString());
} catch (JSONException e) {
e.printStackTrace();
}
callback.onClicked(jsonObject.toString());
}
});
}
backTv.setOnClickListener(v -> {
Util_System_Keyboard.hideSoftKeyboard(finalContext, complaintCommentEt);
complaintContainer.setVisibility(View.VISIBLE);
otherComplaintContainer.setVisibility(View.GONE);
});
commitTv.setOnClickListener(v -> {
if (complaintCommentEt.getText().toString().isEmpty()) {
ToastUtils.INSTANCE.showToast("请先输入说明~");
return;
}
dialog.cancel();
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("reason", "其它");
jsonObject.put("description", complaintCommentEt.getText().toString());
} catch (JSONException e) {
e.printStackTrace();
}
callback.onClicked(jsonObject.toString());
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
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(40f);
window.setAttributes(params);
}
}
public static void showViewBadgeDialog(Context context, Badge badge, ConfirmListener listener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_view_badge, null);
TextView titleTv = contentView.findViewById(R.id.dialog_title);
TextView contentTv = contentView.findViewById(R.id.dialog_content);
SimpleDraweeView badgeView = contentView.findViewById(R.id.dialog_badge);
ImageView badgeLightBg = contentView.findViewById(R.id.dialog_badge_light_bg);
ImageUtils.display(badgeView, badge.getIcon());
titleTv.setText(badge.getName());
// 领取条件文本超过一行就不显示
if (badge.getActions() == null || badge.getActions().isEmpty() || badge.getActions().size() > 1) {
contentTv.setVisibility(View.INVISIBLE);
} else {
contentTv.setText(badge.getActions().get(0).getText());
contentTv.post(() -> {
if (contentTv.getLineCount() > 1) contentTv.setVisibility(View.INVISIBLE);
});
}
Animation animation = AnimationUtils.loadAnimation(context, R.anim.anim_badge_light_bg);
badgeLightBg.startAnimation(animation);
contentView.findViewById(R.id.dialog_ok).setOnClickListener(v -> {
listener.onConfirm();
badgeLightBg.clearAnimation();
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
public static void showReceiveBadgeDialog(Context context, BadgeEntity badge, ConfirmListener listener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_receive_badge, null);
TextView titleTv = contentView.findViewById(R.id.dialog_title);
TextView contentTv = contentView.findViewById(R.id.dialog_content);
SimpleDraweeView badgeView = contentView.findViewById(R.id.dialog_badge);
ImageView badgeLightBg = contentView.findViewById(R.id.dialog_badge_light_bg);
TextView receiveTv = contentView.findViewById(R.id.dialog_ok);
ImageUtils.display(badgeView, badge.getIcon());
titleTv.setText(badge.getName());
// 领取条件文本超过一行就不显示
if (badge.getActions() == null || badge.getActions().isEmpty() || badge.getActions().size() > 1) {
contentTv.setVisibility(View.INVISIBLE);
} else {
contentTv.setText(badge.getActions().get(0).getText());
contentTv.post(() -> {
if (contentTv.getLineCount() > 1) contentTv.setVisibility(View.INVISIBLE);
});
}
if ("self".equals(badge.getReceive().getType())) {
receiveTv.setText(R.string.receive_badge);
} else {
receiveTv.setText(R.string.apply_badge);
}
Animation animation = AnimationUtils.loadAnimation(context, R.anim.anim_badge_light_bg);
badgeLightBg.startAnimation(animation);
contentView.findViewById(R.id.dialog_ok).setOnClickListener(v -> {
listener.onConfirm();
badgeLightBg.clearAnimation();
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
public static void showPassRegulationDialog(Context context, String icon) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_pass_regulation, null);
SimpleDraweeView userIcon = contentView.findViewById(R.id.dialog_icon);
ImageUtils.display(userIcon, icon);
contentView.findViewById(R.id.dialog_ok).setOnClickListener(v -> {
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
public static void showShortCutPermissionDialog(Context context) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_shortcut_permission, null);
Context finalContext = context;
contentView.findViewById(R.id.dialog_positive).setOnClickListener(v -> {
dialog.dismiss();
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + finalContext.getPackageName()));
finalContext.startActivity(intent);
});
contentView.findViewById(R.id.dialog_negative).setOnClickListener(v -> {
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);

View File

@ -8,6 +8,7 @@ import android.os.Bundle
import android.text.TextUtils
import androidx.appcompat.app.AppCompatActivity
import com.gh.base.BaseActivity
import com.gh.base.BaseActivity_TabLayout
import com.gh.base.ToolBarActivity
import com.gh.base.fragment.BaseFragment_TabLayout
import com.gh.common.AppExecutor
@ -62,6 +63,9 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.greenrobot.eventbus.EventBus
import retrofit2.HttpException
import java.net.URLEncoder
import java.util.*
import kotlin.math.roundToInt
/**
* 跳转用的方法
@ -260,7 +264,7 @@ object DirectUtils {
* 跳转至QA
*/
@JvmStatic
fun directToQa(context: Context, text: String, id: String) {
fun directToQa(context: Context, text: String? = "", id: String) {
if (id.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, QaActivity::class.java.simpleName)
@ -768,7 +772,29 @@ object DirectUtils {
*/
@JvmStatic
fun directToBadgeWall(context: Context, userId: String?, name: String?, icon: String?) {
context.startActivity(WebActivity.getBadgeCenterIntent(context, userId, name, icon))
var url: String = if ("internal" == BuildConfig.FLAVOR) {
Constants.BADGE_ADDRESS_DEV
} else {
Constants.BADGE_ADDRESS
}
url = String.format(Locale.CHINA, "%s?user_id=%s&name=%s&icon=%s&timestamp=%d", url, userId, name, URLEncoder.encode(icon), (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
* 跳转至徽章详情
*/
@JvmStatic
fun directToBadgeDetail(context: Context, userId: String?, badgeId: String?) {
var url: String = if ("internal" == BuildConfig.FLAVOR) {
Constants.BADGE_DETAIL_ADDRESS_DEV
} else {
Constants.BADGE_DETAIL_ADDRESS
}
url = String.format(Locale.CHINA, "%s?user_id=%s&badge_id=%s&timestamp=%d", url, userId, badgeId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
directToFullScreenWebPage(context, url, true)
}
/**
@ -1005,4 +1031,16 @@ object DirectUtils {
jumpActivity(context, Bundle().apply { putInt(KEY_POSITION, MainWrapperFragment.INDEX_ASK) })
}
}
/**
* 跳转至使用帮助与反馈
* @param position 使用帮助:[HelpAndFeedbackActivity.HELP_ITEM],意见反馈:[HelpAndFeedbackActivity.SUGGESTION_ITEM]
*/
@JvmStatic
fun directToHelpAndFeedback(context: Context, position: Int = HelpAndFeedbackActivity.HELP_ITEM) {
val bundle = Bundle()
bundle.putString(KEY_TO, HelpAndFeedbackActivity::class.java.name)
bundle.putInt(BaseActivity_TabLayout.PAGE_INDEX, position)
jumpActivity(context, bundle)
}
}

View File

@ -15,6 +15,8 @@ import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.history.HistoryHelper;
import com.gh.common.repository.ReservationRepository;
import com.gh.common.simulator.SimulatorDownloadManager;
import com.gh.common.simulator.SimulatorGameManager;
import com.gh.common.xapk.XapkInstaller;
import com.gh.common.xapk.XapkUnzipStatus;
import com.gh.download.DownloadManager;
@ -34,6 +36,7 @@ import com.lightgame.download.DownloadStatus;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
import java.io.File;
import java.util.concurrent.LinkedBlockingQueue;
import androidx.annotation.Nullable;
@ -195,6 +198,10 @@ public class DownloadItemUtils {
holder.gameDownloadBtn.setText("查看");
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(context, R.color.white));
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
} else if ("updating".equals(offStatus)) {
holder.gameDownloadBtn.setText("更新中");
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(context, R.color.white));
holder.gameDownloadBtn.setBackgroundResource(R.drawable.download_button_updating_style);
} else {
holder.gameDownloadBtn.setText("暂无");
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(context, R.color.button_gray));
@ -223,9 +230,18 @@ public class DownloadItemUtils {
if (entryMap != null && !entryMap.isEmpty()) {
DownloadEntity downloadEntity = entryMap.get(apkEntity.getPlatform());
if (downloadEntity != null) {
// 更改进度条和提示文本的状态
changeStatus(context, holder, downloadEntity, isShowPlatform, true);
return;
if (ExtensionsKt.isSimulatorGame(downloadEntity)) {
if (downloadEntity.getStatus() != DownloadStatus.done) {
// 更改进度条和提示文本的状态
changeStatus(context, holder, downloadEntity, isShowPlatform, true);
return;
}
} else {
// 更改进度条和提示文本的状态
changeStatus(context, holder, downloadEntity, isShowPlatform, true);
return;
}
}
}
@ -468,7 +484,7 @@ public class DownloadItemUtils {
HistoryHelper.insertGameEntity(gameEntity);
}
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay,linkEntity.getCloseButton());
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton());
context.startActivity(i);
});
} else if (gameEntity.getApk().size() == 1) {
@ -506,7 +522,115 @@ public class DownloadItemUtils {
});
});
}
}
/**
* @param clickCallback 供那些需要知道点击回调的地方使用,只要触发了点击事件就响应回调(未登录状态下点击预约也要响应回调)
*/
public static void setOnClickListenerWithInvokeCallbackForAllState(final Context context,
final TextView downloadBtn,
final GameEntity gameEntity,
final int position,
final RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter,
final String entrance,
final String location,
final ExposureEvent traceEvent,
@Nullable final EmptyCallback clickCallback) {
if (gameEntity.isReservable()) {
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
CheckLoginUtils.checkLogin(context, entrance, () -> {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
gameEntity,
() -> {
LogUtils.logReservation(gameEntity, traceEvent);
adapter.notifyItemChanged(position);
}
);
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
});
});
});
} else {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
if ("download".equals(gameEntity.getReserveStatus())) {
ReservationHelper.showDeleteReservationDialog(context, () -> {
ReservationHelper.deleteReservation(gameEntity, () -> {
adapter.notifyItemChanged(position);
});
});
} else {
ReservationHelper.showCancelReservationDialog(context, () -> {
ReservationHelper.cancelReservation(gameEntity, () -> {
adapter.notifyItemChanged(position);
});
});
}
});
}
return;
}
if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
LinkEntity linkEntity = gameEntity.getH5Link();
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
if (isPlay) {
HistoryHelper.insertGameEntity(gameEntity);
}
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton());
context.startActivity(i);
});
} else if (gameEntity.getApk().size() == 1) {
downloadBtn.setOnClickListener(v -> {
EmptyCallback clickRunnable = () -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent);
};
// 启动不需要请求存储权限
if (downloadBtn.getText().toString().equals(context.getString(R.string.launch))) {
clickRunnable.onCallback();
} else {
PermissionHelper.checkStoragePermissionBeforeAction(context, clickRunnable);
}
});
} else {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
PermissionHelper.checkStoragePermissionBeforeAction(context, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location);
});
});
});
});
}
}
public static void onNormalClick(final Context context,
@ -541,6 +665,7 @@ public class DownloadItemUtils {
});
});
DataLogUtils.uploadGameLog(context, gameEntity.getId(), gameEntity.getName(), entrance);
} else if (str.equals(context.getString(R.string.attempt))) {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
@ -570,8 +695,30 @@ public class DownloadItemUtils {
});
}
} else if (str.equals(context.getString(R.string.install))) {
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(apk.getUrl());
if (gameEntity.getSimulator() != null) {
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(context, gameEntity.getSimulator().getApk().getPackageName());
if (downloadEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity) && !isInstalled) {
SimulatorDownloadManager.getInstance().showDownloadDialog(context, gameEntity.getSimulator(),
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(),null);
return;
}
}
install(context, gameEntity, position, adapter);
} else if (str.equals(context.getString(R.string.launch))) {
//启动模拟器游戏
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
if (downloadEntity != null) {
File file = new File(downloadEntity.getPath());
if (!file.exists()) {
download(context, gameEntity, downloadBtn, entrance, location, false, traceEvent);
return;
}
SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity);
}
return;
}
if (entrance.contains("我的游戏")) {
MtaHelper.onEvent("我的游戏_启动", "启动", gameEntity.getName());
}

View File

@ -16,6 +16,7 @@ import com.gh.gamecenter.R
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import com.walkud.rom.checker.RomIdentifier
object DownloadNotificationHelper {
@ -29,6 +30,7 @@ object DownloadNotificationHelper {
const val ACTION_DOWNLOAD = "com.gh.gamecenter.DOWNLOAD"
private val mNotifyMap: MutableMap<String, Long> = mutableMapOf()
private val mShouldUseAlternativeNotificationIcon by lazy { RomIdentifier.getRom().versionName == null }
private fun getNotificationManager(): NotificationManager {
return HaloApp.getInstance().application.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@ -43,6 +45,7 @@ object DownloadNotificationHelper {
val xapkStatus = entity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
if (entity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.SILENT_UPDATE) return
if (entity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.SIMULATOR_DOWNLOAD) return
val intent = Intent()
if (entity.status == DownloadStatus.done && xapkStatus != XapkUnzipStatus.FAILURE.name) {
@ -65,7 +68,7 @@ object DownloadNotificationHelper {
val whenTime = 1000 * 60 * (System.currentTimeMillis() / 1000 / 60)
val builder = NotificationCompat.Builder(HaloApp.getInstance().application, DOWNLOAD_CHANNEL_ID)
.setContentTitle(entity.name)
.setSmallIcon(R.mipmap.logo)
.setSmallIcon(getNotificationIcon())
.setContentIntent(pendingIntent)
.setGroup(DOWNLOAD_GROUP_KEY)
.setWhen(whenTime)
@ -112,7 +115,8 @@ object DownloadNotificationHelper {
|| entity.status == DownloadStatus.overflow
|| (entity.status == DownloadStatus.done // 触发安装事件以后也 cancel 掉通知
&& !entity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION].isNullOrEmpty()
&& xapkStatus != XapkUnzipStatus.FAILURE.name)) {
&& xapkStatus != XapkUnzipStatus.FAILURE.name)
||entity.status == DownloadStatus.done && entity.isSimulatorGame()) {//模拟器游戏下载完需要cancel掉通知
requireUpdateNotificationGroupDelay = true
notificationManager.cancel(entity.path, DOWNLOAD_NOTIFICATION_ID)
} else {
@ -160,7 +164,7 @@ object DownloadNotificationHelper {
notificationManager.cancel(DOWNLOAD_NOTIFICATION_FOLD_ID)
} else if (downloadNotificationSize != 0 && downloadGroupNotificationSize == 0) {
val groupBuilder = NotificationCompat.Builder(HaloApp.getInstance().application, DOWNLOAD_CHANNEL_ID)
.setSmallIcon(R.mipmap.logo)
.setSmallIcon(getNotificationIcon())
.setGroup(DOWNLOAD_GROUP_KEY)
.setGroupSummary(true)
.setStyle(NotificationCompat.BigTextStyle().bigText("下载任务"))
@ -178,4 +182,8 @@ object DownloadNotificationHelper {
addOrUpdateDownloadNotification(downloadTask)
}
}
private fun getNotificationIcon(): Int {
return if (mShouldUseAlternativeNotificationIcon) R.drawable.ic_notification else R.mipmap.logo
}
}

View File

@ -6,6 +6,9 @@ import android.preference.PreferenceManager
import com.gh.base.BaseActivity
import com.gh.common.constant.Constants
import com.gh.common.exposure.ExposureUtils
import com.gh.common.simulator.SimulatorDownloadManager
import com.gh.common.simulator.SimulatorGameManager
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.xapk.XapkInstaller
import com.gh.download.DownloadDataHelper
import com.gh.download.DownloadManager
@ -26,7 +29,6 @@ import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import com.lightgame.download.FileUtils
import com.lightgame.utils.AppManager
import com.lightgame.utils.Util_System_Phone_State
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
@ -59,8 +61,8 @@ object DownloadObserver {
if (DownloadStatus.hijack == downloadEntity.status) {
// 链接被劫持
processHijack(downloadEntity)
val nameAndPlatform = (downloadEntity.name + ":"
+ PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
// val nameAndPlatform = (downloadEntity.name + ":"
// + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
// MtaHelper.onEvent("下载劫持",
// "游戏名字", nameAndPlatform,
// "网络状态", DeviceUtils.getNetwork(mApplication))
@ -103,6 +105,9 @@ object DownloadObserver {
Utils.log("DownloadObserver", "下载自动暂停->" + downloadEntity.toJson())
}
}
} else if (DownloadStatus.redirected == downloadEntity.status) {
debugOnly { Utils.log("重定向完毕") }
DownloadDataHelper.uploadRedirectEvent(downloadEntity)
}
if (DownloadStatus.done == downloadEntity.status) {
if (downloadEntity.name.contains(mApplication.getString(R.string.app_name))) {
@ -130,20 +135,36 @@ object DownloadObserver {
Utils.toast(mApplication, downloadEntity.name + " - 下载完成")
}
if (!downloadEntity.isPluggable) {
// 是否是自动安装
if (PreferenceManager.getDefaultSharedPreferences(mApplication).getBoolean(SettingsFragment.AUTO_INSTALL_SP_KEY, true)) {
if (FileUtils.isEmptyFile(downloadEntity.path)) {
Utils.toast(mApplication, R.string.install_failure_hint)
downloadManager.cancel(downloadEntity.url)
} else {
if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) {
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
tryWithDefaultCatch {
PackageInstaller.install(mApplication, downloadEntity, false)
}
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) {
SimulatorDownloadManager.getInstance().showDownloadDialog(AppManager.getInstance().currentActivity(), gameEntity.simulator,
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.id, gameEntity.name
?: "", null)
}
SimulatorGameManager.recordDownloadSimulatorGames(gameEntity.id)
SimulatorGameManager.postPlayedGame(gameEntity.id, downloadEntity.packageName)
}
} else {
val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
// 是否是自动安装
val isAutoInstall = PreferenceManager.getDefaultSharedPreferences(mApplication).getBoolean(SettingsFragment.AUTO_INSTALL_SP_KEY, true)
if (downloadType == Constants.SIMULATOR_DOWNLOAD || isAutoInstall) {
if (FileUtils.isEmptyFile(downloadEntity.path)) {
Utils.toast(mApplication, R.string.install_failure_hint)
downloadManager.cancel(downloadEntity.url)
} else {
// 弹出卸载提示框
EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path))
if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) {
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
tryWithDefaultCatch {
PackageInstaller.install(mApplication, downloadEntity, false)
}
} else {
// 弹出卸载提示框
EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path))
}
}
}
}
@ -194,7 +215,7 @@ object DownloadObserver {
kv1["版本"] = platform
kv1["状态"] = "下载完成"
kv1["用户机型"] = Build.MODEL
kv1["设备IMEI"] = Util_System_Phone_State.getDeviceId(HaloApp.getInstance().application)
kv1["设备IMEI"] = MetaUtil.getIMEI()
kv1["网络状态"] = DeviceUtils.getNetwork(HaloApp.getInstance().application)
kv1["光环助手版本"] = BuildConfig.VERSION_NAME
if (downloadEntity.isUpdate) {
@ -237,6 +258,8 @@ object DownloadObserver {
gameVersion = downloadEntity.versionName ?: ""),
downloadEntity.platform,
downloadEntity.exposureTrace,
downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown",
downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown",
type)
DataCollectionUtils.uploadDownload(mApplication, downloadEntity, "完成")

View File

@ -8,6 +8,9 @@ import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.gh.common.avoidcallback.AvoidOnResultManager;
import com.gh.common.avoidcallback.Callback;
import com.gh.gamecenter.BuildConfig;
@ -23,9 +26,6 @@ import org.json.JSONObject;
import java.util.Iterator;
import java.util.Set;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
/**
* @author CsHeng
@ -89,6 +89,8 @@ public class EntranceUtils {
public static final String HOST_TOOLBOX = "toolbox";
public static final String HOST_FORUM_DETAIL = "forum_detail";
public static final String HOST_GAME_RATING_DETAIL = "game_rating_detail";
public static final String HOST_HELP_AND_FEEDBACK = "help_and_feedback";
public static final String HOST_LAUNCH_SIMULATOR_GAME = "launch_simulator_game";
public static final String KEY_DATA = "data";
public static final String KEY_MESSAGE = "message";
public static final String KEY_MESSAGE_ID = "message_id";
@ -120,6 +122,7 @@ public class EntranceUtils {
public static final String KEY_COMMENT_ID = "comment_id";
public static final String KEY_SHOW_KEYBOARD_IF_NEEDED = "show_key_board_if_needed";
public static final String KEY_PATH = "path";
public static final String KEY_LOCAL_PATH = "local_path";
public static final String KEY_OUTER_INFO = "outerInfo";
public static final String KEY_OLDERUSER = "isOldUser";
public static final String KEY_SEARCHKEY = "searchKey";
@ -195,6 +198,9 @@ public class EntranceUtils {
public static final String KEY_SECTION_NAME = "section_name"; // 专区专题名
public static final String KEY_COLUMNNAME = "columnName";
public static final String KEY_QA_ID = "qaId";
public static final String KEY_QA_CONTENT_ID = "qaContentId";
public static final String KEY_QA_CATEGORY_NAME = "qaCategoryName";
public static final String KEY_QA_TITLE = "qa_title";
public static final String KEY_QA_COLLECTION_ID = "qaCollectionId";
public static final String KEY_SHOW_EDIT_DRAFT = "showEditDraft";
public static final String KEY_ARTICLE_OPEN_IN_NEW_PAGE = "openArticleInNewPage";
@ -207,6 +213,8 @@ public class EntranceUtils {
public static final String KEY_CONFLICT_PHONE = "conflictPhone";
public static final String KEY_CONFLICT_USER = "conflictUser";
public static final String KEY_BBS_ID = "bbs_id";
public static final String KEY_DIAGNOSIS = "diagnosis";
public static final String KEY_SIMULATOR = "simulator";
public static void jumpActivity(Context context, Bundle bundle) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);

View File

@ -15,6 +15,7 @@ import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.PopupWindow
import android.widget.SeekBar
import android.widget.TextView
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
@ -185,6 +186,10 @@ fun View.setDebouncedClickListener(action: () -> Unit) {
setOnClickListener { debounceActionWithInterval(interval = 300L) { action.invoke() } }
}
fun isPublishEnv(): Boolean {
return BuildConfig.FLAVOR != "internal"
}
/**
* LiveData Extensions
*/
@ -250,24 +255,25 @@ fun String.containHtmlTag(): Boolean {
* 用户行为相关
*/
fun Fragment.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
DialogUtils.showRegulationTestDialog(requireContext(),
{ DirectUtils.directToRegulationTestPage(requireContext()) },
{ action.invoke() })
} else {
// if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
// DialogUtils.showRegulationTestDialog(requireContext(),
// { DirectUtils.directToRegulationTestPage(requireContext()) },
// { action.invoke() })
// } else {
action()
}
// }
}
fun Context.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
DialogUtils.showRegulationTestDialog(this,
{ DirectUtils.directToRegulationTestPage(this) },
{ action.invoke() })
} else {
// if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
// DialogUtils.showRegulationTestDialog(this,
// { DirectUtils.directToRegulationTestPage(this) },
// { action.invoke() })
// } else {
action()
}
// }
}
/**
* 在限定 interval 里只触发一次 action
*/
@ -425,7 +431,7 @@ fun Float.px2dip(): Int {
return (this / scale + 0.5f).toInt()
}
fun Float.sp2px():Int{
fun Float.sp2px(): Int {
val scale: Float = HaloApp.getInstance().application.resources.displayMetrics.scaledDensity
return (this * scale + 0.5f).toInt()
}
@ -656,6 +662,14 @@ fun DownloadEntity.isSilentUpdate(): Boolean {
return Constants.SILENT_UPDATE == getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
}
fun DownloadEntity.isSimulatorDownload(): Boolean {
return Constants.SIMULATOR_DOWNLOAD == getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
}
fun DownloadEntity.isSimulatorGame(): Boolean {
return getMetaExtra(Constants.SIMULATOR_GAME).isNotEmpty()
}
/**
* Process related
*/
@ -818,4 +832,21 @@ fun EditText.showKeyBoard() {
val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.showSoftInput(this, 0)
}, 300)
}
fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)? = null, onStopTrackingTouch: (() -> Unit)? = null) {
this.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
progressChange?.invoke(progress)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
onStopTrackingTouch?.invoke()
}
})
}

View File

@ -0,0 +1,23 @@
package com.gh.common.util
import com.gh.common.OnFastClickListener
import io.reactivex.disposables.Disposable
import java.lang.ref.WeakReference
object FastClickUtils {
private var disposable: Disposable? = null
private var ref: WeakReference<OnFastClickListener>? = null
fun click(duration: Int = 500, onClick: OnFastClickListener) {
ref = WeakReference(onClick)
disposable?.dispose()
ref?.get()?.invoke(false)
disposable = rxTimer(1) {
if (it >= duration) {
ref?.get()?.invoke(true)
disposable?.dispose()
}
}
}
}

View File

@ -5,9 +5,8 @@ import android.graphics.Color;
import android.text.TextUtils;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.gh.common.constant.Config;
import com.gh.common.simulator.SimulatorGameManager;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.ApkEntity;
@ -24,6 +23,8 @@ import com.lightgame.download.DownloadStatus;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.Nullable;
public class GameUtils {
/**
@ -116,16 +117,27 @@ public class GameUtils {
installCount++;
}
}
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
DownloadEntity simulatorDownloadEntity = SimulatorGameManager.findDownloadEntityByUrl(apkEntity.getUrl());
if (simulatorDownloadEntity != null && gameEntity.getSimulator() != null) {
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(context, gameEntity.getSimulator().getApk().getPackageName());
if (isInstalled) {
installCount++;
} else {
doneCount++;
}
}
}
}
if (doneCount != 0) {
return context.getString(R.string.install);
} else if (pluginCount != 0) {
return context.getString(R.string.pluggable);
} else if (updateCount != 0) {
return context.getString(R.string.update);
} else if (installCount != 0) {
if (installCount != 0) {
return context.getString(R.string.launch);
} else if (gameEntity.getVersionNumber().contains("无版号") && Config.isGameDomeSwitchOpen()) {
} 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 (gameEntity.getVersionNumber().contains("无版号") && Config.isGameDomeSwitchOpen() && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
return context.getString(R.string.attempt);
} else {
return context.getString(R.string.download);
@ -238,7 +250,7 @@ public class GameUtils {
}
}
}
collectionEntity.setSaveApkEntity(saveApkEntity);
return collectionEntity;
}

View File

@ -1,10 +1,6 @@
package com.gh.common.util
import android.app.Application
import android.text.TextUtils
import com.lightgame.utils.Utils
import com.qq.gdt.action.GDTAction
import org.json.JSONObject
/**
* 广点通辅助类 [https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/403]
@ -22,32 +18,38 @@ object GdtHelper {
const val SCORE = "SCORE"
const val PLATFORM = "PLATFORM"
fun init(application: Application) {
GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a")
fun init(application: Application, channel: String) {
// if (channel == "GH_728") {
// GDTAction.init(application, "1111012969", "9d3d9da5b0948a317c03d08f14d445dc")
// } else if (channel == "GH_729") {
// GDTAction.init(application, "1111013063", "f53dabf458a356b101d99fc4069eb7f1")
// } else {
// GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a")
// }
}
fun logAction(type: String) {
GDTAction.logAction(type)
Utils.log("GDT", type)
// GDTAction.logAction(type)
// Utils.log("GDT", type)
}
fun logAction(type: String, vararg kv: String?) {
try {
val actionParam = JSONObject()
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
actionParam.put(key, value)
}
}
}
Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]")
GDTAction.logAction(type, actionParam)
} catch (e: Exception) {
e.printStackTrace()
}
// try {
// val actionParam = JSONObject()
// for (i in kv.indices) {
// if (i % 2 != 0) {
// val key = kv[i - 1]
// val value = kv[i]
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
// actionParam.put(key, value)
// }
// }
// }
// Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]")
// GDTAction.logAction(type, actionParam)
// } catch (e: Exception) {
// e.printStackTrace()
// }
}
}

View File

@ -10,6 +10,8 @@ import org.json.JSONArray
* Created by khy on 11/10/17.
*/
object GsonUtils {
@JvmStatic
val gson: Gson = Gson()
val gsonThatIgnoreNull: Gson = GsonBuilder().serializeNulls().create()
@ -20,14 +22,22 @@ object GsonUtils {
@JvmStatic
fun <T> fromJsonList(json: JSONArray): List<T> {
val type = object : TypeToken<List<T>>() {}.type
return gson.fromJson(json.toString(), type)
return try {
val type = object : TypeToken<List<T>>() {}.type
return gson.fromJson(json.toString(), type)
} catch (e: Exception) {
listOf()
}
}
@JvmStatic
fun <T> fromJsonList(json: String): List<T> {
val type = object : TypeToken<List<T>>() {}.type
return gson.fromJson(json, type)
return try {
val type = object : TypeToken<List<T>>() {}.type
gson.fromJson(json, type)
} catch (e: Exception) {
listOf()
}
}
@JvmStatic

View File

@ -10,15 +10,22 @@ import android.net.Uri
import android.os.Build
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.facebook.common.executors.CallerThreadExecutor
import com.facebook.common.references.CloseableReference
import com.facebook.datasource.DataSource
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.controller.ControllerListener
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
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.gh.common.constant.Config
import com.gh.common.structure.FixedSizeLinkedHashSet
import com.gh.gamecenter.R
import com.halo.assistant.HaloApp
import com.squareup.picasso.Picasso
@ -27,7 +34,6 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.io.ByteArrayOutputStream
object ImageUtils {
private const val PIC_MAX_FILE_SIZE: Long = 10 * 1024 * 1024
@ -36,6 +42,8 @@ object ImageUtils {
private val LARGE_GIF_SIZE = 80F.dip2px()
private val STANDARD_GIF_SIZE = 60F.dip2px()
private val mImageUrlCacheSet by lazy { FixedSizeLinkedHashSet<String>(maxSize = 200) }
@JvmStatic
fun getUploadFileMaxSize(): Long {
val uploadLimitSize = Config.getSettings()?.image?.uploadLimitSize
@ -221,11 +229,44 @@ object ImageUtils {
.build()
}
// 获取bitmap (使用 fresco 获取 gif bitmap 会为空https://github.com/facebook/fresco/issues/241)
// 所以这里换用 picasso
/**
* 获取bitmap (使用 fresco 获取 gif 的 bitmap 会为空https://github.com/facebook/fresco/issues/241)
* 所以当 url 以 .gif 结尾时换用 picasso 获取
* 优先使用 fresco 是因为可能已经有了缓存
*/
@SuppressLint("CheckResult")
@JvmStatic
fun getBitmap(url: String, callback: BiCallback<Bitmap, Boolean>) {
if (url.endsWith(".gif")) {
getBitmapWithPicasso(url, callback)
} else {
getBitmapWithFresco(url, callback)
}
}
private fun getBitmapWithFresco(url: String, callback: BiCallback<Bitmap, Boolean>) {
val imageRequest = ImageRequestBuilder
.newBuilderWithSource(Uri.parse(url))
.build()
Fresco.getImagePipeline()
.fetchDecodedImage(imageRequest, HaloApp.getInstance().application)
.subscribe(object : BaseBitmapDataSubscriber() {
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
callback.onSecond(true)
}
override fun onNewResultImpl(bitmap: Bitmap?) {
if (bitmap != null) {
callback.onFirst(bitmap)
} else {
callback.onSecond(true)
}
}
}, CallerThreadExecutor.getInstance())
}
@SuppressLint("CheckResult")
private fun getBitmapWithPicasso(url: String, callback: BiCallback<Bitmap, Boolean>) {
Single.just(url)
.map { Picasso.with(HaloApp.getInstance().application).load(url).priority(Picasso.Priority.HIGH).get() }
.subscribeOn(Schedulers.io())
@ -246,34 +287,56 @@ object ImageUtils {
@JvmStatic
fun display(view: SimpleDraweeView?, url: String?) {
url?.let {
// 图片是以 gif 结尾的就
if (it.endsWith(".gif") && view?.getTag(R.id.tag_show_gif) != false) {
if (view?.tag == url) return@let
val width = view?.layoutParams?.width
val height = view?.layoutParams?.height
if (width != null && width > 0) {
val controller = Fresco.newDraweeControllerBuilder()
.setUri(resizeGif(url, width, height ?: 0))
.setAutoPlayAnimations(true)
.build()
view.controller = controller
} else {
view?.post {
val controller = Fresco.newDraweeControllerBuilder()
.setUri(resizeGif(url, view.width, view.height))
.setAutoPlayAnimations(true)
.build()
view.controller = controller
}
val width = view?.layoutParams?.width
val height = view?.layoutParams?.height
var lowResUrl = ""
var highResUrl = ""
// 找同一图片地址已加载过的图片作为低质量预览图
// TODO 根据实际请求大小(w_width)来避免小图用大图作为低质量图片
for (cachedImageUrl in mImageUrlCacheSet) {
if (cachedImageUrl.contains(url)) {
lowResUrl = cachedImageUrl
break
}
} else {
val width = view?.layoutParams?.width
if (width != null && width > 0) {
view.setImageURI(getTransformLimitUrl(url, width, view.context))
}
val loadImageClosure: (autoPlay: Boolean, highResUrl: String, lowResUrl: String) -> Unit = { autoPlay, hUrl, lUrl ->
view?.controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(ImageRequest.fromUri(hUrl))
.apply {
if (lUrl.isNotEmpty()
&& lUrl != hUrl
&& hUrl != view?.getTag(R.string.highResImageTag)) {
lowResImageRequest = ImageRequest.fromUri(lUrl)
}
autoPlayAnimations = autoPlay
}
.build()
view?.setTag(R.string.highResImageTag, highResUrl)
}
val shouldLoadAsGif = it.endsWith(".gif") && 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 {
view?.post {
view.setImageURI(getTransformLimitUrl(url, view.width, view.context))
getTransformLimitUrl(url, width, view.context) ?: ""
}
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
} else {
view?.post {
highResUrl = if (shouldLoadAsGif) {
resizeGif(url, view.width, height ?: 0)
} else {
getTransformLimitUrl(url, view.width, view.context) ?: ""
}
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
}
}
view?.tag = url
@ -285,12 +348,13 @@ object ImageUtils {
fun getTransformLimitUrl(url: String?, width: Int?, context: Context?): String? {
var transformUrl: String? = url
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)
&& Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP
&& DeviceUtils.getTotalRamSizeOfDevice(context) > 1000) {
&& HaloApp.getInstance().deviceRamSize > 1024) {
transformUrl = transformUrlX2
} else {
// 检查X2大图是否被缓存
@ -302,7 +366,7 @@ object ImageUtils {
}
}
}
// Utils.log("displayPost::viewWidth->$width----transformUrl->$transformUrl")
addCachedUrl(transformUrl ?: "")
return transformUrl
}
@ -312,15 +376,19 @@ object ImageUtils {
val width = view?.layoutParams?.width
if (width != null && width > 0) {
view.setImageURI(addLimitWidth(url, width * 2))
// Utils.log("displayIcon::viewWidth->" + view.width + "---transformUrl->" + transformUrl)
} else {
view?.post {
view.setImageURI(addLimitWidth(url, view.width * 2))
// Utils.log("displayIcon::viewWidth->" + view.width + "---transformUrl->" + transformUrl)
}
}
}
private fun addCachedUrl(url: String) {
if (url.startsWith("http")) {
mImageUrlCacheSet.add(url)
}
}
@JvmStatic
fun bmpToByteArray(bmp: Bitmap, needRecycle: Boolean): ByteArray {
val output = ByteArrayOutputStream()
@ -355,7 +423,7 @@ object ImageUtils {
private fun resizeGif(url: String, width: Int, height: Int): String {
val idealSize = getIdealGifSize(width, height)
return "$url?x-oss-process=image/resize,h_$idealSize,w_$idealSize"
return "$url?x-oss-process=image/resize,h_$idealSize,w_$idealSize".also { addCachedUrl(it) }
}
private fun getIdealGifSize(width: Int, height: Int): String {

View File

@ -1,10 +1,9 @@
package com.gh.common.util;
import android.content.Context;
import android.provider.Settings;
import android.text.TextUtils;
import com.lightgame.utils.Util_System_Phone_State;
import com.gh.common.exposure.meta.MetaUtil;
import java.io.File;
import java.io.FileOutputStream;
@ -19,11 +18,11 @@ public class Installation {
private static String sID = null;
public synchronized static String getUUID(Context context) {
String imei = Util_System_Phone_State.getDeviceId(context);
String imei = MetaUtil.getIMEI();
if (!TextUtils.isEmpty(imei)) {
return imei;
}
String android_id = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
String android_id = MetaUtil.getAndroidId();
if (!TextUtils.isEmpty(android_id)) {
return android_id;
}

View File

@ -4,11 +4,8 @@ import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.provider.Settings;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.gh.common.constant.Constants;
import com.gh.common.exposure.ExposureEntity;
import com.gh.common.exposure.ExposureEvent;
@ -27,7 +24,6 @@ import com.gh.gamecenter.qa.entity.Questions;
import com.gh.gamecenter.retrofit.EmptyResponse;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Util_System_Phone_State;
import com.lightgame.utils.Utils;
import org.json.JSONException;
@ -36,6 +32,7 @@ import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.Nullable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
@ -257,14 +254,13 @@ public class LogUtils {
try {
object.put("version", PackageUtils.getVersionName());
object.put("channel", HaloApp.getInstance().getChannel());
object.put("android_id", Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID));
object.put("android_id", MetaUtil.getAndroidId());
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", Util_System_Phone_State.getImei(HaloApp.getInstance()
.getApplication()));
object.put("imei", MetaUtil.getIMEI());
object.put("G_ID", UserManager.getInstance().getDeviceId());
} catch (JSONException e) {
e.printStackTrace();
@ -282,14 +278,13 @@ public class LogUtils {
try {
object.put("version", PackageUtils.getVersionName());
object.put("channel", HaloApp.getInstance().getChannel());
object.put("android_id", Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID));
object.put("android_id", MetaUtil.getAndroidId());
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", Util_System_Phone_State.getImei(HaloApp.getInstance()
.getApplication()));
object.put("imei", MetaUtil.getIMEI());
object.put("G_ID", UserManager.getInstance().getDeviceId());
} catch (JSONException e) {
e.printStackTrace();
@ -522,4 +517,124 @@ public class LogUtils {
.subscribeOn(Schedulers.io())
.subscribe(new EmptyResponse<>());
}
public static JSONObject getMetaObject() {
Meta meta = MetaUtil.INSTANCE.getMeta();
JSONObject metaObject = new JSONObject();
try {
metaObject.put("android_id", meta.getAndroid_id());
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("mac", meta.getMac());
metaObject.put("manufacturer", meta.getManufacturer());
metaObject.put("model", meta.getModel());
metaObject.put("network", meta.getNetwork());
metaObject.put("os", meta.getOs());
metaObject.put("userId", meta.getUserId());
} catch (JSONException e) {
e.printStackTrace();
}
return metaObject;
}
private static void uploadCommunity(JSONObject object) {
try {
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "community", false);
}
public static void uploadAccessToBbs(String bbsId, String location) {
JSONObject object = new JSONObject();
JSONObject payload = new JSONObject();
try {
payload.put("location", location);//关注板块/文章外所属论坛/游戏详情/文章内所属论坛
payload.put("bbs_id", bbsId);
object.put("event", "access_to_bbs");
object.put("payload", payload);
} catch (JSONException e) {
e.printStackTrace();
}
uploadCommunity(object);
}
public static void uploadAccessBbsTab() {
JSONObject object = new JSONObject();
try {
object.put("event", "main_tab[bbs]");
} catch (JSONException e) {
e.printStackTrace();
}
uploadCommunity(object);
}
public static void uploadSimulatorDownload(String event, String fileName, String simulatorId, String simulatorName, String gameId, String location, String downloadType, String startTime) {
JSONObject object = new JSONObject();
JSONObject payload = new JSONObject();
try {
object.put("event", event);// 取值有[开始, 完成] [simulator_download, simulator_download_complete]
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
payload.put("filename", fileName);// 下载模拟器文件名,每次新创建的下载任务文件名都不同,可以用来关联同一次的下载开始与完成
payload.put("simulator_id", simulatorId);
payload.put("simulator_name", simulatorName);
payload.put("location", location);//启动《具体的游戏名称》/模拟器游戏/模拟器游戏-模拟器管理
payload.put("game_id", gameId);//如果是 启动《游戏名称》 这种方式, 记录这个游戏具体的游戏ID
payload.put("download_type", downloadType);// update/download 下载类型(更新/下载)
if (!TextUtils.isEmpty(startTime) && event.equals("simulator_download_complete")) {
payload.put("simulator_download_timestamp", startTime);// 对应的下载开始时间
}
object.put("payload", payload);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void uploadSearchGame(String event, String location, String key, String searchType) {
uploadSearchClick(event, location, key, searchType, "", "");
}
public static void uploadSearchClick(String event, String location, String key, String searchType, String gameId, String gameName) {
JSONObject object = new JSONObject();
JSONObject payload = new JSONObject();
try {
object.put("event", event);
object.put("location", location);
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
payload.put("key", key); //搜索关键词
payload.put("search_type", searchType); //搜索类型, 有四种取值 默认搜索/历史搜索/自动搜索/主动搜索
payload.put("game_id", gameId); //event为search_click才取值
payload.put("game_name", gameName); //event为search_click才取值
object.put("payload", payload);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
}

View File

@ -2,9 +2,6 @@ package com.gh.common.util
import android.app.Activity
import android.content.Intent
import com.bytedance.sdk.open.aweme.authorize.model.Authorization
import com.bytedance.sdk.open.douyin.DouYinOpenApiFactory
import com.bytedance.sdk.open.douyin.DouYinOpenConfig
import com.gh.common.constant.Config
import com.gh.gamecenter.R
import com.gh.gamecenter.user.LoginTag
@ -89,9 +86,9 @@ object LoginHelper {
}
}
WbSdk.install(context, AuthInfo(context, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE))
DouYinOpenApiFactory.init(DouYinOpenConfig(Config.DOUYIN_CLIENTKEY))
// DouYinOpenApiFactory.init(DouYinOpenConfig(Config.DOUYIN_CLIENTKEY))
Utils.log("LoginHelper initialization")
}
@ -163,6 +160,8 @@ object LoginHelper {
// 微博登录
@JvmStatic
fun loginWithWeibo(loginCallback: LoginCallback, context: Activity) {
WbSdk.install(context, AuthInfo(context, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE))
mLoginCallback = WeakReference(loginCallback)
mSsoHandler = WeakReference(SsoHandler(context))
mSsoHandler?.get()?.authorizeClientSso(object : WbAuthListener {
@ -204,14 +203,14 @@ object LoginHelper {
// 抖音登录
@JvmStatic
fun loginWithDouYin(loginCallback: LoginCallback, context: Activity) {
mLoginCallback = WeakReference(loginCallback)
val douYinOpenApi = DouYinOpenApiFactory.create(context)
val request = Authorization.Request()
request.scope = "user_info" // 用户授权时必选权限
//request.state = "ww"; // 用于保持请求和回调的状态,授权请求后原样带回给第三方。
//request.callerLocalEntry = "com.xxx.xxx...activity";
douYinOpenApi.authorize(request)
// mLoginCallback = WeakReference(loginCallback)
// val douYinOpenApi = DouYinOpenApiFactory.create(context)
//
// val request = Authorization.Request()
// request.scope = "user_info" // 用户授权时必选权限
// //request.state = "ww"; // 用于保持请求和回调的状态,授权请求后原样带回给第三方。
// //request.callerLocalEntry = "com.xxx.xxx...activity";
// douYinOpenApi.authorize(request)
}
interface LoginCallback {

View File

@ -3,9 +3,8 @@ package com.gh.common.util;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.net.Uri;
@ -16,6 +15,7 @@ import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.util.Base64;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
@ -26,6 +26,7 @@ import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gh.common.Base64ImageHolder;
import com.gh.common.constant.Config;
import com.gh.gamecenter.R;
import com.lightgame.utils.Utils;
@ -205,6 +206,48 @@ 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);
// 分享
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;
}
}
//QQ分享
private void qqSahre() {
Utils.toast(mContext, "分享跳转中...");

View File

@ -1,61 +1,52 @@
package com.gh.common.util
import android.os.Build
import android.text.TextUtils
import com.gh.gamecenter.BuildConfig
import com.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_Phone_State
import com.lightgame.utils.Utils
import com.tencent.stat.StatService
import java.util.*
object MtaHelper {
@JvmStatic
fun onEvent(eventId: String, vararg kv: String?) {
val prop = Properties()
if (kv.size == 1) {
prop.setProperty(kv[0], kv[0])
StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
return
}
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value)
}
}
}
Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
// val prop = Properties()
//
// if (kv.size == 1) {
// prop.setProperty(kv[0], kv[0])
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
// return
// }
//
// for (i in kv.indices) {
// if (i % 2 != 0) {
// val key = kv[i - 1]
// val value = kv[i]
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
// prop.setProperty(key, value)
// }
// }
// }
//
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
}
@JvmStatic
fun onEventWithTime(eventId: String, time: Int, vararg kv: String?) {
val prop = Properties()
for (i in kv.indices) {
if (i % 2 != 0 || i != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value)
}
}
}
if (prop.size == 0 && kv.size == 1) {
prop.setProperty(kv[0], kv[0])
}
if (prop.size == 0) return
Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}] + last $time seconds")
StatService.trackCustomKVTimeIntervalEvent(HaloApp.getInstance().application, time, eventId, prop)
// val prop = Properties()
// for (i in kv.indices) {
// if (i % 2 != 0 || i != 0) {
// val key = kv[i - 1]
// val value = kv[i]
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
// prop.setProperty(key, value)
// }
// }
// }
//
// if (prop.size == 0 && kv.size == 1) {
// prop.setProperty(kv[0], kv[0])
// }
//
// if (prop.size == 0) return
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}] + last $time seconds")
// StatService.trackCustomKVTimeIntervalEvent(HaloApp.getInstance().application, time, eventId, prop)
}
/**
@ -63,29 +54,29 @@ object MtaHelper {
*/
@JvmStatic
fun onEventWithBasicDeviceInfo(eventId: String, vararg kv: String) {
val prop = Properties()
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value)
}
}
}
prop.setProperty("光环版本", BuildConfig.VERSION_NAME)
prop.setProperty("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
prop.setProperty("IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().application))
prop.setProperty("机型", Build.MODEL)
prop.setProperty("厂商", Build.MANUFACTURER)
prop.setProperty("Android版本", Build.VERSION.RELEASE)
if (!TextUtils.isEmpty(HaloApp.getInstance().gid)) {
prop.setProperty("GID", HaloApp.getInstance().gid)
}
Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
// val prop = Properties()
// for (i in kv.indices) {
// if (i % 2 != 0) {
// val key = kv[i - 1]
// val value = kv[i]
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
// prop.setProperty(key, value)
// }
// }
// }
//
// prop.setProperty("光环版本", BuildConfig.VERSION_NAME)
// prop.setProperty("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
// prop.setProperty("IMEI", MetaUtil.getIMEI())
// prop.setProperty("机型", Build.MODEL)
// prop.setProperty("厂商", Build.MANUFACTURER)
// prop.setProperty("Android版本", Build.VERSION.RELEASE)
// if (!TextUtils.isEmpty(HaloApp.getInstance().gid)) {
// prop.setProperty("GID", HaloApp.getInstance().gid)
// }
//
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
}
}

View File

@ -5,15 +5,10 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationManagerCompat
import com.gh.common.constant.Constants
import com.gh.common.dialog.NotificationHintDialogFragment
import com.gh.gamecenter.entity.NotificationHint
import com.gh.gamecenter.entity.NotificationUgc
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
object NotificationHelper {
@ -159,7 +154,8 @@ object NotificationHelper {
callBack?.invoke(false)
} else {
callBack?.invoke(true)
NotificationHintDialogFragment.getInstance(ugc).show(activity.supportFragmentManager, "notification")
// if (activity.supportFragmentManager.isStateSaved) return
// NotificationHintDialogFragment.getInstance(ugc).show(activity.supportFragmentManager, "notification")
}
}

View File

@ -5,13 +5,16 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import com.gh.common.constant.Constants
import com.gh.common.dialog.InstallPermissionDialogFragment
import com.gh.common.xapk.XapkInstaller
import com.gh.gamecenter.BuildConfig
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.download.FileUtils
import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
import java.io.File
@ -35,15 +38,17 @@ object PackageInstaller {
*/
@JvmStatic
fun install(context: Context, downloadEntity: DownloadEntity, showUnzipToast: Boolean) {
// 取消状态栏下载完成的通知,若存在
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
InstallPermissionDialogFragment.show(AppManager.getInstance().currentActivity() as AppCompatActivity) {
// 取消状态栏下载完成的通知,若存在
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
val pkgPath = downloadEntity.path
if (XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()) {
XapkInstaller.install(context, downloadEntity, showUnzipToast)
} else {
install(context, downloadEntity.path)
val pkgPath = downloadEntity.path
if (XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()) {
XapkInstaller.install(context, downloadEntity, showUnzipToast)
} else {
install(context, downloadEntity.path)
}
}
}

View File

@ -304,6 +304,11 @@ public class PackageUtils {
return intent != null;
}
public static boolean isInstalledFromAllPackage(Context context, String packageName) {
ArrayList<String> allPackageName = getAllPackageName(context);
return allPackageName.contains(packageName);
}
/*
* 获取应用第一次安装的时间
*/

View File

@ -13,6 +13,8 @@ import com.tbruyelle.rxpermissions2.RxPermissions
object PermissionHelper {
const val INSTALL_PERMISS_CODE = 100
@JvmStatic
fun requestReadPhoneStateAndStoragePermissionFromStartUp(context: Context) {
if (context is FragmentActivity) {
@ -221,5 +223,18 @@ object PermissionHelper {
}
/**
* 开启安装未知来源权限
*/
fun toInstallPermissionSetting(activity: Activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
toSystemConfig(activity)
} else {
val packageURI = Uri.fromParts("package", activity.packageName, null)
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI)
activity.startActivityForResult(intent, INSTALL_PERMISS_CODE)
}
}
}

View File

@ -1,82 +1,82 @@
package com.gh.common.util
import android.annotation.SuppressLint
import android.content.Context
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.message.MessageUnreadRepository
import com.gh.gamecenter.receiver.UmengMessageReceiver
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
object PushHelper {
/**
* 提交推送点击事件,会尝试从 SP 读取之前失败的一并提交
*/
@SuppressLint("CheckResult")
@JvmStatic
fun postPushClickAction(context: Context, clickEvent: UmengMessageReceiver.ClickEvent? = null) {
val clickEventList = arrayListOf<UmengMessageReceiver.ClickEvent>()
clickEvent?.let { clickEventList.add(it) }
val failedClickEventList = SPUtils.getString(UmengMessageReceiver.SP_CLICK_EVENT)
.toObject<ArrayList<UmengMessageReceiver.ClickEvent>>()
failedClickEventList?.let { clickEventList.addAll(it) }
// 没有要提交的事件
if (clickEventList.size == 0) return
val body = RequestBody.create(MediaType.parse("application/json"), clickEventList.toJson())
RetrofitManager.getInstance(context)
.api
.postUmengReceiveInfo(body)
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
SPUtils.setString(UmengMessageReceiver.SP_CLICK_EVENT, "")
}
override fun onFailure(exception: Exception) {
SPUtils.setString(UmengMessageReceiver.SP_CLICK_EVENT, clickEventList.toJson())
}
})
}
/**
* 将消息中心的消息标记为已读
* [type] 跳转类型
* [notificationMessageId] 通知中心 ID
*/
fun setNotificationMessageRead(context: Context, type: String, notificationMessageId: String) {
val jsonObject = JSONObject()
jsonObject.put("type", type)
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
RetrofitManager.getInstance(context)
.api
.postMessageRead(UserManager.getInstance().userId, notificationMessageId, body)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
MessageUnreadRepository.loadMessageUnreadData()
}
override fun onFailure(e: HttpException?) {
e?.printStackTrace()
}
})
}
}
//package com.gh.common.util
//
//import android.annotation.SuppressLint
//import android.content.Context
//import com.gh.gamecenter.manager.UserManager
//import com.gh.gamecenter.message.MessageUnreadRepository
//import com.gh.gamecenter.receiver.UmengMessageReceiver
//import com.gh.gamecenter.retrofit.BiResponse
//import com.gh.gamecenter.retrofit.Response
//import com.gh.gamecenter.retrofit.RetrofitManager
//import io.reactivex.schedulers.Schedulers
//import okhttp3.MediaType
//import okhttp3.RequestBody
//import okhttp3.ResponseBody
//import org.json.JSONObject
//import retrofit2.HttpException
//
//object PushHelper {
//
// /**
// * 提交推送点击事件,会尝试从 SP 读取之前失败的一并提交
// */
// @SuppressLint("CheckResult")
// @JvmStatic
// fun postPushClickAction(context: Context, clickEvent: UmengMessageReceiver.ClickEvent? = null) {
// val clickEventList = arrayListOf<UmengMessageReceiver.ClickEvent>()
//
// clickEvent?.let { clickEventList.add(it) }
//
// val failedClickEventList = SPUtils.getString(UmengMessageReceiver.SP_CLICK_EVENT)
// .toObject<ArrayList<UmengMessageReceiver.ClickEvent>>()
//
// failedClickEventList?.let { clickEventList.addAll(it) }
//
// // 没有要提交的事件
// if (clickEventList.size == 0) return
//
// val body = RequestBody.create(MediaType.parse("application/json"), clickEventList.toJson())
//
// RetrofitManager.getInstance(context)
// .api
// .postUmengReceiveInfo(body)
// .subscribeOn(Schedulers.io())
// .subscribe(object : BiResponse<ResponseBody>() {
// override fun onSuccess(data: ResponseBody) {
// SPUtils.setString(UmengMessageReceiver.SP_CLICK_EVENT, "")
// }
//
// override fun onFailure(exception: Exception) {
// SPUtils.setString(UmengMessageReceiver.SP_CLICK_EVENT, clickEventList.toJson())
// }
// })
// }
//
//
// /**
// * 将消息中心的消息标记为已读
// * [type] 跳转类型
// * [notificationMessageId] 通知中心 ID
// */
// fun setNotificationMessageRead(context: Context, type: String, notificationMessageId: String) {
//
// val jsonObject = JSONObject()
// jsonObject.put("type", type)
// val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
//
// RetrofitManager.getInstance(context)
// .api
// .postMessageRead(UserManager.getInstance().userId, notificationMessageId, body)
// .subscribeOn(Schedulers.io())
// .subscribe(object : Response<ResponseBody>() {
// override fun onResponse(response: ResponseBody?) {
// super.onResponse(response)
// MessageUnreadRepository.loadMessageUnreadData()
// }
//
// override fun onFailure(e: HttpException?) {
// e?.printStackTrace()
// }
// })
// }
//}

View File

@ -8,7 +8,6 @@ import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import com.tencent.bugly.beta.tinker.TinkerManager.getApplication
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
@ -57,7 +56,7 @@ object ReservationHelper {
}
override fun onFailure(exception: Exception) {
Utils.toast(getApplication(), exception.message)
Utils.toast(HaloApp.getInstance().application, exception.message)
exception.printStackTrace()
}
})

View File

@ -24,9 +24,6 @@ import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.common.constant.Config;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WeiBoShareActivity;
@ -53,6 +50,9 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import static com.gh.common.util.LoginHelper.WEIBO_SCOPE;
/**
@ -90,7 +90,9 @@ public class ShareUtils {
shareGh("APP分享"),
communityArticle("文章详情"),
video("视频"),
web("web链接");
web("web链接"),
userHome("个人主页"),
qaDetail("QA内容详情");
private String name;
@ -145,7 +147,7 @@ public class ShareUtils {
mContext = context.getApplicationContext();
mTencent = Tencent.createInstance(Config.TENCENT_APPID, mContext); //初始化QQ分享
mIWXAPI = WXAPIFactory.createWXAPI(mContext, Config.WECHAT_APPID); //初始化微信分享
WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
}
public static ShareUtils getInstance(Context context) {
@ -170,6 +172,67 @@ public class ShareUtils {
return false;
}
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);
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);
View contentView = View.inflate(mActivity.get(), R.layout.popup_share_dialog, null);
contentView.setFocusable(true);
contentView.setFocusableInTouchMode(true);
View wechatType = contentView.findViewById(R.id.item_wechat);
View wechatMomentsType = contentView.findViewById(R.id.item_wechat_moments);
View qqType = contentView.findViewById(R.id.item_qq);
View qqZoneType = contentView.findViewById(R.id.item_qq_zone);
View weiboType = contentView.findViewById(R.id.item_weibo);
wechatType.setOnClickListener((v) -> wechatShare());
wechatMomentsType.setOnClickListener((v) -> wechatMomentsShare());
qqType.setOnClickListener((v) -> qqShare());
qqZoneType.setOnClickListener((v) -> qZoneShare());
weiboType.setOnClickListener((v) -> sinaWeiboShare());
popupWindow = new WeakReference<>(new SharePopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT
, LinearLayout.LayoutParams.MATCH_PARENT, true));
// popupWindow.get().setAnimationStyle(R.style.popwindow_exit_only_anim_style);
//解决PopupWindow无法覆盖状态栏
popupWindow.get().setClippingEnabled(false);
int bottomLocation = -DisplayUtils.retrieveNavigationHeight(activity);
if (!DisplayUtils.isNavigationBarShow(activity)) {
bottomLocation = 0;
}
try {
popupWindow.get().showAtLocation(view, Gravity.NO_GRAVITY, 0, bottomLocation);
} catch (Exception e) {
e.printStackTrace();
}
contentView.setOnClickListener(v -> safelyDismiss());
contentView.setOnKeyListener((v, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0
&& popupWindow.get() != null
&& popupWindow.get().isShowing()) {
if (callBack != null) {
callBack.onCancel();
}
safelyDismiss();
}
return false;
});
}
public void showShareWindowsCallback(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);
@ -270,7 +333,8 @@ public class ShareUtils {
switch (mShareEntrance) {
case plugin:
mSummary += "(光环加速版)";
case game:
mTitle += "_要好玩上光环";
break;
case askNormal:
case answerNormal:
@ -312,7 +376,8 @@ public class ShareUtils {
switch (mShareEntrance) {
case plugin:
mSummary += "(光环加速版)";
case game:
mTitle += "_要好玩上光环";
break;
case askNormal:
case answerNormal:
@ -419,8 +484,8 @@ public class ShareUtils {
Bundle params = new Bundle();
switch (mShareEntrance) {
case plugin:
mSummary += "光环加速版)";
case game:
mTitle += "_光环助手";
break;
case askNormal:
case answerNormal:
@ -468,10 +533,8 @@ public class ShareUtils {
switch (mShareEntrance) {
case plugin:
msg.title = mSummary + "(光环加速版)";
break;
case game:
msg.title = mSummary;
msg.title = mTitle + "_要好玩上光环";
break;
case askNormal:
case answerNormal:
@ -499,7 +562,12 @@ public class ShareUtils {
//新浪微博分享
private void sinaWeiboShare() {
WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
if (mShareEntrance == ShareEntrance.qaDetail) {
mTitle = "向你推荐:" + mTitle + " @光环助手 " + shareUrl;
mSummary = "";
}
Activity activity = mActivity.get();
if (activity != null) {
Intent intent = WeiBoShareActivity.getWeiboshareIntent(
@ -528,10 +596,8 @@ public class ShareUtils {
smsBody = mTitle + shareUrl;
break;
case plugin:
smsBody = mTitle + mSummary + "(光环加速版)" + shareUrl;
break;
case game:
smsBody = mTitle + mSummary + shareUrl;
smsBody = "向你推荐:" + mTitle + "_光环助手" + shareUrl;
break;
case shareGh:
smsBody = "这个App可以下载各种热门卡牌手游的加速版绿色安全超级省心做日常效率提高3-5倍光环助手官网地址" + shareUrl;
@ -543,6 +609,9 @@ public class ShareUtils {
case communityArticle:
smsBody = mTitle + " - 光环助手" + shareUrl;
break;
case qaDetail:
smsBody = "向你推荐:" + mTitle + " @光环助手 " + shareUrl;
break;
default:
smsBody = mTitle;
break;
@ -556,7 +625,7 @@ public class ShareUtils {
e.printStackTrace();
}
if (mShareEntrance != ShareEntrance.shareGh ) {
if (mShareEntrance != ShareEntrance.shareGh) {
safelyDismiss();
}
}
@ -683,7 +752,7 @@ public class ShareUtils {
}
}
}
private void safelyDismiss() {
if (popupWindow.get() != null) {
popupWindow.get().dismiss();

View File

@ -46,6 +46,11 @@ object SPUtils {
return sp.getInt(key, defaultValue)
}
@JvmStatic
fun getLong(key: String): Long {
return sp.getLong(key, 0)
}
@JvmStatic
fun getLong(key: String, defaultValue: Long): Long {
return sp.getLong(key, defaultValue)
@ -71,6 +76,11 @@ object SPUtils {
return sp.getBoolean(key, defaultValue)
}
@JvmStatic
fun getBooleanWithContext(context: Context, key: String, defaultValue: Boolean): Boolean {
return context.getSharedPreferences("Halo", Context.MODE_PRIVATE).getBoolean(key, defaultValue)
}
@JvmStatic
fun setString(sp: SharedPreferences, key: String, value: String? = null) {
try {

View File

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

View File

@ -3,6 +3,7 @@ package com.gh.common.util
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
import kotlin.math.log10
object TimeUtils {
@ -21,10 +22,11 @@ object TimeUtils {
return formatter.format(date)
}
@JvmStatic
fun getFormatTime(time: Long, pattern: String = "yyyy-MM-dd"): String {
val f = SimpleDateFormat(pattern, Locale.CHINA)
f.timeZone = TimeZone.getTimeZone("Asia/Shanghai")
return f.format(Date(time * 1000))
return f.format(Date(getJavaTimestamp(time)))
}
fun getFormatDate(timestamp: Long): String {
@ -100,4 +102,27 @@ object TimeUtils {
else -> ""
}
}
@JvmStatic
fun getStartTimeOfToday(): Long = getStartTimeOfDay(System.currentTimeMillis())
@JvmStatic
fun getStartTimeOfDay(currentTime: Long): Long {
val calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"))
calendar.timeInMillis = getJavaTimestamp(currentTime)
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
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) {
timestamp * 1000
} else {
timestamp
}
}
}

View File

@ -56,4 +56,10 @@ object ToastUtils {
}
mOneTime = mTwoTime
}
fun toast(message: String) {
if (mToast != null) mToast?.cancel()
mToast = ToastHandler.INSTANCE.getToastInstance(HaloApp.getInstance().application, message, Toast.LENGTH_SHORT)
mToast?.show()
}
}

View File

@ -32,7 +32,8 @@ object UploadImageUtils {
suggestion,
icon,
poster,
game_upload
game_upload,
user_background
}
// 不处理图片,只是单纯的上传
@ -273,11 +274,11 @@ object UploadImageUtils {
}
// 防止GIF图片文件后缀不是GIF这个FileName只是告诉服务端后缀格式没有其他用处
private fun getFileName(file: File): String {
fun getFileName(file: File): String {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.absolutePath, options)
if (options.outMimeType.contains("gif") && !file.name.toLowerCase().contains(".gif".toLowerCase())) {
if (options.outMimeType != null && options.outMimeType.contains("gif") && !file.name.toLowerCase().contains(".gif".toLowerCase())) {
return System.currentTimeMillis().toString() + ".gif"
}
return URLEncoder.encode(file.name, "utf-8")

View File

@ -47,7 +47,7 @@ object VideoRecordUtils {
}
fun commitVideoRecord() {
if (videoRecordSet.isEmpty()) return
if (videoRecordSet.isEmpty() || !::mApplication.isInitialized) return
videoRecordExecutor.execute {
uploadVideoRecord()
val exposureList = videoRecordSet.toList()

View File

@ -0,0 +1,102 @@
package com.gh.common.view
import android.content.Context
import android.os.Build
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 java.lang.ref.WeakReference
import java.util.*
class AutoScrollRecyclerViewContainerView(context: Context, @Nullable attrs: AttributeSet?)
: LinearLayout(context, attrs), LifecycleObserver {
var autoScrollTask: AutoScrollTask?
private var mIsScrolling = false
private var mIsScrollable = false
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
if (mIsScrolling) pauseScrolling()
mIsScrollable = true
mIsScrolling = true
postDelayed(autoScrollTask, AUTO_SCROLL_INTERVAL)
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun pauseScrolling() {
mIsScrolling = false
removeCallbacks(autoScrollTask)
}
fun setLifeCycleOwner(lifeCycleOwner: Lifecycle) {
lifeCycleOwner.addObserver(this)
}
companion object {
private const val AUTO_SCROLL_INTERVAL: Long = 10
}
class AutoScrollTask(reference: AutoScrollRecyclerViewContainerView?) : Runnable {
private val mReference: WeakReference<AutoScrollRecyclerViewContainerView?>?
private val mScrollSlop = if (Build.MODEL.toLowerCase(Locale.getDefault()) == "mumu") 1 else 2
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(mScrollSlop, mScrollSlop)
}
}
containerView.postDelayed(containerView.autoScrollTask, AUTO_SCROLL_INTERVAL)
}
}
}
}

View File

@ -0,0 +1,144 @@
package com.gh.common.view
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.RelativeLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.GenericDraweeHierarchy
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
import com.facebook.drawee.generic.RoundingParams
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.util.ImageUtils
import com.gh.common.util.dip2px
import com.gh.common.util.px2dip
import com.gh.gamecenter.R
class AvatarBorderView : ConstraintLayout {
var avatarView: SimpleDraweeView? = null
var borderView: SimpleDraweeView? = null
var badgeView: SimpleDraweeView? = null
private var mAvatarWidth = 100f
private var mBadgeWidth = 30f
private var mAvatarBorderColor = Color.parseColor("#ffffff")
private var mAvatarBorderWidth = 2f.dip2px().toFloat()
private var mRatio = 0f
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
initView(attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initView(attrs)
}
private fun initView(attrs: AttributeSet) {
val ta = context.obtainStyledAttributes(attrs, R.styleable.AvatarBorderView)
if (ta.hasValue(R.styleable.AvatarBorderView_avatar_width)) {
mAvatarWidth = ta.getDimension(R.styleable.AvatarBorderView_avatar_width, mAvatarWidth)
}
if (ta.hasValue(R.styleable.AvatarBorderView_badge_width)) {
mBadgeWidth = ta.getDimension(R.styleable.AvatarBorderView_badge_width, mBadgeWidth)
}
if (ta.hasValue(R.styleable.AvatarBorderView_border_width)) {
mAvatarBorderWidth = ta.getDimension(R.styleable.AvatarBorderView_border_width, mAvatarBorderWidth)
}
if (ta.hasValue(R.styleable.AvatarBorderView_border_ratio)) {
mRatio = ta.getFloat(R.styleable.AvatarBorderView_border_ratio, 0f)
}
mAvatarBorderColor = ta.getColor(R.styleable.AvatarBorderView_border_color, mAvatarBorderColor)
ta.recycle()
LayoutInflater.from(context).inflate(R.layout.view_avatar_border, this, true)
avatarView = findViewById(R.id.avatarView)
borderView = findViewById(R.id.borderView)
badgeView = findViewById(R.id.badgeView)
changeLayoutParams()
}
private fun changeLayoutParams() {
avatarView?.apply {
val params = layoutParams
params.width = mAvatarWidth.toInt()
params.height = mAvatarWidth.toInt()
layoutParams = params
val roundingParams = RoundingParams.asCircle()
roundingParams.borderColor = mAvatarBorderColor
roundingParams.borderWidth = mAvatarBorderWidth
hierarchy?.roundingParams = roundingParams
}
borderView?.apply {
val params = layoutParams
if (mRatio > 0) {
params.width = (mAvatarWidth * mRatio).toInt()
params.height = (mAvatarWidth * mRatio).toInt()
} else {
params.width = (mAvatarWidth * 3 / 2).toInt()
params.height = (mAvatarWidth * 3 / 2).toInt()
}
layoutParams = params
}
badgeView?.apply {
val params = layoutParams
params.width = mBadgeWidth.toInt()
params.height = mBadgeWidth.toInt()
layoutParams = params
}
}
fun setAvatarWidth(width: Float) {
mAvatarWidth = width
changeLayoutParams()
}
fun setBadgeWidth(width: Float) {
mBadgeWidth = width
changeLayoutParams()
}
fun display(borderUrl: String? = "", avatarUrl: String? = "", badgeUrl: String? = "") {
if (avatarUrl.isNullOrEmpty()) {
avatarView?.setImageURI("")
} else {
ImageUtils.display(avatarView, avatarUrl)
}
displayBorder(borderUrl)
displayUserBadge(badgeUrl)
}
fun displayAvatar(avatarUrl: String? = "") {
if (avatarUrl.isNullOrEmpty()) {
avatarView?.setImageURI("")
} else {
ImageUtils.display(avatarView, avatarUrl)
}
}
fun displayBorder(borderUrl: String? = "") {
if (!borderUrl.isNullOrEmpty()) {
borderView?.visibility = View.VISIBLE
ImageUtils.display(borderView, borderUrl)
} else {
borderView?.visibility = View.INVISIBLE
}
}
fun displayUserBadge(badgeUrl: String? = "") {
if (badgeUrl.isNullOrEmpty()) {
badgeView?.setImageURI("")
badgeView?.visibility = View.GONE
} else {
badgeView?.visibility = View.VISIBLE
ImageUtils.display(badgeView, badgeUrl)
}
}
}

View File

@ -28,15 +28,16 @@ public class CircleProgressBar extends View {
private int disableProgressColor = Color.parseColor("#999999");//禁用已经走了的进度条颜色
private int disableTextColor = Color.parseColor("#999999");//禁用文字颜色
private int currentNormalColor = normalColor;
private int currentProgressColor = progressColor;
private int currentTextColor = textColor;
private int currentNormalColor;
private int currentProgressColor;
private int currentTextColor;
private float textSize = 20;//文字大小
private int progress = 0;//进度条
private String centerText = "0%";//中心填充文字
private Paint fontPaint = null;
private Paint.Style progress_style = Paint.Style.STROKE;//填充式还是环形式
private boolean mIsShowProgressText;
public CircleProgressBar(Context context) {
this(context, null);
@ -64,6 +65,11 @@ public class CircleProgressBar extends View {
progress = array.getInt(R.styleable.CircleProgressBar_progress, progress);
progress_style = array.getInt(R.styleable.CircleProgressBar_progress_style, 0) == 0 ? Paint.Style.STROKE : Paint.Style.FILL;
mIsShowProgressText = array.getBoolean(R.styleable.CircleProgressBar_show_progress, true);
currentNormalColor = normalColor;
currentProgressColor = progressColor;
currentTextColor = textColor;
array.recycle();
initPaint();
}
@ -113,10 +119,12 @@ public class CircleProgressBar extends View {
mPaint.setColor(currentProgressColor);
canvas.drawArc(rectF, 270, progress, progress_style == Paint.Style.FILL, mPaint);
fontMetrics = fontPaint.getFontMetrics();
float textWidth = fontPaint.measureText(centerText);
float textHeight = fontPaint.ascent() + fontPaint.descent();
canvas.drawText(centerText, width / 2 - textWidth / 2, height / 2 - textHeight / 2, fontPaint);
if (mIsShowProgressText) {
fontMetrics = fontPaint.getFontMetrics();
float textWidth = fontPaint.measureText(centerText);
float textHeight = fontPaint.ascent() + fontPaint.descent();
canvas.drawText(centerText, width / 2 - textWidth / 2, height / 2 - textHeight / 2, fontPaint);
}
}

View File

@ -1,12 +1,15 @@
package com.gh.common.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.gh.gamecenter.R;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@ -37,6 +40,9 @@ public class CropImageCustom extends RelativeLayout {
mHorizontalPadding = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, mHorizontalPadding, getResources()
.getDisplayMetrics());
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CropImageCustom);
mHorizontalPadding = (int) ta.getDimension(R.styleable.CropImageCustom_horizontalPadding, mHorizontalPadding);
ta.recycle();
mZoomImageView.setHorizontalPadding(mHorizontalPadding, mRatio);
mClipImageView.setHorizontalPadding(mHorizontalPadding, mRatio);

View File

@ -0,0 +1,94 @@
package com.gh.common.view
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.view.View
import androidx.appcompat.widget.AppCompatSeekBar
import com.gh.common.util.DisplayUtils
import com.gh.common.util.dip2px
import com.gh.common.util.px2dip
import com.gh.common.util.sp2px
import com.gh.gamecenter.R
/**
* 自定义滑块顶部带进度显示的SeekBar
*/
class CustomSeekBar : AppCompatSeekBar {
private var mProgressTextColor = Color.parseColor("#2496FF")
private var mProgressTextSize = 14f
private var mProgressTextPaddingBottom = 4f
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
initView(attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initView(attrs)
}
private fun initView(attrs: AttributeSet) {
val ta = context.obtainStyledAttributes(attrs, R.styleable.CustomSeekBar)
mProgressTextColor = ta.getColor(R.styleable.CustomSeekBar_progressTextColor, mProgressTextColor)
if (ta.hasValue(R.styleable.CustomSeekBar_progressTextSize)) {
mProgressTextSize = ta.getDimension(R.styleable.CustomSeekBar_progressTextSize, mProgressTextSize)
mProgressTextSize = DisplayUtils.px2sp(context, mProgressTextSize).toFloat()
}
if (ta.hasValue(R.styleable.CustomSeekBar_progressTextPaddingBottom)) {
mProgressTextPaddingBottom = ta.getFloat(R.styleable.CustomSeekBar_progressTextPaddingBottom, mProgressTextPaddingBottom)
mProgressTextPaddingBottom = mProgressTextPaddingBottom.dip2px().toFloat()
}
ta.recycle()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val thumbHeight = if (thumb == null) 0 else thumb.intrinsicHeight
val measureText = measureText("0")
val dh = thumbHeight + measureText.second + mProgressTextPaddingBottom
setMeasuredDimension(
View.getDefaultSize(0, widthMeasureSpec),
View.resolveSizeAndState(dh.toInt(), heightMeasureSpec, 0)
)
}
@SuppressLint("DrawAllocation")
override fun onDraw(canvas: Canvas?) {
canvas?.save()
//由于滑块和进度都是居中绘制,所以这里需要向下移动
canvas?.translate(0f, mProgressTextPaddingBottom)
super.onDraw(canvas)
canvas?.restore()
val paint = Paint()
paint.isAntiAlias = true
paint.textSize = mProgressTextSize.sp2px().toFloat()
paint.color = mProgressTextColor
val textString = "${progress * 100 / max}%"
val pair = measureText(textString)
val percent = progress.toFloat() / max
val progressWidth = width - paddingLeft - paddingRight
val offsetX = progressWidth * percent + paddingLeft - pair.first / 2
canvas?.drawText(
textString,
offsetX,
pair.second.toFloat() - paint.fontMetrics.descent,
paint
)
}
private fun measureText(str: String): Pair<Int, Int> {
val paint = Paint()
paint.textSize = mProgressTextSize.sp2px().toFloat()
val rect = Rect()
paint.getTextBounds(str, 0, str.length, rect)
val w: Int = rect.width()
val h: Int = rect.height()
return Pair(w, h + paint.fontMetrics.descent.toInt())
}
}

View File

@ -39,6 +39,7 @@ public class DownloadProgressBar extends ProgressBar {
RESERVABLE,
RESERVED,
H5_GAME,
UPDATING,
XAPK_UNZIPPING,
XAPK_SUCCESS,
@ -212,17 +213,21 @@ public class DownloadProgressBar extends ProgressBar {
break;
case RESERVABLE:
setProgressDrawable(getResources().getDrawable(R.drawable.button_reserve));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.all_white);
mDefaultColor = ContextCompat.getColor(getContext(), R.color.white);
break;
case UPDATING:
setProgressDrawable(getResources().getDrawable(R.drawable.download_button_updating_style));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.white);
break;
case RESERVED:
setProgressDrawable(getResources().getDrawable(R.drawable.game_item_btn_pause_dn));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.all_white);
mDefaultColor = ContextCompat.getColor(getContext(), R.color.white);
break;
case XAPK_FAILURE:
case XAPK_SUCCESS:
case XAPK_UNZIPPING:
setProgressDrawable(getResources().getDrawable(R.drawable.progressbar_xapk_detail_style));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.all_white);
mDefaultColor = ContextCompat.getColor(getContext(), R.color.white);
break;
}

View File

@ -19,6 +19,7 @@ class GameIconView : ConstraintLayout {
private var mCornerRadius = 10
private var mBorderColor = 0
private var mBorderWidth = 1
private var mFadeDuration = -1
constructor(context: Context) : super(context, null)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs, 0) {
@ -36,6 +37,7 @@ class GameIconView : ConstraintLayout {
mCornerRadius = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconCornerRadius, DisplayUtils.dip2px(10F))
mBorderColor = ta.getColor(R.styleable.GameIconView_gameIconBorderColor, 0)
mBorderWidth = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconBorderWidth, 1)
mFadeDuration = ta.getInt(R.styleable.GameIconView_gameIconFadeDuration, -1)
ta.recycle()
val roundingParams = RoundingParams.fromCornersRadius(mCornerRadius.toFloat())
@ -45,6 +47,10 @@ class GameIconView : ConstraintLayout {
}
gameIconIv.hierarchy.roundingParams = roundingParams
gameIconDecoratorIv.hierarchy.roundingParams = roundingParams
if (mFadeDuration != -1) {
gameIconIv.hierarchy.fadeDuration = mFadeDuration
}
}
fun displayGameIcon(game: GameEntity) {

View File

@ -0,0 +1,13 @@
package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.webkit.WebView
class LongScrollbarWebView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
: WebView(context, attrs) {
override fun computeVerticalScrollExtent(): Int {
return super.computeVerticalScrollExtent() * 3
}
}

View File

@ -10,25 +10,29 @@ import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.webkit.WebView;
import android.widget.OverScroller;
import android.widget.ScrollView;
import com.gh.common.view.dsbridge.DWebView;
import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.InputDeviceCompat;
import androidx.core.view.NestedScrollingChild2;
import androidx.core.view.NestedScrollingChildHelper;
import androidx.core.view.NestedScrollingParent;
import androidx.core.view.NestedScrollingParent2;
import androidx.core.view.NestedScrollingParentHelper;
import androidx.core.view.ViewCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityRecordCompat;
import com.gh.common.view.dsbridge.DWebView;
/**
* 注意父view中有实现了{@link NestedScrollingParent2}才会有嵌套滑动功能
*
* Copyright (c) Tuenti Technologies. All rights reserved.
* <p>
* WebView compatible with CoordinatorLayout.
@ -54,6 +58,7 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
private int mMinimumVelocity;
private int mMaximumVelocity;
private static final AccessibilityDelegate ACCESSIBILITY_DELEGATE = new AccessibilityDelegate();
private Boolean mIsParentViewImplNestedScrolling = false;
public NestedScrollWebView2(Context context, AttributeSet attrs) {
super(context, attrs);
@ -64,13 +69,21 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
super(context);
init();
}
private void init(){
private void init() {
setOverScrollMode(WebView.OVER_SCROLL_NEVER);
initScrollView();
mChildHelper = new NestedScrollingChildHelper(this);
mParentHelper = new NestedScrollingParentHelper(this);
setNestedScrollingEnabled(true);
ViewCompat.setAccessibilityDelegate(this, ACCESSIBILITY_DELEGATE);
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
mIsParentViewImplNestedScrolling = isParentViewImplNestedScrolling(NestedScrollWebView2.this);
}
});
}
@ -98,6 +111,9 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (!mIsParentViewImplNestedScrolling) {
return super.onInterceptTouchEvent(ev);
}
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
@ -171,6 +187,10 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!mIsParentViewImplNestedScrolling) {
return super.onTouchEvent(ev);
}
boolean returnValue = false;
initVelocityTrackerIfNotExists();
@ -497,6 +517,10 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
@Override
public void computeScroll() {
if (!mIsParentViewImplNestedScrolling){
super.computeScroll();
return;
}
if (mScroller.computeScrollOffset()) {
final int x = mScroller.getCurrX();
final int y = mScroller.getCurrY();
@ -789,4 +813,16 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
mScroller.forceFinished(true);
}
}
//判断是否有父view实现了NestedScrollingParent2
public boolean isParentViewImplNestedScrolling(View view) {
if (view instanceof NestedScrollingParent2) {
return true;
}
if (view.getParent() != null && view.getParent() instanceof View) {
return isParentViewImplNestedScrolling((View) view.getParent());
} else {
return false;
}
}
}

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