Compare commits

..

168 Commits

Author SHA1 Message Date
beee85fe15 chore: 版本更新至 5.36.4 2024-07-01 15:43:18 +08:00
d77545f242 feat: merge va 2024-07-01 15:40:34 +08:00
11a0d55d12 chore: 版本更新至 5.36.3 2024-06-27 16:35:08 +08:00
5d7056735a Merge branch 'hotfix/v5.36.2-1072/install_status_update' into 'release'
fix: 修复列表游戏的安装状态更新问题

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

See merge request halo/android/assistant-android!1719
2024-06-27 10:59:29 +08:00
7310056d2e fix:修复线上crash:https://sentry.shanqu.cc/organizations/lightgame/issues/393670/?project=22 2024-06-27 10:55:05 +08:00
5fd7d0bb62 fix: 移除极光推送定位权限的申请 2024-06-25 17:38:06 +08:00
a45d6ce0b4 Merge branch 'feature-GHZS-5816' into 'release'
feat:【光环助手】QQ小游戏登录 https://jira.shanqu.cc/browse/GHZSCY-5816

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

See merge request halo/android/assistant-android!1646
2024-04-25 10:36:50 +08:00
6beb060e63 fix: 【光环助手】开屏广告神策埋点数据上报问题 https://jira.shanqu.cc/browse/GHZSCY-5261 2024-04-25 10:31:22 +08:00
d11ccba0b7 feat: 穿山甲广告SDK更换新版本与信息流广告优化 https://jira.shanqu.cc/browse/GHZSCY-5243
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-04-22 16:29:42 +08:00
564 changed files with 19156 additions and 5347 deletions

4
.gitignore vendored
View File

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

View File

@ -71,7 +71,8 @@ android_build:
exit_codes: 137
only:
- dev
- feat/GHZSCY-5250
- release
- feature-GHZS-5816
# 代码检查
sonarqube_analysis:
@ -152,4 +153,5 @@ oss-upload&send-email:
- /usr/local/bin/python /ci-android-mail-jira-comment.py
only:
- dev
- feat/GHZSCY-5250
- release
- feature-GHZS-5816

3
.gitmodules vendored
View File

@ -8,3 +8,6 @@
[submodule "ndownload"]
path = ndownload
url = ../../../android/ndownload.git
[submodule "vasdk"]
path = vasdk
url = ../../../sdg/android/vasdk.git

View File

@ -75,7 +75,7 @@ android {
versionName rootProject.ext.versionName
applicationId rootProject.ext.applicationId
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt', rootProject.ext.va_proguard_rules
String CORE_EVENT_GAME_CATEGORY = ""
@ -126,6 +126,10 @@ android {
}
}
packagingOptions {
exclude 'META-INF/gradle/incremental.annotation.processors'
}
buildTypes {
debug {
debuggable true
@ -164,6 +168,15 @@ android {
flavorDimensions("env", "region")
sourceSets {
debug {
assets.srcDirs += 'src/main/assets-debug'
}
release {
assets.srcDirs += 'src/main/assets-release'
}
publish {
java.srcDirs = ['src/main/java', "src/default/java"]
}
@ -348,7 +361,7 @@ dependencies {
implementation "com.llew.huawei:verifier:${verifier}"
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:${bytedanceApplog}"
teaImplementation "com.bytedance.applog:RangersAppLog-All-convert:${bytedanceApplog}"
teaImplementation "com.bytedance.ads:AppConvert:${bytedanceAppConvert}"
implementation "net.lingala.zip4j:zip4j:${zip4j}"
@ -357,7 +370,9 @@ dependencies {
implementation "com.lg:easyfloat:${easyFloat}"
implementation "com.lg:apksig:${apksig}"
implementation ("com.lg:apksig:${apksig}") {
exclude group: 'com.google.protobuf'
}
implementation "com.lg:gid:${gid}"
@ -368,7 +383,7 @@ dependencies {
kapt "com.alibaba:arouter-compiler:$arouterVersion"
implementation project(':ndownload')
implementation project(':vspace-bridge:vspace')
implementation project(':vspace-bridge')
implementation (project(':module_common')) {
exclude group: 'androidx.swiperefreshlayout'
@ -397,7 +412,6 @@ dependencies {
implementation(project(':module_message')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':feature:vpn'))
implementation(project(':feature:pkg'))
implementation(project(':feature:oaid'))
implementation(project(':feature:floating-window'))
@ -409,12 +423,24 @@ dependencies {
}
internalImplementation(project(':module_internal_test'))
// 根据BUILD_PUSH_TYPE决定使用哪个推送SDK目前默认使用阿里云推送
def pushProject = findProperty('BUILD_PUSH_TYPE') == 'jg'
def pushProperty = findProperty('BUILD_PUSH_TYPE')
// 根据BUILD_PUSH_TYPE决定使用哪个推送SDK目前默认使用极光推送
def pushProject = (pushProperty == null || pushProperty == 'jg')
? project(':feature:jg_push') : project(':feature:acloud_push')
implementation(pushProject) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(":va-lib"))
implementation(project(':va-main')) {
exclude group: 'androidx.swiperefreshlayout'
}
debugImplementation "com.bytedance.tools.codelocator:codelocator-core:2.0.3"
compileOnly project(":va-core")
compileOnly project(":va-plugin-host-lib")
implementation project(":va-plugin-host")
implementation project(":va-archive")
}
File propFile = file('sign.properties')
@ -568,7 +594,16 @@ andResGuard {
"R.id.cardMask",
"R.id.cardGradientMask",
"R.id.gameIconIv",
"R.id.titleContainer"
"R.id.titleContainer",
"R.id.v_login_background",
"R.id.tv_login_tips",
"R.id.tv_login",
"R.id.v_code_background",
"R.id.tv_code_tips",
"R.id.tv_code",
"R.id.tv_copy",
"R.id.v_indicator_background",
"R.id.v_indicator"
]
compressFilePattern = [
"*.png",

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

View File

@ -92,7 +92,30 @@
com.tencent.qqmini,
com.tencent.qqmini.minigame.external,
com.tencent.qqmini.minigame.opensdk,
com.tencent.qqmini.union.ad" />
com.tencent.qqmini.union.ad,
com.lg.vspace,
io.lg.va.common,
com.va.floating,
com.lg.cloud,
com.lg.archive,
com.lg.vclient,
com.va.realname,
com.lg.vspace.flavor,
com.lg.update,
com.lg.login,
com.lg.accelerator,
com.lody.virtual,
com.lg.core,
com.lg.ads,
com.lg.common,
com.lg.vspace.network,
com.lody.virtual.lib.res,
com.va.host,
com.lg.vspace.plugin.host,
com.lg.plugin.constant,
com.bytedance.tools.codelocator,
org.chickenhook.restrictionbypass,
com.lody.virtual.sandhook,com.lg.vspace.common" />
<!-- 去掉 SDK 一些流氓权限 -->
<uses-permission
@ -111,6 +134,14 @@
android:name="android.permission.ACCESS_COARSE_LOCATION"
tools:node="remove" />
<uses-permission
android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
tools:node="remove" />
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"
tools:node="remove" />
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
@ -747,11 +778,11 @@
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qgame.QGameHomeWrapperActivity"
android:name="com.gh.gamecenter.minigame.qq.QGameHomeWrapperActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qgame.QGameSearchActivity"
android:name="com.gh.gamecenter.minigame.MiniGameSearchActivity"
android:screenOrientation="portrait" />
<activity
@ -770,8 +801,19 @@
android:name="com.gh.gamecenter.wrapper.ToolbarWrapperActivity"
android:screenOrientation="portrait" />
<activity android:name=".forum.home.CommunityActivity"
android:screenOrientation="portrait"/>
<activity
android:name=".forum.home.CommunityActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.home.follow.FollowDynamicActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Transparent" />
<activity
android:name=".forum.home.follow.AllFollowedActivity"
android:screenOrientation="portrait"
android:theme="@style/AppCompatTheme.APP" />
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
@ -783,7 +825,8 @@
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"
android:exported="false"
android:grantUriPermissions="true">
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />

View File

@ -191,10 +191,11 @@ object AdDelegateHelper {
}
/**
* 热启动是否需要显示开屏广告
* 热启动是否需要显示开屏广告(目前只展示第三方广告)
*/
private fun shouldShowStartUpAdWhenHotLaunch() =
mSplashAd?.displayRule?.hotStartSplashAd?.type == AD_TYPE_SDK && mSplashAd?.hotStartThirdPartyAd != null
private fun shouldShowStartUpAdWhenHotLaunch() = (mCsjAdImpl != null || mBeiziAdImpl != null)
&& mSplashAd?.displayRule?.hotStartSplashAd?.type == AD_TYPE_SDK
&& mSplashAd?.hotStartThirdPartyAd != null
/**
* 是否需要显示下载管理广告
@ -203,6 +204,10 @@ object AdDelegateHelper {
return mDownloadManagerAd != null && !isMatchAdFreeRule(mDownloadManagerAd) && isMatchDownloadManagerAdDisplayRule()
}
fun shouldShowHelperLaunchAd(): Boolean {
return mVGameLaunchAd != null && !isMatchAdFreeRule(mVGameLaunchAd) && isMatchAdDisplayRule(mVGameLaunchAd, Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME)
}
/**
* 是否需要显示游戏搜索广告
*/
@ -247,10 +252,11 @@ object AdDelegateHelper {
/**
* 是否大于广告管理展示间隔时长
*/
private fun isMatchDownloadManagerAdDisplayRule(): Boolean {
mDownloadManagerAd?.displayRule?.run {
private fun isMatchDownloadManagerAdDisplayRule(): Boolean = isMatchAdDisplayRule(mDownloadManagerAd, Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME)
private fun isMatchAdDisplayRule(adConfig: AdConfig?, spKey: String): Boolean {
adConfig?.displayRule?.run {
if (adDisplayInterval > 0) {
val lastShowTime = SPUtils.getLong(Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME, 0L)
val lastShowTime = SPUtils.getLong(spKey, 0L)
val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60
return durationInMinutes > adDisplayInterval
} else {

View File

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

View File

@ -18,8 +18,11 @@ import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.PackageFlavorHelper
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.feedback.view.suggest.SuggestionActivity
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lg.vspace.ui.launcher.LaunchActivity
// TODO移动到对应的模块
class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
@ -40,11 +43,20 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
&& activity !is SkipActivity
&& activity !is AuthorizationActivity
&& activity !is SplashAdActivity
&& activity !is SuggestionActivity
) {
activity.startActivity(SplashAdActivity.getIntent(activity))
}
isFromBackgroundToForeground = false
}
if (activityCount == 1) {
// 清除桌面角标
if (activity !is SplashScreenActivity && activity !is AuthorizationActivity) {
val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
pushProvider?.cleanBadgeNumber(activity.applicationContext)
}
}
}
override fun onActivityResumed(activity: Activity) {
@ -76,6 +88,8 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
if (activity is AppCompatActivity
&& activity !is LaunchActivity
&& activity !is LoginActivity
&& activity !is SplashScreenActivity
&& activity !is SkipActivity
&& activity !is AuthorizationActivity
@ -84,10 +98,6 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
XapkInstaller.updateCurrentInstallStatus()
// 清除桌面角标
val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
pushProvider?.cleanBadgeNumber(activity.applicationContext)
}
override fun onActivityPaused(activity: Activity) {

View File

@ -32,9 +32,13 @@ import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.SensorsEvent
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
@ -69,7 +73,7 @@ class DefaultJsApi(
private var mFragment: Fragment? = null,
private var mBbsId: String? = "",
private var mOriginUrl: String? = "",
private val mForumName: String? = ""
private val mForumName: String? = "",
) {
companion object {
@ -89,6 +93,11 @@ class DefaultJsApi(
}
}
@JavascriptInterface
fun isEnableForceDark(msg: Any): Boolean {
return DarkModeUtils.isWebViewForceDarkEnabled
}
@JavascriptInterface
fun isGhzs(msg: Any): String {
return "true"
@ -219,7 +228,7 @@ class DefaultJsApi(
runOnUiThread {
// 若畅玩列表中安装了,优先启动畅玩游戏
if (VHelper.isInstalled(packageName)) {
if (!VHelper.showDialogIfVSpaceIsNeeded(context, "", "", "", "")) {
VHelper.validateVSpaceBeforeAction(context, packageName, null) {
VHelper.launch(context, packageName)
}
} else {
@ -333,6 +342,12 @@ class DefaultJsApi(
return HaloApp.getInstance().oaid
}
@JavascriptInterface
fun getPushId(): String {
val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
return pushProvider?.getRegistrationId(HaloApp.getInstance()) ?: "unknown"
}
@JavascriptInterface
fun showIncompatibleVersionDialog(msg: Any) {
DialogHelper.showUpgradeDialog(context)

View File

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

View File

@ -1,6 +1,7 @@
package com.gh.common.constant;
import android.annotation.SuppressLint;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
@ -14,6 +15,7 @@ import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.constant.CommonConsts;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.common.utils.DarkModeUtils;
@ -21,14 +23,18 @@ import com.gh.gamecenter.common.utils.EnvHelper;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.UrlFilterUtils;
import com.gh.gamecenter.entity.AppEntity;
import com.gh.gamecenter.entity.GameGuidePopupEntity;
import com.gh.gamecenter.entity.NewApiSettingsEntity;
import com.gh.gamecenter.entity.NewSettingsEntity;
import com.gh.gamecenter.entity.VNewSetting;
import com.gh.gamecenter.entity.VSetting;
import com.gh.gamecenter.feature.entity.SettingsEntity;
import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.feature.utils.ContentBlockedHelper;
import com.gh.gamecenter.receiver.PackageChangeBroadcastReceiver;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.retrofit.service.VApiService;
import com.gh.vspace.VHelper;
import com.halo.assistant.HaloApp;
@ -39,8 +45,12 @@ import org.json.JSONObject;
import java.io.IOException;
import java.util.Locale;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
import okhttp3.ResponseBody;
public class Config {
@ -68,6 +78,10 @@ public class Config {
private static NewApiSettingsEntity.NightMode mNightModeSetting;
private static SimulatorEntity mNewSimulatorEntity;
private static VSetting mVSetting;
private static VNewSetting mVNewSetting;
private static AppEntity mNew32UpdateEntity;
public static BehaviorSubject<VNewSetting> vNewSettingSubject = BehaviorSubject.create();
private static GameGuidePopupEntity mGameGuidePopupEntity;
private static SharedPreferences mDefaultSharedPreferences;
@ -77,24 +91,11 @@ public class Config {
return !SPUtils.getBoolean(Constants.SP_TEENAGER_MODE);
}
/**
* VPN 开关选项是否开启
*/
public static boolean isVpnOptionEnabled() {
if (mNewApiSettingsEntity == null
|| mNewApiSettingsEntity.getInstall() == null
|| mNewApiSettingsEntity.getInstall().getVpnRequired() == null) {
return false;
}
return mNewApiSettingsEntity.getInstall().getVpnRequired().getShouldShowVpnOption();
}
public static void setSettings(SettingsEntity settingsEntity) {
getPreferences().edit().putString(SETTINGS_KEY, GsonUtils.toJson(settingsEntity)).apply();
mSettingsEntity = settingsEntity;
PackageHelper.refreshList();
PackageHelper.refreshPackageNameList();
}
@Nullable
@ -195,6 +196,27 @@ public class Config {
return mVSetting;
}
@Nullable
public static VNewSetting getVNewSettingEntity() {
if (mVNewSetting == null) {
try {
String json = SPUtils.getString(Constants.SP_V_NEW_SETTINGS);
if (!TextUtils.isEmpty(json)) {
mVNewSetting = GsonUtils.fromJson(json, VNewSetting.class);
vNewSettingSubject.onNext(mVNewSetting);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return mVNewSetting;
}
@Nullable
public static AppEntity getNew32UpdateEntity() {
return mNew32UpdateEntity;
}
/**
* 请求网络数据,尝试刷新畅玩相关配置
*/
@ -215,6 +237,36 @@ public class Config {
});
}
@SuppressLint("CheckResult")
public static void getNewSetting() {
VApiService vApi = RetrofitManager.getInstance().getVApi();
vApi.getNewSettings(BuildConfig.VERSION_NAME, Build.VERSION.SDK_INT).flatMap(new Function<VNewSetting, SingleSource<AppEntity>>() {
@Override
public SingleSource<AppEntity> apply(VNewSetting data) throws Exception {
mVNewSetting = data;
vNewSettingSubject.onNext(mVNewSetting);
SPUtils.setString(Constants.SP_V_NEW_SETTINGS, GsonUtils.toJson(data));
if (data.getVa() != null && data.getVa().getArch32() != null) {
String versionNameByPackageName = PackageUtils.getVersionNameByPackageName(data.getVa().getArch32().getPackageName());
return vApi.getNewPackageUpdate(
BuildConfig.VERSION_NAME,
versionNameByPackageName != null ? versionNameByPackageName : "",
HaloApp.getInstance().getChannel()
);
}
return Single.error(new IllegalStateException("VNewSetting entity is not expected"));
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<AppEntity>() {
@Override
public void onSuccess(AppEntity data) {
mNew32UpdateEntity = data;
}
});
}
@Nullable
public static GameGuidePopupEntity getGameGuidePopupEntity() {
return mGameGuidePopupEntity;
@ -269,6 +321,7 @@ public class Config {
});
refreshVSettingEntity();
getNewSetting();
RetrofitManager.getInstance()
.getApi().getGameGuidePopup(Build.MANUFACTURER, Build.VERSION.RELEASE, Build.MODEL, channel, BuildConfig.VERSION_NAME)
@ -309,7 +362,9 @@ public class Config {
String filterString = UrlFilterUtils.getFilterQuery(
"manufacturer", Build.MANUFACTURER,
"model", Build.MODEL,
"android_sdk_version", String.valueOf(Build.VERSION.SDK_INT));
"android_sdk_version", String.valueOf(Build.VERSION.SDK_INT),
"rom", MetaUtil.INSTANCE.getRom().name() + " " + MetaUtil.INSTANCE.getRom().getVersionName()
);
RetrofitManager.getInstance()
.getNewApi().getNewSettings(PackageUtils.getGhVersionName(), channel, filterString)
@ -331,8 +386,31 @@ public class Config {
if (mNewApiSettingsEntity.getGameShieldContents() != null) {
ContentBlockedHelper.INSTANCE.init(mNewApiSettingsEntity.getGameShieldContents());
}
// 更新安装列表是否开启的配置
if (mNewApiSettingsEntity.getInstalledComplianceSwitch() != null) {
PackageHelper.INSTANCE.updateIsGetInstalledPackagesApiAgreedRequired(mNewApiSettingsEntity.getInstalledComplianceSwitch());
} else {
PackageHelper.INSTANCE.updateIsGetInstalledPackagesApiAgreedRequired(false);
}
// 更新包名监听是否开启
if (mNewApiSettingsEntity.isPackageObserveEnable()) {
observePackageChange(mNewApiSettingsEntity.getPackageObserveActions());
}
}
});
}
}
public static void observePackageChange(NewApiSettingsEntity.PackageObserveActions packageObserveActions) {
PackageChangeBroadcastReceiver receiver = new PackageChangeBroadcastReceiver(packageObserveActions);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(packageObserveActions.getAdd());
intentFilter.addAction(packageObserveActions.getRem());
intentFilter.addAction(packageObserveActions.getRep());
intentFilter.addDataScheme("package");
HaloApp.getInstance().registerReceiver(receiver, intentFilter);
}
}

View File

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

View File

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

View File

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

View File

@ -8,6 +8,7 @@ import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IAppProvider
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.halo.assistant.HaloApp
import com.va.host.HostUtils
@Route(path = RouteConsts.provider.app, name = "Application暴露服务")
class AppProviderImpl : IAppProvider {
@ -86,4 +87,6 @@ class AppProviderImpl : IAppProvider {
override fun setSkippingThirdParty(isSkippingThirdParty: Boolean) {
HaloApp.getInstance().isSkippingThirdParty = isSkippingThirdParty
}
override fun getPluginVersion(): String = HostUtils.getPluginVersion()
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
package com.gh.common.provider
import android.app.Activity
import android.content.Context
import android.os.Bundle
import com.alibaba.android.arouter.facade.annotation.Route
@ -69,10 +70,18 @@ class DirectProviderImpl : IDirectProvider {
DirectUtils.directToAmway(context, fixedTopAmwayCommentId, entrance, path)
}
override fun directToQGame(context: Context) {
override fun directToQQGameHome(context: Context) {
return DirectUtils.directToQGameHome(context)
}
override fun directToQQGameById(activity: Activity, qqAppId: String) {
DirectUtils.directToQQGameById(activity, qqAppId)
}
override fun directToWechatGameById(activity: Activity, qqAppId: String) {
DirectUtils.directToWechatGameById(activity, qqAppId)
}
override fun directToExternalBrowser(context: Context, url: String) {
DirectUtils.directToExternalBrowser(context, url)
}

View File

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

View File

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

View File

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

View File

@ -14,12 +14,10 @@ import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.base.GlobalActivityManager;
import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.login.entity.IdCardEntity;
@ -32,8 +30,6 @@ import com.halo.assistant.HaloApp;
import com.lightgame.config.CommonDebug;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import io.reactivex.schedulers.Schedulers;
import io.sentry.Sentry;
import io.sentry.android.core.SentryAndroid;
@ -108,45 +104,51 @@ public class DataUtils {
}
public static void getGid() {
GidHelper.getInstance().registerDevice(HaloApp.getInstance().getApplication(), new GidCallback() {
@Override
public void onSuccess(String gid) {
Utils.log("Gid", gid);
PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit().putString(Constants.DEVICE_KEY, gid).apply();
// 默认用 APP 级已存储的 GID 来使用,不使用外部 GID
String savedGid = SPUtils.getString(Constants.GID);
if (!TextUtils.isEmpty(savedGid)) {
HaloApp.getInstance().setGid(savedGid);
onGidReceived(savedGid);
} else {
GidHelper.getInstance().registerDevice(HaloApp.getInstance().getApplication(), new GidCallback() {
@Override
public void onSuccess(String gid) {
Utils.log("Gid", gid);
PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit().putString(Constants.DEVICE_KEY, gid).apply();
// 默认用 APP 级已存储的 GID 来使用,不使用外部 GID
String savedGid = SPUtils.getString(Constants.GID);
if (!TextUtils.isEmpty(savedGid)) {
gid = savedGid;
} else {
SPUtils.setString(Constants.GID, gid);
onGidReceived(gid);
}
HaloApp.getInstance().setGid(gid);
// 更新广告配置
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
getDeviceCertification(gid);
// 避免初始化顺序问题导致 MetaUtil 一直持有空的 gid
MetaUtil.INSTANCE.refreshMeta();
ContentValues values = new ContentValues();
values.put(GhContentProvider.KEY_GID, gid);
values.put(GhContentProvider.KEY_ANDROID_ID, MetaUtil.getBase64EncodedAndroidId());
try {
HaloApp.getInstance().getContentResolver().insert(Uri.parse("content://com.gh.gamecenter.provider/device"), values);
} catch (Exception exception) {
SentryHelper.INSTANCE.onEvent("DEVICE_INSERT_ERROR", "exception_digest", exception.getLocalizedMessage());
exception.printStackTrace();
@Override
public void onFailure(String s) {
// 更新广告配置
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
}
}
});
}
}
@Override
public void onFailure(String s) {
// 更新广告配置
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
private static void onGidReceived(String gid) {
HaloApp.getInstance().setGid(gid);
// 更新广告配置
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
getDeviceCertification(gid);
// 避免初始化顺序问题导致 MetaUtil 一直持有空的 gid
MetaUtil.INSTANCE.refreshMeta();
AppExecutor.getIoExecutor().execute(() -> {
ContentValues values = new ContentValues();
values.put(GhContentProvider.KEY_GID, gid);
values.put(GhContentProvider.KEY_ANDROID_ID, MetaUtil.getBase64EncodedAndroidId());
try {
HaloApp.getInstance().getContentResolver().insert(Uri.parse("content://com.gh.gamecenter.provider/device"), values);
} catch (Exception exception) {
SentryHelper.INSTANCE.onEvent("DEVICE_INSERT_ERROR", "exception_digest", exception.getLocalizedMessage());
exception.printStackTrace();
}
});
}

View File

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

View File

@ -43,11 +43,13 @@ import com.gh.gamecenter.feature.entity.MeEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.feature.provider.IConcernInfoProvider
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.forum.home.CommunityActivity
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailActivity
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailFragment
import com.gh.gamecenter.game.commoncollection.detail.CustomCommonCollectionDetailActivity
import com.gh.gamecenter.game.upload.GameSubmissionActivity
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
@ -63,6 +65,9 @@ import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.help.HelpAndFeedbackBridge
import com.gh.gamecenter.libao.LibaoDetailActivity
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.minigame.MiniGameRecentlyPlayUseCase
import com.gh.gamecenter.minigame.MiniGameSearchActivity
import com.gh.gamecenter.minigame.qq.QGameHomeWrapperActivity
import com.gh.gamecenter.newsdetail.NewsDetailActivity
import com.gh.gamecenter.personalhome.UserHomeActivity
import com.gh.gamecenter.personalhome.background.PersonalityBackgroundActivity
@ -73,9 +78,6 @@ import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
import com.gh.gamecenter.qgame.QGameHomeWrapperActivity
import com.gh.gamecenter.qgame.QGameSearchActivity
import com.gh.gamecenter.qgame.QGameViewModel
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.servers.GameServerTestActivity
import com.gh.gamecenter.servers.GameServersActivity
@ -95,6 +97,8 @@ import com.gh.vspace.VDownloadManagerActivity
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.WebFragment
import com.lightgame.utils.Utils
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
@ -108,8 +112,14 @@ import kotlin.math.roundToInt
object DirectUtils {
@JvmStatic
fun directToLinkPage(context: Context, linkEntity: LinkEntity, entrance: String, path: String, sourceEntrance: String = "") {
directToLinkPage(context, linkEntity, entrance, path, null, sourceEntrance)
fun directToLinkPage(
context: Context,
linkEntity: LinkEntity,
entrance: String,
path: String,
sourceEntrance: String = ""
) {
directToLinkPage(context, linkEntity, entrance, path, null, sourceEntrance)
}
@JvmStatic
@ -243,7 +253,7 @@ object DirectUtils {
path
)
HOST_WEB, HOST_WEB_INURL, HOST_WEB_AL -> {
HOST_WEB, HOST_WEB_INURL, HOST_WEB_AL, HOST_QA_CONTENT -> {
when {
linkEntity.link!!.contains("v.douyin") && PackageHelper.localPackageNameSet.contains("com.ss.android.ugc.aweme") -> {
directDouyin(context, "1402577827140941")
@ -343,7 +353,7 @@ object DirectUtils {
"feedback" -> directToFeedback(context, linkEntity.name, false, "", false, false, entrance)
"qa", "qa_content", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
"qa", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
"qa_list" -> directToHelpAndFeedback(context)
@ -475,17 +485,22 @@ object DirectUtils {
)
)
"qq_mini_game_column" -> directToQGameHome(context)
ColumnCollectionDetailFragment.TYPE_QQ_MINI_GAME_COLUMN -> directToQGameHome(context)
// QQ游戏专题详情页
"qq_mini_game_column_detail" -> {
ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN, ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN -> {
val subjectType = if (linkEntity.type == ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN) {
SubjectData.SubjectType.QQ_GAME
} else {
SubjectData.SubjectType.WECHAT_GAME
}
directToSubject(
context = context,
id = linkEntity.link ?: "",
subjectName = linkEntity.text,
entrance = BaseActivity.mergeEntranceAndPath(entrance, path),
exposureEvent = exposureEvent,
isQQMiniGame = true
subjectType = subjectType
)
}
@ -536,6 +551,10 @@ object DirectUtils {
}
}
"wechat_game" -> linkEntity.link?.let {
MiniGameItemHelper.launchMiniGame(it, Constants.WECHAT_MINI_GAME)
}
"" -> {
// do nothing
}
@ -774,7 +793,12 @@ object DirectUtils {
}
}
if (traceEvent != null) {
val clickEvent = createEvent(GameEntity(id = id, name = name), traceEvent.source, appendTrace(traceEvent), ExposureType.CLICK)
val clickEvent = createEvent(
GameEntity(id = id, name = name),
traceEvent.source,
appendTrace(traceEvent),
ExposureType.CLICK
)
log(clickEvent)
bundle.putParcelable(KEY_TRACE_EVENT, clickEvent)
}
@ -837,12 +861,12 @@ object DirectUtils {
subjectName: String? = "",
entrance: String? = null,
exposureEvent: ExposureEvent? = null,
isQQMiniGame: Boolean = false,
subjectType: SubjectData.SubjectType = SubjectData.SubjectType.NORMAL
) {
if (id.isEmpty()) return
val bundle = Bundle()
val subjectData =
SubjectData(subjectId = id, subjectName = subjectName, isOrder = false, isQQMiniGame = isQQMiniGame)
SubjectData(subjectId = id, subjectName = subjectName, isOrder = false, subjectType = subjectType)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, SubjectActivity::class.java.name)
bundle.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, subjectData)
@ -991,7 +1015,13 @@ object DirectUtils {
}
@JvmStatic
fun directToQuestionDetail(context: Context, id: String, entrance: String? = null, path: String? = null, sourceEntrance: String = "") {
fun directToQuestionDetail(
context: Context,
id: String,
entrance: String? = null,
path: String? = null,
sourceEntrance: String = ""
) {
if (id.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
@ -1935,7 +1965,7 @@ object DirectUtils {
}
@JvmStatic
fun directToQGameSearch(
fun directToMiniGameSearch(
context: Context,
hint: String,
sourceEntrance: String,
@ -1947,7 +1977,7 @@ object DirectUtils {
searchBoxPattern: String = ""
) {
context.startActivity(
QGameSearchActivity.getIntent(
MiniGameSearchActivity.getIntent(
context,
hint,
sourceEntrance,
@ -1963,11 +1993,10 @@ object DirectUtils {
@SuppressLint("CheckResult")
@JvmStatic
fun directToQGameById(
fun directToQQGameById(
activity: Activity,
qqGameId: String
qqAppId: String
) {
if (activity !is AppCompatActivity || activity.supportFragmentManager.isDestroyed) {
ToastUtils.toast("启动QQ小游戏失败请稍后再试")
return
@ -1988,25 +2017,40 @@ object DirectUtils {
val qGameProvider = ARouter
.getInstance()
.build(RouteConsts.provider.qGame)
.navigation() as IQGameProvider<*>
.navigation() as IQGameProvider
qGameProvider.setLoginInfo(activity, userId, userName, userToken)
qGameProvider.launchGame(activity, qqGameId) { _, _ ->
RetrofitManager
.getInstance()
.newApi
.postQGamePlay(qqGameId, userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
QGameViewModel.notifyQGameSubjectUpdate() // 通知QQ小游戏首页列表刷新
},
{}
) // 秒玩记录上报
qGameProvider.launchGame(activity, qqAppId) { _, _ ->
MiniGameRecentlyPlayUseCase.submitRecentPlayedQGame(qqAppId, userId)
}
}
}
@SuppressLint("CheckResult")
fun directToWechatGameById(
activity: Activity,
wechatAppId: String,
) {
val wxApiProxy = WXAPIFactory.createWXAPI(
activity,
Config.WECHAT_APPID
)
if (!wxApiProxy.isWXAppInstalled) {
ToastUtils.toast("请安装微信客户端")
return
}
wxApiProxy.sendReq(
WXLaunchMiniProgram.Req().apply {
userName = wechatAppId
path = Constants.WECHAT_MINI_GAME_PCS
miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE;
}
)
MiniGameRecentlyPlayUseCase.submitRecentPlayedWGame(wechatAppId, HaloApp.getInstance().gid)
}
@JvmStatic
fun directToMessageCenter(defaultTabIndex: Int) {
ARouter.getInstance().build(RouteConsts.activity.messageWrapperActivity)
@ -2082,7 +2126,7 @@ object DirectUtils {
)
)
BottomTab.SearchStyle.TYPE_QQ_MINI_GAME -> directToQGameSearch(
BottomTab.SearchStyle.TYPE_MINI_GAME -> directToMiniGameSearch(
context,
"请输入小游戏关键词",
sourceEntrance,

View File

@ -27,7 +27,6 @@ import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.callback.CancelListener
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
@ -41,6 +40,7 @@ import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.teenagermode.TeenagerModeActivity
import com.gh.vspace.VHelper
import com.lightgame.download.DownloadConfig
@ -247,9 +247,8 @@ object DownloadItemUtils {
}
return
}
if (gameEntity.isQQMiniGame()) {
val isQQMiniGameOffShelve = gameEntity.qqMiniGameAppStatus == 1 // QQ小游戏是否下架
if (isQQMiniGameOffShelve) {
if (gameEntity.isMiniGame()) {
if (gameEntity.isMiniGameOffShelve()) {
downloadBtn.apply {
isClickable = false
text = context.getString(R.string.off_shelve)
@ -844,12 +843,11 @@ object DownloadItemUtils {
}
return
}
if (gameEntity.isQQMiniGame()) {
if (gameEntity.isMiniGame()) {
downloadBtn.setOnClickListener {
NewFlatLogUtils.logQGameClick(gameEntity.qqMiniGameAppId, gameEntity.name)
GlobalActivityManager.currentActivity?.let { activity ->
DirectUtils.directToQGameById(activity, gameEntity.qqMiniGameAppId)
}
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
clickCallback?.onCallback()
allStateClickCallback?.onCallback()
}
return
}

View File

@ -508,11 +508,18 @@ object DownloadObserver {
"space_schema_type",
if (downloadEntity.packageName == VHelper.VSPACE_32BIT_PACKAGENAME) "32位" else "64位"
)
} else if(downloadEntity.gameId == Constants.HALO_FUN_NEW_32_GAME_ID) {
SensorsBridge.trackEvent(
"HaloFunDownloadDone",
"space_schema_type",
"32位(新)"
)
}
if (downloadEntity.gameId != Constants.GHZS_GAME_ID
&& downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) != Constants.SIMULATOR_DOWNLOAD
&& downloadEntity.gameId != Constants.HALO_FUN_GAME_ID
&& downloadEntity.gameId != Constants.HALO_FUN_NEW_32_GAME_ID
) {
val trackJson = downloadEntity.customPageTrackDataJson
val kvs = if (!trackJson.isNullOrBlank()) {

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
package com.gh.common.util
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
@ -7,15 +8,31 @@ import android.content.pm.PackageManager
import android.content.pm.PermissionInfo
import android.os.Build
import android.provider.Settings
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.gh.common.constant.Config
import com.gh.gamecenter.common.utils.PermissionHelper.isGetInstalledListPermissionDisabled
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.PermissionHelper
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.core.GHThreadFactory
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.WhitePackageListEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.*
import java.util.HashMap
import java.util.concurrent.Executors
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
@ -23,16 +40,34 @@ object PackageHelper {
private const val TAG = "PackageHelper"
private const val SP_GET_INSTALLED_API_AGREED = "get_installed_api_agreed"
private const val SP_GET_INSTALLED_PACKAGES_AGREED = "get_installed_packages_agreed" // 用户是否同意使用已安装应用列表 API
private const val SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API = "get_installed_packages_by_alternative_api" // 是否使用另类方式获取已安装应用列表
private const val SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE = "user_used_get_installed_api_switch_package" // 用户是否使用过含有已安装应用列表获取开关的包
private const val SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST = "additional_whitelist_package_name_list" // 额外的白名单包名列表 (曾经更正为已安装的包名列表)
private const val UNKNOWN = -1
private const val UNSUPPORTED = 0
private const val SUPPORTED = 1
private var lastInstalledPackageListTime = 0L
private var installedPackageList: List<PackageInfo> = arrayListOf()
private var isGetInstalledPackagesApiAgreed = false
private var isGetInstalledListPermissionSupported = UNKNOWN // 设备是否支持禁用获取已安装应用列表。-1 代表支持情况未知0 代表不支持, 1 代表支持
private const val ENABLED = 2
private const val DISABLED = 3
private var lastSuccessfullyGetInstalledPackagesTimeMills = 0L
private var cachedInstalledPackagesList: List<PackageInfo> = arrayListOf()
private var additionalWhiteListPackageNameSet: HashSet<String> = hashSetOf()
private var isGetInstalledPackagesAgreed = false // 用户是否已经同意使用已安装应用列表
private var isGetInstalledPackagesAgreedRequired = UNKNOWN // 需要用户手动授权才获取已安装应用列表的功能的开关
private var isGetInstalledPackagesPermissionSupported = UNKNOWN // 设备是否支持禁用获取已安装应用列表
private var useAlternativeWayToGetInstalledPackages = false
private var cachedPkgNameAndGameEntityMap = HashMap<String, GameEntity>() // 缓存的状态异常包名和游戏实体的映射 (用于免接口请求更新状态)
private val packageExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_PACKAGE_THREAD")) }
// 评论黑名单包名列表,避免用户安装了 Xposed Installer 这样的工具,也能在包含该安装包的游戏详情页评论
private var _commentPackageNameBlackList = arrayListOf<String>()
@ -50,6 +85,10 @@ object PackageHelper {
private var _relatedPackageList = arrayListOf<SettingsEntity.GameWithPackages>()
val relatedPackageList: ArrayList<SettingsEntity.GameWithPackages> = _relatedPackageList
// 接口控制的已安装应用列表获取开关状态 (UI 显示)
private var _installedPackageApiSwitchStatusLiveData = MutableLiveData<Boolean>()
val installedPackageApiSwitchStatusLiveData: LiveData<Boolean> = _installedPackageApiSwitchStatusLiveData
// 本地已安装包的列表
var localPackageNameSet = hashSetOf<String>()
get() {
@ -61,6 +100,62 @@ object PackageHelper {
}
}
/**
* 检查是否需要忽略接口控制的已安装应用列表获取开关
* 用于覆盖安装首次启动时的检查 https://jira.shanqu.cc/browse/GHZSCY-5694
*/
fun checkIfGetInstalledApiSwitchShouldBeIgnored(context: Context) {
val userHasUsedGetInstalledApiSwitchPackage = SPUtils.getBoolean(SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE, false)
if (!userHasUsedGetInstalledApiSwitchPackage) {
val isSupportGetInstalledAppsPermission = isSupportGetInstalledAppsPermission(context)
if (!isSupportGetInstalledAppsPermission) {
// 设备不支持动态管理获取已安装应用列表,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
onGetInstalledPackagesAgreed()
} else if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
// 设备支持动态管理获取已安装应用列表但已经授权,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
onGetInstalledPackagesAgreed()
}
SPUtils.getBoolean(SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE, true)
}
}
/**
* 获取包名白名单列表(为了在没有已安装应用列表获取能力的时候也能正常判断更新、插件化)
* @param additionalWhiteList 额外的已安装白名单
*/
@SuppressLint("CheckResult")
fun getPackagesWhiteList(additionalWhiteList: HashSet<String>) {
RetrofitManager.getInstance().newApi.installWhitelist
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<WhitePackageListEntity>() {
override fun onSuccess(data: WhitePackageListEntity) {
val installedWhiteList = hashSetOf<String>()
if (additionalWhiteList.isNotEmpty()) {
installedWhiteList.addAll(additionalWhiteList)
}
data.data?.let {
installedWhiteList.addAll(it)
}
addInstalledButMissingPackages(installedWhiteList)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
if (additionalWhiteList.isNotEmpty()) {
addInstalledButMissingPackages(additionalWhiteList)
}
}
})
}
@JvmStatic
fun refreshLocalPackageList() {
localPackageNameSet = getAllPackageName(HaloApp.getInstance().application)
@ -68,7 +163,7 @@ object PackageHelper {
}
@JvmStatic
fun refreshList() {
fun refreshPackageNameList() {
Config.getSettings()?.gameCommentBlackList?.let { _commentPackageNameBlackList = ArrayList(it) }
Config.getSettings()?.gameDownloadBlackList?.let { _downloadPackageNameBlackList = ArrayList(it) }
Config.getSettings()?.gamePackageMatch?.let { _relatedPackageList = ArrayList(it) }
@ -106,24 +201,90 @@ object PackageHelper {
* 弃用已安装列表缓存
*/
fun dumpInstalledListCache() {
lastInstalledPackageListTime = 0
lastSuccessfullyGetInstalledPackagesTimeMills = 0
}
/**
* 在超时后,若后台没有开启获取已安装应用列表的功能,回落到以接口不控制的方式获取已安装应用列表
*/
fun ignoreInstalledPackageApiSwitchAfterTimeout(timeout: Long) {
CoroutineScope(SupervisorJob()).launch {
delay(timeout)
if (isGetInstalledPackagesAgreedRequired == UNKNOWN && !isGetInstalledPackagesAgreed()) {
Utils.log(TAG, "后台没有开启获取已安装应用列表的功能,超时后回落到以接口不控制的方式获取已安装应用列表")
updateIsGetInstalledPackagesApiAgreedRequired(false)
}
}
}
/**
* 更新已安装应用列表获取开关状态
*/
fun updateIsGetInstalledPackagesApiAgreedRequired(isEnabled: Boolean) {
Utils.log(TAG, "updateIsGetInstalledPackagesApiAgreedRequired 入参为 $isEnabled")
// 状态不变,无需更新
if ((isEnabled == true && isGetInstalledPackagesAgreedRequired == ENABLED)
|| (isEnabled == false && isGetInstalledPackagesAgreedRequired == DISABLED)
) {
Utils.log(TAG, "isGetInstalledPackagesApiAgreedRequired 状态不变,无需更新")
return
}
// 若用户已经同意使用了,无需更新
if (isGetInstalledPackagesAgreed()) {
Utils.log(TAG, "用户已经同意使用了,无需再更新已安装应用列表获取开关状态")
return
}
if (isEnabled) {
Utils.log(TAG, "开启获取已安装应用列表限制")
additionalWhiteListPackageNameSet = SPUtils.getString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST).toObject() ?: hashSetOf()
Utils.log(TAG, "额外的白名单为 $additionalWhiteListPackageNameSet")
getPackagesWhiteList(additionalWhiteListPackageNameSet)
_installedPackageApiSwitchStatusLiveData.postValue(true)
isGetInstalledPackagesAgreedRequired = ENABLED
} else {
Utils.log(TAG, "不开启获取已安装应用列表限制")
isGetInstalledPackagesAgreedRequired = DISABLED
// 启用另类获取已安装应用列表的 API
updateUseAlternativeWayToGetInstalledPackages()
onGetInstalledPackagesAgreed()
}
}
/**
* 用户是否已经允许了调用获取已安装应用列表接口
* 优先用内存的值,没有再从 SP 中获取并更新
*/
fun isGetInstalledPackagesApiAgreed(): Boolean {
return isGetInstalledPackagesApiAgreed
|| (SPUtils.getBoolean(SP_GET_INSTALLED_API_AGREED).also { isGetInstalledPackagesApiAgreed = it })
fun isGetInstalledPackagesAgreed(): Boolean {
return isGetInstalledPackagesAgreed
|| (SPUtils.getBoolean(SP_GET_INSTALLED_PACKAGES_AGREED).also { isGetInstalledPackagesAgreed = it })
}
/**
* 同意使用已安装应用列表 API
* 用户是否已经允许了调用获取已安装应用列表接口
* 优先用内存的值,没有再从 SP 中获取并更新
*/
fun agreeOnGetInstalledPackagesApi() {
isGetInstalledPackagesApiAgreed = true
SPUtils.setBoolean(SP_GET_INSTALLED_API_AGREED, true)
private fun isUseAlternativeWayToGetInstalledPackages(): Boolean {
return useAlternativeWayToGetInstalledPackages
|| (SPUtils.getBoolean(SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API).also { useAlternativeWayToGetInstalledPackages = it })
}
private fun updateUseAlternativeWayToGetInstalledPackages() {
// 启用另类获取已安装应用列表的 API
useAlternativeWayToGetInstalledPackages = true
SPUtils.setBoolean(SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API, true)
}
fun isGetInstalledPackagesAgreedRequired(): Boolean {
return isGetInstalledPackagesAgreedRequired == ENABLED
}
/**
@ -132,52 +293,158 @@ object PackageHelper {
fun getInstalledPackages(context: Context?, flags: Int): List<PackageInfo> {
Utils.log(TAG, "即将获取已安装应用列表")
// Utils.log(TAG, "即将获取已安装应用列表" + Thread.currentThread().getStackTrace().contentToString().replace( ',', '\n' ))
// 用户未同意使用已安装应用列表 API返回空列表
if (!isGetInstalledPackagesApiAgreed()) {
if (!isGetInstalledPackagesAgreed()) {
Utils.log(TAG, "用户未同意使用已安装应用列表 API返回空列表")
return installedPackageList
return cachedInstalledPackagesList
}
// 简单 debounce 过于频繁的获取已安装应用列表调用
if (System.currentTimeMillis() - lastInstalledPackageListTime < 3000 && installedPackageList.isNotEmpty()) {
if (System.currentTimeMillis() - lastSuccessfullyGetInstalledPackagesTimeMills < 20 * 1000
&& cachedInstalledPackagesList.isNotEmpty()) {
Utils.log(TAG, "使用了缓存的已安装应用列表")
return installedPackageList
return cachedInstalledPackagesList
}
var shouldGetNewInstalledPackagedList = false
// 当前设备是否支持限制获取已安装应用列表的功能
if (isSupportGetInstalledAppsPermission(context!!)) {
Utils.log(TAG, "当前设备支持限制获取已安装应用列表的功能")
Utils.log(TAG, "当前设备支持动态管理获取已安装应用列表的功能")
// 当前设备是否支持禁用了获取已安装应用列表
if (!isGetInstalledListPermissionDisabled(context)) {
Utils.log(TAG, "当前设备没有限制获取已安装应用列表的功能")
if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
Utils.log(TAG, "当前设备支持动态管理但没有限制获取已安装应用列表的功能")
shouldGetNewInstalledPackagedList = true
} else {
Utils.log(TAG, "当前设备已限制获取已安装应用列表的功能")
Utils.log(TAG, "当前设备支持动态管理且已限制获取已安装应用列表的功能")
}
} else {
Utils.log(TAG, "当前设备不支持限制获取已安装应用列表的功能")
Utils.log(TAG, "当前设备不支持动态管理获取已安装应用列表的功能")
shouldGetNewInstalledPackagedList = true
}
if (shouldGetNewInstalledPackagedList) {
lastInstalledPackageListTime = System.currentTimeMillis()
installedPackageList = getInstalledPackagesInternal(context, flags)
lastSuccessfullyGetInstalledPackagesTimeMills = System.currentTimeMillis()
cachedInstalledPackagesList = getInstalledPackagesInternal(context, flags)
Utils.log(TAG, "获取已安装应用列表成功,数量为 ${cachedInstalledPackagesList.size}")
}
return installedPackageList
return cachedInstalledPackagesList
}
/**
* 显示获取已安装应用列表的对话框并请求权限
*/
fun showGetInstallAppsListDialogAndRequestPermissionIfNeeded(
activity: FragmentActivity,
ignorePermanentlyDenied: Boolean = false,
resultClosure: (Boolean) -> Unit
) {
if (isSupportGetInstalledAppsPermission(activity)) {
// 若系统已经授予了获取应用列表的权限,直接执行授权成功回调
if (!PermissionHelper.isGetInstalledListPermissionDisabled(activity)) {
onGetInstalledPackagesAgreed()
resultClosure.invoke(true)
return
}
PermissionHelper.showGetInstalledAppsListPermissionDialog(
activity = activity,
requestPermission = true,
ignorePermanentlyDenied = ignorePermanentlyDenied
) { isGranted ->
if (isGranted) {
SensorsBridge.trackInstalledListPermissionsResult("成功")
onGetInstalledPackagesAgreed()
resultClosure.invoke(true)
trackInstalledListAfterDelay()
} else {
resultClosure.invoke(false)
SensorsBridge.trackInstalledListPermissionsResult("拒绝")
}
}
} else {
val hintDialog = PermissionHelper.showGetInstalledAppsListPermissionDialog(
activity = activity,
requestPermission = false,
) {
// do nothing
}
SensorsBridge.trackInstalledListPermissionsCustomDialogShow()
val noticeDialog = DialogHelper.showGuideDialog(
context = activity,
title = "权限申请",
content = "是否允许“光环助手”获取已安装的应用信息",
confirmText = "开启",
cancelText = "拒绝",
confirmClickCallback = {
SensorsBridge.trackInstalledListPermissionsCustomClick("开启")
onGetInstalledPackagesAgreed()
resultClosure.invoke(true)
trackInstalledListAfterDelay()
},
cancelClickCallback = {
resultClosure.invoke(false)
SensorsBridge.trackInstalledListPermissionsCustomClick("拒绝")
}
)
noticeDialog?.setOnDismissListener {
hintDialog?.dismiss()
}
}
}
/**
* 执行用户授权获取已安装应用列表的操作
*/
private fun onGetInstalledPackagesAgreed() {
isGetInstalledPackagesAgreed = true
SPUtils.setBoolean(SP_GET_INSTALLED_PACKAGES_AGREED, true)
_installedPackageApiSwitchStatusLiveData.postValue(false)
// 进行包名初始化相关的操作
initPackageRelatedData()
}
/**
* 进行包名初始化相关的操作
*/
fun initPackageRelatedData() {
PackageRepository.initData()
refreshLocalPackageList()
refreshPackageNameList()
}
/**
* 延迟5秒后上报已安装应用列表
*/
private fun trackInstalledListAfterDelay() {
CoroutineScope(SupervisorJob()).launch {
delay(5000)
SensorsBridge.trackNumberOfInstalledList(localPackageNameSet.size, localPackageNameSet)
}
}
/**
* 是否支持动态获取已安装应用列表权限
*/
fun isSupportGetInstalledAppsPermission(context: Context): Boolean {
if (isUseAlternativeWayToGetInstalledPackages()) {
// 已经使用另类获取已安装应用列表形式,强制判定为不支持动态获取已安装应用列表权限
return false
}
// 若存在缓存,直接返回缓存结果。
if (isGetInstalledListPermissionSupported != UNKNOWN) {
return isGetInstalledListPermissionSupported != UNSUPPORTED
if (isGetInstalledPackagesPermissionSupported != UNKNOWN) {
return isGetInstalledPackagesPermissionSupported != UNSUPPORTED
}
try {
@ -185,7 +452,7 @@ object PackageHelper {
val flag =
Settings.Secure.getInt(context.contentResolver, "oem_installed_apps_runtime_permission_enable", 0)
if (flag == 1) {
isGetInstalledListPermissionSupported = SUPPORTED
isGetInstalledPackagesPermissionSupported = SUPPORTED
return true
}
@ -194,62 +461,239 @@ object PackageHelper {
val permissionInfo = packageManager.getPermissionInfo("com.android.permission.GET_INSTALLED_APPS", 0)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (permissionInfo.protection == PermissionInfo.PROTECTION_DANGEROUS) {
isGetInstalledListPermissionSupported = SUPPORTED
isGetInstalledPackagesPermissionSupported = SUPPORTED
return true
} else {
isGetInstalledListPermissionSupported = UNSUPPORTED
isGetInstalledPackagesPermissionSupported = UNSUPPORTED
return false
}
} else {
isGetInstalledListPermissionSupported = UNSUPPORTED
isGetInstalledPackagesPermissionSupported = UNSUPPORTED
return false
}
} catch (e: PackageManager.NameNotFoundException) {
isGetInstalledListPermissionSupported = UNSUPPORTED
isGetInstalledPackagesPermissionSupported = UNSUPPORTED
return false
}
}
/**
* 在5.1系统手机使用PackageManager获取已安装应用容易发生Package manager has died异常
* https://stackoverflow.com/questions/13235793/transactiontoolargeeception-when-trying-tÏo-get-a-list-of-applications-installed/30062632#30062632
* 确保指定包名的应用在已安装了的情况下能正常收录
*/
private fun getInstalledPackagesInternal(context: Context, flags: Int): List<PackageInfo> {
Utils.log(TAG, "调用系统 API 获取已安装应用列表")
fun addInstalledButMissingPackages(packageNameSet: HashSet<String>) {
Utils.log(TAG, "addInstalledButMissingPackages 检查已安装但未收录的应用")
val installedPackageNameSet: HashSet<String> = hashSetOf()
for (packageName in packageNameSet) {
val installedPkgNameExistInMemory = PackagesManager.isInstalled(packageName)
val packageNameInstalledOnDevice = PackageUtils.getVersionNameByPackageName(packageName) != null
if (!installedPkgNameExistInMemory && packageNameInstalledOnDevice) {
installedPackageNameSet.add(packageName)
}
if (!packageNameInstalledOnDevice) {
additionalWhiteListPackageNameSet.remove(packageName)
}
}
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toJson())
Utils.log(TAG, "addInstalledButMissingPackages 需要请求接口获取的包数量为 ${installedPackageNameSet.size}")
PackageRepository.addInstalledGames(
pkgNameList = ArrayList(installedPackageNameSet),
updateInstallStatus = true
)
}
/**
* 更新额外的白名单包名列表
* @param packageName 包名
* @param isAdd 是否添加
*/
fun updateAdditionalWhiteListPackageName(packageName: String, isAdd: Boolean) {
val isUpdated = if (isAdd) {
additionalWhiteListPackageNameSet.add(packageName)
} else {
additionalWhiteListPackageNameSet.remove(packageName)
}
Utils.log(TAG, "updateAdditionalWhiteListPackageName 更新额外的白名单包名列表 $isAdd $packageName ,结果是 $isUpdated")
if (isUpdated) {
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toJson())
}
}
/**
* 刷新安装状态异常 (适用于仅存在包名信息的列表)
*/
fun refreshWrongInstallStatus(packageNameSet: MutableSet<String>) {
packageExecutor.execute {
Utils.log(TAG, "refreshWrongInstallStatus 检查安装状态异常的应用")
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
for (packageName in packageNameSet) {
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
if (PackagesManager.isInstalled(packageName)
&& installedVersionName == null) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName != null
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)) {
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
}
}
Utils.log(TAG, "refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}")
Utils.log(TAG, "refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}")
runOnUiThread {
if (uninstalledButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in uninstalledButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUninstall(packageName)
additionalWhiteListPackageNameSet.remove(packageName)
}
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toString())
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUpdate(packageName)
}
}
}
}
}
/**
* 刷新安装状态异常 (适用于存在游戏信息的列表)
*/
fun refreshWrongInstallStatus(gameEntityList: ArrayList<GameEntity>) {
packageExecutor.execute {
Utils.log(TAG, "refreshWrongInstallStatus 检查安装状态异常的应用")
val installedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
for (game in gameEntityList) {
for (apk in game.getApk()) {
val packageName = apk.packageName
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
if (!PackagesManager.isInstalled(packageName)
&& installedVersionName != null
) {
cachedPkgNameAndGameEntityMap.put(packageName, game)
installedButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName == null
) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName != null
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
&& !PackagesManager.isCanUpdate(game.id, packageName, false)
) {
cachedPkgNameAndGameEntityMap.put(packageName, game)
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
}
}
}
Utils.log(TAG, "refreshWrongInstallStatus 需要更新已安装状态的包数量为 ${installedButKeepingWrongStatusPackageNameSet.size}")
Utils.log(TAG, "refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}")
Utils.log(TAG, "refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}")
runOnUiThread {
if (installedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in installedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addInstall(packageName, cachedPkgNameAndGameEntityMap.remove(packageName))
additionalWhiteListPackageNameSet.add(packageName)
}
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toString())
}
if (uninstalledButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in uninstalledButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUninstall(packageName)
additionalWhiteListPackageNameSet.remove(packageName)
}
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toString())
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUpdate(packageName, cachedPkgNameAndGameEntityMap.remove(packageName))
}
}
}
}
}
private fun getInstalledPackagesInternal(
context: Context,
flags: Int
): List<PackageInfo> {
return if (isUseAlternativeWayToGetInstalledPackages()) {
Utils.log(TAG, "调用另类系统 API 获取已安装应用列表")
getInstalledPackageByAlternative(context)
} else {
Utils.log(TAG, "调用默认系统 API 获取已安装应用列表")
getInstalledPackageByDefault(context, flags)
}
}
private fun getInstalledPackageByDefault(context: Context, flags: Int): List<PackageInfo> {
val pm = context.packageManager
try {
return pm.getInstalledPackages(flags)
} catch (ignored: java.lang.Exception) {
//we don't care why it didn't succeed. We'll do it using an alternative way instead
}
// use fallback:
val process: Process
val result: MutableList<PackageInfo> = java.util.ArrayList()
var bufferedReader: BufferedReader? = null
try {
process = Runtime.getRuntime().exec("pm list packages")
bufferedReader = BufferedReader(InputStreamReader(process.inputStream))
var line: String
while ((bufferedReader.readLine().also { line = it }) != null) {
val packageName = line.substring(line.indexOf(':') + 1)
val packageInfo = pm.getPackageInfo(packageName, flags)
result.add(packageInfo)
}
process.waitFor()
} catch (e: java.lang.Exception) {
e.printStackTrace()
if (e is InterruptedException) {
Thread.currentThread().interrupt()
}
} finally {
if (bufferedReader != null) try {
bufferedReader.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return result
return arrayListOf()
}
private fun getInstalledPackageByAlternative(context: Context): ArrayList<PackageInfo> {
val packageManager = context.getPackageManager()
val packageList = arrayListOf<PackageInfo>()
var packagesArray: Array<String>? = null
var uid = android.os.Process.FIRST_APPLICATION_UID
while (uid <= android.os.Process.LAST_APPLICATION_UID) {
try {
packagesArray = packageManager.getPackagesForUid(uid)
if (packagesArray != null && packagesArray.isNotEmpty()) {
for (packageName in packagesArray) {
try {
val packageInfo = packageManager.getPackageInfo(packageName, 0)
if (packageInfo == null) {
break
}
packageList.add(packageInfo)
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
}
}
}
} catch (securityException: SecurityException) {
securityException.printStackTrace()
}
uid++
}
return packageList
}
}

View File

@ -6,7 +6,6 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import com.gh.common.dialog.InstallPermissionDialogFragment
@ -20,13 +19,13 @@ import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.install.InstallService
import com.gh.gamecenter.vpn.VpnHelper
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import java.io.File
// TODO 将弹窗改成以责任链模式来处理
object PackageInstaller {
/**
@ -108,6 +107,12 @@ object PackageInstaller {
return
}
val packageName = downloadEntity?.packageName ?: PackageUtils.getPackageNameByPath(context, pkgPath)
packageName?.let {
PackageChangeHelper.addInstallPendingPackage(packageName)
}
try {
// 判断是否需要使用浏览器来进行安装
if (BrowserInstallHelper.isUseBrowserToInstallEnabled()
@ -118,13 +123,13 @@ object PackageInstaller {
}
if (PackageUtils.isCanLaunchSetup(context, pkgPath)) {
val currentActivity = CurrentActivityHolder.getCurrentActivity()
if (VpnHelper.shouldUseVpn() && currentActivity is AppCompatActivity) {
turnOnVpnThenInstall(currentActivity, pkgPath, downloadEntity)
} else {
install(context, pkgPath)
}
installWithPureModeHandled(
context,
pkgPath,
downloadEntity?.gameId ?: "unknown",
downloadEntity?.name ?: "unknown",
downloadEntity?.categoryChinese ?: "unknown"
)
} else {
if (isPluggin) {
DialogHelper.showPluginDialog(
@ -154,6 +159,21 @@ object PackageInstaller {
}
}
/**
* 处理纯净模式后的安装
*/
private fun installWithPureModeHandled(
context: Context,
pkgPath: String,
gameId: String,
gameName: String,
gameType: String,
) {
PureModeHelper.handlePureModeIfNeeded(context, gameId, gameName, gameType) {
install(context, pkgPath)
}
}
/**
* 最终执行安装的方法
*/
@ -250,6 +270,8 @@ object PackageInstaller {
fun uninstallForPackageName(context: Context, pkn: String?) {
if (pkn.isNullOrEmpty()) return
PackageChangeHelper.addUninstallPendingPackage(pkn)
val uninstallIntent = Intent()
uninstallIntent.action = Intent.ACTION_DELETE
uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT)
@ -283,82 +305,4 @@ object PackageInstaller {
return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis())
}
/**
* 启动 VPN 然后安装应用 (若没有授权会先提醒授权 VPN ,若拒绝授权会回落到直接执行安装)
*/
private fun turnOnVpnThenInstall(currentActivity: AppCompatActivity,
pkgPath: String,
downloadEntity: DownloadEntity?) {
if (VpnHelper.isVpnPermissionGranted(currentActivity) == true) {
VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
if (shouldShowVpnError) {
ToastUtils.toast("安装防护功能启动失败")
}
install(currentActivity, pkgPath)
}
} else {
val isTheFirstTimeToShowVpnHintDialog = VpnHelper.isTheFistTimeToShowVpnHintDialog()
downloadEntity?.let {
NewFlatLogUtils.logVpnHintDialogShow(it.gameId, it.name)
}
// 将 VPN 提示弹窗标记为已读(已读后的下一次显示"不再提醒"按钮)
VpnHelper.setVpnHintDialogShowed()
if (!VpnHelper.shouldShowVpnHintDialog()) {
VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
if (shouldShowVpnError) {
ToastUtils.toast("安装防护功能启动失败")
}
install(currentActivity, pkgPath)
}
} else {
DialogHelper.showGuideDialog(
context = currentActivity,
title = "开启安装防护",
content = "建议您开启安装防护功能该功能有助于帮助您更快的完成安装避免因提示和置换导致的重复下载等问题安装防护功能需要获取您的VPN权限",
confirmText = "立即授权开启防护",
cancelText = "不再提醒",
confirmClickCallback = {
VpnHelper.ignoreVpnHintDialog()
VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
if (shouldShowVpnError) {
ToastUtils.toast("安装防护功能启动失败")
}
install(currentActivity, pkgPath)
}
downloadEntity?.let {
NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "立即授权")
}
},
cancelClickCallback = {
VpnHelper.ignoreVpnFunction()
install(currentActivity, pkgPath)
downloadEntity?.let {
NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "不再提醒")
}
},
extraConfig = DialogHelper.Config(
showCloseIcon = true,
showAlternativeCancelStyle = !isTheFirstTimeToShowVpnHintDialog
),
uiModificationCallback = { binding ->
binding.cancelTv.visibility = View.GONE
binding.closeContainer.setOnClickListener {
binding.markDismissByTouchInside()
install(currentActivity, pkgPath)
binding.dismiss()
downloadEntity?.let {
NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "关闭按钮")
}
}
}
)
}
}
}
}

View File

@ -7,14 +7,12 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionInfo;
import android.content.pm.Signature;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.TextUtils;
import androidx.annotation.NonNull;
@ -29,7 +27,6 @@ import com.gh.common.xapk.XapkInstaller;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.PermissionHelper;
import com.gh.gamecenter.core.utils.MD5Utils;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.feature.entity.ApkEntity;
@ -48,12 +45,10 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@ -74,7 +69,7 @@ public class PackageUtils {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).applicationInfo.sourceDir;
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return null;
}
@ -312,7 +307,7 @@ public class PackageUtils {
return new String[]{null, null};
}
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return new String[]{null, null};
}
@ -592,7 +587,7 @@ public class PackageUtils {
.getPackageInfo(packageName, 0);
return packageInfo.firstInstallTime;
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return 0;
}
@ -619,7 +614,7 @@ public class PackageUtils {
return HaloApp.getInstance().getApplication().getPackageManager()
.getPackageInfo(BuildConfig.APPLICATION_ID, 0).lastUpdateTime;
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return 0;
@ -633,7 +628,7 @@ public class PackageUtils {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return null;
}
@ -646,7 +641,7 @@ public class PackageUtils {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionCode;
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return 0;
}
@ -660,7 +655,7 @@ public class PackageUtils {
PackageManager packageManager = context.getApplicationContext().getPackageManager();
return packageManager.getApplicationIcon(packageName);
} catch (NameNotFoundException e) {
e.printStackTrace();
// do nothing
}
return null;
}

View File

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

View File

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

View File

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

View File

@ -62,7 +62,8 @@ object ViewPagerFragmentHelper {
const val TYPE_GAME_LIST = "game_list" // 游戏单广场
const val TYPE_FEEDBACK = "feedback" // 帮助与反馈
const val TYPE_COLUMN = "column" // 游戏专题详情页
const val TYPE_QQ_MINI_GAME_COLUMN = "qq_mini_game_column_detail" // QQ游戏专题详情页
const val TYPE_QQ_MINI_GAME_COLUMN = "qq_mini_game_column_detail" // QQ游戏专题详情页
const val TYPE_WECHAT_GAME_COLUMN = "wechat_game_column_detail" // 微信小游戏专题详情页
const val TYPE_COLUMN_COLLECTION = "column_collection" // 专题合集详情页
const val TYPE_SERVER = "server" // 开服表
const val TYPE_COLUMN_TEST = "column_test_v2" // 新游开测
@ -151,11 +152,16 @@ object ViewPagerFragmentHelper {
className = GameCollectionSquareFragment::class.java.name
}
// 游戏专题详情页/QQ游戏专题详情页
TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN -> {
TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN, TYPE_WECHAT_GAME_COLUMN -> {
val subjectType = when(entity.type) {
TYPE_QQ_MINI_GAME_COLUMN -> SubjectData.SubjectType.QQ_GAME
TYPE_WECHAT_GAME_COLUMN -> SubjectData.SubjectType.WECHAT_GAME
else -> SubjectData.SubjectType.NORMAL
}
className = SubjectFragment::class.java.name
bundle.putParcelable(
EntranceConsts.KEY_SUBJECT_DATA,
SubjectData(entity.link, entity.text, false, isQQMiniGame = entity.type == "qq_mini_game_column_detail")
SubjectData(entity.link, entity.text, false, subjectType = subjectType)
)
bundle.putBoolean(EntranceConsts.KEY_SHOW_DOWNLOAD_MENU, !isTabWrapper)
}

View File

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

View File

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

View File

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

View File

@ -22,7 +22,6 @@ import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.feature.entity.TagStyleEntity;
import com.gh.gamecenter.feature.entity.CustomPageTrackData;
import com.gh.gamecenter.feature.entity.TagStyleEntity;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
import com.gh.common.exposure.ExposureUtils;
import com.gh.common.history.HistoryHelper;
@ -34,16 +33,10 @@ import com.gh.common.util.LunchType;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.base.GlobalActivityManager;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.utils.DeviceUtils;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.FileUtils;
import com.gh.gamecenter.common.utils.NetworkUtils;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.utils.AppDebugConfig;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
import com.gh.gamecenter.core.utils.SPUtils;
@ -55,7 +48,6 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.PluginLocation;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.gamecenter.packagehelper.PackageRepository;
@ -64,7 +56,6 @@ import com.gh.ndownload.NDownloadBridge;
import com.gh.ndownload.NDownloadService;
import com.gh.vspace.VHelper;
import com.halo.assistant.HaloApp;
import com.lightgame.download.ConnectionUtils;
import com.lightgame.download.DataWatcher;
import com.lightgame.download.DownloadConfig;
import com.lightgame.download.DownloadDao;
@ -179,9 +170,6 @@ public class DownloadManager implements DownloadStatusListener {
mUpdateMarks = SPUtils.getStringSet(UPDATE_IS_READ_MARK);
// 只有下载模块需要这坨东西,因此移动到这里初始化
ConnectionUtils.initHttpsUrlConnection(mContext);
updateDownloadMetaMap();
lastTimeMap = new ArrayMap<>();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -24,7 +24,7 @@ import com.halo.assistant.HaloApp
/**
* Created by khy on 2017/3/24.
* 游戏详情适配器
* 游戏详情
*/
class GameDetailActivity : DownloadToolbarActivity() {

View File

@ -16,6 +16,7 @@ import java.util.ArrayList;
/**
* Created by khy on 2016/12/12.
* 礼包中心
*/
@Deprecated
public class LibaoActivity extends ToolBarActivity {

View File

@ -136,6 +136,9 @@ import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.HttpException;
@ -281,13 +284,12 @@ public class MainActivity extends BaseActivity {
Config.getGhzsSettings();
} else if (Config.getVSettingEntity() == null) {
Config.refreshVSettingEntity();
} else if (Config.getVNewSettingEntity() == null) {
Config.getNewSetting();
}
// 耗时操作
AppExecutor.getIoExecutor().execute(() -> {
// 上传数据
DataCollectionManager.getInstance().upload();
// 初始化PlatformUtils
PlatformUtils.getInstance(getApplicationContext());
@ -556,7 +558,10 @@ public class MainActivity extends BaseActivity {
} else {
TextView jumpBtn = findViewById(R.id.jumpBtn);
jumpBtn.setText(String.format(Locale.CHINA, "跳过 %d", COUNTDOWN_MAX_COUNT - mCountdownCount));
mBaseHandler.sendEmptyMessageDelayed(COUNTDOWN_AD, 1000);
Message newMsg = Message.obtain();
newMsg.what = COUNTDOWN_AD;
newMsg.obj = msg.obj;
mBaseHandler.sendMessageDelayed(newMsg, 1000);
}
}
}
@ -735,14 +740,11 @@ public class MainActivity extends BaseActivity {
ToastUtils.showToast("游戏启动中,请稍后~");
handler.postDelayed(() -> {
VHelper.postOnInitialized(() -> {
if (VHelper.isInstalled(gamePackageName)) {
VHelper.launch(this, gamePackageName, false, true);
} else {
ToastUtils.showToast("应用已被卸载!");
}
return null;
});
if(VHelper.isInnerInstalled(gamePackageName)) {
launchGame(gamePackageName).invoke();
} else {
VHelper.postOnInitialized(launchGame(gamePackageName));
}
}, 500);
break;
case KEY_MARKET_DETAILS:
@ -760,6 +762,19 @@ public class MainActivity extends BaseActivity {
}, 500);
}
@NonNull
private Function0<Unit> launchGame(String gamePackageName) {
return () -> {
if (!VHelper.isInnerInstalled(gamePackageName) && !VHelper.isInstalled(gamePackageName)) {
ToastUtils.showToast("应用已被卸载!");
} else {
VHelper.shortcutLaunch();
VHelper.launch(this, gamePackageName, false, true);
}
return null;
};
}
/**
* 应用跳转
*/
@ -877,13 +892,6 @@ public class MainActivity extends BaseActivity {
return true;
}
@Override
public void finish() {
// 上传数据
DataCollectionManager.getInstance().statClickData();
super.finish();
}
@Override
protected void onSaveInstanceState(@NotNull Bundle outState) {
super.onSaveInstanceState(outState);
@ -927,9 +935,11 @@ public class MainActivity extends BaseActivity {
Config.getGhzsSettings();
} else if (Config.getVSettingEntity() == null) {
Config.refreshVSettingEntity();
} else if (Config.getVNewSettingEntity() == null) {
Config.getNewSetting();
}
mPackageViewModel.checkData();
// mPackageViewModel.checkData();
deleteSimulatorGame();
}
}
@ -937,8 +947,10 @@ public class MainActivity extends BaseActivity {
// 接收登录和登出更新事件统计的 Meta
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBReuse reuse) {
if (reuse.getType().equals(LOGIN_TAG) || reuse.getType().equals(LOGOUT_TAG)) {
boolean isLoginEvent = reuse.getType().equals(LOGIN_TAG);
if (isLoginEvent || reuse.getType().equals(LOGOUT_TAG)) {
MetaUtil.INSTANCE.refreshMeta();
VHelper.INSTANCE.updateAuthorizeInfo(isLoginEvent);
}
}

View File

@ -17,6 +17,7 @@ import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.db.SearchHistoryDao
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.search.SearchDefaultFragment
@ -29,6 +30,9 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.concurrent.TimeUnit
/**
* 游戏搜索页
*/
open class SearchActivity : BaseActivity() {
lateinit var searchEt: EditText
@ -36,7 +40,7 @@ open class SearchActivity : BaseActivity() {
lateinit var backBtn: RelativeLayout
private lateinit var deleteIv: ImageView
private var mDao: SearchHistoryDao? = null
protected val mDao: ISearchHistoryDao by lazy { provideDao() }
protected var mSearchKey: String? = null
protected var mIsAutoSearchDisabled: Boolean = false
@ -75,7 +79,6 @@ open class SearchActivity : BaseActivity() {
val searchImmediately = intent.getBooleanExtra(KEY_SEARCH_IMMEDIATELY, false)
var ignoreTextChanges = savedInstanceState != null
mDao = SearchHistoryDao(this)
mPublishSubject = PublishSubject.create()
mPublishSubject!!
@ -99,7 +102,7 @@ open class SearchActivity : BaseActivity() {
searchEt.hint = hint
if (searchImmediately) {
mDisplayType = GAME_DETAIL
mDao?.add(hint)
mDao.add(hint)
search(SearchType.DEFAULT, hint)
}
} else {
@ -187,12 +190,12 @@ open class SearchActivity : BaseActivity() {
mIsAutoSearchDisabled = false
}
private fun handleAutoSearch(key: String?) {
protected open fun handleAutoSearch(key: String?) {
val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
if (newSearchKey.isEmpty()) {
val hint = searchEt.hint.toString()
if (!TextUtils.isEmpty(hint) && HINT_TEXT != hint) {
mDao?.add(hint)
mDao.add(hint)
search(SearchType.DEFAULT, hint)
}
} else {
@ -210,7 +213,7 @@ open class SearchActivity : BaseActivity() {
}
}
private fun handleDefaultSearch(key: String?) {
protected open fun handleDefaultSearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
@ -227,14 +230,14 @@ open class SearchActivity : BaseActivity() {
// MtaHelper.onEvent("游戏搜索", "默认搜索", key)
}
private fun handleHotSearch(key: String?) {
protected open fun handleHotSearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
updateDisplayType(GAME_DETAIL)
}
private fun handleHistorySearch(key: String?) {
protected open fun handleHistorySearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
@ -251,12 +254,12 @@ open class SearchActivity : BaseActivity() {
// MtaHelper.onEvent("游戏搜索", "历史搜索", key)
}
private fun handleManualSearch() {
protected open fun handleManualSearch() {
val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
if (newSearchKey.isEmpty()) {
val hint = searchEt.hint.toString()
if (!TextUtils.isEmpty(hint) && HINT_TEXT != hint) {
mDao?.add(hint)
mDao.add(hint)
search(SearchType.DEFAULT, hint)
}
} else if (newSearchKey != mSearchKey || mDisplayType != GAME_DETAIL) {
@ -270,7 +273,7 @@ open class SearchActivity : BaseActivity() {
mSourceEntrance
)
mDao?.add(mSearchKey)
mDao.add(mSearchKey)
updateDisplayType(GAME_DETAIL)
} else {
toast("请输入搜索内容")
@ -280,6 +283,8 @@ open class SearchActivity : BaseActivity() {
// MtaHelper.onEvent("游戏搜索", "主动搜索", newSearchKey)
}
protected open fun provideDao(): ISearchHistoryDao = SearchHistoryDao(this)
open fun updateDisplayType(type: DisplayType) {
val transaction = supportFragmentManager.beginTransaction()
when (type) {

View File

@ -48,6 +48,7 @@ import io.reactivex.functions.Consumer;
/**
* Created by khy on 2016/11/7.
* 分享卡片
*/
public class ShareCardPicActivity extends ToolBarActivity {

View File

@ -21,6 +21,7 @@ import com.tencent.tauth.Tencent;
/**
* Created by khy on 2017/2/6.
* 分享光环
*/
public class ShareGhActivity extends ToolBarActivity {

View File

@ -3,6 +3,7 @@ package com.gh.gamecenter;
import static com.gh.gamecenter.common.constant.EntranceConsts.ENTRANCE_BROWSER;
import static com.gh.gamecenter.common.constant.EntranceConsts.ENTRANCE_PUSH;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ANSWER;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ARCHIVE_LOGIN;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ARTICLE;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_CATEGORY;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COLUMN;
@ -21,6 +22,7 @@ import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_GAME;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_GROUP;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_QUN;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QUESTION;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_RESTART_GAME;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_SUGGESTION;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_TOOLBOX;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_UPLOAD_VIDEO;
@ -55,17 +57,22 @@ import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.entity.CommunityEntity;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.entity.SimpleGameEntity;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.entity.SubjectData;
import com.gh.gamecenter.entity.SubjectRecommendEntity;
import com.gh.gamecenter.entity.VideoLinkEntity;
import com.gh.gamecenter.feature.utils.PlatformUtils;
import com.gh.gamecenter.login.view.LoginActivity;
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper;
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel;
import com.gh.gamecenter.video.videomanager.VideoManagerActivity;
import com.gh.vspace.VHelper;
import com.gh.vspace.shortcut.OnCreateShortcutResult;
import com.gh.vspace.shortcut.ShortcutManager;
import com.gh.vspace.shortcut.ShortcutPermissionTipsDialog;
@ -152,7 +159,7 @@ public class SkipActivity extends BaseActivity {
DirectUtils.directToGameDetail(this, path, "", entrance, "true".equals(uri.getQueryParameter("auto_download")), to, null);
break;
case HOST_COLUMN:
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), entrance, null, false);
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), entrance, null, SubjectData.SubjectType.NORMAL);
break;
case HOST_SUGGESTION:
if (!TextUtils.isEmpty(qaId)) {
@ -401,10 +408,31 @@ public class SkipActivity extends BaseActivity {
try {
JSONObject extJsonObject = new JSONObject(extJson);
String qqGameId = extJsonObject.optString("aid");
DirectUtils.directToQGameById(this, qqGameId);
MiniGameItemHelper.INSTANCE.launchMiniGame(qqGameId, Constants.QQ_MINI_GAME);
} catch (JSONException ignored) {
}
break;
case HOST_ARCHIVE_LOGIN:
String gamePkg = uri.getQueryParameter(EntranceConsts.KEY_GAME_PKG);
if(CheckLoginUtils.isLogin()) {
VHelper.INSTANCE.updateAuthorizeInfo(true);
} else {
Bundle newBundle = new Bundle();
newBundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(this, null, newBundle, (resultCode, data) -> {
if(CheckLoginUtils.isLogin()) {
VHelper.INSTANCE.updateAuthorizeInfo(true);
}
VHelper.launch(this, gamePkg, false, false);
finish();
});
return;
}
break;
case HOST_RESTART_GAME:
String restartGamePkg = uri.getQueryParameter(EntranceConsts.KEY_GAME_PKG);
VHelper.launch(this, restartGamePkg, false, true);
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;

View File

@ -115,6 +115,7 @@ class SplashScreenActivity : BaseActivity() {
)
}
} else {
PackageHelper.checkIfGetInstalledApiSwitchShouldBeIgnored(this)
cancelPreviousUpdateTask()
launchMainActivity()
}
@ -167,10 +168,12 @@ class SplashScreenActivity : BaseActivity() {
if (isMalfunctioningHonorDevice) {
showHonorNotification()
mBaseHandler.postDelayed({
requestGetInstallListPermissionAndLaunchMainActivity()
launchMainActivity()
// requestGetInstallListPermissionAndLaunchMainActivity()
}, 100L)
} else {
requestGetInstallListPermissionAndLaunchMainActivity()
launchMainActivity()
// requestGetInstallListPermissionAndLaunchMainActivity()
}
} else {
DialogUtils.showPrivacyPolicyDisallowDialog(this) {
@ -196,9 +199,17 @@ class SplashScreenActivity : BaseActivity() {
}
// 尝试获取安装应用列表权限并启动首页(不在乎结果)
private fun requestGetInstallListPermissionAndLaunchMainActivity() {
launchMainActivity()
}
// private fun requestGetInstallListPermissionAndLaunchMainActivity() {
// if (PackageHelper.isSupportGetInstalledAppsPermission(this)
// && PermissionHelper.isGetInstalledListPermissionDisabled(this)
// ) {
// PermissionHelper.requestGetInstalledAppsListPermission(this, true) {
// launchMainActivity()
// }
// } else {
// launchMainActivity()
// }
// }
// 删除更新后的光环助手包
private fun cancelPreviousUpdateTask() {

View File

@ -7,6 +7,9 @@ import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.halo.assistant.fragment.user.UserInfoFragment
/**
* 编辑资料
*/
class UserInfoActivity : ToolBarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -8,6 +8,9 @@ import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.login.user.UserViewModel
import com.halo.assistant.fragment.user.UserInfoEditFragment
/**
* 修改个人信息
*/
class UserInfoEditActivity : ToolBarActivity() {
companion object {
fun getIntent(context: Context, editType: String): Intent {

View File

@ -8,6 +8,7 @@ import com.halo.assistant.fragment.user.SelectRegionFragment;
/**
* Created by khy on 25/09/17.
* 选择地区
*/
public class UserRegionActivity extends ToolBarActivity {

View File

@ -27,7 +27,7 @@ class CommunicationService : Service() {
override fun installGameCompleted(packageName: String, params: VGameInstallerResult) {
Utils.log(VHelper.LOG_TAG, "包名 $packageName 安装的结果是 ${params.status}")
VHelper.onInstallFinished(packageName, params)
VHelper.onInstallFinished(packageName, params.status)
}
override fun connectionCompleted() {

View File

@ -45,7 +45,7 @@ import kotlin.math.abs
class AmwayFragment : LazyListFragment<AmwayListItemData, AmwayViewModel>() {
private lateinit var mViewModel: AmwayViewModel
private val mViewModel: AmwayViewModel by lazy { viewModelProvider() }
private val mElapsedHelper by lazy { TimeElapsedHelper() }
private lateinit var mExposureListener: ExposureListener
@ -131,14 +131,13 @@ class AmwayFragment : LazyListFragment<AmwayListItemData, AmwayViewModel>() {
}
}
override fun provideListViewModel(): AmwayViewModel {
mViewModel = viewModelProvider()
return mViewModel
}
override fun getItemDecoration() = VerticalItemDecoration(context, 12F, false)
.apply { mItemDecoration = this }
override fun provideListViewModel(): AmwayViewModel? {
return mViewModel
}
override fun provideListAdapter(): ListAdapter<*> {
if (mAdapter == null) {
val basicExposureSource = arrayListOf<ExposureSource>().apply {

View File

@ -9,12 +9,12 @@ import com.gh.gamecenter.DisplayType
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.search.SearchDefaultFragment
class AmwaySearchActivity : SearchActivity() {
private lateinit var mViewModel: AmwaySearchViewModel
private val mSearchHistoryDao by lazy { AmwaySearchDao() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -22,38 +22,43 @@ class AmwaySearchActivity : SearchActivity() {
mViewModel = viewModelProvider()
}
override fun provideDao(): ISearchHistoryDao = AmwaySearchDao()
override fun handleAutoSearch(key: String?) {
mSearchKey = key
updateDisplayType(DisplayType.GAME_DIGEST)
mViewModel.getSearchResult(mSearchKey!!)
}
override fun handleHistorySearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
mViewModel.getSearchResult(mSearchKey!!)
updateDisplayType(DisplayType.GAME_DETAIL)
}
private fun handleOtherSearch() {
val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
if (newSearchKey != mSearchKey || mDisplayType != DisplayType.GAME_DETAIL) {
mSearchKey = newSearchKey
if (!TextUtils.isEmpty(mSearchKey)) {
mViewModel.getSearchResult(mSearchKey!!)
mDao.add(mSearchKey!!)
updateDisplayType(DisplayType.GAME_DETAIL)
} else {
toast("请先输入游戏名再搜索~")
}
}
}
override fun search(type: SearchType, key: String?) {
mSearchType = type
mIsAutoSearchDisabled = true
when (type) {
SearchType.AUTO -> {
mSearchKey = key
updateDisplayType(DisplayType.GAME_DIGEST)
mViewModel.getSearchResult(mSearchKey!!)
}
SearchType.HISTORY -> {
mSearchKey = key
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
mViewModel.getSearchResult(mSearchKey!!)
updateDisplayType(DisplayType.GAME_DETAIL)
}
else -> {
val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
if (newSearchKey != mSearchKey || mDisplayType != DisplayType.GAME_DETAIL) {
mSearchKey = newSearchKey
if (!TextUtils.isEmpty(mSearchKey)) {
mViewModel.getSearchResult(mSearchKey!!)
mSearchHistoryDao.add(mSearchKey!!)
updateDisplayType(DisplayType.GAME_DETAIL)
} else {
toast("请先输入游戏名再搜索~")
}
}
}
SearchType.AUTO -> handleAutoSearch(key)
SearchType.HISTORY -> handleHistorySearch(key)
else -> handleOtherSearch()
}
mIsAutoSearchDisabled = false
}

View File

@ -1,9 +1,11 @@
package com.gh.gamecenter.amway.search
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.db.ISearchHistoryDao
class AmwaySearchDao {
fun add(keyword: String) {
class AmwaySearchDao : ISearchHistoryDao {
override fun add(keyword: String) {
val originString = SPUtils.getString(SP_KEY)
if (originString.isEmpty()) {
@ -28,16 +30,18 @@ class AmwaySearchDao {
}
}
fun getAll(): ArrayList<String>? {
override fun getAll(): ArrayList<String>? {
val list = SPUtils.getString(SP_KEY).split(SEARCH_KEY_DIVIDER)
return if (list.size == 1 && list[0].isEmpty()) null else ArrayList(list)
}
fun deleteAll() {
override fun deleteAll() {
SPUtils.setString(SP_KEY, "")
}
override fun delete(item: String) {}
companion object {
const val SP_KEY = "amway_key"
const val SEARCH_KEY_DIVIDER = "<-||->"

View File

@ -7,6 +7,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.FragmentAmwaySearchDefaultBinding
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.search.SearchDefaultFragment
import com.lightgame.utils.Util_System_Keyboard
@ -14,7 +15,6 @@ import org.greenrobot.eventbus.EventBus
class AmwaySearchDefaultFragment : SearchDefaultFragment() {
private lateinit var mSearchDao: AmwaySearchDao
private lateinit var mViewModel: AmwaySearchViewModel
private val mAmwayBinding by lazy { FragmentAmwaySearchDefaultBinding.inflate(layoutInflater) }
@ -22,11 +22,15 @@ class AmwaySearchDefaultFragment : SearchDefaultFragment() {
override fun getLayoutId() = 0
override fun getInflatedLayout() = mAmwayBinding.root
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mViewModel = viewModelProviderFromParent()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewModel = viewModelProviderFromParent()
mViewModel.playedGames.observeNonNull(this) {
mViewModel.playedGames.observeNonNull(viewLifecycleOwner) {
defaultViewModel?.isExistHotSearch = it.isNotEmpty()
updateView()
mBinding.hotList.run {
@ -38,28 +42,21 @@ class AmwaySearchDefaultFragment : SearchDefaultFragment() {
}
}
override fun initDao() {
mSearchDao = AmwaySearchDao()
mHistoryList = mSearchDao.getAll()
}
override fun provideDao(): ISearchHistoryDao = AmwaySearchDao()
override fun initView() {
mBinding = mAmwayBinding.searchContent
defaultViewModel?.isExistHistory = mHistoryList?.isNotEmpty() == true
updateView()
mBinding.hotHeadContainer.headTitle.text = "最近玩过"
mBinding.historyFlexContainer.setLimitHeight(mFlexMaxHeight)
createFlexContent(mBinding.historyFlex, mHistoryList, clickListener = {
val key = mHistoryList!![it]
mSearchDao.add(key)
EventBus.getDefault().post(EBSearch("history", key))
Util_System_Keyboard.hideSoftKeyboardByIBinder(context, mBinding.historyFlex.windowToken)
})
initHistoryHeadView()
updateHistorySearchView(null)
defaultViewModel?.historySearchLiveData?.observe(this) {
updateHistorySearchView(it)
}
initHeadView()
}
private fun initHistoryHeadView() {
override fun initHeadView() {
mBinding.historyHeadContainer.run {
headTitle.text = getString(R.string.search_history)
headTitle.textSize = 16F
@ -73,17 +70,15 @@ class AmwaySearchDefaultFragment : SearchDefaultFragment() {
)
headActionTv.setOnClickListener {
DialogHelper.showCenterWarningDialog(requireContext(), "清空记录", "确定清空历史搜索记录?", confirmClickCallback = {
mSearchDao.deleteAll()
defaultViewModel?.isExistHistory = false
updateView()
updateNoPlayedGameHint()
defaultViewModel?.deleteAll()
})
}
}
}
private fun updateNoPlayedGameHint() {
if (mSearchDao.getAll() != null && mSearchDao.getAll()?.size != 0) {
val historyList = defaultViewModel?.historySearchLiveData?.value
if (!historyList.isNullOrEmpty()) {
mAmwayBinding.noDataContainer.visibility = View.GONE
return
}
@ -95,4 +90,21 @@ class AmwaySearchDefaultFragment : SearchDefaultFragment() {
}
}
override fun updateHistorySearchView(historyList: List<String>?) {
defaultViewModel?.isExistHistory = historyList?.isNotEmpty() == true
updateView()
updateNoPlayedGameHint()
historyList?.let {
createFlexContent(mBinding.historyFlex, historyList, clickListener = { id ->
val key = it[id]
defaultViewModel?.add(key)
EventBus.getDefault().post(EBSearch("history", key))
Util_System_Keyboard.hideSoftKeyboardByIBinder(
context,
mBinding.historyFlex.windowToken
)
})
}
}
}

View File

@ -15,7 +15,9 @@ import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.ActivityAuthorizationBinding
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.vspace.VHelper
import com.lightgame.utils.Utils
/**
* @author : liujiarui
@ -162,9 +164,12 @@ class AuthorizationActivity : ToolBarActivity() {
private fun checkLogin(block: () -> Unit) {
//判断光环是否登陆
CheckLoginUtils.checkLogin(this, "光环助手授权登陆") {
if (CheckLoginUtils.isLogin()) {
initData()
block()
} else {
Utils.toast(this, "需要登录")
startActivity(LoginActivity.getIntent(this, "光环助手授权登陆"))
}
}

View File

@ -8,6 +8,9 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
/**
* 新分类2.0
*/
class CategoryV2Activity : DownloadToolbarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -5,6 +5,7 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.R
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.utils.formatTime
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.databinding.ItemArchiveLimitBinding
import com.gh.gamecenter.entity.ArchiveEntity
@ -29,10 +30,7 @@ class ArchiveLimitAdapter(context: Context) : ListAdapter<ArchiveLimitAdapter.Ar
if (holder is ArchiveLimitViewHolder) {
val item = mEntityList[position]
holder.binding.tvTitle.text = item.data.name
val timeLong = item.data.time.create
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.CHINA)
val date = Date(timeLong)
holder.binding.tvTime.text = sdf.format(date)
holder.binding.tvTime.text = item.data.time.create.formatTime("yyyy-MM-dd HH:mm")
val resId = if (item.isChecked) R.drawable.ic_selector_selected else R.drawable.ic_selector_default
holder.binding.ivSelector.setImageResource(resId)
@ -53,10 +51,10 @@ class ArchiveLimitAdapter(context: Context) : ListAdapter<ArchiveLimitAdapter.Ar
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: MutableList<Any?>) {
if(holder is ArchiveLimitViewHolder){
if(payloads.isEmpty()){
if (holder is ArchiveLimitViewHolder) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position)
}else{
} else {
val item = mEntityList[position]
val resId = if (item.isChecked) R.drawable.ic_selector_selected else R.drawable.ic_selector_default
holder.binding.ivSelector.setImageResource(resId)

View File

@ -33,14 +33,19 @@ import com.gh.gamecenter.livedata.EventObserver
import com.gh.gamecenter.manager.PackagesManager
import com.gh.vspace.VArchiveHelper
import com.gh.vspace.VHelper
import com.gh.vspace.VHelper.is32
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import com.lightgame.utils.Utils
import com.lody.virtual.client.core.VirtualCore
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.io.File
/**
* 云存档管理
*/
class CloudArchiveManagerActivity : BaseActivity_TabLayout(), ArchiveLimitSelectedListener {
private lateinit var mBinding: ActivityCloudArchiveManagerBinding
@ -101,6 +106,10 @@ class CloudArchiveManagerActivity : BaseActivity_TabLayout(), ArchiveLimitSelect
controlUploadGameArchive()
uploadTv.setOnClickListener {
when {
mGameEntity.is32() && VHelper.isInnerInstalled(mGameEntity?.getUniquePackageName()) && !VirtualCore.get().isExtPackageInstalled -> {
VHelper.newCwValidateVspaceBeforeAction(this@CloudArchiveManagerActivity, mGameEntity) {
}
}
// 检查是否已安装游戏
!VHelper.isInstalled(mGameEntity?.getUniquePackageName()) -> toast("暂未检测到本地的存档数据,请玩会儿游戏再试~")
else -> {

View File

@ -1,120 +0,0 @@
package com.gh.gamecenter.db;
import android.content.Context;
import com.gh.gamecenter.db.info.DataCollectionInfo;
import com.j256.ormlite.dao.Dao;
import java.sql.SQLException;
import java.util.List;
// TODO 这个数据库其实没有用了,上传到 loghub 已经有相关的逻辑处理,有空删掉它
public class DataCollectionDao {
private DatabaseHelper helper;
private Dao<DataCollectionInfo, String> dao;
public DataCollectionDao(Context context) {
try {
helper = DatabaseHelper.getHelper(context);
dao = helper.getDao(DataCollectionInfo.class);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查找一个数据
*/
public List<DataCollectionInfo> findByType(String type) {
try {
return dao.queryForEq("type", type);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 添加一个数据
*/
public void add(DataCollectionInfo entity) {
try {
dao.create(entity);
} catch (Exception e) {
// java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase:
e.printStackTrace();
}
}
/**
* 删除一个数据
*/
public void delete(String id) {
try {
dao.deleteById(id);
} catch (Exception e) {
// java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase:
e.printStackTrace();
}
}
/**
* 删除一组数据
*/
public void delete(List<String> ids) {
try {
dao.deleteIds(ids);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据id获取某一个数据
*/
public DataCollectionInfo find(String id) {
try {
return dao.queryForId(id);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取所有的数据
*/
public List<DataCollectionInfo> getAll() {
try {
return dao.queryForAll();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取点击数据
*/
public List<DataCollectionInfo> getClickData() {
try {
return dao.queryForEq("type", "click-item");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 更新数据
*/
public void update(DataCollectionInfo entity) {
try {
dao.update(entity);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -5,9 +5,7 @@ import android.database.sqlite.SQLiteDatabase;
import androidx.collection.ArrayMap;
import com.gh.gamecenter.db.info.DataCollectionInfo;
import com.gh.gamecenter.db.info.GameTrendsInfo;
import com.gh.gamecenter.db.info.PackageInfo;
import com.gh.gamecenter.db.info.SearchHistoryInfo;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
@ -52,8 +50,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
try {
Utils.log("DatabaseHelper onCreate");
TableUtils.createTable(connectionSource, SearchHistoryInfo.class);
TableUtils.createTable(connectionSource, DataCollectionInfo.class);
TableUtils.createTable(connectionSource, PackageInfo.class);
TableUtils.createTable(connectionSource, GameTrendsInfo.class);
} catch (SQLException e) {
e.printStackTrace();
@ -65,8 +61,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
try {
Utils.log("DatabaseHelper onUpgrade");
TableUtils.dropTable(connectionSource, SearchHistoryInfo.class, true);
TableUtils.dropTable(connectionSource, DataCollectionInfo.class, true);
TableUtils.dropTable(connectionSource, PackageInfo.class, true);
TableUtils.dropTable(connectionSource, GameTrendsInfo.class, true);
onCreate(database, connectionSource);
} catch (SQLException e) {

View File

@ -0,0 +1,14 @@
package com.gh.gamecenter.db;
import java.util.List;
public interface ISearchHistoryDao {
void deleteAll();
void add(String item);
void delete(String item);
List<String> getAll();
}

View File

@ -11,7 +11,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SearchHistoryDao {
public class SearchHistoryDao implements ISearchHistoryDao {
private DatabaseHelper helper;
private Dao<SearchHistoryInfo, String> dao;
@ -25,6 +25,7 @@ public class SearchHistoryDao {
}
}
@Override
public void add(String item) {
AppExecutor.getIoExecutor().execute(() -> {
try {
@ -35,6 +36,7 @@ public class SearchHistoryDao {
});
}
@Override
public void delete(String item) {
AppExecutor.getIoExecutor().execute(() -> {
try {
@ -45,6 +47,7 @@ public class SearchHistoryDao {
});
}
@Override
public void deleteAll() {
AppExecutor.getIoExecutor().execute(() -> {
CloseableIterator<SearchHistoryInfo> iterator = dao.iterator();
@ -59,6 +62,7 @@ public class SearchHistoryDao {
return;
}
@Override
public List<String> getAll() {
List<String> history = new ArrayList<String>();

View File

@ -1,65 +0,0 @@
package com.gh.gamecenter.db.info;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import java.io.Serializable;
@DatabaseTable(tableName = "tb_datacollection")
public class DataCollectionInfo implements Serializable {
/**
*
*/
private static final long serialVersionUID = 3196892351397147390L;
@DatabaseField(id = true, columnName = "id")
private String id;
@DatabaseField(columnName = "type")
private String type;
@DatabaseField(columnName = "data")
private String data;
public DataCollectionInfo() {
}
public DataCollectionInfo(String id, String type, String data) {
this.id = id;
this.type = type;
this.data = data;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
@Override
public String toString() {
return "DataCollectionEntity [id=" + id + ", type=" + type + ", data="
+ data + "]";
}
}

View File

@ -1,42 +0,0 @@
package com.gh.gamecenter.db.info;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import java.io.Serializable;
@DatabaseTable(tableName = "tb_package")
public class PackageInfo implements Serializable {
@DatabaseField(id = true, columnName = "packageName")
private String packageName;
@DatabaseField(columnName = "time")
private long time;
public PackageInfo() {
}
public PackageInfo(String packageName, long time) {
this.packageName = packageName;
this.time = time;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
}

View File

@ -6,12 +6,10 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.DirectUtils
import com.gh.common.util.DownloadItemUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.safelyGetInRelease
@ -21,6 +19,7 @@ import com.gh.gamecenter.entity.AdConfig
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.game.GameItemViewHolder
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lightgame.download.DownloadEntity
@ -93,11 +92,8 @@ class AdGameBannerAdapter(
it.id,
it.name ?: ""
)
if (it.isQQMiniGame()) {
GlobalActivityManager.currentActivity?.let { activity ->
NewFlatLogUtils.logQGameClick(it.qqMiniGameAppId, it.name)
DirectUtils.directToQGameById(activity, it.qqMiniGameAppId)
}
if (it.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(it.miniGameAppId, it.miniGameType)
} else {
GameDetailActivity.startGameDetailActivity(
mContext,

View File

@ -21,6 +21,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.gh.ad.AdDelegateHelper
import com.gh.common.util.HomePluggableHelper
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.PackageHelper
import com.gh.common.util.PackageInstaller
import com.gh.download.DownloadManager
import com.gh.gamecenter.DownloadManagerActivity
@ -276,6 +277,12 @@ class DownloadFragment : BaseFragment_TabLayout() {
if (mBinding.adGameItemContainer.isVisible) {
DownloadManager.getInstance().addObserver(mDataWatcher)
}
refreshInstallStatus()
}
private fun refreshInstallStatus() {
PackageHelper.refreshWrongInstallStatus(PackagesManager.getInstalledSet())
}
override fun onParentActivityFinish() {

View File

@ -10,8 +10,8 @@ import com.ethanhua.skeleton.ViewSkeletonScreen
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.DirectUtils
import com.gh.common.util.DownloadItemUtils
import com.gh.common.util.PackageHelper
import com.gh.download.DownloadManager
import com.gh.gamecenter.MainActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
import com.gh.gamecenter.common.eventbus.EBReuse
@ -27,9 +27,7 @@ import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.GameInstall
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.packagehelper.PackageViewModel
import com.gh.gamecenter.wrapper.MainWrapperFragment
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
@ -110,6 +108,11 @@ class NewInstalledGameFragment : ToolbarFragment() {
mPackageViewModel =
ViewModelProvider(this, PackageViewModel.Factory()).get(PackageViewModel::class.java)
if (mPackageViewModel?.getGameInstalledLiveData()?.value.isNullOrEmpty() == true) {
mInstallGameViewModel.initData(arrayListOf())
}
mPackageViewModel?.getGameInstalledLiveData()?.observe(
this
) { gameInstalls ->
@ -147,15 +150,20 @@ class NewInstalledGameFragment : ToolbarFragment() {
}
mBinding.run {
if (PermissionHelper.isGetInstalledListPermissionDisabled(requireContext())) {
val isGetInstalledListDisagreed = PackageHelper.isGetInstalledPackagesAgreedRequired()
&& !PackageHelper.isGetInstalledPackagesAgreed()
val isGetInstalledListPermissionDisabled = PermissionHelper.isGetInstalledListPermissionDisabled(requireContext())
if (isGetInstalledListDisagreed || isGetInstalledListPermissionDisabled) {
reuseNoneData.reuseNoneDataIv.visibility = View.GONE
reuseNoneData.reuseNoneDataTv.text = "开启应用列表权限"
reuseNoneData.reuseNoneDataDescTv.text = " 及时获悉游戏最新的更新消息"
reuseNoneData.reuseResetLoadTv.text = "去开启"
reuseNoneData.reuseResetLoadTv.setOnClickListener {
PermissionHelper.showGetInstalledAppsListPermissionDialogAndRequestPermission(requireActivity()) {
updateNoDataView()
PackageRepository.initData()
PackageHelper.showGetInstallAppsListDialogAndRequestPermissionIfNeeded(requireActivity()) { isGranted ->
if (isGranted) {
updateNoDataView()
}
}
}
} else {

View File

@ -3,6 +3,7 @@ package com.gh.gamecenter.download
import android.view.View
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.DirectUtils
import com.gh.common.util.PackageHelper
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.LazyFragment
@ -13,7 +14,6 @@ import com.gh.gamecenter.common.view.FixLinearLayoutManager
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.FragmentGameUpdatableBinding
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.packagehelper.PackageViewModel
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
@ -51,10 +51,16 @@ class UpdatableGameFragment : LazyFragment() {
super.onFragmentFirstVisible()
mPackageViewModel = viewModelProvider(PackageViewModel.Factory())
if (mPackageViewModel?.getGameUpdateIncludeCurrentVersion()?.value.isNullOrEmpty() == true) {
mViewModel?.setUpdatableList(arrayListOf())
}
mPackageViewModel?.getGameUpdateIncludeCurrentVersion()
?.observeNonNull(viewLifecycleOwner) { updatableList ->
mViewModel?.setUpdatableList(updatableList)
}
mViewModel?.updatableData?.observe(viewLifecycleOwner) {
mAdapter?.submitList(it)
mBinding?.noDataContainer?.root?.goneIf(!it.isNullOrEmpty())
@ -94,18 +100,19 @@ class UpdatableGameFragment : LazyFragment() {
noDataContainer.reuseResetLoadTv.layoutParams = layoutParam
noDataContainer.reuseResetLoadTv.visibility = View.VISIBLE
noDataContainer.reuseNoneDataDescTv.visibility = View.VISIBLE
if (PermissionHelper.isGetInstalledListPermissionDisabled(requireContext())) {
val isGetInstalledListDisagreed = !PackageHelper.isGetInstalledPackagesAgreed()
val isGetInstalledListPermissionDisabled = PermissionHelper.isGetInstalledListPermissionDisabled(requireContext())
if (isGetInstalledListDisagreed || isGetInstalledListPermissionDisabled) {
noDataContainer.reuseNoneDataIv.visibility = View.GONE
noDataContainer.reuseNoneDataTv.text = "开启应用列表权限"
noDataContainer.reuseNoneDataDescTv.text = "及时获悉游戏最新的更新消息"
noDataContainer.reuseResetLoadTv.text = "去开启"
noDataContainer.reuseResetLoadTv.setOnClickListener {
PermissionHelper.showGetInstalledAppsListPermissionDialogAndRequestPermission(
requireActivity()
) { isGranted ->
PackageHelper.showGetInstallAppsListDialogAndRequestPermissionIfNeeded(requireActivity()) { isGranted ->
if (isGranted) {
updateNoDataView()
PackageRepository.initData()
}
}
}

View File

@ -34,7 +34,9 @@ class AppEntity(
*/
var alert: String? = null,
// 关联64位更新
var relation: AppEntity? = null
var relation: AppEntity? = null,
@SerializedName("_id")
var id: String? = null
) : Parcelable {
fun isAlertEveryTime() = alert == "EVERY_TIME_OPEN"

View File

@ -26,19 +26,19 @@ data class BottomTab(
@SerializedName("is_default_page")
var default: Boolean = false, // 是否为默认显示页
var isTransparentStyle: Boolean = false // 本地字段透明底部Tab
): Parcelable {
) : Parcelable {
@Parcelize
data class SearchStyle(
@SerializedName("style_type")
var styleType: String = STYLE_TWO_LINES, // 样式类型two_lines搜索栏与顶部tab分为两行、apposition搜索栏与顶部tab同一行
@SerializedName("search_type")
var searchType: String = TYPE_HALO_GAME, // 搜索类型halo_game光环游戏、qq_mini_gameQQ小游戏、bbs论坛
): Parcelable {
var searchType: String = TYPE_HALO_GAME, // 搜索类型halo_game光环游戏、bbs论坛、mini_game小游戏搜索低于v5.36版本返回qq_mini_game
) : Parcelable {
companion object {
const val STYLE_TWO_LINES = "two_lines"
const val STYLE_APPOSITION = "apposition"
const val TYPE_HALO_GAME = "halo_game"
const val TYPE_QQ_MINI_GAME = "qq_mini_game"
const val TYPE_MINI_GAME = "mini_game"
const val TYPE_BBS = "bbs"
}
}

View File

@ -0,0 +1,23 @@
package com.gh.gamecenter.entity
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.home.custom.model.CustomPageData
import com.google.gson.annotations.SerializedName
data class FollowCommonContentCollection(
@SerializedName("title")
private val _title: String? = null,
@SerializedName("link")
private val _link: LinkEntity? = null,
@SerializedName("link_common_collection")
private val _linkCommonCollection: CustomPageData.CommonContentCollection? = null
) {
val title: String
get() = _title ?: ""
val link: LinkEntity
get() = _link ?: LinkEntity()
val linkCommonCollection: CustomPageData.CommonContentCollection
get() = _linkCommonCollection ?: CustomPageData.CommonContentCollection()
}

View File

@ -0,0 +1,137 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.gh.gamecenter.feature.entity.*
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
data class FollowDynamicEntity(
@SerializedName("type")
private val _type: String? = null,
@SerializedName("libao")
val libao: LibaoEntity? = null,
@SerializedName("libao_exchange")
val libaoExchange: LibaoEntity? = null,
@SerializedName("game")
private val _game: GameEntity? = null,
@SerializedName("me")
private val _me: MeEntity? = null,
@SerializedName("time")
private val _time: Long? = null,
@SerializedName("article")
val article: Article? = null,
@SerializedName("user_post")
val userPost: ArticleEntity? = null
) : Parcelable {
val type: String
get() = _type ?: ""
val game: GameEntity
get() = _game ?: GameEntity()
val me: MeEntity
get() = _me ?: MeEntity()
val time: Long
get() = _time ?: 0L
companion object {
const val FOLLOW_UPDATE_TYPE_LIBAO = "libao"
const val FOLLOW_UPDATE_TYPE_LIBAO_EXCHANGE = "libao_exchange"
const val FOLLOW_UPDATE_TYPE_ARTICLE = "article"
const val FOLLOW_UPDATE_TYPE_USER_POST = "user_post"
}
@Parcelize
data class Article(
@SerializedName("_id")
private val _id: String? = null,
@SerializedName("title")
private val _title: String? = null,
@SerializedName("content")
private val _content: String? = null,
@SerializedName("img")
private val _img: List<String>? = null,
@SerializedName("count")
private val _count: Count? = null,
@SerializedName("game")
private val _game: GameEntity? = null,
@SerializedName("time")
private val _time: Long? = null,
@SerializedName("_seq")
private val _shortId: String? = null
) : Parcelable {
val id: String
get() = _id ?: ""
val title: String
get() = _title ?: ""
val content: String
get() = _content ?: ""
val img: List<String>
get() = _img ?: listOf()
val count: Count
get() = _count ?: Count()
val game: GameEntity
get() = _game ?: GameEntity()
val time: Long
get() = _time ?: 0L
val shortId: String
get() = _shortId ?: ""
@Parcelize
data class Count(
@SerializedName("comment")
private val _comment: Int? = null
) : Parcelable {
val comment: Int
get() = _comment ?: 0
}
}
@Parcelize
data class LibaoExchange(
@SerializedName("_id")
private val _id: String? = null,
@SerializedName("libao_id")
private val _libaoId: String? = null,
@SerializedName("libao_code")
private val _libaoCode: String? = null,
@SerializedName("name")
private val _name: String? = null,
@SerializedName("content")
private val _content: String? = null,
@SerializedName("active")
private val _active: Boolean? = null
) : Parcelable {
val id: String
get() = _id ?: ""
val libaoId: String
get() = _libaoId ?: ""
val libaoCode: String
get() = _libaoCode ?: ""
val name: String
get() = _name ?: ""
val content: String
get() = _content ?: ""
val active: Boolean
get() = _active ?: false
}
}

View File

@ -0,0 +1,7 @@
package com.gh.gamecenter.entity
data class FollowOperateTopRequest(
val _id: String,
val order: Int
) {
}

View File

@ -0,0 +1,159 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.User
import com.gh.gamecenter.feature.entity.UserEntity
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import java.util.Objects
@Parcelize
data class FollowUserEntity(
@SerializedName("_id")
private val _id: String? = null,
@SerializedName("type")
private val _type: String? = null, // user用户、bbs论坛
@SerializedName("user")
private val _user: UserEntity? = null,
@SerializedName("bbs")
private var _bbs: Bbs? = null,
@SerializedName("is_top")
private val _isTop: Int? = null,
@SerializedName("is_show_tip")
private val _isShowTip: Int? = null,
) : Parcelable {
val id: String
get() = _id ?: ""
val type: String
get() = _type ?: ""
val user: UserEntity
get() = _user ?: UserEntity()
val isTop: Boolean
get() = _isTop == 1
val isShowTip: Boolean
get() = _isShowTip == 1
val bbs: Bbs
get() = _bbs ?: Bbs()
val isUser: Boolean
get() = type == TYPE_USER
val name: String
get() = if (isUser) {
user.name ?: ""
} else {
bbs.name
}
val icon: String
get() = when {
type == TYPE_USER -> user.icon ?: ""
bbs.type == BBS_TYPE_GAME -> bbs.game.icon ?: ""
else -> bbs.icon
}
override fun equals(other: Any?): Boolean {
return other is FollowUserEntity
&& id == other.id
&& type == other.type
&& user.id == other.user.id
&& user.name == other.user.name
&& bbs.id == other.bbs.id
&& bbs.name == other.bbs.name
&& bbs.type == other.bbs.type
&& bbs.icon == other.bbs.icon
&& bbs.game.icon == other.bbs.game.icon
&& isTop == other.isTop
&& isShowTip == other.isShowTip
&& icon == other.icon
}
override fun hashCode(): Int {
return Objects.hash(
_id,
type,
user.id,
user.name,
bbs.id,
bbs.name,
bbs.type,
bbs.icon,
bbs.game.icon,
isTop,
isShowTip,
icon
)
}
companion object {
private const val TYPE_USER = "user"
private const val BBS_TYPE_GAME = "game_bbs"
}
@Parcelize
data class Bbs(
@SerializedName("_id")
private val _id: String? = null,
@SerializedName("name")
private val _name: String? = null,
@SerializedName("type")
private val _type: String? = null,
@SerializedName("icon")
private val _icon: String? = null,
@SerializedName("game")
private val _game: GameEntity? = null
) : Parcelable {
val id: String
get() = _id ?: ""
val name: String
get() = _name ?: ""
val type: String
get() = _type ?: ""
val icon: String
get() = _icon ?: ""
val game: GameEntity
get() = _game ?: GameEntity()
}
@Parcelize
data class Game(
@SerializedName("_id")
private val _id: String? = null,
@SerializedName("name")
private val _name: String? = null,
@SerializedName("icon")
private val _icon: String? = null,
@SerializedName("ori_icon")
private val _oriIcon: String? = null,
@SerializedName("active")
private val _active: Boolean? = null
) : Parcelable {
val id: String
get() = _id ?: ""
val name: String
get() = _name ?: ""
val icon: String
get() = _icon ?: ""
val oriIcon: String
get() = _oriIcon ?: ""
val active: Boolean
get() = _active ?: false
}
}

View File

@ -1,6 +1,7 @@
package com.gh.gamecenter.entity
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.feature.entity.SimulatorEntity
import com.google.gson.annotations.SerializedName
@ -11,9 +12,16 @@ class NewApiSettingsEntity(
var startup: StartupAdEntity? = null,//启动文案广告
@SerializedName("user_interested_game")
var userInterestedGame: Boolean = false, //偏好设置状态开关
@SerializedName("installed_compliance_switch")
var installedComplianceSwitch: Boolean? = false, //安装合规开关
@SerializedName("listen_switch")
var isPackageObserveEnable: Boolean = false, // 安装包监听开关
@SerializedName("listen_str")
var packageObserveActions: PackageObserveActions? = null, // 安装包监听的三个 action
var install: Install, // 安装相关的
@SerializedName("game_shield_contents")
var gameShieldContents: List<String>? = listOf(),//游戏屏蔽内容
var search: SettingsEntity.Search? = null// 游戏搜索配置
) {
/**
*
@ -27,23 +35,51 @@ class NewApiSettingsEntity(
val install: Boolean
)
// VPN 配置
class Install(
@SerializedName("vpn_required")
val vpnRequired: VpnSetting? = null,
@SerializedName("guides")
val guides: List<Guide>? = null
)
class VpnSetting(
@SerializedName("current_device")
val shouldShowVpnOption: Boolean,
@SerializedName("packages")
val vpnMatchedPackagesName: HashSet<String>
)
/**
* 当为鸿蒙纯净模式相关时
* {
* "type': "harmony_os_pure_mode", // 华为鸿蒙系统纯净模式相关 harmony_os_pure_mode/harmony_os_pure_enhanced_mode
* "link": {
* "type": "qa_content",
* "link": "61026d03802abe4d7260fdc3",
* "text": "点击查看教程" // 链接文案,有设置时替换该字段,无设置时读取对应通用链接原本的文案
* },
* "title": "",
* "content": "",
* "link_text_prefix": "关闭场景模式:", // 链接引导文案
* "button_text_close": "", // 关闭按钮
* "button_text_setting_jump": "", // 前往设置按钮
* "dialog_frequency": "once" // once/every_time
* }
*/
class Guide(
val type: String,
val link: LinkEntity
val link: LinkEntity,
val title: String = "",
val content: String = "",
@SerializedName("link_text_prefix")
val linkTextPrefix: String = "",
@SerializedName("link_text")
val linkText: String = "",
@SerializedName("button_text_close")
val buttonTextClose: String = "",
@SerializedName("button_text_setting_jump")
val buttonTextSettingJump: String = "",
@SerializedName("dialog_frequency")
val dialogFrequency: String = "",
)
class PackageObserveActions(
@SerializedName("ADD")
val add: String,
@SerializedName("REM")
val rem: String,
@SerializedName("REP")
val rep: String
)
}

View File

@ -163,6 +163,14 @@ data class PersonalHistoryEntity(
get() = community.name
set(_) {}
override fun vote(isVote: Boolean) {
_count.vote = if (isVote) {
_count.vote + 1
} else {
_count.vote - 1
}
}
fun getPassVideos(): List<CommunityVideoEntity> {
val passVideos = arrayListOf<CommunityVideoEntity>()
for (video in videos) {

View File

@ -17,7 +17,7 @@ class SubjectData(
var filter: String = "", // Filter: 类型(分类)
var tagType: String? = "", // 游戏Item 标签类型
var briefStyle: String = "",
var isQQMiniGame: Boolean = false,
var subjectType: SubjectType = SubjectType.NORMAL,
var subjectStyle: String = "",
var requireUpdateSetting: Boolean = false, // 多专题页面需要专题页面自行获取专题配置
@ -43,4 +43,24 @@ class SubjectData(
tag = tagType
)
}
/**
* 专题类型
*/
enum class SubjectType {
/**
* 普通专题
*/
NORMAL,
/**
* QQ小游戏专题
*/
QQ_GAME,
/**
* 微信小游戏专题
*/
WECHAT_GAME
}
}

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