Compare commits

...

428 Commits
v2.5 ... v3.0.2

Author SHA1 Message Date
44deb59624 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	gradle.properties
2017-12-11 18:42:29 +08:00
27fc39cb70 revert tinkerid 2017-12-11 17:35:25 +08:00
5480caf44e update gradle to 3.0 & fix tinker filepath 2017-12-11 17:33:44 +08:00
a448a974f1 1.开服日历页面时关闭日历详情
2.删除对开服信息时间的判断 如果有开服信息就显示开服日历
2017-12-07 16:14:15 +08:00
1738fac5fd Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-12-06 18:33:10 +08:00
7b74318ca5 修复详情页面 启动需要检查网络的BUG 2017-12-06 18:32:19 +08:00
6dabbe19dd update libs 2017-12-06 16:15:20 +08:00
e286be7f1e 修复开服表过年无法显示问题,修改开服表显示规则 2017-12-05 16:39:21 +08:00
ef040f68c7 区分企业QQ和普通QQ的打开方式 2017-12-05 10:15:44 +08:00
b134d077cf 礼包领取判断修正 2017-12-04 12:01:43 +08:00
69fe3b3d76 fix appbar scroll behavior 2017-11-28 15:37:57 +08:00
c134c4bf9e 删除无用log 2017-11-28 09:22:09 +08:00
633acb9236 礼包领取限制 2017-11-27 16:03:32 +08:00
cf84205571 修复礼包列表和专题列表分页加载过慢问题 2017-11-27 15:04:12 +08:00
5aced2c03c 光环助手V3.0.2优化需求与bug汇总(11-27) 2017-11-27 11:57:11 +08:00
6cfa949493 解决跳转QQ后无法聊天问题 2017-11-27 09:27:29 +08:00
dcfe3dee0e Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-11-23 20:04:24 +08:00
8348568ea7 修复3.0.1意见反馈Bug
1.ImageUtils传入的url允许为空
2.修复专题ActionBarTitle有可能为空问题
2017-11-23 19:58:00 +08:00
1d5dece894 fix git submodule update script 2017-11-23 15:57:52 +08:00
64594c4457 调整下载重试时间间隔 2017-11-22 17:12:07 +08:00
c2274d6b6f 3.0升级日志 2017-11-22 15:44:04 +08:00
165059ca2d 快传 传送最低时间设为1秒 2017-11-22 15:07:29 +08:00
89e05d1a29 设置GH_TEST渠道为Bugly(tinker)开发设备 2017-11-20 17:24:02 +08:00
9f00cab409 优化首页缓存 2017-11-19 12:00:00 +08:00
e8a795f97b 1117测试问题:
1.如果后台隐藏了评论,前端在消息中心点击跳转对话详情,会一直转圈圈,也没任何提示(应该要出现飞碟提示才对)
2.消息中心-客服,排版和“评论”不一致
(1)分割线与头像之间的间距(比“评论”那边窄了)
(2)昵称和时间之间的间距(比“评论”那边宽了)
2017-11-17 11:37:00 +08:00
96c233ebd0 光环助手V3.0.2 评论对话增加弹窗(回复/点赞/复制 等) 2017-11-16 20:04:03 +08:00
36ef13b237 光环助手V3.0.2优化需求汇总(20171116) 2017-11-16 18:06:23 +08:00
f54fdd6016 可以多次重定向,但有数量限制.断网重连先延迟后判断 2017-11-16 12:02:32 +08:00
a43947077a 新增打渠道包脚本 2017-11-16 09:19:47 +08:00
a863b7be13 fix proguard library 2017-11-15 17:33:47 +08:00
ab1ce8e179 HttpDns版本和友盟HttpDns改成一致 2017-11-15 17:12:27 +08:00
d391ab20b7 更换3.0.1tinker_id以及tinker_base_apk_dir 2017-11-15 15:13:47 +08:00
8403bc3a64 求版本敏感词优化 2017-11-15 15:07:34 +08:00
038e736eb1 下载暂停和继续延迟一秒,防止一个包同时有多个线程在下载(后续想一个更好的方案) 2017-11-15 10:41:02 +08:00
a215192175 下载增加httpdns 2017-11-14 20:42:27 +08:00
22a1895050 消息中心优化, 求版本功能完善(敏感词toast还要确认), 修复搜索游戏失败时无法重试问题 2017-11-13 17:44:10 +08:00
2df42c772b 下载重试优化 2017-11-13 15:34:24 +08:00
82fea04460 首页启动性能优化-获取到了新数据后 要更新界面 2017-11-10 15:53:53 +08:00
6ccd70dad2 首页启动性能优化,修复游戏平台面板插件图标异常问题 2017-11-09 19:28:24 +08:00
ec2d14bffe 修复refreshToken过期重试问题 2017-11-09 11:47:13 +08:00
1d544ff558 修复登录相关问题(删除用户数据后发注销广播) 2017-11-08 20:06:40 +08:00
867cd29e0f 修复强制弹窗 2017-11-08 19:39:59 +08:00
d1cf660af6 修复获取验证码返回处理 2017-11-08 18:36:58 +08:00
adabe3a227 20171108issues: http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/91
登录无网络处理
2017-11-08 18:31:38 +08:00
b57ef6c3b4 refreshToken抽离 refreshToken同一时间只能访问一次 2017-11-08 10:53:23 +08:00
1b50823843 修复第一次登录头像提示 2017-11-07 21:04:31 +08:00
18ddad522a 补丁弹窗问题 2017-11-07 14:40:50 +08:00
85b034ecfb make sure that update dialog show 2017-11-07 12:05:11 +08:00
5a04749ef2 make sure that update dialog show 2017-11-07 11:59:22 +08:00
bcd32dde85 fix tinker patch 2017-11-07 11:31:41 +08:00
7832cb810b fix tinker script bug 2017-11-07 10:59:00 +08:00
cb652721a7 fix tinker script bug 2017-11-07 10:57:19 +08:00
4ad005fb53 update about version 2017-11-07 10:46:19 +08:00
ce312aea72 fix tinkerId show update log 2017-11-07 10:39:40 +08:00
6c5dc556e8 fix tinker support 2017-11-07 10:21:03 +08:00
95dc18f1d0 remove tinkerid before tinker release base 2017-11-07 10:17:10 +08:00
f284cc8676 test 2017-11-07 09:59:47 +08:00
0cc456c4a1 3.0.1优化
http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/87
2017-11-06 18:29:34 +08:00
0666146374 11-6 打母包 2017-11-06 15:56:32 +08:00
5860ca720e 优化掉线问题 2017-11-03 19:43:49 +08:00
91ee8362ba 修复查看评论 2017-11-02 19:43:04 +08:00
dd81460826 修复补丁弹窗问题 2017-11-01 17:29:50 +08:00
5180916d9f Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-11-01 17:16:18 +08:00
4d92ddcc75 ... 2017-11-01 17:15:09 +08:00
f1f0900e13 get tinkerid 2017-11-01 17:12:46 +08:00
6edf68d03c 补丁安装完成弹窗提示优化 2017-11-01 15:23:11 +08:00
c643ae507b 添加额外渠道 2017-10-31 18:13:05 +08:00
fdc843a93a V3.0.1优化完成 补丁安装完成要出现弹窗提示->还没测试 2017-10-31 18:11:09 +08:00
383c06c72a V3.0.1优化 1~9 2017-10-31 11:10:29 +08:00
a255ce3e36 添加渠道 2017-10-27 18:16:00 +08:00
fa58e820c1 修改老用户同步逻辑 2017-10-27 18:07:51 +08:00
fad011e2fc 修复登录掉线问题(应该OK了),关于版本显示补丁包版本号 2017-10-26 14:51:51 +08:00
9fad040e14 修复礼包(从文章超链接进入礼包详情),登录问题 2017-10-25 18:39:24 +08:00
8d0ab82f15 整理hardcode问题,整理imageUtils工具类 2017-10-19 09:11:22 +08:00
3d7e994b93 增加NormalActivity/fragment 2017-10-17 20:35:03 +08:00
4d40c0f431 修复首页页面切换时 插件化模块自动滑动问题 2017-10-16 17:53:39 +08:00
d9bb60e66b 整理Entrance type 2017-10-16 16:49:22 +08:00
52433ba347 抽离部分java代码中的字符串,equals判断常量放在前面 2017-10-14 15:52:15 +08:00
4290846698 抽离代码中的fromHtml的content,修复个人中心同步问题 2017-10-14 14:44:25 +08:00
6bbd7ec00d ... 2017-10-13 17:01:51 +08:00
dc535ddb38 V3.0 10-12汇总, 优化我的关注和登录页面 2017-10-13 16:54:37 +08:00
dfe087e702 登录增加进度弹窗,统一toast 2017-10-12 17:57:40 +08:00
930e0b92eb 修改下载管理更新游戏逻辑 2017-10-12 16:37:18 +08:00
3199bc6118 10-12优化补充 2017-10-12 09:57:36 +08:00
b1384375a3 打publish包 2017-10-12 09:24:45 +08:00
81dd98cefd 关于版本号更改, gson工具类 2017-10-11 20:19:14 +08:00
02108b3273 ViewPager 指针四舍五入取整 2017-10-11 15:34:12 +08:00
c5deb87c23 整理代码中的文本 2017-10-11 10:24:07 +08:00
572274a2e3 V3.0 10月10日测试包 2017-10-10 16:36:10 +08:00
7f303b362d bug修复 2017-10-10 15:19:17 +08:00
41ce6cce05 打tinker包 2017-10-10 10:17:38 +08:00
f6e1c55749 ... 2017-10-10 09:53:14 +08:00
d24bcf8e6e 修复游戏详情空白提示异常问题 2017-10-09 18:42:46 +08:00
2b497ff679 登录成功提示逻辑修改 2017-10-09 16:05:09 +08:00
627c20f6fd 修复验证码礼包无法领取问题 2017-10-09 15:15:18 +08:00
cfab918bea layout的颜色代码抽离 2017-10-09 14:29:53 +08:00
89746203fe 登录完成后自动刷新页面(我的关注,存号箱,礼包-关注), 修复资讯-关注礼包同步问题 2017-10-09 11:47:25 +08:00
8bc6947c94 dialog由默认layout改为在xml创建 2017-10-08 17:58:53 +08:00
5a264804da 整理礼包详情内容(layout抽离到xml) 2017-10-08 15:42:04 +08:00
1f5e025fea java代码抽离颜色代码,修复历史礼包已知bug 2017-10-08 14:56:40 +08:00
3201e220a0 礼包重复领取修复已知问题,收藏页面优化 2017-10-08 11:39:49 +08:00
d41129011b Tab指针居中 2017-09-28 17:50:20 +08:00
6eb1aefb1c V3.0 09-27 Tab指针居中问题未解决 2017-09-28 15:25:06 +08:00
433646b455 修改登录相关接口循环请求问题, 定时任务统一用postDelayedRunnable在baseFragment 统一remove 避免刷新过程中对出闪退 2017-09-28 11:57:34 +08:00
257e7d1d27 viewPager+fragment adapter notifyItemRangeInserted去除判断(好像是recyclerview修复了这个bug) 2017-09-27 18:22:51 +08:00
f668d6492a 整理部分可以快速弄好的todo 2017-09-27 17:44:15 +08:00
b8ea968a58 抽离列表的onclick事件 还未完成(太太太多啦), click startActivityForResult相关已经完成 2017-09-27 17:15:58 +08:00
5b361afc67 更换沉浸栏实现方法, actionBar menu 修改 2017-09-27 11:28:07 +08:00
0947cd1e24 fix tinker 2017-09-26 19:22:30 +08:00
f8ab1f108b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-26 18:39:53 +08:00
84f53bbf81 fix gnu/bsd script 2017-09-26 18:39:50 +08:00
ad2656a24b ... 2017-09-26 18:39:42 +08:00
4734fbd651 fix tinker 2017-09-26 17:46:20 +08:00
a947755383 tinker test 2017-09-26 17:05:45 +08:00
f4a1283073 将列表onclick事件提取出来(只完成资讯模块) 2017-09-26 16:34:51 +08:00
f37a2c5b24 测试tinker回退, 没有测试成功.
获取VERSION_CODE失败 返回的是null.
跑patch脚本 gradle指定baseApk路径和脚本生成(多出两层目录)的路径不一致.
打出来的补丁包上传时提示"未匹配到可应用补丁app版本".
2017-09-25 20:56:10 +08:00
cca7d770f1 测试tinker 改了一些脚本 待会改回来哈 2017-09-25 19:28:30 +08:00
2c7f3f2321 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-25 18:34:16 +08:00
cc92e025f2 fix tinker build.gradle file 2017-09-25 18:32:57 +08:00
ce0e28dad6 activity入口整理(涉及到外部启动(插件跳转/推送)的未完成) 2017-09-25 17:22:07 +08:00
b483f7cdb6 整理xml的hardCode(部分固定文案尚未抽离) 2017-09-25 16:36:40 +08:00
8ce0694099 重写选择地区页面 2017-09-25 16:04:52 +08:00
910b356a05 push LGLibrary?? 2017-09-25 12:05:13 +08:00
d74e0310f8 测试tinker 2017-09-25 11:40:10 +08:00
ee19879577 整理startActivityForResult CODE 2017-09-22 18:02:20 +08:00
5e3d7d2f2b 删除无用的数据库相关类(concernDao还需整理), 修复不能重复领取/淘号问题 2017-09-22 15:27:54 +08:00
f292eb0fc6 9月19日测试包 完成 2017-09-22 09:21:49 +08:00
475de2281b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-21 16:15:12 +08:00
949c8331d2 礼包详情重复淘号,从存号箱和普通列表进去礼包详情 数据同步 2017-09-21 16:09:06 +08:00
a5e0fa8402 fix conflict 2017-09-21 15:27:03 +08:00
f0066b3dac fix strings.xml formatable string 2017-09-21 15:26:04 +08:00
10480a533c add readme sample 2017-09-21 12:12:45 +08:00
d36dcac817 登录失败提示 2017-09-21 10:33:42 +08:00
d6d49ac7ad 整理Activity入口(还有部分未检查) 2017-09-20 20:01:07 +08:00
573e127fc7 整理消息页面(阅读后即时提交) 2017-09-20 15:39:20 +08:00
9cb6e599a4 整理无用代码 2017-09-20 14:37:40 +08:00
f42dd1013e Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-19 15:05:48 +08:00
70441658e5 收藏同步相关 2017-09-19 15:04:59 +08:00
0ca71f25f6 fix context related 2017-09-19 14:28:43 +08:00
5d3a4e24f9 fix debug keystore 2017-09-19 10:29:03 +08:00
3b8faf47c4 资讯-关注 优化 2017-09-18 19:33:01 +08:00
ac21776d3b 退出登录时增加过程弹窗, 防止过早或过慢清除token造成的页面错误 2017-09-18 18:36:13 +08:00
e5127c9040 退出登录时增加过程弹窗, 防止过早或过慢清除token造成的页面错误 2017-09-18 18:35:32 +08:00
8533d06943 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-18 17:11:27 +08:00
066dd6103f 用户数据同步-收藏增加多页面同步, 礼包部分整理(资讯-关注接口欠缺礼包用户数据, 评论相关接口欠缺用户数据) 2017-09-18 17:11:15 +08:00
670f9c280c add debug bugly 2017-09-18 15:37:43 +08:00
5ea3c58b77 update tree image 2017-09-18 14:16:50 +08:00
6e15571ef4 create patch test 2017-09-18 12:17:49 +08:00
ad46fced4f Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-18 12:06:54 +08:00
5acf42423e add rsync to 2.100 for backup 2017-09-18 12:06:44 +08:00
2a2bef8a47 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-16 18:31:20 +08:00
2ffb0f59a2 用户数据同步-礼包相关(优化/整理) 2017-09-16 18:30:51 +08:00
400bdaa6f5 fix script var naming 2017-09-16 18:10:54 +08:00
fa449966f3 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-16 17:29:41 +08:00
f4078493f6 fix patch/channel/ release scripts 2017-09-16 17:29:31 +08:00
5007f7e83d 用户数据同步-我的关注(页面更新逻辑修改) 2017-09-16 14:49:25 +08:00
ca1a8e15cb Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-16 09:24:35 +08:00
b9f299805f 用户数据同步-基本完成(比较多细节问题需优化) 2017-09-15 18:38:31 +08:00
acde49012f test tinker multiple channel release & patch 2017-09-15 18:17:35 +08:00
76c69f0d19 fix tinkerid not the same 2017-09-15 17:38:51 +08:00
c0b91b4a63 Merge remote-tracking branch 'origin/dev' into dev 2017-09-15 17:00:47 +08:00
f6a194ae92 fix patch script 2017-09-15 16:57:27 +08:00
9e7d178972 fix tinker patch path 2017-09-15 16:25:03 +08:00
17b2e2dca7 test patch 2017-09-15 16:03:22 +08:00
eb73bcd25f fix script 2017-09-15 16:00:13 +08:00
f96c090120 test script 2017-09-15 15:39:46 +08:00
aefdaee424 fix script 2017-09-15 15:34:50 +08:00
27ceee37c0 fix script 2017-09-15 15:33:24 +08:00
e1c2e3c984 fix script 2017-09-15 15:25:56 +08:00
48e3718fc2 add tinker scripts 2017-09-15 15:24:44 +08:00
ee20f65a9b 用户数据同步-礼包相关(基本完成, 尚未测试) 2017-09-15 14:22:40 +08:00
235a13855b 用户数据同步相关 2017-09-14 20:03:47 +08:00
acec42c6af 光环助手V3.0(9月12日测试包) 2017-09-14 17:16:33 +08:00
6d009eddf5 test tinker 2017-09-14 16:54:17 +08:00
b0dde281ea 相关数据关联UserDataEntity, 统一在Interceptor添加token 2017-09-14 15:23:08 +08:00
1e7d43bc72 优化6.0权限, 快传部分权限先搁置 2017-09-14 11:54:19 +08:00
8576a1edaf test patch 2017-09-13 19:24:26 +08:00
5dc97d2191 add test 2017-09-13 19:12:48 +08:00
a32b45e067 fix conflict 2017-09-13 18:31:41 +08:00
ff8210c72b proxy app logic 2017-09-13 18:27:11 +08:00
85031e89b6 Android 6.0及以上 权限适配 2017-09-13 18:23:55 +08:00
f2676532ce test fresco 2017-09-13 17:58:18 +08:00
7a996ee8f4 test fresco 2017-09-13 17:50:04 +08:00
d09e28d653 fix fresco crash 2017-09-13 17:08:24 +08:00
e446f4190f remove crash button 2017-09-13 16:57:34 +08:00
f53534b803 add crash button 2017-09-13 16:40:49 +08:00
fb6792f71b add crash button 2017-09-13 16:40:37 +08:00
5d66d55db1 remove crash me 2017-09-13 16:19:40 +08:00
d3bdd48425 test 2017-09-13 16:07:33 +08:00
c89f675ccf remove uncaught handler 2017-09-13 16:02:30 +08:00
f0b989d20e add crash button 2017-09-13 15:54:18 +08:00
3b950b6b28 fix extend 2017-09-13 15:47:37 +08:00
d10a0f956e fix crash 2017-09-13 15:11:41 +08:00
2317228642 test tinker patch 2017-09-13 14:47:08 +08:00
78a4571a8a Merge remote-tracking branch 'origin/dev' into merge 2017-09-12 15:03:56 +08:00
c7b16ce91b fix npe 2017-09-12 15:02:46 +08:00
2e84aeaccf 9月7日测试包 UI部分完成 2017-09-12 10:52:17 +08:00
49e9a532b8 Merge remote-tracking branch 'origin/dev' into merge 2017-09-11 15:37:45 +08:00
47f7d70cfb fix apiservice 2017-09-11 15:37:31 +08:00
a3b03efcbe Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-11 10:44:47 +08:00
814d4faf3e 9月7日测试包 UI部分未完成 2017-09-11 10:44:30 +08:00
c487dc2f03 fix webview focus issue 2017-09-08 15:22:40 +08:00
f552a06bd7 1、takingdata升级,精简无用的组件,480kb->220kb
2、数据统计部分整理,切勿更改数据统计和错误上报任何顺序
3、依赖整理
2017-09-08 11:58:56 +08:00
4de5593802 9月7日测试包 部分修复 2017-09-08 11:04:45 +08:00
4294e9f98d 最新礼包合并 2017-09-07 16:13:23 +08:00
05a911f1e3 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-07 16:06:08 +08:00
464f8d7851 最新礼包重做完成 2017-09-07 16:05:26 +08:00
370b07be31 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-07 14:32:30 +08:00
cb49c71279 check entrance 2017-09-07 14:32:20 +08:00
f637fb9596 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-06 17:01:27 +08:00
5c8072cc9e 完善礼包最新页面(未完成), 9.5测试需求 2017-09-06 17:00:59 +08:00
40cd057c28 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-06 16:18:52 +08:00
0bcd37c1f1 礼包最新页面修改实现逻辑(未完成), 9.5测试需求 2017-09-06 14:37:10 +08:00
6fce6fd80b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-09-06 10:43:50 +08:00
bc13a6056d update gradle.properties to use https 2017-09-06 10:43:13 +08:00
00879964e4 3.0Bug修复/UI优化/礼包优化
暂时未解决:礼包页面切换时,礼包搜索条自动顶上去/LibaoEntity getId和getLibaoId混乱
2017-09-05 11:57:19 +08:00
64711d6175 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/base/AppController.java
2017-09-04 10:54:35 +08:00
0d3704f55d 3.0bug优化,3.0UI问题汇总,3.0礼包问题.部分未完成需要检查 2017-09-04 10:52:21 +08:00
0856eed7fc update lglibrary 2017-09-03 17:13:23 +08:00
8efaa9e724 1、更改build variant,debugCompile,确保正式打包不包含debug类库
2、支持按照debug/release简单区分更多代码逻辑
2017-09-03 17:11:04 +08:00
98983ff4eb 关注操作成功时才改变按钮状态 2017-08-29 11:52:04 +08:00
0ae36ed7a7 完善token重试逻辑和多设备登录 2017-08-28 16:58:39 +08:00
8e8b20c3dd 光环助手V3.0(8月24日)测试包问题汇总 2017-08-25 17:40:17 +08:00
82e2aa45c6 更新登录相关错误码 多设备登录提示优化(没效果) 2017-08-25 10:47:15 +08:00
e4be47e7e7 部分UI调整,优化登录模块 2017-08-23 17:48:42 +08:00
404c605a1e 优化开服表(主要是单个游戏开服点下载是非常卡,修复后还是有点卡),把首页控制台的消息提示红点移到我的光环 2017-08-22 10:51:23 +08:00
4966d85634 新开服表(默认定位未完成,等待根据游戏id获取开服信息接口) 2017-08-20 17:47:53 +08:00
043eebf013 修改获取token逻辑,以及处理token 401问题 2017-08-18 11:25:28 +08:00
3b521ddd08 首页-游戏插件化模块改成可伸缩,user部分接口移到api(关注) 2017-08-16 16:00:42 +08:00
bd74d3a1a3 底部点击回到顶部(首页-游戏),闪退重启出现提示框 2017-08-15 11:30:04 +08:00
0dc867ce64 重做登录页面(普通登录和老用户登录) 2017-08-14 17:19:41 +08:00
dde08e2d67 老用户登录,token过去处理,登录模块优化 2017-08-14 15:17:26 +08:00
3c5871526d 登录签名认证 专题列表开服时间格式更改  收藏优化 2017-08-10 10:20:35 +08:00
49f4ba2da8 同步最后修改2.6代码 2017-08-01 17:10:47 +08:00
77b660576a 登录验证(还不行) 2017-08-01 16:43:59 +08:00
a15ab62f03 收藏相关(文章检查是否修改未完成) 2017-07-28 18:32:29 +08:00
c65250973c fix okhttp retry logic 2017-07-24 16:36:16 +08:00
d5872aad55 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/base/AppController.java
2017-07-23 18:42:41 +08:00
9d27bba6fd 增加流量统计(尚未完善) 2017-07-23 18:36:45 +08:00
caeecce50b add okhttp request retry logic 2017-07-21 19:58:03 +08:00
f6c82dd767 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-07-21 18:21:16 +08:00
f88205f957 消息页面入口移到我的光环 2017-07-21 18:19:59 +08:00
3a0a4726b9 fix host and gradle vars 2017-07-21 10:11:30 +08:00
a113fc1c73 优化登录流程,修复2.6已知的BUG 2017-07-20 18:04:38 +08:00
92d122b0a3 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-07-19 11:24:15 +08:00
d96a2d22e0 增加收藏页面,优化登录流程 2017-07-19 11:21:42 +08:00
8d96b9fe7f add init submodule scripts 2017-07-19 10:25:17 +08:00
fdf7bdd64d 修改用户信息(更换头像未完成) 2017-07-18 15:43:02 +08:00
4f4c90f792 对接测试登录流程(第三方登录以及手机号码登录) 2017-07-18 10:43:38 +08:00
f42674ed6f add dev/public host product flavors 2017-07-14 17:15:05 +08:00
e66b697663 修改域名为ghzs666 2017-07-14 16:45:00 +08:00
a21e40a4f1 Merge branch '3.0' of gitlab.ghzhushou.com:halo/assistant-android into 3.0 2017-07-10 17:03:06 +08:00
03dd58ca41 .. 2017-07-10 17:00:41 +08:00
6f3827db15 Merge branch '3.0' of gitlab.ghzhushou.com:halo/assistant-android into 3.0
# Conflicts:
#	app/src/main/java/com/gh/common/util/GetLoginDataUtils.java
#	app/src/main/java/com/gh/gamecenter/LoginActivity.java
2017-07-10 17:00:22 +08:00
fd2b333bc7 fix weibo webview proguard 2017-07-10 16:37:18 +08:00
ba3e882f47 微信获取登录数据成功回调,登录模块优化 2017-07-10 16:22:13 +08:00
b9a80e12a8 patch viewpagerfragment for onactivityresult callback 2017-07-10 16:07:38 +08:00
979ee209dd Merge branch '3.0' of gitlab.ghzhushou.com:halo/assistant-android into 3.0 2017-07-10 15:01:39 +08:00
10b1380aad 1、下载模块部分重构
2、整理actionbar高度问题,测试toolbar,暂时未启用
3、sharedpreference使用default文件
2017-07-10 14:35:32 +08:00
b239407c25 模拟对接登录接口已经登录流程(未完成) 2017-07-07 19:31:58 +08:00
475221a011 debug和release生成对应域名 2017-07-07 14:36:15 +08:00
658ee78213 分离build/release key 2017-07-07 10:46:23 +08:00
5244fe73ea 1、处理release debug build区分 2017-07-07 10:43:29 +08:00
243e024d1a 修复友盟推送初始化异常,ImageUtils代码转换kotlin 2017-07-06 19:50:40 +08:00
5930996e1c 修复插件平台图片(旧版本)无法更新问题, 优化登录 2017-07-06 09:10:44 +08:00
a05e6917b8 更改弹出软键盘时移动布局方法(防止软键盘挡住布局),以适配个别手机计算错误 2017-07-05 15:09:51 +08:00
d05e9e57c3 实体类全部转换成kotlin 2017-07-04 17:07:12 +08:00
1b88e9c238 ... 2017-07-03 19:51:51 +08:00
ce32b8d63a Merge remote-tracking branch 'origin/3.0' into 3.0 2017-07-03 10:04:15 +08:00
2bc26c9046 接入微信登录, 增加个人信息编辑页面,我的光环增加自动检测更新,登录页面增加新老用户切换 2017-07-03 09:58:54 +08:00
714a64975f 1、对下载器任务的状态变化修改
2、对下载器内部的handler的消息屏蔽,pause的修改,剩余download roll未改动。
2017-07-02 09:49:21 +08:00
7a6354e781 Merge remote-tracking branch 'origin/3.0' into 3.0 2017-06-30 17:30:03 +08:00
5f11c2d0b6 接入微信登录, 增加个人信息编辑页面,我的光环增加自动检测更新,登录页面增加新老用户切换 2017-06-30 17:29:43 +08:00
9c6814482d 1、downloadmangeractivity逻辑改动到viewpager fragment 2017-06-30 11:44:23 +08:00
94a5736939 fix data error in gameentity 2017-06-29 16:36:27 +08:00
bc496d8277 update lib 2017-06-29 16:00:32 +08:00
2b23665cb5 fix entity 2017-06-29 15:59:36 +08:00
1d1c9666dc Merge remote-tracking branch 'origin/3.0' into 3.0 2017-06-29 11:27:21 +08:00
1b14f3f608 微博登录改动 2017-06-29 11:27:07 +08:00
d370e817c0 update lib 2017-06-29 11:25:06 +08:00
ea4c6c95a1 Merge branch '3.0' of gitlab.ghzhushou.com:halo/assistant-android into 3.0
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/adapter/CommentDetailAdapter.java
#	app/src/main/java/com/gh/gamecenter/adapter/MessageDetailAdapter.java
#	app/src/main/java/com/gh/gamecenter/newsdetail/NewsDetailAdapter.java
2017-06-29 11:23:47 +08:00
f97ccd5c5d 1、更改部分下载类,未完成
2、@#&@*#
2017-06-29 11:17:01 +08:00
0b2a672f2d Merge remote-tracking branch 'origin/3.0' into 3.0
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/newsdetail/NewsDetailAdapter.java
2017-06-28 18:09:08 +08:00
f960b07ee1 涉及到用户操作的加上登录验证, 把评论点赞抽离成工具方法 2017-06-28 18:06:36 +08:00
5cbf06f6a6 1、回退umeng push版本到3.1.1
2、catch umeng初始化。
2017-06-28 11:06:50 +08:00
70ea517a3a update LGLibrary, fix libaodetail entrance 2017-06-28 10:12:48 +08:00
957305d6f5 抽离详情页面下载模块(已完成) 2017-06-28 09:53:03 +08:00
bbd1d429a6 Merge remote-tracking branch 'origin/3.0' into 3.0 2017-06-27 16:31:48 +08:00
56ba47a844 抽离详情页面下载模块(新闻详情已完成) 2017-06-27 16:31:27 +08:00
8101d394a8 fix conflict 2017-06-27 16:28:33 +08:00
496144f8ad 1、统一下载逻辑,下一步准备移动到通用类库
2、修复viewimageactivity npe
2017-06-27 16:27:51 +08:00
4cbee71636 fix submodule 2017-06-26 18:57:09 +08:00
7aed643eba fix conflict 2017-06-26 18:38:16 +08:00
829da52101 更换新版Dialog,微博获取用户信息 2017-06-26 18:27:36 +08:00
9dd449c2ef 1、移动公用文件、样式到libraries/LGLibrary
2、请使用git submodule foreach git pull更新代码
2017-06-26 16:35:36 +08:00
f78bdaa358 mv BaseRecyclerAdapter to lib 2017-06-26 15:16:00 +08:00
16236e1361 remove weibo lib 2017-06-26 15:12:18 +08:00
8e52d45037 fix build script 2017-06-26 14:57:33 +08:00
2246670487 1、移除libraries/LGLibrary,使用submodule替代,具体使用方式参考README.md
2、更新readme.md的说明
3、添加CHANGELOG.md文件,用于保存版本更新记录
2017-06-26 14:48:16 +08:00
cde325198e 登录模块界面 2017-06-26 09:20:08 +08:00
faa0710fd5 ... 2017-06-22 16:28:54 +08:00
d1bb27ad6b 雷达扫描动画GIF 用自定义View实现 2017-06-22 16:28:08 +08:00
8f1f679077 修改代码遗留问题 2017-06-22 15:05:11 +08:00
b632cbba0f 命名规则 2017-06-22 11:08:22 +08:00
de438e90c4 大于两个的if分支,使用switch 2017-06-21 20:54:12 +08:00
7a3b1d4dbe viewpager滑动时,tab无法同步问题 2017-06-21 17:17:35 +08:00
44e9b4da4d Activity 统一入口 2017-06-21 12:03:27 +08:00
559710b4b4 部分Intent.putExtras参数传递实体类 用Parcelable来处理, 修复游戏插件下载闪退 2017-06-20 18:29:49 +08:00
a05c5b4976 登录页面 2017-06-20 09:30:49 +08:00
51cfe767ee 合并冲突 2017-06-19 11:30:25 +08:00
0891e78b8d Merge remote-tracking branch 'origin/3.0' into 3.0
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.java
2017-06-19 11:06:16 +08:00
5c834ec09c gradle引入weiboSDK,接入第三点登录(QQ、微信、微博(未完善)), 我的光环改版 2017-06-19 11:05:16 +08:00
fc5b6ae4e4 1、处理viewpager fragment
2、将MainActivity管理的逻辑移到MainFragment,MessageFragment,NewsFragment同理,
3、处理首页ViewPager等手动计算size的问题
4、添加一堆ScaleXXXView,可以用来设定View本身的比例大小

TODO
1、将DownloadManagerActivity也处理成Fragment
2、其他界面也慢慢处理成Fragment
2017-06-17 15:52:42 +08:00
5e668d9e13 fix deprecated 2017-06-16 16:12:28 +08:00
b3d63c5698 1、处理viewholder
2、处理adapter
3、
2017-06-16 15:39:45 +08:00
079c160268 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-06-16 14:11:25 +08:00
f5425c2bea 1、统一所有fragment初始化流程,继承自BaseFragment
2、统一大部分viewholder
3、TODO fragment adapter viewholder的分包还没处理完成
2017-06-16 14:11:18 +08:00
8c4967abc4 Merge remote-tracking branch 'origin/dev' into dev 2017-06-15 17:28:03 +08:00
8dd069b38d 切换正式接口 2017-06-15 17:27:49 +08:00
1160fb999e 修改mta接入,然而貌似并没有什么卵用
禁用tcagent的uncaught exception 上报
2017-06-15 17:24:16 +08:00
948329f79e 0614小问题优化 2017-06-14 20:02:12 +08:00
a61ef37a22 Merge remote-tracking branch 'origin/dev' into dev 2017-06-14 18:23:10 +08:00
66e8de06f0 gif移到assets 2017-06-14 18:22:26 +08:00
b5c3daea0c fix conflict 2017-06-14 18:20:08 +08:00
ba70ecc063 1、修复验证码出现的各种奇葩问题和崩溃,传入activity作为显示,但不持有引用
2、增加重试机制,3次获取不成功才失败。
3、修复okhttp Response返回非HTTPException导致的NPE
2017-06-14 18:19:25 +08:00
3b1145133a 1、修复验证码textview 初始化崩溃的bug
2、修复验证码返回时activity 已被销毁仍然弹窗导致的崩溃
2017-06-14 16:46:38 +08:00
3e0e4caa0c 专题头图增加跳转 2017-06-14 11:22:41 +08:00
a55a969588 修复部分bug 2017-06-13 09:25:40 +08:00
8b46435808 增加eventbus混淆 2017-06-12 15:08:48 +08:00
1a6966e522 EventBus版本升级(旧版的lib未删) 2017-06-09 16:08:19 +08:00
2fcee4cea0 优化代码,删除无用文件 2017-06-08 14:55:29 +08:00
223b7c6069 修改平铺专题实现方法, 修复资讯关注推荐小板块BUG,版本升至2.6 2017-06-07 10:25:30 +08:00
771946918a 工具想搜索关注的游戏优先, 开服表修改显示逻辑 2017-06-05 11:20:06 +08:00
d7e113108b 修复部分BUG,工具箱增加搜索功能 2017-05-31 20:39:18 +08:00
e3d9fac1b0 修改游戏详情协调布局的实现方法 2017-05-28 18:36:58 +08:00
7c78109bf2 整理专题合并,首页游戏列表和专题列表增加游戏标签 2017-05-28 16:10:33 +08:00
b7ccf66418 合并专题Acticity 2017-05-28 15:08:50 +08:00
8c5265f9b5 对接工具箱接口,工具箱详情增加分享功能 2017-05-27 16:46:02 +08:00
e81bbf5195 增加平铺游戏专题(缺少数据借口) 2017-05-26 11:44:39 +08:00
f219b62fcc 工具箱(为对接数据接口),解决footeritem高度不一问题和开服表闪退问题 2017-05-25 09:54:21 +08:00
6347260522 修复模拟器闪退问题,增加DEBUG推送appid和appkey 2017-05-24 10:13:27 +08:00
9fe80cfb66 Merge remote-tracking branch 'origin/dev' into dev 2017-05-23 14:35:05 +08:00
62975e5e1b .... 2017-05-23 14:34:56 +08:00
9b4e62149f add umeng debug 2017-05-23 14:30:15 +08:00
8643a12744 new Thread用RxJava或者线程池代替 2017-05-22 09:07:18 +08:00
9369218821 reformat code & optimize import & rearrange code 2017-05-19 10:54:56 +08:00
0c1b48cee2 规范部分Thread 2017-05-19 10:47:43 +08:00
5865fdbd23 调整界面 2017-05-19 09:23:09 +08:00
6b5fe82d47 1、修复url匹配正则
2、部分onclick处理
3、代码整理
2017-05-18 12:05:25 +08:00
49624d5afd 修改游戏详情插件介绍实现方法(页面视图在XML创建,解决展开时位置移动) 2017-05-18 11:49:55 +08:00
a92de9ffa0 切换接口 2017-05-17 19:52:01 +08:00
d4133cc51d Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/SuggestionActivity.java
2017-05-17 18:35:37 +08:00
611068a9b0 修复意见反馈提示顺序混乱问题 2017-05-17 18:32:51 +08:00
7930ecaea9 fix entrance 2017-05-17 18:28:26 +08:00
3c72080802 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-05-17 18:19:03 +08:00
4c762a1aa8 1、统一了entrance
2、统一了部分跳转intent,传参返回intent
3、修改出dialogfragment
4、clipboardmanager等处理
2017-05-17 18:18:46 +08:00
4f99477d83 修改游戏详情空白页优化, 开服表修改部分显示规则和增加滑动动画 2017-05-17 14:47:00 +08:00
6d4de6795e 优化汇总(20170513)补充 2017-05-16 17:43:59 +08:00
4f8b93cb6a 优化代码 2017-05-15 18:21:07 +08:00
48a4aefe96 Merge remote-tracking branch 'origin/dev' into dev 2017-05-14 17:54:02 +08:00
dc530be9be V2.5优化汇总(20170513) 2017-05-14 17:53:36 +08:00
bb5e9e739b fix td npe 2017-05-12 15:53:43 +08:00
7264249ef8 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-05-12 15:46:57 +08:00
5eb5f6807e 1、使用新的渠道打包方案,将渠道值写入到已经签名的apk上面,具体参考README.md
2、将各种第三方工具使用的appid、key和渠道值改成用gradle.properties的配置方式
2017-05-12 15:46:46 +08:00
8bb50a6e2c 游戏详情部分位置和显示方式修改 2017-05-12 11:39:31 +08:00
7b7987b574 部分代码整理 2017-05-11 14:55:54 +08:00
a209edc181 Merge remote-tracking branch 'origin/dev' into dev 2017-05-10 18:24:19 +08:00
e744a475c3 插件包增加隐藏状态(只能识别到插件化) 2017-05-10 18:24:02 +08:00
b280e1bf89 add shrinkresources & resconfig in order to reduce apk size 2017-05-10 16:26:55 +08:00
decb763a5f filter unused abi 2017-05-10 16:07:40 +08:00
28f685ae10 fix wrong arg in compress_resources.sh 2017-05-10 15:45:16 +08:00
6270d59f3f Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-05-10 15:23:02 +08:00
11c6f33392 1、升级support v4 系列到24.1.0
2、增加混淆配置,release默认启用
2017-05-10 15:22:50 +08:00
a75b613744 Merge remote-tracking branch 'origin/dev' into dev 2017-05-09 18:25:06 +08:00
ccca070dd2 修改礼包倒数领取规则 2017-05-09 18:24:45 +08:00
bd2ce2e82d 1、升级umeng push到3.1.1a,解决通知栏持续运行中的问题
2、fix game adapter
2017-05-09 18:17:28 +08:00
a88c920ef0 Merge remote-tracking branch 'origin/dev' into dev 2017-05-08 18:37:07 +08:00
6aee2ae6b9 ProgressBar固定样式(防止5.0以上样式改变),修改SwitchButton样式 2017-05-08 18:36:45 +08:00
0ec14da2ac 1、修复AppController push被禁用的问题
2、修复deprecated api call, Resources.getColor()
2017-05-08 17:41:58 +08:00
375f538bc1 1、fix skipactivity/baseappcompatactivity potential npe
2、fix appcontroller logic
2017-05-08 15:22:57 +08:00
1c6907373b 直接导入的swipelayout无法适应需求,直接源码导入进行修改 2017-05-08 14:58:53 +08:00
64fe9048f0 Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/LibaoDetailActivity.java
2017-05-05 18:25:14 +08:00
c96193b3d0 代码整理 2017-05-05 18:24:37 +08:00
b1035c24bc resolve conflict 2017-05-05 18:21:21 +08:00
d69e75480e 1、将所有Activity统一到一个base(主题AppCompatTheme),layout和contentView统一处理
2、MainActivity tab切换方式的重构
3、下一步更改toolbar实现方式,然后再是尽量用fragment替换
2017-05-05 18:12:51 +08:00
4da12055e9 优化字符串叠加 2017-05-05 17:11:05 +08:00
7ca9272fe7 提取activity title到strings.xml 2017-05-05 10:23:13 +08:00
5f0bf827ae 游戏专题自动获取专题名称 2017-05-04 16:21:25 +08:00
87cd020e94 调整资讯位置 2017-05-04 15:15:44 +08:00
4fd7095fbf Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.java
2017-05-04 14:44:24 +08:00
c1ebcf33e5 引入design包,游戏专题改版 2017-05-04 14:42:36 +08:00
d0f72a8d96 1、修改autoscrollviewpager/swipelayout为gradle引用
2、添加google iosched部分ui类
2017-05-04 11:59:54 +08:00
6e5ac76b52 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2017-05-04 11:49:03 +08:00
8ae3b93307 文章详情webview链接跳转修改 2017-05-04 11:48:34 +08:00
7246e06973 Merge remote-tracking branch 'origin/dev' into dev 2017-05-03 16:44:04 +08:00
0ae824b9f5 合并 2017-05-03 16:43:15 +08:00
deee22b6db Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/CleanApkActivity.java
#	app/src/main/java/com/gh/gamecenter/MessageDetailActivity.java
#	app/src/main/java/com/gh/gamecenter/VoteActivity.java
#	app/src/main/java/com/gh/gamecenter/adapter/LibaoDetailAdapter.java
#	app/src/main/java/com/gh/gamecenter/adapter/MessageDetailAdapter.java
#	app/src/main/java/com/gh/gamecenter/adapter/VoteAdapter.java
#	app/src/main/java/com/gh/gamecenter/libao/Libao1FragmentAdapter.java
#	app/src/main/java/com/gh/gamecenter/libao/Libao2FragmentAdapter.java
#	app/src/main/java/com/gh/gamecenter/libao/Libao3FragmentAdapter.java
#	app/src/main/java/com/gh/gamecenter/message/CommentFragmentAdapter.java
#	app/src/main/java/com/gh/gamecenter/news/News1FragmentAdapter.java
2017-05-03 16:32:10 +08:00
c8e01182f4 1、fix splashscreen test
2、fix multidex lib
3、add stetho
2017-05-03 16:14:49 +08:00
dec6bd6779 产品优化汇总 2017-05-03 16:09:14 +08:00
b00b791107 启动屏幕部分逻辑修改 2017-05-02 17:15:37 +08:00
4db2b1cc29 retrofit2.adapter.rxjava.HttpException修改为retrofit2.HttpException 2017-05-02 10:44:23 +08:00
471ebb3b6e icon-default问题修改 2017-05-02 10:39:10 +08:00
e057b6530b confirem修改为confirm 2017-05-02 10:28:04 +08:00
b5328324f8 产品测试汇总 2017-04-29 17:25:37 +08:00
18aa853948 fix color back 2017-04-28 16:37:08 +08:00
c8559bd36a Merge branch 'dev' of git.oschina.net:dreamhua/GH-ASSISTv1.45 into dev 2017-04-28 16:13:44 +08:00
b71e717da1 1、提取xml的字符串和部分java文件的字符串到strings.xml
2、提取color到colors.xml
2017-04-28 16:13:32 +08:00
60677b36f6 沉浸栏颜色修改 2017-04-28 14:32:42 +08:00
339d32b1dd 推荐位数据收集修改 2017-04-28 11:53:11 +08:00
9432e34571 reformat code & optimize import & reorder entries 2017-04-27 14:27:17 +08:00
153f33f44b 1、所有引用整理到从dependencies.gradle文件,部分库做了升级
2、添加httplogginginteceptor记录网络请求情况
2017-04-27 14:15:05 +08:00
fc2f20ee6e Merge branch 'dev' of https://git.oschina.net/dreamhua/GH-ASSISTv1.45 into dev
Conflicts:
	app/src/main/java/com/gh/gamecenter/MainActivity.java
2017-04-26 15:59:44 +08:00
cfa70feac5 应用上报 2017-04-26 15:56:19 +08:00
6a851f7247 应用数据上报 2017-04-26 15:55:53 +08:00
khy
a0cae1b7b8 游戏详情接入游戏推荐(大家都在玩),优化代码 2017-04-26 15:34:58 +08:00
khy
5798ba9e89 Merge remote-tracking branch 'origin/dev' into dev 2017-04-25 19:17:20 +08:00
khy
919e3c386d 增加MessageService(更改域名), 取消显示公告 2017-04-25 19:16:58 +08:00
e85bb40904 Merge remote-tracking branch 'origin/dev' into dev 2017-04-25 18:45:28 +08:00
d23a2df809 1、systembar tint/switchbutton/mipush做了更新整理
2、部分跳转常量整理
3、工程结构整理,基本国内几个sdk解决完了
2017-04-25 18:45:10 +08:00
khy
b9185cce15 合并整理 2017-04-25 14:53:57 +08:00
khy
c14605b598 Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/adapter/PlatformAdapter.java
#	app/src/main/java/com/gh/gamecenter/adapter/VoteAdapter.java
2017-04-25 14:35:03 +08:00
khy
68c2f3c754 对接求版本投票数据接口, 礼包重复领取优化 2017-04-25 14:29:58 +08:00
2725a59826 基本处理完成recyclerview adapter 2017-04-25 13:16:16 +08:00
khy
9ef8f5d1f2 Merge remote-tracking branch 'origin/dev' into dev 2017-04-25 10:17:18 +08:00
khy
39cd66032d 修改Handler 在 ondestroy时 remove全部消息,Context获取的Manager,改为Application Context持有,游戏列表增加开服信息 2017-04-24 19:14:47 +08:00
ee53e7218f add so files. 2017-04-24 18:49:17 +08:00
72a1cded27 fix so libs 2017-04-21 18:08:40 +08:00
3295b6a7b7 fix gradle version 2017-04-21 17:45:13 +08:00
1186 changed files with 65021 additions and 80069 deletions

3
.gitignore vendored
View File

@ -5,4 +5,5 @@ local.properties
# sign.properties
.DS_Store
captures/
build/
build/
release-app/

4
.gitmodules vendored Normal file
View File

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

15
CHANGELOG.md Normal file
View File

@ -0,0 +1,15 @@
### Ver 3.0
* 升级账号系统(登录流程/用户信息相关/用户账号相关操作(评论,礼包...))
* 新增收藏功能(文章/工具箱)
* 删除用户相关的所有本地数据库
* 重做总开服表
* 重做首页插件化模块
* 礼包重复领取机制改变(可重复领取的礼包,领取后立刻显示再领一个/再淘一个)
* 游戏下载平台面板修改(加快弹出速度,不再读取本地平台图片)
* 接入bugly(tinker)
### Ver 2.6
* xx
### Ver 2.5
* 此处写本次更新所做的业务和代码修改

View File

@ -1,4 +1,40 @@
# 光环助手
# 光环助手Android客户端
### Ver 2.5
* xxx
### Sourceset/debug/release
* https://developer.android.com/studio/build/build-variants.html#sourcesets
### 多渠道打包配置
* 使用[ApkChannelPackage](https://github.com/ltlovezh/ApkChannelPackage)的方案
* 正式打包命令:请使用./gradlew channelPubRelease打包渠道包
### 混淆配置
* 配置文件Android默认配置+proguard-rules.txt等
* 参考libraries下每个项目独立的配置文件``proguard-project.txt``
### apk大小优化
* 限制resConfig资源集
* 开启ShrinkResources
* 开启混淆使用minifyEnabled(仅在release开启
* pngquant对png压缩、png/jpg->webp(未尝试)
### 第三方appkey等配置
* 修改``gradle.properties``文件将各种key填入其中实现统一管理
* 通过gradle文件内的resValue/buildConfigField/manifestPlaceHolder方式实现编译期间修改具体情况请参考``./build.gradle``和``./app/build.gradle``配置
### 拉取代码步骤
1. 拉取主项目代码: `git clone -b dev git@gitlab.ghzhushou.com:halo/assistant-android.git`
2. 初始化公用类库: `bash ./scripts/init_submodules.sh`
### submodule管理方式(只拉取master)
* 提交代码需要cd到submodule文件夹去做修改
### TODO
* GSON 序列化用统一的一个, GsonUtil fromJson
* CleanApkAdapter 转化字符串size工具函数 比如SpeedUtils
* getString 解决 字符串hardcode问题
* Adapter 里面clicklistener 用接口传参将点击操作委托给controller
* Adapter ViewHolder的功能部分重写到ViewHolder类本身
* activity 统一入口未完成(外部入口相关)

View File

@ -1,7 +1,11 @@
apply plugin: 'com.android.application'
//butterknife
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'kotlin-android' // kotlin
// apkChannelPackage
apply plugin: 'channel'
apply from: 'tinker-support.gradle'
android {
@ -14,28 +18,58 @@ android {
jumboMode = true
}
/**
* 定位编译出错的图片
*/
aaptOptions.cruncherEnabled = false
aaptOptions.useNewCruncher = false
defaultConfig {
// jackOptions {
// enabled true
// }
multiDexEnabled true
javaCompileOptions {
annotationProcessorOptions {
arguments = [eventBusIndex: 'com.gh.EventBusIndex']
}
}
/**
* 只支持两种架构减少apk大小有疑问请参考
* https://developer.android.com/ndk/guides/abis.html
* http://allenfeng.com/2016/11/06/what-you-should-know-about-android-abi-and-so/
* 为了性能考虑armeabi可以考虑替换成armeabi-v7a[需要先收集用户设备情况]
*/
ndk {
abiFilters "armeabi", "x86"
}
// 由于app只针对中文用户所以仅保留zh资源其他删掉
resConfigs "zh"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
applicationId rootProject.ext.applicationId
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
/**
* All third-party appid/appkey
*/
buildConfigField "String", "WECHAT_APPID", "\"${WECHAT_APPID}\""
buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\""
buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\""
buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\""
buildConfigField "String", "MTA_APPKEY", "\"${MTA_APPKEY}\""
buildConfigField "String", "TD_APPID", "\"${TD_APPID}\""
buildConfigField "String", "PATCH_VERSION_NAME", "\"${PATCH_VERSION_NAME}\""
}
// gradle 2.2以上默认同时启用v1和v2优先用于Android N
signingConfigs {
debug {
v1SigningEnabled true
v2SigningEnabled true
}
release {
v1SigningEnabled true
v2SigningEnabled true
}
}
@ -44,113 +78,166 @@ android {
debuggable true
minifyEnabled false
zipAlignEnabled false
// versionNameSuffix "-debug"
versionNameSuffix "-debug"
signingConfig signingConfigs.debug
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "MIPUSH_APPID", "\"${DEBUG_MIPUSH_APPID}\""
buildConfigField "String", "MIPUSH_APPKEY", "\"${DEBUG_MIPUSH_APPKEY}\""
}
release {
debuggable false
minifyEnabled false
zipAlignEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
minifyEnabled true
zipAlignEnabled true
shrinkResources true
signingConfig signingConfigs.release
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
}
}
flavorDimensions "nonsense"
/**
* 多渠道打包
* 多渠道打包,渠道请参考"channel.txt"文件所有渠道值均通过java code设置
*/
productFlavors {
GH_100 {}
GH_101 {}
GH_102 {}
GH_103 {}
GH_104 {}
GH_106 {}
GH_107 {}
GH_108 {}
GH_109 {}
GH_110 {}
GH_111 {}
GH_113 {}
GH_114 {}
GH_115 {}
GH_116 {}
GH_117 {}
GH_118 {}
GH_119 {}
GH_120 {}
GH_121 {}
GH_123 {}
GH_127 {}
GH_200 {}
GH_201 {}
GH_202 {}
GH_203 {}
GH_204 {}
GH_205 {}
GH_222 {}
GH_307 {}
GH_TEST {}
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [CHANNEL_VALUE: name]//命令 gradlew assembleRelease
// publish release host
publish {
dimension "nonsense"
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "USER_HOST", "\"${USER_HOST}\""
buildConfigField "String", "COMMENT_HOST", "\"${COMMENT_HOST}\""
buildConfigField "String", "LIBAO_HOST", "\"${LIBAO_HOST}\""
buildConfigField "String", "MESSAGE_HOST", "\"${MESSAGE_HOST}\""
buildConfigField "String", "DATA_HOST", "\"${DATA_HOST}\""
buildConfigField "String", "USERSEA_HOST", "\"${USERSEA_HOST}\""
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
buildConfigField "String", "USERSEA_APP_ID", "\"${USERSEA_APP_ID}\""
buildConfigField "String", "USERSEA_APP_SECRET", "\"${USERSEA_APP_SECRET}\""
}
// internal test dev host
internal {
dimension "nonsense"
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
buildConfigField "String", "USER_HOST", "\"${DEV_USER_HOST}\""
buildConfigField "String", "COMMENT_HOST", "\"${DEV_COMMENT_HOST}\""
buildConfigField "String", "LIBAO_HOST", "\"${DEV_LIBAO_HOST}\""
buildConfigField "String", "MESSAGE_HOST", "\"${DEV_MESSAGE_HOST}\""
buildConfigField "String", "DATA_HOST", "\"${DEV_DATA_HOST}\""
buildConfigField "String", "USERSEA_HOST", "\"${DEV_USERSEA_HOST}\""
buildConfigField "String", "BUGLY_APPID", "\"${DEBUG_BUGLY_APPID}\""
buildConfigField "String", "USERSEA_APP_ID", "\"${DEV_USERSEA_APP_ID}\""
buildConfigField "String", "USERSEA_APP_SECRET", "\"${DEV_USERSEA_APP_SECRET}\""
}
}
// productFlavors.all { flavor ->
// flavor.manifestPlaceholders = [CHANNEL_VALUE: name]//命令 gradlew assembleRelease
// }
}
// apkChannelPackage
channel {
//多渠道包的输出目录默认为new File(project.buildDir,"channel")
baseOutputDir = new File(project.buildDir, "channel")
//多渠道包的命名规则,默认为:${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}
apkNameFormat = '${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}'
}
rebuildChannel {
// baseDebugApk = 已有Debug APK
// baseReleaseApk = 已有Release APK
// //默认为new File(project.buildDir, "rebuildChannel/debug")
// debugOutputDir = Debug渠道包输出目录
// //默认为new File(project.buildDir, "rebuildChannel/release")
// releaseOutputDir = Release渠道包输出目录
}
dependencies {
testCompile 'junit:junit:4.12'
implementation fileTree(include: '*.jar', dir: 'libs')
compile fileTree(dir: 'libs', include: '*.jar')
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakcanary}"
debugImplementation "com.facebook.stetho:stetho:${stetho}"
debugImplementation "com.facebook.stetho:stetho-okhttp3:${stetho}"
debugImplementation "com.squareup.okhttp3:logging-interceptor:${okHttp}"
compile 'com.android.support:appcompat-v7:23.2.1'
// compile 'com.android.support:cardview-v7:21.0.0'
// fresco图片框架
compile 'com.facebook.fresco:fresco:0.12.0'
compile 'com.facebook.fresco:animated-gif:0.12.0'
// Retrofit2所需要的包
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
// okhttp
compile 'com.squareup.okhttp3:okhttp:3.2.0'
// ConverterFactory的Gson依赖包
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
// ConverterFactory的String依赖包
// compile 'com.squareup.retrofit2:converter-scalars:2.0.0-beta4'
// ConverterFactory的RxJava依赖包
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
// gson
compile 'com.google.code.gson:gson:2.8.0'
// OrmLite数据库
compile 'com.j256.ormlite:ormlite-android:5.0'
compile 'com.j256.ormlite:ormlite-core:5.0'
// butterknife
compile 'com.jakewharton:butterknife:8.4.0'
apt 'com.jakewharton:butterknife-compiler:8.4.0'
// RxJava && RxAndroid
compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0'
// RxBinding
compile 'com.jakewharton.rxbinding:rxbinding:0.3.0'
// compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.3.0'
// compile 'com.jakewharton.rxbinding:rxbinding-design:0.3.0'
implementation "com.android.support:multidex:${multidex}"
implementation "com.android.support:design:${androidSupport}"
implementation "com.android.support:support-v4:${androidSupport}"
implementation "com.android.support:appcompat-v7:${androidSupport}"
implementation "com.android.support:support-annotations:${androidSupport}"
implementation "com.android.support:percent:${androidSupport}"
// zxing 二维码扫描以及生成
compile 'com.google.zxing:core:3.2.1'
compile 'com.google.zxing:android-core:3.2.1'
//tinker
// compile("com.tencent.tinker:tinker-android-lib:${TINKER_VERSION}") { changing = true }
// compile "com.android.support:multidex:1.0.1"
implementation "com.kyleduo.switchbutton:library:${switchButton}"
implementation "com.readystatesoftware.systembartint:systembartint:${systemBarTint}"
compile project(':libraries:EventBus')
compile project(':libraries:MiPush')
compile project(':libraries:MTA')
compile project(':libraries:QQShare')
compile project(':libraries:TalkingData')
compile project(':libraries:UmengPush')
compile project(':libraries:WechatShare')
compile project(':libraries:WeiboShare')
implementation "com.facebook.fresco:fresco:${fresco}"
implementation "com.facebook.fresco:animated-gif:${fresco}"
implementation "com.squareup.okhttp3:okhttp:${okHttp}"
implementation "com.leon.channel:helper:${apkChannelPackage}"
implementation "com.squareup.retrofit2:retrofit:${retrofit}"
implementation "com.squareup.retrofit2:converter-gson:${retrofit}" // include gson 2.7
implementation "com.squareup.retrofit2:adapter-rxjava:${retrofit}"
// implementation "com.google.code.gson:gson:${gson}"
implementation "com.j256.ormlite:ormlite-android:${ormlite}"
implementation "com.j256.ormlite:ormlite-core:${ormlite}"
implementation "com.jakewharton:butterknife:${butterKnife}"
annotationProcessor "com.jakewharton:butterknife-compiler:${butterKnife}"
implementation "org.greenrobot:eventbus:${eventbus}"
annotationProcessor "org.greenrobot:eventbus-annotation-processor:${eventbusApt}"
implementation "io.reactivex:rxjava:${rxJava}"
implementation "io.reactivex:rxandroid:${rxAndroid}"
implementation "com.jakewharton.rxbinding:rxbinding:${rxBinding}"
//TODO update to rx 2.x
// implementation "io.reactivex.rxjava2:rxjava:${rxJava2}"
// implementation "io.reactivex.rxjava2:rxandroid:${rxAndroid2}"
// implementation "com.jakewharton.rxbinding2:rxbinding:${rxBinding2}"
implementation "com.google.zxing:core:${zxing}"
implementation "com.google.zxing:android-core:${zxing}"
implementation "com.daimajia.swipelayout:library:${swipeLayout}"
implementation("cn.trinea.android.view.autoscrollviewpager:android-auto-scroll-view-pager:${autoScrollViewPager}") {
exclude module: 'support-v4'
}
implementation "com.sina.weibo.sdk:core:${weiboSDK}"
// bugly with tinker support
implementation "com.tencent.bugly:crashreport_upgrade:${buglyTinkerSupport}"
implementation "pub.devrel:easypermissions:${easypermissions}"
implementation project(':libraries:MiPush')
implementation project(':libraries:MTA')
implementation project(':libraries:QQShare')
implementation project(':libraries:TalkingData')
implementation project(':libraries:UmengPush')
implementation project(':libraries:WechatShare')
implementation project(':libraries:iosched')
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
File propFile = file('sign.properties');
File propFile = file('sign.properties')
if (propFile.exists()) {
def Properties props = new Properties()
props.load(new FileInputStream(propFile))
@ -158,12 +245,13 @@ if (propFile.exists()) {
if (props.containsKey('keyAlias') && props.containsKey('keyPassword') &&
props.containsKey('storeFile') && props.containsKey('storePassword')) {
android.signingConfigs {
// debug {
// keyAlias props.get('keyAlias')
// keyPassword props.get('keyPassword')
// storeFile file(props.get('storeFile'))
// storePassword props.get('storePassword')
// }
// debug 不要使用正式签名这样tinker才不会打补丁。
debug {
keyAlias props.get('keyAlias')
keyPassword props.get('keyPassword')
storeFile file(props.get('storeFile'))
storePassword props.get('storePassword')
}
release {
keyAlias props.get('keyAlias')
keyPassword props.get('keyPassword')

21
app/proguard-fresco.txt Normal file
View File

@ -0,0 +1,21 @@
# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.facebook.common.internal.DoNotStrip class *
-keepclassmembers class * {
@com.facebook.common.internal.DoNotStrip *;
}
# Keep native methods
-keepclassmembers class * {
native <methods>;
}
-dontwarn okio.**
-dontwarn com.squareup.okhttp.**
-dontwarn okhttp3.**
-dontwarn javax.annotation.**
-dontwarn com.android.volley.toolbox.**
-dontwarn com.facebook.infer.**

View File

@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod
-dontwarn InnerClasses
-dontoptimize

192
app/proguard-rules.txt Normal file
View File

@ -0,0 +1,192 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
#--------- remove logs start ----------------
-assumenosideeffects class com.lightgame.config.CommonDebug {
private static String getLogTag(...);
private static String getMethodName();
public static void logMethodName(...);
public static void logParams(...);
public static void logFields(...);
public static void logMethodWithParams(...);
}
#-assumenosideeffects class com.lightgame.config.CommonDebug {*;}
#-dontoptimize
#--------- remove logs end ----------------
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod
-dontwarn InnerClasses
# OrmLite uses reflection
-keep class com.j256.**
-keepclassmembers class com.j256.** { *; }
-keep enum com.j256.**
-keepclassmembers enum com.j256.** { *; }
-keep interface com.j256.**
-keepclassmembers interface com.j256.** { *; }
-dontwarn com.j256.**
#okhttp3
-dontwarn com.squareup.okhttp3.**
-dontwarn okio.**
-keep class com.squareup.okhttp3.** { *;}
# stetho
-keep class com.facebook.stetho.** { *; }
-dontwarn com.facebook.stetho.**
# Retrofit 2.2
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
# Retrofit 2.X
## https://square.github.io/retrofit/ ##
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
# rxjava
-keep class rx.schedulers.Schedulers {
public static <methods>;
}
-keep class rx.schedulers.ImmediateScheduler {
public <methods>;
}
-keep class rx.schedulers.TestScheduler {
public <methods>;
}
-keep class rx.schedulers.Schedulers {
public static ** test();
}
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
long producerNode;
long consumerNode;
}
-dontwarn rx.internal.util.**
## AutoScrollViewPager
-keep class cn.trinea.android.** { *; }
-keepclassmembers class cn.trinea.android.** { *; }
-dontwarn cn.trinea.android.**
## butterknife
# Retain generated class which implement Unbinder.
#-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
#
## Prevent obfuscation of types which use ButterKnife annotations since the simple name
## is used to reflectively look up the generated ViewBinding.
#-keep class butterknife.*
#-keepclasseswithmembernames class * { @butterknife.* <methods>; }
#-keepclasseswithmembernames class * { @butterknife.* <fields>; }
-dontwarn butterknife.internal.**
-keep class **$$ViewInjector { *; }
-keepnames class * { @butterknife.InjectView *;}
-dontwarn butterknife.Views$InjectViewProcessor
-dontwarn com.gc.materialdesign.views.**
# eventbus
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}
# weiboSdk
-keep class com.sina.weibo.sdk.** { *; }
-dontwarn android.webkit.WebView
-dontwarn android.webkit.WebViewClient
# app models
-keep class com.gh.common.view.** {*;}
-keep class com.gh.gamecenter.db.info.** {*;}
-keep class com.gh.gamecenter.entity.** {*;}
-keep class com.gh.gamecenter.retrofit.** {*;}
-keep class com.gh.gamecenter.eventbus.** {*;}
-keep class * extends rx.Subscriber
#---------------------------------webview------------------------------------
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String);
}
#----------------------------------------------------------------------------
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
-keepclassmembers enum * { *; }
##---------------End: proguard configuration for Gson ----------
# ------ bugly ---------
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# easypermission
-keepclassmembers class * {
@pub.devrel.easypermissions.AfterPermissionGranted <methods>;
}
# 重命名文件为SourceFile再配合mapping符号表可以拿到真实的类名
-renamesourcefileattribute SourceFile
# 保留源文件行号
-keepattributes SourceFile,LineNumberTable

View File

@ -1,13 +0,0 @@
package com.gh.gamecenter;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -0,0 +1,69 @@
package com.gh.gamecenter;
import android.app.Application;
import com.facebook.stetho.Stetho;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.lightgame.utils.Utils;
import com.squareup.leakcanary.LeakCanary;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
/**
* @author CsHeng
* @Date 03/09/2017
* @Time 4:34 PM
*/
public class Injection {
public static boolean appInit(Application application) {
// init leakcanary
if (LeakCanary.isInAnalyzerProcess(application)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return false;
}
LeakCanary.install(application);
// init stetho
Stetho.initializeWithDefaults(application);
return true;
}
public static OkHttpClient.Builder provideRetrofitBuilder() {
// HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
//
// @Override
// public void log(String message) {
// //分段打印retrofit日志
// if (message.startsWith("{") || message.startsWith("["))
// if (message.length() > 4000) {
// for (int i = 0; i < message.length(); i += 4000) {
// if (i + 4000 < message.length())
// Utils.log("OkHttp_Body::" + i, message.substring(i, i + 4000));
// else
// Utils.log("OkHttp_Body::" + i, message.substring(i, message.length()));
// }
// } else
// Utils.log("OkHttp_Body::", message);
// }
// });
// loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
builder.addNetworkInterceptor(interceptor);
builder.addNetworkInterceptor(new StethoInterceptor());
// if (BuildConfig.DEBUG) {
// builder.addNetworkInterceptor(loggingInterceptor);
// }
return builder;
}
}

View File

@ -1,368 +1,306 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gh.gamecenter" >
<manifest xmlns:android = "http://schemas.android.com/apk/res/android"
package = "com.gh.gamecenter" >
<!-- 允许应用程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name = "android.permission.INTERNET" />
<!-- 允许应用程序写入外部存储如SD卡上写文件 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 允许应用程序读取扩展存储器 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name = "android.permission.READ_EXTERNAL_STORAGE" />
<!-- 允许挂载和反挂载文件系统可移动存储 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 允许应用程序访问Wi-Fi网络状态信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />
<!-- 允许应用程序获取网络信息状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" />
<!-- 允许应用程序读取电话状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name = "android.permission.READ_PHONE_STATE" />
<!-- 允许应用程序获取当前或最近运行的应用 -->
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name = "android.permission.GET_TASKS" />
<!-- 允许访问振动设备 -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name = "android.permission.VIBRATE" />
<!-- 允许应用程序通过WiFi或移动基站获取粗略的位置信息 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name = "android.permission.ACCESS_COARSE_LOCATION" />
<!-- 允许应用程序通过GPS获取精确的位置信息 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name = "android.permission.ACCESS_FINE_LOCATION" />
<!-- 允许应用程序改变Wi-Fi连接状态 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name = "android.permission.CHANGE_WIFI_STATE" />
<!-- 允许应用程序管理AccountManager中的账户列表 -->
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name = "android.permission.MANAGE_ACCOUNTS" />
<!-- 允许应用程序访问GMail账户列表 -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name = "android.permission.GET_ACCOUNTS" />
<!-- 允许应用程序连接配对过的蓝牙设备 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name = "android.permission.BLUETOOTH" />
<!-- 允许应用程序管理蓝牙,搜索和配对新的蓝牙设备 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name = "android.permission.BLUETOOTH_ADMIN" />
<!-- 允许应用程序打开系统窗口,显示其他应用程序 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 小米推送需要的权限 -->
<uses-permission android:name="com.gh.gamecenter.permission.MIPUSH_RECEIVE" />
<uses-permission android:name = "android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 修改系统设置的权限 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name = "android.permission.WRITE_SETTINGS" />
<permission
android:name="com.gh.gamecenter.permission.MIPUSH_RECEIVE"
android:protectionLevel="signature" />
<!-- bugly with tinker -->
<uses-permission android:name = "android.permission.READ_PHONE_STATE" />
<uses-permission android:name = "android.permission.INTERNET" />
<uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name = "android.permission.READ_LOGS" />
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true" />
android:anyDensity = "true"
android:largeScreens = "true"
android:normalScreens = "true"
android:resizeable = "true"
android:smallScreens = "true" />
<!--android:largeHeap = "true"-->
<application
android:name="com.gh.base.AppController"
android:icon="@drawable/logo"
android:label="@string/app_name"
android:theme="@style/AppNormalTheme" >
<!-- TalkingData -->
<meta-data
android:name="TD_APP_ID"
android:value="81DB144D555386A38A70B833537EC256" />
<meta-data
android:name="TD_CHANNEL_ID"
android:value="GH_TEST"/>
<!--android:value="${CHANNEL_VALUE}"-->
android:name = "com.halo.assistant.TinkerApp"
android:allowBackup = "true"
android:icon = "@drawable/logo"
android:label = "@string/app_name"
android:theme = "@style/AppCompatTheme.APP" >
<!--android:launchMode = "singleTask"-->
<activity
android:name = "com.gh.gamecenter.SplashScreenActivity"
android:configChanges = "keyboardHidden|orientation|screenSize"
android:noHistory = "true"
android:screenOrientation = "portrait"
android:theme = "@style/AppGuideTheme" >
<intent-filter >
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter >
<!-- 友盟推送 -->
<meta-data
android:name="UMENG_APPKEY"
android:value="58e5b0b9c62dca35a00005e6">
<!-- TODO 585a29fa8f4a9d327600023e -->
</meta-data>
<meta-data
android:name="UMENG_MESSAGE_SECRET"
android:value="ca08596492f8a7fde2ab48dceab8c1f3">
<!-- TODO 8bcce6bed547ee624f5c2cc64d39a9e9 -->
</meta-data>
<!-- MTA可视化启动连接接口 -->
<intent-filter >
<data android:scheme = "${tencentAppScheme}" />
<action android:name = "android.intent.action.VIEW" />
<category android:name = "android.intent.category.DEFAULT" />
<category android:name = "android.intent.category.BROWSABLE" />
</intent-filter >
</activity >
<activity
android:name="com.gh.gamecenter.SplashScreenActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait"
android:theme="@style/AppGuideTheme"
android:uiOptions="splitActionBarWhenNarrow" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
android:name = "com.gh.gamecenter.MainActivity"
android:launchMode = "singleTask"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateAlwaysHidden|adjustResize" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.gh.gamecenter.MainActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"/>
<activity
android:name="com.gh.gamecenter.DownloadManagerActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.ViewImageActivity"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" />
<activity
android:name="com.gh.gamecenter.SearchActivity"
android:screenOrientation="portrait"
android:configChanges="keyboardHidden" />
<activity
android:name="com.gh.gamecenter.NewsDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SettingActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.ConcernActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SubjectActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.PluginActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.NewsSearchActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.GameNewsActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.CropImageActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.WebActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ShareCardPicActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ShareCardActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.MessageDetailActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.LibaoActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.LibaoDetailActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ShareGhWfifActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ShareGhActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.CleanApkActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.KcSelectGameActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ChooseReceiverActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ReceiverWaitingActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.FileSenderActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.FileReceiverActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.SelectUserIconActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.AboutActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.NewsNormalActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.KaiFuActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.CommentDetailActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.GameDetailActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.SuggestSelectActivity"
android:screenOrientation="portrait"/>
<activity
android:name=".SuggestionActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden|adjustResize" />
<activity
android:name="com.gh.gamecenter.VoteActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"/>
<activity
android:name="com.gh.gamecenter.SkipActivity"
android:theme="@android:style/Theme.Translucent">
<intent-filter>
<data android:scheme="ghzhushou"/>
android:name = "com.gh.gamecenter.DownloadManagerActivity"
android:launchMode = "singleTask"
android:screenOrientation = "portrait" />
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
<activity
android:name="com.gh.gamecenter.wxapi.WXEntryActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="sdksample"/>
</intent-filter>
</activity>
<!-- QQ 分享 -->
android:name = "com.gh.gamecenter.ViewImageActivity"
android:theme = "@android:style/Theme.Black.NoTitleBar.Fullscreen" />
<activity
android:name="com.tencent.tauth.AuthActivity"
android:launchMode="singleTask"
android:noHistory="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tencent1104659243" />
</intent-filter>
</activity>
android:name = "com.gh.gamecenter.SearchActivity"
android:configChanges = "keyboardHidden"
android:screenOrientation = "portrait" />
<activity
android:name="com.tencent.connect.common.AssistActivity"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="behind"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<!--微博分享-->
android:name = "com.gh.gamecenter.NewsDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.sina.weibo.sdk.component.WeiboSdkBrowser"
android:configChanges="keyboardHidden|orientation"
android:windowSoftInputMode="adjustResize"
android:exported="false" >
</activity>
android:name = "com.gh.gamecenter.SettingActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.WeiBoShareActivity"
android:configChanges="keyboardHidden|orientation"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="com.sina.weibo.sdk.action.ACTION_SDK_REQ_ACTIVITY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
android:name = "com.gh.gamecenter.ConcernActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.SubjectActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.PluginActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.NewsSearchActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
<activity
android:name = "com.gh.gamecenter.GameNewsActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.CropImageActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.WebActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ShareCardPicActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ShareCardActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.MessageDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.LibaoActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
<activity
android:name = "com.gh.gamecenter.LibaoDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ShareGhWfifActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ShareGhActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.CleanApkActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.KcSelectGameActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ChooseReceiverActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ReceiverWaitingActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.FileSenderActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.FileReceiverActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.SelectUserIconActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.AboutActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.CommentDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.GameDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.SuggestSelectActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.SuggestionActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.VoteActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateAlwaysHidden|adjustResize" />
<activity
android:name = "com.gh.gamecenter.ToolBoxActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
<receiver android:name="com.gh.gamecenter.receiver.InstallAndUninstallReceiver" >
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<activity
android:name = "com.gh.gamecenter.WeiBoShareActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<activity
android:name = "com.gh.gamecenter.InstallActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.LoginActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
<activity
android:name = "com.gh.gamecenter.UserInfoActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.UserRegionActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.CollectionActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.MessageActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.UserInfoEditActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
<activity
android:name = "com.gh.gamecenter.KaiFuActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.NormalActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.SkipActivity"
android:theme = "@style/Theme.AppCompat.Light.Fullscreen.Transparent" >
<intent-filter >
<data android:scheme = "ghzhushou" />
<category android:name = "android.intent.category.DEFAULT" />
<action android:name = "android.intent.action.VIEW" />
<category android:name = "android.intent.category.BROWSABLE" />
</intent-filter >
</activity >
<activity
android:name = ".CommonActivity"
android:screenOrientation = "portrait" />
<receiver android:name = "com.gh.gamecenter.receiver.InstallAndUninstallReceiver" >
<intent-filter >
<action android:name = "android.intent.action.PACKAGE_ADDED" />
<action android:name = "android.intent.action.PACKAGE_REMOVED" />
<action android:name = "android.intent.action.PACKAGE_REPLACED" />
<data android:scheme = "package" />
</intent-filter >
</receiver >
<receiver
android:name="com.gh.gamecenter.receiver.NotificationReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.gh.gamecenter.NOTIFICATION" />
</intent-filter>
</receiver>
android:name = "com.gh.gamecenter.receiver.NotificationReceiver"
android:exported = "false" >
<intent-filter >
<action android:name = "com.gh.gamecenter.NOTIFICATION" />
</intent-filter >
</receiver >
<receiver
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.gh.gamecenter.DOWNLOAD" />
</intent-filter>
</receiver>
android:name = "com.gh.gamecenter.receiver.DownloadReceiver"
android:exported = "false" >
<intent-filter >
<action android:name = "com.gh.gamecenter.DOWNLOAD" />
</intent-filter >
</receiver >
<receiver
android:name="com.gh.gamecenter.receiver.InstallReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.gh.gamecenter.INSTALL" />
</intent-filter>
</receiver>
<receiver android:name="com.gh.gamecenter.receiver.NetworkStateReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
android:name = "com.gh.gamecenter.receiver.InstallReceiver"
android:exported = "false" >
<intent-filter >
<action android:name = "com.gh.gamecenter.INSTALL" />
</intent-filter >
</receiver >
<receiver android:name = "com.gh.gamecenter.receiver.NetworkStateReceiver" >
<intent-filter >
<action android:name = "android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter >
</receiver >
<receiver
android:name="com.xiaomi.push.service.receivers.PingReceiver"
android:exported="false"
android:process=":pushservice" >
<intent-filter>
<action android:name="com.xiaomi.push.PING_TIMER" />
</intent-filter>
</receiver>
<receiver
android:name="com.gh.base.GHPushMessageReceiver"
android:exported="true" >
<intent-filter>
<action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE" />
</intent-filter>
<intent-filter>
<action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED" />
</intent-filter>
<intent-filter>
<action android:name="com.xiaomi.mipush.ERROR" />
</intent-filter>
</receiver>
<receiver
android:name="com.xiaomi.push.service.receivers.NetworkStatusReceiver"
android:exported="true" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
android:name = "com.gh.gamecenter.receiver.ActivitySkipReceiver"
android:exported = "true" >
<intent-filter >
<action android:name = "com.gh.gamecenter.ACTIVITYSKIP" />
</intent-filter >
</receiver >
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver
android:name="com.gh.gamecenter.receiver.ActivitySkipReceiver"
android:exported="true" >
<intent-filter>
<action android:name="com.gh.gamecenter.ACTIVITYSKIP" />
</intent-filter>
</receiver>
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->
<service
android:name="com.gh.download.DownloadService" />
</application >
<!--<service-->
<!--android:name="com.gh.base.AppTinkerResultService"-->
<!--android:exported="false" />-->
<service
android:name="com.gh.gamecenter.statistics.AppStaticService" />
<service
android:name="com.xiaomi.push.service.XMJobService"
android:enabled="true"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":pushservice" />
<service
android:name="com.xiaomi.push.service.XMPushService"
android:enabled="true"
android:process=":pushservice" />
<service
android:name="com.xiaomi.mipush.sdk.PushMessageHandler"
android:enabled="true"
android:exported="true" />
<service
android:name="com.xiaomi.mipush.sdk.MessageHandleService"
android:enabled="true" />
</application>
</manifest>
</manifest >

View File

@ -1,13 +1,13 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<head>
<head>
<meta charset="utf-8">
<title>光环助手</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<style>
@ -46,22 +46,24 @@ article {
margin-bottom:20%;
}
}
</style>
</head>
</style>
</head>
<body>
<header>
</header>
<header>
</header>
<article>
<img src="http://192.168.43.1:3100/image/gh_icon.png" width="28%">
<p class="title">光环助手</p>
<br class="info">乐于分享的人是最帅的^_^ </p>
<div class="download">
<a href="http://192.168.43.1:3100/download/ghzs.apk">免流量下载</a>
<article>
<img src="http://192.168.43.1:3100/image/gh_icon.png" width="28%">
<p class="title">光环助手</p>
<br class="info">乐于分享的人是最帅的^_^ </p>
<div class="download">
<a href="http://192.168.43.1:3100/download/ghzs.apk">免流量下载</a>
</div>
<p class="title"><font color="#9A9A9A" size="3em">仅限安卓系统 </font></p>
</article>
<p class="title"><font color="#9A9A9A" size="3em">仅限安卓系统 </font></p>
</article>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,699 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import android.support.v4.util.Pools;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static android.support.v7.widget.RecyclerView.ViewHolder;
/**
* Helper class that can enqueue and process adapter update operations.
* <p>
* To support animations, RecyclerView presents an older version the Adapter to best represent
* previous state of the layout. Sometimes, this is not trivial when items are removed that were
* not laid out, in which case, RecyclerView has no way of providing that item's view for
* animations.
* <p>
* AdapterHelper creates an UpdateOp for each adapter data change then pre-processes them. During
* pre processing, AdapterHelper finds out which UpdateOps can be deferred to second layout pass
* and which cannot. For the UpdateOps that cannot be deferred, AdapterHelper will change them
* according to previously deferred operation and dispatch them before the first layout pass. It
* also takes care of updating deferred UpdateOps since order of operations is changed by this
* process.
* <p>
* Although operations may be forwarded to LayoutManager in different orders, resulting data set
* is guaranteed to be the consistent.
*/
class AdapterHelper implements OpReorderer.Callback {
final static int POSITION_TYPE_INVISIBLE = 0;
final static int POSITION_TYPE_NEW_OR_LAID_OUT = 1;
private static final boolean DEBUG = false;
private static final String TAG = "AHT";
private Pools.Pool<UpdateOp> mUpdateOpPool = new Pools.SimplePool<UpdateOp>(UpdateOp.POOL_SIZE);
final ArrayList<UpdateOp> mPendingUpdates = new ArrayList<UpdateOp>();
final ArrayList<UpdateOp> mPostponedList = new ArrayList<UpdateOp>();
final Callback mCallback;
Runnable mOnItemProcessedCallback;
final boolean mDisableRecycler;
final OpReorderer mOpReorderer;
AdapterHelper(Callback callback) {
this(callback, false);
}
AdapterHelper(Callback callback, boolean disableRecycler) {
mCallback = callback;
mDisableRecycler = disableRecycler;
mOpReorderer = new OpReorderer(this);
}
AdapterHelper addUpdateOp(UpdateOp... ops) {
Collections.addAll(mPendingUpdates, ops);
return this;
}
void reset() {
recycleUpdateOpsAndClearList(mPendingUpdates);
recycleUpdateOpsAndClearList(mPostponedList);
}
void preProcess() {
mOpReorderer.reorderOps(mPendingUpdates);
final int count = mPendingUpdates.size();
for (int i = 0; i < count; i++) {
UpdateOp op = mPendingUpdates.get(i);
switch (op.cmd) {
case UpdateOp.ADD:
applyAdd(op);
break;
case UpdateOp.REMOVE:
applyRemove(op);
break;
case UpdateOp.UPDATE:
applyUpdate(op);
break;
case UpdateOp.MOVE:
applyMove(op);
break;
}
if (mOnItemProcessedCallback != null) {
mOnItemProcessedCallback.run();
}
}
mPendingUpdates.clear();
}
void consumePostponedUpdates() {
final int count = mPostponedList.size();
for (int i = 0; i < count; i++) {
mCallback.onDispatchSecondPass(mPostponedList.get(i));
}
recycleUpdateOpsAndClearList(mPostponedList);
}
private void applyMove(UpdateOp op) {
// MOVE ops are pre-processed so at this point, we know that item is still in the adapter.
// otherwise, it would be converted into a REMOVE operation
postponeAndUpdateViewHolders(op);
}
private void applyRemove(UpdateOp op) {
int tmpStart = op.positionStart;
int tmpCount = 0;
int tmpEnd = op.positionStart + op.itemCount;
int type = -1;
for (int position = op.positionStart; position < tmpEnd; position++) {
boolean typeChanged = false;
ViewHolder vh = mCallback.findViewHolder(position);
if (vh != null || canFindInPreLayout(position)) {
// If a ViewHolder exists or this is a newly added item, we can defer this update
// to post layout stage.
// * For existing ViewHolders, we'll fake its existence in the pre-layout phase.
// * For items that are added and removed in the same process cycle, they won't
// have any effect in pre-layout since their add ops are already deferred to
// post-layout pass.
if (type == POSITION_TYPE_INVISIBLE) {
// Looks like we have other updates that we cannot merge with this one.
// Create an UpdateOp and dispatch it to LayoutManager.
UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount);
dispatchAndUpdateViewHolders(newOp);
typeChanged = true;
}
type = POSITION_TYPE_NEW_OR_LAID_OUT;
} else {
// This update cannot be recovered because we don't have a ViewHolder representing
// this position. Instead, post it to LayoutManager immediately
if (type == POSITION_TYPE_NEW_OR_LAID_OUT) {
// Looks like we have other updates that we cannot merge with this one.
// Create UpdateOp op and dispatch it to LayoutManager.
UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount);
postponeAndUpdateViewHolders(newOp);
typeChanged = true;
}
type = POSITION_TYPE_INVISIBLE;
}
if (typeChanged) {
position -= tmpCount; // also equal to tmpStart
tmpEnd -= tmpCount;
tmpCount = 1;
} else {
tmpCount++;
}
}
if (tmpCount != op.itemCount) { // all 1 effect
recycleUpdateOp(op);
op = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount);
}
if (type == POSITION_TYPE_INVISIBLE) {
dispatchAndUpdateViewHolders(op);
} else {
postponeAndUpdateViewHolders(op);
}
}
private void applyUpdate(UpdateOp op) {
int tmpStart = op.positionStart;
int tmpCount = 0;
int tmpEnd = op.positionStart + op.itemCount;
int type = -1;
for (int position = op.positionStart; position < tmpEnd; position++) {
ViewHolder vh = mCallback.findViewHolder(position);
if (vh != null || canFindInPreLayout(position)) { // deferred
if (type == POSITION_TYPE_INVISIBLE) {
UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount);
dispatchAndUpdateViewHolders(newOp);
tmpCount = 0;
tmpStart = position;
}
type = POSITION_TYPE_NEW_OR_LAID_OUT;
} else { // applied
if (type == POSITION_TYPE_NEW_OR_LAID_OUT) {
UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount);
postponeAndUpdateViewHolders(newOp);
tmpCount = 0;
tmpStart = position;
}
type = POSITION_TYPE_INVISIBLE;
}
tmpCount++;
}
if (tmpCount != op.itemCount) { // all 1 effect
recycleUpdateOp(op);
op = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount);
}
if (type == POSITION_TYPE_INVISIBLE) {
dispatchAndUpdateViewHolders(op);
} else {
postponeAndUpdateViewHolders(op);
}
}
private void dispatchAndUpdateViewHolders(UpdateOp op) {
// tricky part.
// traverse all postpones and revert their changes on this op if necessary, apply updated
// dispatch to them since now they are after this op.
if (op.cmd == UpdateOp.ADD || op.cmd == UpdateOp.MOVE) {
throw new IllegalArgumentException("should not dispatch add or move for pre layout");
}
if (DEBUG) {
Log.d(TAG, "dispatch (pre)" + op);
Log.d(TAG, "postponed state before:");
for (UpdateOp updateOp : mPostponedList) {
Log.d(TAG, updateOp.toString());
}
Log.d(TAG, "----");
}
// handle each pos 1 by 1 to ensure continuity. If it breaks, dispatch partial
// TODO Since move ops are pushed to end, we should not need this anymore
int tmpStart = updatePositionWithPostponed(op.positionStart, op.cmd);
if (DEBUG) {
Log.d(TAG, "pos:" + op.positionStart + ",updatedPos:" + tmpStart);
}
int tmpCnt = 1;
int offsetPositionForPartial = op.positionStart;
final int positionMultiplier;
switch (op.cmd) {
case UpdateOp.UPDATE:
positionMultiplier = 1;
break;
case UpdateOp.REMOVE:
positionMultiplier = 0;
break;
default:
throw new IllegalArgumentException("op should be remove or update." + op);
}
for (int p = 1; p < op.itemCount; p++) {
final int pos = op.positionStart + (positionMultiplier * p);
int updatedPos = updatePositionWithPostponed(pos, op.cmd);
if (DEBUG) {
Log.d(TAG, "pos:" + pos + ",updatedPos:" + updatedPos);
}
boolean continuous = false;
switch (op.cmd) {
case UpdateOp.UPDATE:
continuous = updatedPos == tmpStart + 1;
break;
case UpdateOp.REMOVE:
continuous = updatedPos == tmpStart;
break;
}
if (continuous) {
tmpCnt++;
} else {
// need to dispatch this separately
UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt);
if (DEBUG) {
Log.d(TAG, "need to dispatch separately " + tmp);
}
dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial);
recycleUpdateOp(tmp);
if (op.cmd == UpdateOp.UPDATE) {
offsetPositionForPartial += tmpCnt;
}
tmpStart = updatedPos;// need to remove previously dispatched
tmpCnt = 1;
}
}
recycleUpdateOp(op);
if (tmpCnt > 0) {
UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt);
if (DEBUG) {
Log.d(TAG, "dispatching:" + tmp);
}
dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial);
recycleUpdateOp(tmp);
}
if (DEBUG) {
Log.d(TAG, "post dispatch");
Log.d(TAG, "postponed state after:");
for (UpdateOp updateOp : mPostponedList) {
Log.d(TAG, updateOp.toString());
}
Log.d(TAG, "----");
}
}
void dispatchFirstPassAndUpdateViewHolders(UpdateOp op, int offsetStart) {
mCallback.onDispatchFirstPass(op);
switch (op.cmd) {
case UpdateOp.REMOVE:
mCallback.offsetPositionsForRemovingInvisible(offsetStart, op.itemCount);
break;
case UpdateOp.UPDATE:
mCallback.markViewHoldersUpdated(offsetStart, op.itemCount);
break;
default:
throw new IllegalArgumentException("only remove and update ops can be dispatched"
+ " in first pass");
}
}
private int updatePositionWithPostponed(int pos, int cmd) {
final int count = mPostponedList.size();
for (int i = count - 1; i >= 0; i--) {
UpdateOp postponed = mPostponedList.get(i);
if (postponed.cmd == UpdateOp.MOVE) {
int start, end;
if (postponed.positionStart < postponed.itemCount) {
start = postponed.positionStart;
end = postponed.itemCount;
} else {
start = postponed.itemCount;
end = postponed.positionStart;
}
if (pos >= start && pos <= end) {
//i'm affected
if (start == postponed.positionStart) {
if (cmd == UpdateOp.ADD) {
postponed.itemCount++;
} else if (cmd == UpdateOp.REMOVE) {
postponed.itemCount--;
}
// op moved to left, move it right to revert
pos++;
} else {
if (cmd == UpdateOp.ADD) {
postponed.positionStart++;
} else if (cmd == UpdateOp.REMOVE) {
postponed.positionStart--;
}
// op was moved right, move left to revert
pos--;
}
} else if (pos < postponed.positionStart) {
// postponed MV is outside the dispatched OP. if it is before, offset
if (cmd == UpdateOp.ADD) {
postponed.positionStart++;
postponed.itemCount++;
} else if (cmd == UpdateOp.REMOVE) {
postponed.positionStart--;
postponed.itemCount--;
}
}
} else {
if (postponed.positionStart <= pos) {
if (postponed.cmd == UpdateOp.ADD) {
pos -= postponed.itemCount;
} else if (postponed.cmd == UpdateOp.REMOVE) {
pos += postponed.itemCount;
}
} else {
if (cmd == UpdateOp.ADD) {
postponed.positionStart++;
} else if (cmd == UpdateOp.REMOVE) {
postponed.positionStart--;
}
}
}
if (DEBUG) {
Log.d(TAG, "dispath (step" + i + ")");
Log.d(TAG, "postponed state:" + i + ", pos:" + pos);
for (UpdateOp updateOp : mPostponedList) {
Log.d(TAG, updateOp.toString());
}
Log.d(TAG, "----");
}
}
for (int i = mPostponedList.size() - 1; i >= 0; i--) {
UpdateOp op = mPostponedList.get(i);
if (op.cmd == UpdateOp.MOVE) {
if (op.itemCount == op.positionStart || op.itemCount < 0) {
mPostponedList.remove(i);
recycleUpdateOp(op);
}
} else if (op.itemCount <= 0) {
mPostponedList.remove(i);
recycleUpdateOp(op);
}
}
return pos;
}
private boolean canFindInPreLayout(int position) {
final int count = mPostponedList.size();
for (int i = 0; i < count; i++) {
UpdateOp op = mPostponedList.get(i);
if (op.cmd == UpdateOp.MOVE) {
if (findPositionOffset(op.itemCount, i + 1) == position) {
return true;
}
} else if (op.cmd == UpdateOp.ADD) {
// TODO optimize.
final int end = op.positionStart + op.itemCount;
for (int pos = op.positionStart; pos < end; pos++) {
if (findPositionOffset(pos, i + 1) == position) {
return true;
}
}
}
}
return false;
}
private void applyAdd(UpdateOp op) {
postponeAndUpdateViewHolders(op);
}
private void postponeAndUpdateViewHolders(UpdateOp op) {
if (DEBUG) {
Log.d(TAG, "postponing " + op);
}
// Utils.log("add UpdateOp to PostponedList");
mPostponedList.add(op);
// Utils.log("op" + op.positionStart + "=" + op.itemCount);
switch (op.cmd) {
case UpdateOp.ADD:
mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount);
break;
case UpdateOp.MOVE:
mCallback.offsetPositionsForMove(op.positionStart, op.itemCount);
break;
case UpdateOp.REMOVE:
mCallback.offsetPositionsForRemovingLaidOutOrNewView(op.positionStart,
op.itemCount);
break;
case UpdateOp.UPDATE:
mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount);
break;
default:
throw new IllegalArgumentException("Unknown update op type for " + op);
}
}
boolean hasPendingUpdates() {
return mPendingUpdates.size() > 0;
}
int findPositionOffset(int position) {
return findPositionOffset(position, 0);
}
int findPositionOffset(int position, int firstPostponedItem) {
int count = mPostponedList.size();
for (int i = firstPostponedItem; i < count; ++i) {
UpdateOp op = mPostponedList.get(i);
if (op.cmd == UpdateOp.MOVE) {
if (op.positionStart == position) {
position = op.itemCount;
} else {
if (op.positionStart < position) {
position--; // like a remove
}
if (op.itemCount <= position) {
position++; // like an add
}
}
} else if (op.positionStart <= position) {
if (op.cmd == UpdateOp.REMOVE) {
if (position < op.positionStart + op.itemCount) {
return -1;
}
position -= op.itemCount;
} else if (op.cmd == UpdateOp.ADD) {
position += op.itemCount;
}
}
}
return position;
}
/**
* @return True if updates should be processed.
*/
boolean onItemRangeChanged(int positionStart, int itemCount) {
mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount));
return mPendingUpdates.size() == 1;
}
/**
* @return True if updates should be processed.
*/
boolean onItemRangeInserted(int positionStart, int itemCount) {
mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount));
return mPendingUpdates.size() == 1;
}
/**
* @return True if updates should be processed.
*/
boolean onItemRangeRemoved(int positionStart, int itemCount) {
mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount));
return mPendingUpdates.size() == 1;
}
/**
* @return True if updates should be processed.
*/
boolean onItemRangeMoved(int from, int to, int itemCount) {
if (from == to) {
return false;//no-op
}
if (itemCount != 1) {
throw new IllegalArgumentException("Moving more than 1 item is not supported yet");
}
mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to));
return mPendingUpdates.size() == 1;
}
/**
* Skips pre-processing and applies all updates in one pass.
*/
void consumeUpdatesInOnePass() {
// we still consume postponed updates (if there is) in case there was a pre-process call
// w/o a matching consumePostponedUpdates.
consumePostponedUpdates();
final int count = mPendingUpdates.size();
for (int i = 0; i < count; i++) {
UpdateOp op = mPendingUpdates.get(i);
switch (op.cmd) {
case UpdateOp.ADD:
mCallback.onDispatchSecondPass(op);
mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount);
break;
case UpdateOp.REMOVE:
mCallback.onDispatchSecondPass(op);
mCallback.offsetPositionsForRemovingInvisible(op.positionStart, op.itemCount);
break;
case UpdateOp.UPDATE:
mCallback.onDispatchSecondPass(op);
mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount);
break;
case UpdateOp.MOVE:
mCallback.onDispatchSecondPass(op);
mCallback.offsetPositionsForMove(op.positionStart, op.itemCount);
break;
}
if (mOnItemProcessedCallback != null) {
mOnItemProcessedCallback.run();
}
}
recycleUpdateOpsAndClearList(mPendingUpdates);
}
/**
* Queued operation to happen when child views are updated.
*/
static class UpdateOp {
static final int ADD = 0;
static final int REMOVE = 1;
static final int UPDATE = 2;
static final int MOVE = 3;
static final int POOL_SIZE = 30;
int cmd;
int positionStart;
// holds the target position if this is a MOVE
int itemCount;
UpdateOp(int cmd, int positionStart, int itemCount) {
this.cmd = cmd;
this.positionStart = positionStart;
this.itemCount = itemCount;
}
String cmdToString() {
switch (cmd) {
case ADD:
return "add";
case REMOVE:
return "rm";
case UPDATE:
return "up";
case MOVE:
return "mv";
}
return "??";
}
@Override
public String toString() {
return "[" + cmdToString() + ",s:" + positionStart + "c:" + itemCount + "]";
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
UpdateOp op = (UpdateOp) o;
if (cmd != op.cmd) {
return false;
}
if (cmd == MOVE && Math.abs(itemCount - positionStart) == 1) {
// reverse of this is also true
if (itemCount == op.positionStart && positionStart == op.itemCount) {
return true;
}
}
if (itemCount != op.itemCount) {
return false;
}
if (positionStart != op.positionStart) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = cmd;
result = 31 * result + positionStart;
result = 31 * result + itemCount;
return result;
}
}
@Override
public UpdateOp obtainUpdateOp(int cmd, int positionStart, int itemCount) {
UpdateOp op = mUpdateOpPool.acquire();
if (op == null) {
op = new UpdateOp(cmd, positionStart, itemCount);
} else {
op.cmd = cmd;
op.positionStart = positionStart;
op.itemCount = itemCount;
}
return op;
}
@Override
public void recycleUpdateOp(UpdateOp op) {
if (!mDisableRecycler) {
mUpdateOpPool.release(op);
}
}
void recycleUpdateOpsAndClearList(List<UpdateOp> ops) {
final int count = ops.size();
for (int i = 0; i < count; i++) {
recycleUpdateOp(ops.get(i));
}
ops.clear();
}
/**
* Contract between AdapterHelper and RecyclerView.
*/
static interface Callback {
ViewHolder findViewHolder(int position);
void offsetPositionsForRemovingInvisible(int positionStart, int itemCount);
void offsetPositionsForRemovingLaidOutOrNewView(int positionStart, int itemCount);
void markViewHoldersUpdated(int positionStart, int itemCount);
void onDispatchFirstPass(UpdateOp updateOp);
void onDispatchSecondPass(UpdateOp updateOp);
void offsetPositionsForAdd(int positionStart, int itemCount);
void offsetPositionsForMove(int from, int to);
}
}

View File

@ -1,484 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* Helper class to manage children.
* <p>
* It wraps a RecyclerView and adds ability to hide some children. There are two sets of methods
* provided by this class. <b>Regular</b> methods are the ones that replicate ViewGroup methods
* like getChildAt, getChildCount etc. These methods ignore hidden children.
* <p>
* When RecyclerView needs direct access to the view group children, it can call unfiltered
* methods like get getUnfilteredChildCount or getUnfilteredChildAt.
*/
class ChildHelper {
private static final boolean DEBUG = false;
private static final String TAG = "ChildrenHelper";
final Callback mCallback;
final Bucket mBucket;
final List<View> mHiddenViews;
ChildHelper(Callback callback) {
mCallback = callback;
mBucket = new Bucket();
mHiddenViews = new ArrayList<View>();
}
/**
* Adds a view to the ViewGroup
*
* @param child View to add.
* @param hidden If set to true, this item will be invisible from regular methods.
*/
void addView(View child, boolean hidden) {
addView(child, -1, hidden);
}
/**
* Add a view to the ViewGroup at an index
*
* @param child View to add.
* @param index Index of the child from the regular perspective (excluding hidden views).
* ChildHelper offsets this index to actual ViewGroup index.
* @param hidden If set to true, this item will be invisible from regular methods.
*/
void addView(View child, int index, boolean hidden) {
final int offset;
if (index < 0) {
offset = mCallback.getChildCount();
} else {
offset = getOffset(index);
}
mCallback.addView(child, offset);
mBucket.insert(offset, hidden);
if (hidden) {
mHiddenViews.add(child);
}
if (DEBUG) {
Log.d(TAG, "addViewAt " + index + ",h:" + hidden + ", " + this);
}
}
private int getOffset(int index) {
if (index < 0) {
return -1; //anything below 0 won't work as diff will be undefined.
}
final int limit = mCallback.getChildCount();
int offset = index;
while (offset < limit) {
final int removedBefore = mBucket.countOnesBefore(offset);
final int diff = index - (offset - removedBefore);
if (diff == 0) {
while (mBucket.get(offset)) { // ensure this offset is not hidden
offset ++;
}
return offset;
} else {
offset += diff;
}
}
return -1;
}
/**
* Removes the provided View from underlying RecyclerView.
*
* @param view The view to remove.
*/
void removeView(View view) {
int index = mCallback.indexOfChild(view);
if (index < 0) {
return;
}
mCallback.removeViewAt(index);
if (mBucket.remove(index)) {
mHiddenViews.remove(view);
}
if (DEBUG) {
Log.d(TAG, "remove View off:" + index + "," + this);
}
}
/**
* Removes the view at the provided index from RecyclerView.
*
* @param index Index of the child from the regular perspective (excluding hidden views).
* ChildHelper offsets this index to actual ViewGroup index.
*/
void removeViewAt(int index) {
final int offset = getOffset(index);
final View view = mCallback.getChildAt(offset);
if (view == null) {
return;
}
mCallback.removeViewAt(offset);
if (mBucket.remove(offset)) {
mHiddenViews.remove(view);
}
if (DEBUG) {
Log.d(TAG, "removeViewAt " + index + ", off:" + offset + ", " + this);
}
}
/**
* Returns the child at provided index.
*
* @param index Index of the child to return in regular perspective.
*/
View getChildAt(int index) {
final int offset = getOffset(index);
return mCallback.getChildAt(offset);
}
/**
* Removes all views from the ViewGroup including the hidden ones.
*/
void removeAllViewsUnfiltered() {
mCallback.removeAllViews();
mBucket.reset();
mHiddenViews.clear();
if (DEBUG) {
Log.d(TAG, "removeAllViewsUnfiltered");
}
}
/**
* This can be used to find a disappearing view by position.
*
* @param position The adapter position of the item.
* @param type View type, can be {@link RecyclerView#INVALID_TYPE}.
* @return A hidden view with a valid ViewHolder that matches the position and type.
*/
View findHiddenNonRemovedView(int position, int type) {
final int count = mHiddenViews.size();
for (int i = 0; i < count; i++) {
final View view = mHiddenViews.get(i);
RecyclerView.ViewHolder holder = mCallback.getChildViewHolder(view);
if (holder.getPosition() == position && !holder.isInvalid() &&
(type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
return view;
}
}
return null;
}
/**
* Attaches the provided view to the underlying ViewGroup.
*
* @param child Child to attach.
* @param index Index of the child to attach in regular perspective.
* @param layoutParams LayoutParams for the child.
* @param hidden If set to true, this item will be invisible to the regular methods.
*/
void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams,
boolean hidden) {
final int offset;
if (index < 0) {
offset = mCallback.getChildCount();
} else {
offset = getOffset(index);
}
mCallback.attachViewToParent(child, offset, layoutParams);
mBucket.insert(offset, hidden);
if (DEBUG) {
Log.d(TAG, "attach view to parent index:" + index + ",off:" + offset + "," +
"h:" + hidden + ", " + this);
}
}
/**
* Returns the number of children that are not hidden.
*
* @return Number of children that are not hidden.
* @see #getChildAt(int)
*/
int getChildCount() {
return mCallback.getChildCount() - mHiddenViews.size();
}
/**
* Returns the total number of children.
*
* @return The total number of children including the hidden views.
* @see #getUnfilteredChildAt(int)
*/
int getUnfilteredChildCount() {
return mCallback.getChildCount();
}
/**
* Returns a child by ViewGroup offset. ChildHelper won't offset this index.
*
* @param index ViewGroup index of the child to return.
* @return The view in the provided index.
*/
View getUnfilteredChildAt(int index) {
return mCallback.getChildAt(index);
}
/**
* Detaches the view at the provided index.
*
* @param index Index of the child to return in regular perspective.
*/
void detachViewFromParent(int index) {
final int offset = getOffset(index);
mCallback.detachViewFromParent(offset);
mBucket.remove(offset);
if (DEBUG) {
Log.d(TAG, "detach view from parent " + index + ", off:" + offset);
}
}
/**
* Returns the index of the child in regular perspective.
*
* @param child The child whose index will be returned.
* @return The regular perspective index of the child or -1 if it does not exists.
*/
int indexOfChild(View child) {
final int index = mCallback.indexOfChild(child);
if (index == -1) {
return -1;
}
if (mBucket.get(index)) {
if (DEBUG) {
throw new IllegalArgumentException("cannot get index of a hidden child");
} else {
return -1;
}
}
// reverse the index
return index - mBucket.countOnesBefore(index);
}
/**
* Returns whether a View is visible to LayoutManager or not.
*
* @param view The child view to check. Should be a child of the Callback.
* @return True if the View is not visible to LayoutManager
*/
boolean isHidden(View view) {
return mHiddenViews.contains(view);
}
/**
* Marks a child view as hidden.
*
* @param view The view to hide.
*/
void hide(View view) {
final int offset = mCallback.indexOfChild(view);
if (offset < 0) {
throw new IllegalArgumentException("view is not a child, cannot hide " + view);
}
if (DEBUG && mBucket.get(offset)) {
throw new RuntimeException("trying to hide same view twice, how come ? " + view);
}
mBucket.set(offset);
mHiddenViews.add(view);
if (DEBUG) {
Log.d(TAG, "hiding child " + view + " at offset " + offset+ ", " + this);
}
}
@Override
public String toString() {
return mBucket.toString();
}
/**
* Removes a view from the ViewGroup if it is hidden.
*
* @param view The view to remove.
* @return True if the View is found and it is hidden. False otherwise.
*/
boolean removeViewIfHidden(View view) {
final int index = mCallback.indexOfChild(view);
if (index == -1) {
if (mHiddenViews.remove(view) && DEBUG) {
throw new IllegalStateException("view is in hidden list but not in view group");
}
return true;
}
if (mBucket.get(index)) {
mBucket.remove(index);
mCallback.removeViewAt(index);
if (!mHiddenViews.remove(view) && DEBUG) {
throw new IllegalStateException(
"removed a hidden view but it is not in hidden views list");
}
return true;
}
return false;
}
/**
* Bitset implementation that provides methods to offset indices.
*/
static class Bucket {
final static int BITS_PER_WORD = Long.SIZE;
final static long LAST_BIT = 1L << (Long.SIZE - 1);
long mData = 0;
Bucket next;
void set(int index) {
if (index >= BITS_PER_WORD) {
ensureNext();
next.set(index - BITS_PER_WORD);
} else {
mData |= 1L << index;
}
}
private void ensureNext() {
if (next == null) {
next = new Bucket();
}
}
void clear(int index) {
if (index >= BITS_PER_WORD) {
if (next != null) {
next.clear(index - BITS_PER_WORD);
}
} else {
mData &= ~(1L << index);
}
}
boolean get(int index) {
if (index >= BITS_PER_WORD) {
ensureNext();
return next.get(index - BITS_PER_WORD);
} else {
return (mData & (1L << index)) != 0;
}
}
void reset() {
mData = 0;
if (next != null) {
next.reset();
}
}
void insert(int index, boolean value) {
if (index >= BITS_PER_WORD) {
ensureNext();
next.insert(index - BITS_PER_WORD, value);
} else {
final boolean lastBit = (mData & LAST_BIT) != 0;
long mask = (1L << index) - 1;
final long before = mData & mask;
final long after = ((mData & ~mask)) << 1;
mData = before | after;
if (value) {
set(index);
} else {
clear(index);
}
if (lastBit || next != null) {
ensureNext();
next.insert(0, lastBit);
}
}
}
boolean remove(int index) {
if (index >= BITS_PER_WORD) {
ensureNext();
return next.remove(index - BITS_PER_WORD);
} else {
long mask = (1L << index);
final boolean value = (mData & mask) != 0;
mData &= ~mask;
mask = mask - 1;
final long before = mData & mask;
// cannot use >> because it adds one.
final long after = Long.rotateRight(mData & ~mask, 1);
mData = before | after;
if (next != null) {
if (next.get(0)) {
set(BITS_PER_WORD - 1);
}
next.remove(0);
}
return value;
}
}
int countOnesBefore(int index) {
if (next == null) {
if (index >= BITS_PER_WORD) {
return Long.bitCount(mData);
}
return Long.bitCount(mData & ((1L << index) - 1));
}
if (index < BITS_PER_WORD) {
return Long.bitCount(mData & ((1L << index) - 1));
} else {
return next.countOnesBefore(index - BITS_PER_WORD) + Long.bitCount(mData);
}
}
@Override
public String toString() {
return next == null ? Long.toBinaryString(mData)
: next.toString() + "xx" + Long.toBinaryString(mData);
}
}
static interface Callback {
int getChildCount();
void addView(View child, int index);
int indexOfChild(View view);
void removeViewAt(int index);
View getChildAt(int offset);
void removeAllViews();
RecyclerView.ViewHolder getChildViewHolder(View view);
void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams);
void detachViewFromParent(int offset);
}
}

View File

@ -1,628 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
* This implementation of {@link RecyclerView.ItemAnimator} provides basic
* animations on remove, add, and move events that happen to the items in
* a RecyclerView. RecyclerView uses a DefaultItemAnimator by default.
*
* @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
*/
public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
private static final boolean DEBUG = false;
private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<ViewHolder>();
private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<ViewHolder>();
private ArrayList<MoveInfo> mPendingMoves = new ArrayList<MoveInfo>();
private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<ChangeInfo>();
private ArrayList<ArrayList<ViewHolder>> mAdditionsList =
new ArrayList<ArrayList<ViewHolder>>();
private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<ArrayList<MoveInfo>>();
private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<ArrayList<ChangeInfo>>();
private ArrayList<ViewHolder> mAddAnimations = new ArrayList<ViewHolder>();
private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<ViewHolder>();
private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<ViewHolder>();
private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<ViewHolder>();
private static class MoveInfo {
public ViewHolder holder;
public int fromX, fromY, toX, toY;
private MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
this.holder = holder;
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
}
private static class ChangeInfo {
public ViewHolder oldHolder, newHolder;
public int fromX, fromY, toX, toY;
private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) {
this.oldHolder = oldHolder;
this.newHolder = newHolder;
}
private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder,
int fromX, int fromY, int toX, int toY) {
this(oldHolder, newHolder);
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
@Override
public String toString() {
return "ChangeInfo{" +
"oldHolder=" + oldHolder +
", newHolder=" + newHolder +
", fromX=" + fromX +
", fromY=" + fromY +
", toX=" + toX +
", toY=" + toY +
'}';
}
}
@Override
public void runPendingAnimations() {
boolean removalsPending = !mPendingRemovals.isEmpty();
boolean movesPending = !mPendingMoves.isEmpty();
boolean changesPending = !mPendingChanges.isEmpty();
boolean additionsPending = !mPendingAdditions.isEmpty();
if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
// nothing to animate
return;
}
// First, remove stuff
for (ViewHolder holder : mPendingRemovals) {
animateRemoveImpl(holder);
}
mPendingRemovals.clear();
// Next, move stuff
if (movesPending) {
final ArrayList<MoveInfo> moves = new ArrayList<MoveInfo>();
moves.addAll(mPendingMoves);
mMovesList.add(moves);
mPendingMoves.clear();
Runnable mover = new Runnable() {
@Override
public void run() {
for (MoveInfo moveInfo : moves) {
animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
moveInfo.toX, moveInfo.toY);
}
moves.clear();
mMovesList.remove(moves);
}
};
if (removalsPending) {
View view = moves.get(0).holder.itemView;
ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration());
} else {
mover.run();
}
}
// Next, change stuff, to run in parallel with move animations
if (changesPending) {
final ArrayList<ChangeInfo> changes = new ArrayList<ChangeInfo>();
changes.addAll(mPendingChanges);
mChangesList.add(changes);
mPendingChanges.clear();
Runnable changer = new Runnable() {
@Override
public void run() {
for (ChangeInfo change : changes) {
animateChangeImpl(change);
}
changes.clear();
mChangesList.remove(changes);
}
};
if (removalsPending) {
ViewHolder holder = changes.get(0).oldHolder;
ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration());
} else {
changer.run();
}
}
// Next, add stuff
if (additionsPending) {
final ArrayList<ViewHolder> additions = new ArrayList<ViewHolder>();
additions.addAll(mPendingAdditions);
mAdditionsList.add(additions);
mPendingAdditions.clear();
Runnable adder = new Runnable() {
public void run() {
for (ViewHolder holder : additions) {
animateAddImpl(holder);
}
additions.clear();
mAdditionsList.remove(additions);
}
};
if (removalsPending || movesPending || changesPending) {
long removeDuration = removalsPending ? getRemoveDuration() : 0;
long moveDuration = movesPending ? getMoveDuration() : 0;
long changeDuration = changesPending ? getChangeDuration() : 0;
long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
View view = additions.get(0).itemView;
ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
} else {
adder.run();
}
}
}
@Override
public boolean animateRemove(final ViewHolder holder) {
endAnimation(holder);
mPendingRemovals.add(holder);
return true;
}
private void animateRemoveImpl(final ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
animation.setDuration(getRemoveDuration())
.alpha(0).setListener(new VpaListenerAdapter() {
@Override
public void onAnimationStart(View view) {
dispatchRemoveStarting(holder);
}
@Override
public void onAnimationEnd(View view) {
animation.setListener(null);
ViewCompat.setAlpha(view, 1);
dispatchRemoveFinished(holder);
mRemoveAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
mRemoveAnimations.add(holder);
}
@Override
public boolean animateAdd(final ViewHolder holder) {
endAnimation(holder);
ViewCompat.setAlpha(holder.itemView, 0);
mPendingAdditions.add(holder);
return true;
}
private void animateAddImpl(final ViewHolder holder) {
final View view = holder.itemView;
mAddAnimations.add(holder);
final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
animation.alpha(1).setDuration(getAddDuration()).
setListener(new VpaListenerAdapter() {
@Override
public void onAnimationStart(View view) {
dispatchAddStarting(holder);
}
@Override
public void onAnimationCancel(View view) {
ViewCompat.setAlpha(view, 1);
}
@Override
public void onAnimationEnd(View view) {
animation.setListener(null);
dispatchAddFinished(holder);
mAddAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
public boolean animateMove(final ViewHolder holder, int fromX, int fromY,
int toX, int toY) {
final View view = holder.itemView;
fromX += ViewCompat.getTranslationX(holder.itemView);
fromY += ViewCompat.getTranslationY(holder.itemView);
endAnimation(holder);
int deltaX = toX - fromX;
int deltaY = toY - fromY;
if (deltaX == 0 && deltaY == 0) {
dispatchMoveFinished(holder);
return false;
}
if (deltaX != 0) {
ViewCompat.setTranslationX(view, -deltaX);
}
if (deltaY != 0) {
ViewCompat.setTranslationY(view, -deltaY);
}
mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
return true;
}
private void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) {
final View view = holder.itemView;
final int deltaX = toX - fromX;
final int deltaY = toY - fromY;
if (deltaX != 0) {
ViewCompat.animate(view).translationX(0);
}
if (deltaY != 0) {
ViewCompat.animate(view).translationY(0);
}
// TODO: make EndActions end listeners instead, since end actions aren't called when
// vpas are canceled (and can't end them. why?)
// need listener functionality in VPACompat for this. Ick.
mMoveAnimations.add(holder);
final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() {
@Override
public void onAnimationStart(View view) {
dispatchMoveStarting(holder);
}
@Override
public void onAnimationCancel(View view) {
if (deltaX != 0) {
ViewCompat.setTranslationX(view, 0);
}
if (deltaY != 0) {
ViewCompat.setTranslationY(view, 0);
}
}
@Override
public void onAnimationEnd(View view) {
animation.setListener(null);
dispatchMoveFinished(holder);
mMoveAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
int fromX, int fromY, int toX, int toY) {
final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
endAnimation(oldHolder);
int deltaX = (int) (toX - fromX - prevTranslationX);
int deltaY = (int) (toY - fromY - prevTranslationY);
// recover prev translation state after ending animation
ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
if (newHolder != null && newHolder.itemView != null) {
// carry over translation values
endAnimation(newHolder);
ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
ViewCompat.setTranslationY(newHolder.itemView, -deltaY);
ViewCompat.setAlpha(newHolder.itemView, 0);
}
mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
return true;
}
private void animateChangeImpl(final ChangeInfo changeInfo) {
final ViewHolder holder = changeInfo.oldHolder;
final View view = holder.itemView;
final ViewHolder newHolder = changeInfo.newHolder;
final View newView = newHolder != null ? newHolder.itemView : null;
mChangeAnimations.add(changeInfo.oldHolder);
final ViewPropertyAnimatorCompat oldViewAnim = ViewCompat.animate(view).setDuration(
getChangeDuration());
oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);
oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);
oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() {
@Override
public void onAnimationStart(View view) {
dispatchChangeStarting(changeInfo.oldHolder, true);
}
@Override
public void onAnimationEnd(View view) {
oldViewAnim.setListener(null);
ViewCompat.setAlpha(view, 1);
ViewCompat.setTranslationX(view, 0);
ViewCompat.setTranslationY(view, 0);
dispatchChangeFinished(changeInfo.oldHolder, true);
mChangeAnimations.remove(changeInfo.oldHolder);
dispatchFinishedWhenDone();
}
}).start();
if (newView != null) {
mChangeAnimations.add(changeInfo.newHolder);
final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView);
newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).
alpha(1).setListener(new VpaListenerAdapter() {
@Override
public void onAnimationStart(View view) {
dispatchChangeStarting(changeInfo.newHolder, false);
}
@Override
public void onAnimationEnd(View view) {
newViewAnimation.setListener(null);
ViewCompat.setAlpha(newView, 1);
ViewCompat.setTranslationX(newView, 0);
ViewCompat.setTranslationY(newView, 0);
dispatchChangeFinished(changeInfo.newHolder, false);
mChangeAnimations.remove(changeInfo.newHolder);
dispatchFinishedWhenDone();
}
}).start();
}
}
private void endChangeAnimation(List<ChangeInfo> infoList, ViewHolder item) {
for (int i = infoList.size() - 1; i >= 0; i--) {
ChangeInfo changeInfo = infoList.get(i);
if (endChangeAnimationIfNecessary(changeInfo, item)) {
if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
infoList.remove(changeInfo);
}
}
}
}
private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) {
if (changeInfo.oldHolder != null) {
endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder);
}
if (changeInfo.newHolder != null) {
endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder);
}
}
private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) {
boolean oldItem = false;
if (changeInfo.newHolder == item) {
changeInfo.newHolder = null;
} else if (changeInfo.oldHolder == item) {
changeInfo.oldHolder = null;
oldItem = true;
} else {
return false;
}
ViewCompat.setAlpha(item.itemView, 1);
ViewCompat.setTranslationX(item.itemView, 0);
ViewCompat.setTranslationY(item.itemView, 0);
dispatchChangeFinished(item, oldItem);
return true;
}
@Override
public void endAnimation(ViewHolder item) {
final View view = item.itemView;
// this will trigger end callback which should set properties to their target values.
ViewCompat.animate(view).cancel();
// TODO if some other animations are chained to end, how do we cancel them as well?
for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
MoveInfo moveInfo = mPendingMoves.get(i);
if (moveInfo.holder == item) {
ViewCompat.setTranslationY(view, 0);
ViewCompat.setTranslationX(view, 0);
dispatchMoveFinished(item);
mPendingMoves.remove(item);
}
}
endChangeAnimation(mPendingChanges, item);
if (mPendingRemovals.remove(item)) {
ViewCompat.setAlpha(view, 1);
dispatchRemoveFinished(item);
}
if (mPendingAdditions.remove(item)) {
ViewCompat.setAlpha(view, 1);
dispatchAddFinished(item);
}
for (int i = mChangesList.size() - 1; i >= 0; i--) {
ArrayList<ChangeInfo> changes = mChangesList.get(i);
endChangeAnimation(changes, item);
if (changes.isEmpty()) {
mChangesList.remove(changes);
}
}
for (int i = mMovesList.size() - 1; i >= 0; i--) {
ArrayList<MoveInfo> moves = mMovesList.get(i);
for (int j = moves.size() - 1; j >= 0; j--) {
MoveInfo moveInfo = moves.get(j);
if (moveInfo.holder == item) {
ViewCompat.setTranslationY(view, 0);
ViewCompat.setTranslationX(view, 0);
dispatchMoveFinished(item);
moves.remove(j);
if (moves.isEmpty()) {
mMovesList.remove(moves);
}
break;
}
}
}
for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
ArrayList<ViewHolder> additions = mAdditionsList.get(i);
if (additions.remove(item)) {
ViewCompat.setAlpha(view, 1);
dispatchAddFinished(item);
if (additions.isEmpty()) {
mAdditionsList.remove(additions);
}
}
}
// animations should be ended by the cancel above.
if (mRemoveAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mRemoveAnimations list");
}
if (mAddAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mAddAnimations list");
}
if (mChangeAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mChangeAnimations list");
}
if (mMoveAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mMoveAnimations list");
}
dispatchFinishedWhenDone();
}
@Override
public boolean isRunning() {
return (!mPendingAdditions.isEmpty() ||
!mPendingChanges.isEmpty() ||
!mPendingMoves.isEmpty() ||
!mPendingRemovals.isEmpty() ||
!mMoveAnimations.isEmpty() ||
!mRemoveAnimations.isEmpty() ||
!mAddAnimations.isEmpty() ||
!mChangeAnimations.isEmpty() ||
!mMovesList.isEmpty() ||
!mAdditionsList.isEmpty() ||
!mChangesList.isEmpty());
}
/**
* Check the state of currently pending and running animations. If there are none
* pending/running, call {@link #dispatchAnimationsFinished()} to notify any
* listeners.
*/
private void dispatchFinishedWhenDone() {
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
@Override
public void endAnimations() {
int count = mPendingMoves.size();
for (int i = count - 1; i >= 0; i--) {
MoveInfo item = mPendingMoves.get(i);
View view = item.holder.itemView;
ViewCompat.setTranslationY(view, 0);
ViewCompat.setTranslationX(view, 0);
dispatchMoveFinished(item.holder);
mPendingMoves.remove(i);
}
count = mPendingRemovals.size();
for (int i = count - 1; i >= 0; i--) {
ViewHolder item = mPendingRemovals.get(i);
dispatchRemoveFinished(item);
mPendingRemovals.remove(i);
}
count = mPendingAdditions.size();
for (int i = count - 1; i >= 0; i--) {
ViewHolder item = mPendingAdditions.get(i);
View view = item.itemView;
ViewCompat.setAlpha(view, 1);
dispatchAddFinished(item);
mPendingAdditions.remove(i);
}
count = mPendingChanges.size();
for (int i = count - 1; i >= 0; i--) {
endChangeAnimationIfNecessary(mPendingChanges.get(i));
}
mPendingChanges.clear();
if (!isRunning()) {
return;
}
int listCount = mMovesList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<MoveInfo> moves = mMovesList.get(i);
count = moves.size();
for (int j = count - 1; j >= 0; j--) {
MoveInfo moveInfo = moves.get(j);
ViewHolder item = moveInfo.holder;
View view = item.itemView;
ViewCompat.setTranslationY(view, 0);
ViewCompat.setTranslationX(view, 0);
dispatchMoveFinished(moveInfo.holder);
moves.remove(j);
if (moves.isEmpty()) {
mMovesList.remove(moves);
}
}
}
listCount = mAdditionsList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<ViewHolder> additions = mAdditionsList.get(i);
count = additions.size();
for (int j = count - 1; j >= 0; j--) {
ViewHolder item = additions.get(j);
View view = item.itemView;
ViewCompat.setAlpha(view, 1);
dispatchAddFinished(item);
additions.remove(j);
if (additions.isEmpty()) {
mAdditionsList.remove(additions);
}
}
}
listCount = mChangesList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<ChangeInfo> changes = mChangesList.get(i);
count = changes.size();
for (int j = count - 1; j >= 0; j--) {
endChangeAnimationIfNecessary(changes.get(j));
if (changes.isEmpty()) {
mChangesList.remove(changes);
}
}
}
cancelAll(mRemoveAnimations);
cancelAll(mMoveAnimations);
cancelAll(mAddAnimations);
cancelAll(mChangeAnimations);
dispatchAnimationsFinished();
}
void cancelAll(List<ViewHolder> viewHolders) {
for (int i = viewHolders.size() - 1; i >= 0; i--) {
ViewCompat.animate(viewHolders.get(i).itemView).cancel();
}
}
private static class VpaListenerAdapter implements ViewPropertyAnimatorListener {
@Override
public void onAnimationStart(View view) {}
@Override
public void onAnimationEnd(View view) {}
@Override
public void onAnimationCancel(View view) {}
};
}

View File

@ -1,816 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific languag`e governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
import java.util.Arrays;
/**
* A {@link RecyclerView.LayoutManager} implementations that lays out items in a grid.
* <p>
* By default, each item occupies 1 span. You can change it by providing a custom
* {@link SpanSizeLookup} instance via {@link #setSpanSizeLookup(SpanSizeLookup)}.
*/
public class GridLayoutManager extends LinearLayoutManager {
private static final boolean DEBUG = false;
private static final String TAG = "GridLayoutManager";
public static final int DEFAULT_SPAN_COUNT = -1;
/**
* The measure spec for the scroll direction.
*/
static final int MAIN_DIR_SPEC =
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int mSpanCount = DEFAULT_SPAN_COUNT;
/**
* The size of each span
*/
int mSizePerSpan;
/**
* Temporary array to keep views in layoutChunk method
*/
View[] mSet;
final SparseIntArray mPreLayoutSpanSizeCache = new SparseIntArray();
final SparseIntArray mPreLayoutSpanIndexCache = new SparseIntArray();
SpanSizeLookup mSpanSizeLookup = new DefaultSpanSizeLookup();
// re-used variable to acquire decor insets from RecyclerView
final Rect mDecorInsets = new Rect();
/**
* Creates a vertical GridLayoutManager
*
* @param context Current context, will be used to access resources.
* @param spanCount The number of columns in the grid
*/
public GridLayoutManager(Context context, int spanCount) {
super(context);
setSpanCount(spanCount);
}
/**
* @param context Current context, will be used to access resources.
* @param spanCount The number of columns or rows in the grid
* @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link
* #VERTICAL}.
* @param reverseLayout When set to true, layouts from end to start.
*/
public GridLayoutManager(Context context, int spanCount, int orientation,
boolean reverseLayout) {
super(context, orientation, reverseLayout);
setSpanCount(spanCount);
}
/**
* stackFromEnd is not supported by GridLayoutManager. Consider using
* {@link #setReverseLayout(boolean)}.
*/
@Override
public void setStackFromEnd(boolean stackFromEnd) {
if (stackFromEnd) {
throw new UnsupportedOperationException(
"GridLayoutManager does not support stack from end."
+ " Consider using reverse layout");
}
super.setStackFromEnd(false);
}
@Override
public int getRowCountForAccessibility(RecyclerView.Recycler recycler,
RecyclerView.State state) {
if (mOrientation == HORIZONTAL) {
return mSpanCount;
}
if (state.getItemCount() < 1) {
return 0;
}
return getSpanGroupIndex(recycler, state, state.getItemCount() - 1);
}
@Override
public int getColumnCountForAccessibility(RecyclerView.Recycler recycler,
RecyclerView.State state) {
if (mOrientation == VERTICAL) {
return mSpanCount;
}
if (state.getItemCount() < 1) {
return 0;
}
return getSpanGroupIndex(recycler, state, state.getItemCount() - 1);
}
@Override
public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
ViewGroup.LayoutParams lp = host.getLayoutParams();
if (!(lp instanceof LayoutParams)) {
super.onInitializeAccessibilityNodeInfoForItem(host, info);
return;
}
LayoutParams glp = (LayoutParams) lp;
int spanGroupIndex = getSpanGroupIndex(recycler, state, glp.getViewPosition());
if (mOrientation == HORIZONTAL) {
info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
glp.getSpanIndex(), glp.getSpanSize(),
spanGroupIndex, 1,
mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false));
} else { // VERTICAL
info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
spanGroupIndex , 1,
glp.getSpanIndex(), glp.getSpanSize(),
mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false));
}
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (state.isPreLayout()) {
cachePreLayoutSpanMapping();
}
super.onLayoutChildren(recycler, state);
if (DEBUG) {
validateChildOrder();
}
clearPreLayoutSpanMappingCache();
}
private void clearPreLayoutSpanMappingCache() {
mPreLayoutSpanSizeCache.clear();
mPreLayoutSpanIndexCache.clear();
}
private void cachePreLayoutSpanMapping() {
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
final int viewPosition = lp.getViewPosition();
mPreLayoutSpanSizeCache.put(viewPosition, lp.getSpanSize());
mPreLayoutSpanIndexCache.put(viewPosition, lp.getSpanIndex());
}
}
@Override
public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
mSpanSizeLookup.invalidateSpanIndexCache();
}
@Override
public void onItemsChanged(RecyclerView recyclerView) {
mSpanSizeLookup.invalidateSpanIndexCache();
}
@Override
public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
mSpanSizeLookup.invalidateSpanIndexCache();
}
@Override
public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) {
mSpanSizeLookup.invalidateSpanIndexCache();
}
@Override
public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) {
mSpanSizeLookup.invalidateSpanIndexCache();
}
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) {
return new LayoutParams(c, attrs);
}
@Override
public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
if (lp instanceof ViewGroup.MarginLayoutParams) {
return new LayoutParams((ViewGroup.MarginLayoutParams) lp);
} else {
return new LayoutParams(lp);
}
}
@Override
public boolean checkLayoutParams(RecyclerView.LayoutParams lp) {
return lp instanceof LayoutParams;
}
/**
* Sets the source to get the number of spans occupied by each item in the adapter.
*
* @param spanSizeLookup {@link SpanSizeLookup} instance to be used to query number of spans
* occupied by each item
*/
public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup) {
mSpanSizeLookup = spanSizeLookup;
}
/**
* Returns the current {@link SpanSizeLookup} used by the GridLayoutManager.
*
* @return The current {@link SpanSizeLookup} used by the GridLayoutManager.
*/
public SpanSizeLookup getSpanSizeLookup() {
return mSpanSizeLookup;
}
private void updateMeasurements() {
int totalSpace;
if (getOrientation() == VERTICAL) {
totalSpace = getWidth() - getPaddingRight() - getPaddingLeft();
} else {
totalSpace = getHeight() - getPaddingBottom() - getPaddingTop();
}
mSizePerSpan = totalSpace / mSpanCount;
}
@Override
void onAnchorReady(RecyclerView.State state, AnchorInfo anchorInfo) {
super.onAnchorReady(state, anchorInfo);
updateMeasurements();
if (state.getItemCount() > 0 && !state.isPreLayout()) {
ensureAnchorIsInFirstSpan(anchorInfo);
}
if (mSet == null || mSet.length != mSpanCount) {
mSet = new View[mSpanCount];
}
}
private void ensureAnchorIsInFirstSpan(AnchorInfo anchorInfo) {
int span = mSpanSizeLookup.getCachedSpanIndex(anchorInfo.mPosition, mSpanCount);
while (span > 0 && anchorInfo.mPosition > 0) {
anchorInfo.mPosition--;
span = mSpanSizeLookup.getCachedSpanIndex(anchorInfo.mPosition, mSpanCount);
}
}
private int getSpanGroupIndex(RecyclerView.Recycler recycler, RecyclerView.State state,
int viewPosition) {
if (!state.isPreLayout()) {
return mSpanSizeLookup.getSpanGroupIndex(viewPosition, mSpanCount);
}
final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(viewPosition);
if (adapterPosition == -1) {
if (DEBUG) {
throw new RuntimeException("Cannot find span group index for position "
+ viewPosition);
}
Log.w(TAG, "Cannot find span size for pre layout position. " + viewPosition);
return 0;
}
return mSpanSizeLookup.getSpanGroupIndex(adapterPosition, mSpanCount);
}
private int getSpanIndex(RecyclerView.Recycler recycler, RecyclerView.State state, int pos) {
if (!state.isPreLayout()) {
return mSpanSizeLookup.getCachedSpanIndex(pos, mSpanCount);
}
final int cached = mPreLayoutSpanIndexCache.get(pos, -1);
if (cached != -1) {
return cached;
}
final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(pos);
if (adapterPosition == -1) {
if (DEBUG) {
throw new RuntimeException("Cannot find span index for pre layout position. It is"
+ " not cached, not in the adapter. Pos:" + pos);
}
Log.w(TAG, "Cannot find span size for pre layout position. It is"
+ " not cached, not in the adapter. Pos:" + pos);
return 0;
}
return mSpanSizeLookup.getCachedSpanIndex(adapterPosition, mSpanCount);
}
private int getSpanSize(RecyclerView.Recycler recycler, RecyclerView.State state, int pos) {
if (!state.isPreLayout()) {
return mSpanSizeLookup.getSpanSize(pos);
}
final int cached = mPreLayoutSpanSizeCache.get(pos, -1);
if (cached != -1) {
return cached;
}
final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(pos);
if (adapterPosition == -1) {
if (DEBUG) {
throw new RuntimeException("Cannot find span size for pre layout position. It is"
+ " not cached, not in the adapter. Pos:" + pos);
}
Log.w(TAG, "Cannot find span size for pre layout position. It is"
+ " not cached, not in the adapter. Pos:" + pos);
return 1;
}
return mSpanSizeLookup.getSpanSize(adapterPosition);
}
@Override
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
LayoutState layoutState, LayoutChunkResult result) {
final boolean layingOutInPrimaryDirection =
layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_TAIL;
int count = 0;
int consumedSpanCount = 0;
int remainingSpan = mSpanCount;
if (!layingOutInPrimaryDirection) {
int itemSpanIndex = getSpanIndex(recycler, state, layoutState.mCurrentPosition);
int itemSpanSize = getSpanSize(recycler, state, layoutState.mCurrentPosition);
remainingSpan = itemSpanIndex + itemSpanSize;
}
while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) {
int pos = layoutState.mCurrentPosition;
final int spanSize = getSpanSize(recycler, state, pos);
if (spanSize > mSpanCount) {
throw new IllegalArgumentException("Item at position " + pos + " requires " +
spanSize + " spans but GridLayoutManager has only " + mSpanCount
+ " spans.");
}
remainingSpan -= spanSize;
if (remainingSpan < 0) {
break; // item did not fit into this row or column
}
View view = layoutState.next(recycler);
if (view == null) {
break;
}
consumedSpanCount += spanSize;
mSet[count] = view;
count++;
}
if (count == 0) {
result.mFinished = true;
return;
}
int maxSize = 0;
// we should assign spans before item decor offsets are calculated
assignSpans(recycler, state, count, consumedSpanCount, layingOutInPrimaryDirection);
for (int i = 0; i < count; i++) {
View view = mSet[i];
if (layoutState.mScrapList == null) {
if (layingOutInPrimaryDirection) {
addView(view);
} else {
addView(view, 0);
}
} else {
if (layingOutInPrimaryDirection) {
addDisappearingView(view);
} else {
addDisappearingView(view, 0);
}
}
int spanSize = getSpanSize(recycler, state, getPosition(view));
final int spec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan * spanSize,
View.MeasureSpec.EXACTLY);
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (mOrientation == VERTICAL) {
measureChildWithDecorationsAndMargin(view, spec, getMainDirSpec(lp.height));
} else {
measureChildWithDecorationsAndMargin(view, getMainDirSpec(lp.width), spec);
}
final int size = mOrientationHelper.getDecoratedMeasurement(view);
if (size > maxSize) {
maxSize = size;
}
}
// views that did not measure the maxSize has to be re-measured
final int maxMeasureSpec = getMainDirSpec(maxSize);
for (int i = 0; i < count; i ++) {
final View view = mSet[i];
if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) {
int spanSize = getSpanSize(recycler, state, getPosition(view));
final int spec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan * spanSize,
View.MeasureSpec.EXACTLY);
if (mOrientation == VERTICAL) {
measureChildWithDecorationsAndMargin(view, spec, maxMeasureSpec);
} else {
measureChildWithDecorationsAndMargin(view, maxMeasureSpec, spec);
}
}
}
result.mConsumed = maxSize;
int left = 0, right = 0, top = 0, bottom = 0;
if (mOrientation == VERTICAL) {
if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
bottom = layoutState.mOffset;
top = bottom - maxSize;
} else {
top = layoutState.mOffset;
bottom = top + maxSize;
}
} else {
if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
right = layoutState.mOffset;
left = right - maxSize;
} else {
left = layoutState.mOffset;
right = left + maxSize;
}
}
for (int i = 0; i < count; i++) {
View view = mSet[i];
LayoutParams params = (LayoutParams) view.getLayoutParams();
if (mOrientation == VERTICAL) {
left = getPaddingLeft() + mSizePerSpan * params.mSpanIndex;
right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
} else {
top = getPaddingTop() + mSizePerSpan * params.mSpanIndex;
bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
}
// We calculate everything with View's bounding box (which includes decor and margins)
// To calculate correct layout position, we subtract margins.
layoutDecorated(view, left + params.leftMargin, top + params.topMargin,
right - params.rightMargin, bottom - params.bottomMargin);
if (DEBUG) {
Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:"
+ (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:"
+ (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin)
+ ", span:" + params.mSpanIndex + ", spanSize:" + params.mSpanSize);
}
// Consume the available space if the view is not removed OR changed
if (params.isItemRemoved() || params.isItemChanged()) {
result.mIgnoreConsumed = true;
}
result.mFocusable |= view.isFocusable();
}
Arrays.fill(mSet, null);
}
private int getMainDirSpec(int dim) {
if (dim < 0) {
return MAIN_DIR_SPEC;
} else {
return View.MeasureSpec.makeMeasureSpec(dim, View.MeasureSpec.EXACTLY);
}
}
private void measureChildWithDecorationsAndMargin(View child, int widthSpec, int heightSpec) {
calculateItemDecorationsForChild(child, mDecorInsets);
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + mDecorInsets.left,
lp.rightMargin + mDecorInsets.right);
heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mDecorInsets.top,
lp.bottomMargin + mDecorInsets.bottom);
child.measure(widthSpec, heightSpec);
}
private int updateSpecWithExtra(int spec, int startInset, int endInset) {
if (startInset == 0 && endInset == 0) {
return spec;
}
final int mode = View.MeasureSpec.getMode(spec);
if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
return View.MeasureSpec.makeMeasureSpec(
View.MeasureSpec.getSize(spec) - startInset - endInset, mode);
}
return spec;
}
private void assignSpans(RecyclerView.Recycler recycler, RecyclerView.State state, int count,
int consumedSpanCount, boolean layingOutInPrimaryDirection) {
int span, spanDiff, start, end, diff;
// make sure we traverse from min position to max position
if (layingOutInPrimaryDirection) {
start = 0;
end = count;
diff = 1;
} else {
start = count - 1;
end = -1;
diff = -1;
}
if (mOrientation == VERTICAL && isLayoutRTL()) { // start from last span
span = consumedSpanCount - 1;
spanDiff = -1;
} else {
span = 0;
spanDiff = 1;
}
for (int i = start; i != end; i += diff) {
View view = mSet[i];
LayoutParams params = (LayoutParams) view.getLayoutParams();
params.mSpanSize = getSpanSize(recycler, state, getPosition(view));
if (spanDiff == -1 && params.mSpanSize > 1) {
params.mSpanIndex = span - (params.mSpanSize - 1);
} else {
params.mSpanIndex = span;
}
span += spanDiff * params.mSpanSize;
}
}
/**
* Returns the number of spans laid out by this grid.
*
* @return The number of spans
* @see #setSpanCount(int)
*/
public int getSpanCount() {
return mSpanCount;
}
/**
* Sets the number of spans to be laid out.
* <p>
* If {@link #getOrientation()} is {@link #VERTICAL}, this is the number of columns.
* If {@link #getOrientation()} is {@link #HORIZONTAL}, this is the number of rows.
*
* @param spanCount The total number of spans in the grid
* @see #getSpanCount()
*/
public void setSpanCount(int spanCount) {
if (spanCount == mSpanCount) {
return;
}
if (spanCount < 1) {
throw new IllegalArgumentException("Span count should be at least 1. Provided "
+ spanCount);
}
mSpanCount = spanCount;
mSpanSizeLookup.invalidateSpanIndexCache();
}
/**
* A helper class to provide the number of spans each item occupies.
* <p>
* Default implementation sets each item to occupy exactly 1 span.
*
* @see GridLayoutManager#setSpanSizeLookup(SpanSizeLookup)
*/
public static abstract class SpanSizeLookup {
final SparseIntArray mSpanIndexCache = new SparseIntArray();
private boolean mCacheSpanIndices = false;
/**
* Returns the number of span occupied by the item at <code>position</code>.
*
* @param position The adapter position of the item
* @return The number of spans occupied by the item at the provided position
*/
abstract public int getSpanSize(int position);
/**
* Sets whether the results of {@link #getSpanIndex(int, int)} method should be cached or
* not. By default these values are not cached. If you are not overriding
* {@link #getSpanIndex(int, int)}, you should set this to true for better performance.
*
* @param cacheSpanIndices Whether results of getSpanIndex should be cached or not.
*/
public void setSpanIndexCacheEnabled(boolean cacheSpanIndices) {
mCacheSpanIndices = cacheSpanIndices;
}
/**
* Clears the span index cache. GridLayoutManager automatically calls this method when
* adapter changes occur.
*/
public void invalidateSpanIndexCache() {
mSpanIndexCache.clear();
}
/**
* Returns whether results of {@link #getSpanIndex(int, int)} method are cached or not.
*
* @return True if results of {@link #getSpanIndex(int, int)} are cached.
*/
public boolean isSpanIndexCacheEnabled() {
return mCacheSpanIndices;
}
int getCachedSpanIndex(int position, int spanCount) {
if (!mCacheSpanIndices) {
return getSpanIndex(position, spanCount);
}
final int existing = mSpanIndexCache.get(position, -1);
if (existing != -1) {
return existing;
}
final int value = getSpanIndex(position, spanCount);
mSpanIndexCache.put(position, value);
return value;
}
/**
* Returns the final span index of the provided position.
* <p>
* If you have a faster way to calculate span index for your items, you should override
* this method. Otherwise, you should enable span index cache
* ({@link #setSpanIndexCacheEnabled(boolean)}) for better performance. When caching is
* disabled, default implementation traverses all items from 0 to
* <code>position</code>. When caching is enabled, it calculates from the closest cached
* value before the <code>position</code>.
* <p>
* If you override this method, you need to make sure it is consistent with
* {@link #getSpanSize(int)}. GridLayoutManager does not call this method for
* each item. It is called only for the reference item and rest of the items
* are assigned to spans based on the reference item. For example, you cannot assign a
* position to span 2 while span 1 is empty.
* <p>
* Note that span offsets always start with 0 and are not affected by RTL.
*
* @param position The position of the item
* @param spanCount The total number of spans in the grid
* @return The final span position of the item. Should be between 0 (inclusive) and
* <code>spanCount</code>(exclusive)
*/
public int getSpanIndex(int position, int spanCount) {
int positionSpanSize = getSpanSize(position);
if (positionSpanSize == spanCount) {
return 0; // quick return for full-span items
}
int span = 0;
int startPos = 0;
// If caching is enabled, try to jump
if (mCacheSpanIndices && mSpanIndexCache.size() > 0) {
int prevKey = findReferenceIndexFromCache(position);
if (prevKey >= 0) {
span = mSpanIndexCache.get(prevKey) + getSpanSize(prevKey);
startPos = prevKey + 1;
}
}
for (int i = startPos; i < position; i++) {
int size = getSpanSize(i);
span += size;
if (span == spanCount) {
span = 0;
} else if (span > spanCount) {
// did not fit, moving to next row / column
span = size;
}
}
if (span + positionSpanSize <= spanCount) {
return span;
}
return 0;
}
int findReferenceIndexFromCache(int position) {
int lo = 0;
int hi = mSpanIndexCache.size() - 1;
while (lo <= hi) {
final int mid = (lo + hi) >>> 1;
final int midVal = mSpanIndexCache.keyAt(mid);
if (midVal < position) {
lo = mid + 1;
} else {
hi = mid - 1;
}
}
int index = lo - 1;
if (index >= 0 && index < mSpanIndexCache.size()) {
return mSpanIndexCache.keyAt(index);
}
return -1;
}
/**
* Returns the index of the group this position belongs.
* <p>
* For example, if grid has 3 columns and each item occupies 1 span, span group index
* for item 1 will be 0, item 5 will be 1.
*
* @param adapterPosition The position in adapter
* @param spanCount The total number of spans in the grid
* @return The index of the span group including the item at the given adapter position
*/
public int getSpanGroupIndex(int adapterPosition, int spanCount) {
int span = 0;
int group = 0;
int positionSpanSize = getSpanSize(adapterPosition);
for (int i = 0; i < adapterPosition; i++) {
int size = getSpanSize(i);
span += size;
if (span == spanCount) {
span = 0;
group++;
} else if (span > spanCount) {
// did not fit, moving to next row / column
span = size;
group++;
}
}
if (span + positionSpanSize > spanCount) {
group++;
}
return group;
}
}
@Override
public boolean supportsPredictiveItemAnimations() {
return mPendingSavedState == null;
}
/**
* Default implementation for {@link SpanSizeLookup}. Each item occupies 1 span.
*/
public static final class DefaultSpanSizeLookup extends SpanSizeLookup {
@Override
public int getSpanSize(int position) {
return 1;
}
@Override
public int getSpanIndex(int position, int spanCount) {
return position % spanCount;
}
}
/**
* LayoutParams used by GridLayoutManager.
*/
public static class LayoutParams extends RecyclerView.LayoutParams {
/**
* Span Id for Views that are not laid out yet.
*/
public static final int INVALID_SPAN_ID = -1;
private int mSpanIndex = INVALID_SPAN_ID;
private int mSpanSize = 0;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(ViewGroup.MarginLayoutParams source) {
super(source);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(RecyclerView.LayoutParams source) {
super(source);
}
/**
* Returns the current span index of this View. If the View is not laid out yet, the return
* value is <code>undefined</code>.
* <p>
* Note that span index may change by whether the RecyclerView is RTL or not. For
* example, if the number of spans is 3 and layout is RTL, the rightmost item will have
* span index of 2. If the layout changes back to LTR, span index for this view will be 0.
* If the item was occupying 2 spans, span indices would be 1 and 0 respectively.
* <p>
* If the View occupies multiple spans, span with the minimum index is returned.
*
* @return The span index of the View.
*/
public int getSpanIndex() {
return mSpanIndex;
}
/**
* Returns the number of spans occupied by this View. If the View not laid out yet, the
* return value is <code>undefined</code>.
*
* @return The number of spans occupied by this View.
*/
public int getSpanSize() {
return mSpanSize;
}
}
}

View File

@ -1,87 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific languag`e governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import android.view.View;
/**
* Helper class that keeps temporary state while {LayoutManager} is filling out the empty
* space.
*/
class LayoutState {
final static String TAG = "LayoutState";
final static int LAYOUT_START = -1;
final static int LAYOUT_END = 1;
final static int INVALID_LAYOUT = Integer.MIN_VALUE;
final static int ITEM_DIRECTION_HEAD = -1;
final static int ITEM_DIRECTION_TAIL = 1;
final static int SCOLLING_OFFSET_NaN = Integer.MIN_VALUE;
/**
* Number of pixels that we should fill, in the layout direction.
*/
int mAvailable;
/**
* Current position on the adapter to get the next item.
*/
int mCurrentPosition;
/**
* Defines the direction in which the data adapter is traversed.
* Should be {@link #ITEM_DIRECTION_HEAD} or {@link #ITEM_DIRECTION_TAIL}
*/
int mItemDirection;
/**
* Defines the direction in which the layout is filled.
* Should be {@link #LAYOUT_START} or {@link #LAYOUT_END}
*/
int mLayoutDirection;
/**
* Used if you want to pre-layout items that are not yet visible.
* The difference with {@link #mAvailable} is that, when recycling, distance rendered for
* {@link #mExtra} is not considered not to recycle visible children.
*/
int mExtra = 0;
/**
* @return true if there are more items in the data adapter
*/
boolean hasMore(RecyclerView.State state) {
return mCurrentPosition >= 0 && mCurrentPosition < state.getItemCount();
}
/**
* Gets the view for the next element that we should render.
* Also updates current item index to the next item, based on {@link #mItemDirection}
*
* @return The next element that we should render.
*/
View next(RecyclerView.Recycler recycler) {
final View view = recycler.getViewForPosition(mCurrentPosition);
mCurrentPosition += mItemDirection;
return view;
}
}

View File

@ -1,338 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import android.content.Context;
import android.graphics.PointF;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
/**
* {@link RecyclerView.SmoothScroller} implementation which uses
* {@link LinearInterpolator} until the target position becames a child of
* the RecyclerView and then uses
* {@link DecelerateInterpolator} to slowly approach to target position.
*/
abstract public class LinearSmoothScroller extends RecyclerView.SmoothScroller {
private static final String TAG = "LinearSmoothScroller";
private static final boolean DEBUG = false;
private static final float MILLISECONDS_PER_INCH = 25f;
private static final int TARGET_SEEK_SCROLL_DISTANCE_PX = 10000;
/**
* Align child view's left or top with parent view's left or top
*
* @see #calculateDtToFit(int, int, int, int, int)
* @see #calculateDxToMakeVisible(View, int)
* @see #calculateDyToMakeVisible(View, int)
*/
public static final int SNAP_TO_START = -1;
/**
* Align child view's right or bottom with parent view's right or bottom
*
* @see #calculateDtToFit(int, int, int, int, int)
* @see #calculateDxToMakeVisible(View, int)
* @see #calculateDyToMakeVisible(View, int)
*/
public static final int SNAP_TO_END = 1;
/**
* <p>Decides if the child should be snapped from start or end, depending on where it
* currently is in relation to its parent.</p>
* <p>For instance, if the view is virtually on the left of RecyclerView, using
* {@code SNAP_TO_ANY} is the same as using {@code SNAP_TO_START}</p>
*
* @see #calculateDtToFit(int, int, int, int, int)
* @see #calculateDxToMakeVisible(View, int)
* @see #calculateDyToMakeVisible(View, int)
*/
public static final int SNAP_TO_ANY = 0;
// Trigger a scroll to a further distance than TARGET_SEEK_SCROLL_DISTANCE_PX so that if target
// view is not laid out until interim target position is reached, we can detect the case before
// scrolling slows down and reschedule another interim target scroll
private static final float TARGET_SEEK_EXTRA_SCROLL_RATIO = 1.2f;
protected final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
protected final DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator();
protected PointF mTargetVector;
private final float MILLISECONDS_PER_PX;
// Temporary variables to keep track of the interim scroll target. These values do not
// point to a real item position, rather point to an estimated location pixels.
protected int mInterimTargetDx = 0, mInterimTargetDy = 0;
public LinearSmoothScroller(Context context) {
MILLISECONDS_PER_PX = calculateSpeedPerPixel(context.getResources().getDisplayMetrics());
}
/**
* {@inheritDoc}
*/
@Override
protected void onStart() {
}
/**
* {@inheritDoc}
*/
@Override
protected void onTargetFound(View targetView, RecyclerView.State state, Action action) {
final int dx = calculateDxToMakeVisible(targetView, getHorizontalSnapPreference());
final int dy = calculateDyToMakeVisible(targetView, getVerticalSnapPreference());
final int distance = (int) Math.sqrt(dx * dx + dy * dy);
final int time = calculateTimeForDeceleration(distance);
if (time > 0) {
action.update(-dx, -dy, time, mDecelerateInterpolator);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void onSeekTargetStep(int dx, int dy, RecyclerView.State state, Action action) {
if (getChildCount() == 0) {
stop();
return;
}
if (DEBUG && mTargetVector != null
&& ((mTargetVector.x * dx < 0 || mTargetVector.y * dy < 0))) {
throw new IllegalStateException("Scroll happened in the opposite direction"
+ " of the target. Some calculations are wrong");
}
mInterimTargetDx = clampApplyScroll(mInterimTargetDx, dx);
mInterimTargetDy = clampApplyScroll(mInterimTargetDy, dy);
if (mInterimTargetDx == 0 && mInterimTargetDy == 0) {
updateActionForInterimTarget(action);
} // everything is valid, keep going
}
/**
* {@inheritDoc}
*/
@Override
protected void onStop() {
mInterimTargetDx = mInterimTargetDy = 0;
mTargetVector = null;
}
/**
* Calculates the scroll speed.
*
* @param displayMetrics DisplayMetrics to be used for real dimension calculations
* @return The time (in ms) it should take for each pixel. For instance, if returned value is
* 2 ms, it means scrolling 1000 pixels with LinearInterpolation should take 2 seconds.
*/
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
/**
* <p>Calculates the time for deceleration so that transition from LinearInterpolator to
* DecelerateInterpolator looks smooth.</p>
*
* @param dx Distance to scroll
* @return Time for DecelerateInterpolator to smoothly traverse the distance when transitioning
* from LinearInterpolation
*/
protected int calculateTimeForDeceleration(int dx) {
// we want to cover same area with the linear interpolator for the first 10% of the
// interpolation. After that, deceleration will take control.
// area under curve (1-(1-x)^2) can be calculated as (1 - x/3) * x * x
// which gives 0.100028 when x = .3356
// this is why we divide linear scrolling time with .3356
return (int) Math.ceil(calculateTimeForScrolling(dx) / .3356);
}
/**
* Calculates the time it should take to scroll the given distance (in pixels)
*
* @param dx Distance in pixels that we want to scroll
* @return Time in milliseconds
* @see #calculateSpeedPerPixel(DisplayMetrics)
*/
protected int calculateTimeForScrolling(int dx) {
// In a case where dx is very small, rounding may return 0 although dx > 0.
// To avoid that issue, ceil the result so that if dx > 0, we'll always return positive
// time.
return (int) Math.ceil(Math.abs(dx) * MILLISECONDS_PER_PX);
}
/**
* When scrolling towards a child view, this method defines whether we should align the left
* or the right edge of the child with the parent RecyclerView.
*
* @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector
* @see #SNAP_TO_START
* @see #SNAP_TO_END
* @see #SNAP_TO_ANY
*/
protected int getHorizontalSnapPreference() {
return mTargetVector == null || mTargetVector.x == 0 ? SNAP_TO_ANY :
mTargetVector.x > 0 ? SNAP_TO_END : SNAP_TO_START;
}
/**
* When scrolling towards a child view, this method defines whether we should align the top
* or the bottom edge of the child with the parent RecyclerView.
*
* @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector
* @see #SNAP_TO_START
* @see #SNAP_TO_END
* @see #SNAP_TO_ANY
*/
protected int getVerticalSnapPreference() {
return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY :
mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START;
}
/**
* When the target scroll position is not a child of the RecyclerView, this method calculates
* a direction vector towards that child and triggers a smooth scroll.
*
* @see #computeScrollVectorForPosition(int)
*/
protected void updateActionForInterimTarget(Action action) {
// find an interim target position
PointF scrollVector = computeScrollVectorForPosition(getTargetPosition());
if (scrollVector == null || (scrollVector.x == 0 && scrollVector.y == 0)) {
Log.e(TAG, "To support smooth scrolling, you should override \n"
+ "LayoutManager#computeScrollVectorForPosition.\n"
+ "Falling back to instant scroll");
final int target = getTargetPosition();
stop();
instantScrollToPosition(target);
return;
}
normalize(scrollVector);
mTargetVector = scrollVector;
mInterimTargetDx = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.x);
mInterimTargetDy = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.y);
final int time = calculateTimeForScrolling(TARGET_SEEK_SCROLL_DISTANCE_PX);
// To avoid UI hiccups, trigger a smooth scroll to a distance little further than the
// interim target. Since we track the distance travelled in onSeekTargetStep callback, it
// won't actually scroll more than what we need.
action.update((int) (mInterimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO)
, (int) (mInterimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO)
, (int) (time * TARGET_SEEK_EXTRA_SCROLL_RATIO), mLinearInterpolator);
}
private int clampApplyScroll(int tmpDt, int dt) {
final int before = tmpDt;
tmpDt -= dt;
if (before * tmpDt <= 0) { // changed sign, reached 0 or was 0, reset
return 0;
}
return tmpDt;
}
/**
* Helper method for {@link #calculateDxToMakeVisible(View, int)} and
* {@link #calculateDyToMakeVisible(View, int)}
*/
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int
snapPreference) {
switch (snapPreference) {
case SNAP_TO_START:
return boxStart - viewStart;
case SNAP_TO_END:
return boxEnd - viewEnd;
case SNAP_TO_ANY:
final int dtStart = boxStart - viewStart;
if (dtStart > 0) {
return dtStart;
}
final int dtEnd = boxEnd - viewEnd;
if (dtEnd < 0) {
return dtEnd;
}
break;
default:
throw new IllegalArgumentException("snap preference should be one of the"
+ " constants defined in SmoothScroller, starting with SNAP_");
}
return 0;
}
/**
* Calculates the vertical scroll amount necessary to make the given view fully visible
* inside the RecyclerView.
*
* @param view The view which we want to make fully visible
* @param snapPreference The edge which the view should snap to when entering the visible
* area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or
* {@link #SNAP_TO_END}.
* @return The vertical scroll amount necessary to make the view visible with the given
* snap preference.
*/
public int calculateDyToMakeVisible(View view, int snapPreference) {
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (!layoutManager.canScrollVertically()) {
return 0;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
final int top = layoutManager.getDecoratedTop(view) - params.topMargin;
final int bottom = layoutManager.getDecoratedBottom(view) + params.bottomMargin;
final int start = layoutManager.getPaddingTop();
final int end = layoutManager.getHeight() - layoutManager.getPaddingBottom();
return calculateDtToFit(top, bottom, start, end, snapPreference);
}
/**
* Calculates the horizontal scroll amount necessary to make the given view fully visible
* inside the RecyclerView.
*
* @param view The view which we want to make fully visible
* @param snapPreference The edge which the view should snap to when entering the visible
* area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or
* {@link #SNAP_TO_END}
* @return The vertical scroll amount necessary to make the view visible with the given
* snap preference.
*/
public int calculateDxToMakeVisible(View view, int snapPreference) {
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (!layoutManager.canScrollHorizontally()) {
return 0;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
final int left = layoutManager.getDecoratedLeft(view) - params.leftMargin;
final int right = layoutManager.getDecoratedRight(view) + params.rightMargin;
final int start = layoutManager.getPaddingLeft();
final int end = layoutManager.getWidth() - layoutManager.getPaddingRight();
return calculateDtToFit(left, right, start, end, snapPreference);
}
abstract public PointF computeScrollVectorForPosition(int targetPosition);
}

View File

@ -1,238 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import android.support.v7.widget.AdapterHelper.UpdateOp;
import java.util.List;
import static android.support.v7.widget.AdapterHelper.UpdateOp.ADD;
import static android.support.v7.widget.AdapterHelper.UpdateOp.MOVE;
import static android.support.v7.widget.AdapterHelper.UpdateOp.REMOVE;
import static android.support.v7.widget.AdapterHelper.UpdateOp.UPDATE;
class OpReorderer {
final Callback mCallback;
public OpReorderer(Callback callback) {
mCallback = callback;
}
void reorderOps(List<UpdateOp> ops) {
// since move operations breaks continuity, their effects on ADD/RM are hard to handle.
// we push them to the end of the list so that they can be handled easily.
int badMove;
while ((badMove = getLastMoveOutOfOrder(ops)) != -1) {
swapMoveOp(ops, badMove, badMove + 1);
}
}
private void swapMoveOp(List<UpdateOp> list, int badMove, int next) {
final UpdateOp moveOp = list.get(badMove);
final UpdateOp nextOp = list.get(next);
switch (nextOp.cmd) {
case REMOVE:
swapMoveRemove(list, badMove, moveOp, next, nextOp);
break;
case ADD:
swapMoveAdd(list, badMove, moveOp, next, nextOp);
break;
case UPDATE:
swapMoveUpdate(list, badMove, moveOp, next, nextOp);
break;
}
}
void swapMoveRemove(List<UpdateOp> list, int movePos, UpdateOp moveOp,
int removePos, UpdateOp removeOp) {
UpdateOp extraRm = null;
// check if move is nulled out by remove
boolean revertedMove = false;
final boolean moveIsBackwards;
if (moveOp.positionStart < moveOp.itemCount) {
moveIsBackwards = false;
if (removeOp.positionStart == moveOp.positionStart
&& removeOp.itemCount == moveOp.itemCount - moveOp.positionStart) {
revertedMove = true;
}
} else {
moveIsBackwards = true;
if (removeOp.positionStart == moveOp.itemCount + 1 &&
removeOp.itemCount == moveOp.positionStart - moveOp.itemCount) {
revertedMove = true;
}
}
// going in reverse, first revert the effect of add
if (moveOp.itemCount < removeOp.positionStart) {
removeOp.positionStart--;
} else if (moveOp.itemCount < removeOp.positionStart + removeOp.itemCount) {
// move is removed.
removeOp.itemCount --;
moveOp.cmd = REMOVE;
moveOp.itemCount = 1;
if (removeOp.itemCount == 0) {
list.remove(removePos);
mCallback.recycleUpdateOp(removeOp);
}
// no need to swap, it is already a remove
return;
}
// now affect of add is consumed. now apply effect of first remove
if (moveOp.positionStart <= removeOp.positionStart) {
removeOp.positionStart++;
} else if (moveOp.positionStart < removeOp.positionStart + removeOp.itemCount) {
final int remaining = removeOp.positionStart + removeOp.itemCount
- moveOp.positionStart;
extraRm = mCallback.obtainUpdateOp(REMOVE, moveOp.positionStart + 1, remaining);
removeOp.itemCount = moveOp.positionStart - removeOp.positionStart;
}
// if effects of move is reverted by remove, we are done.
if (revertedMove) {
list.set(movePos, removeOp);
list.remove(removePos);
mCallback.recycleUpdateOp(moveOp);
return;
}
// now find out the new locations for move actions
if (moveIsBackwards) {
if (extraRm != null) {
if (moveOp.positionStart > extraRm.positionStart) {
moveOp.positionStart -= extraRm.itemCount;
}
if (moveOp.itemCount > extraRm.positionStart) {
moveOp.itemCount -= extraRm.itemCount;
}
}
if (moveOp.positionStart > removeOp.positionStart) {
moveOp.positionStart -= removeOp.itemCount;
}
if (moveOp.itemCount > removeOp.positionStart) {
moveOp.itemCount -= removeOp.itemCount;
}
} else {
if (extraRm != null) {
if (moveOp.positionStart >= extraRm.positionStart) {
moveOp.positionStart -= extraRm.itemCount;
}
if (moveOp.itemCount >= extraRm.positionStart) {
moveOp.itemCount -= extraRm.itemCount;
}
}
if (moveOp.positionStart >= removeOp.positionStart) {
moveOp.positionStart -= removeOp.itemCount;
}
if (moveOp.itemCount >= removeOp.positionStart) {
moveOp.itemCount -= removeOp.itemCount;
}
}
list.set(movePos, removeOp);
if (moveOp.positionStart != moveOp.itemCount) {
list.set(removePos, moveOp);
} else {
list.remove(removePos);
}
if (extraRm != null) {
list.add(movePos, extraRm);
}
}
private void swapMoveAdd(List<UpdateOp> list, int move, UpdateOp moveOp, int add,
UpdateOp addOp) {
int offset = 0;
// going in reverse, first revert the effect of add
if (moveOp.itemCount < addOp.positionStart) {
offset--;
}
if (moveOp.positionStart < addOp.positionStart) {
offset++;
}
if (addOp.positionStart <= moveOp.positionStart) {
moveOp.positionStart += addOp.itemCount;
}
if (addOp.positionStart <= moveOp.itemCount) {
moveOp.itemCount += addOp.itemCount;
}
addOp.positionStart += offset;
list.set(move, addOp);
list.set(add, moveOp);
}
void swapMoveUpdate(List<UpdateOp> list, int move, UpdateOp moveOp, int update,
UpdateOp updateOp) {
UpdateOp extraUp1 = null;
UpdateOp extraUp2 = null;
// going in reverse, first revert the effect of add
if (moveOp.itemCount < updateOp.positionStart) {
updateOp.positionStart--;
} else if (moveOp.itemCount < updateOp.positionStart + updateOp.itemCount) {
// moved item is updated. add an update for it
updateOp.itemCount--;
extraUp1 = mCallback.obtainUpdateOp(UPDATE, moveOp.positionStart, 1);
}
// now affect of add is consumed. now apply effect of first remove
if (moveOp.positionStart <= updateOp.positionStart) {
updateOp.positionStart++;
} else if (moveOp.positionStart < updateOp.positionStart + updateOp.itemCount) {
final int remaining = updateOp.positionStart + updateOp.itemCount
- moveOp.positionStart;
extraUp2 = mCallback.obtainUpdateOp(UPDATE, moveOp.positionStart + 1, remaining);
updateOp.itemCount -= remaining;
}
list.set(update, moveOp);
if (updateOp.itemCount > 0) {
list.set(move, updateOp);
} else {
list.remove(move);
mCallback.recycleUpdateOp(updateOp);
}
if (extraUp1 != null) {
list.add(move, extraUp1);
}
if (extraUp2 != null) {
list.add(move, extraUp2);
}
}
private int getLastMoveOutOfOrder(List<UpdateOp> list) {
boolean foundNonMove = false;
for (int i = list.size() - 1; i >= 0; i--) {
final UpdateOp op1 = list.get(i);
if (op1.cmd == MOVE) {
if (foundNonMove) {
return i;
}
} else {
foundNonMove = true;
}
}
return -1;
}
static interface Callback {
UpdateOp obtainUpdateOp(int cmd, int startPosition, int itemCount);
void recycleUpdateOp(UpdateOp op);
}
}

View File

@ -1,338 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import android.view.View;
import android.widget.LinearLayout;
/**
* Helper class for LayoutManagers to abstract measurements depending on the View's orientation.
* <p>
* It is developed to easily support vertical and horizontal orientations in a LayoutManager but
* can also be used to abstract calls around view bounds and child measurements with margins and
* decorations.
*
* @see #createHorizontalHelper(RecyclerView.LayoutManager)
* @see #createVerticalHelper(RecyclerView.LayoutManager)
*/
public abstract class OrientationHelper {
private static final int INVALID_SIZE = Integer.MIN_VALUE;
protected final RecyclerView.LayoutManager mLayoutManager;
public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
public static final int VERTICAL = LinearLayout.VERTICAL;
private int mLastTotalSpace = INVALID_SIZE;
private OrientationHelper(RecyclerView.LayoutManager layoutManager) {
mLayoutManager = layoutManager;
}
/**
* Call this method after onLayout method is complete if state is NOT pre-layout.
* This method records information like layout bounds that might be useful in the next layout
* calculations.
*/
public void onLayoutComplete() {
mLastTotalSpace = getTotalSpace();
}
/**
* Returns the layout space change between the previous layout pass and current layout pass.
* <p>
* Make sure you call {@link #onLayoutComplete()} at the end of your LayoutManager's
* {@link RecyclerView.LayoutManager#onLayoutChildren(RecyclerView.Recycler,
* RecyclerView.State)} method.
*
* @return The difference between the current total space and previous layout's total space.
* @see #onLayoutComplete()
*/
public int getTotalSpaceChange() {
return INVALID_SIZE == mLastTotalSpace ? 0 : getTotalSpace() - mLastTotalSpace;
}
/**
* Returns the start of the view including its decoration and margin.
* <p>
* For example, for the horizontal helper, if a View's left is at pixel 20, has 2px left
* decoration and 3px left margin, returned value will be 15px.
*
* @param view The view element to check
* @return The first pixel of the element
* @see #getDecoratedEnd(View)
*/
public abstract int getDecoratedStart(View view);
/**
* Returns the end of the view including its decoration and margin.
* <p>
* For example, for the horizontal helper, if a View's right is at pixel 200, has 2px right
* decoration and 3px right margin, returned value will be 205.
*
* @param view The view element to check
* @return The last pixel of the element
* @see #getDecoratedStart(View)
*/
public abstract int getDecoratedEnd(View view);
/**
* Returns the space occupied by this View in the current orientation including decorations and
* margins.
*
* @param view The view element to check
* @return Total space occupied by this view
* @see #getDecoratedMeasurementInOther(View)
*/
public abstract int getDecoratedMeasurement(View view);
/**
* Returns the space occupied by this View in the perpendicular orientation including
* decorations and margins.
*
* @param view The view element to check
* @return Total space occupied by this view in the perpendicular orientation to current one
* @see #getDecoratedMeasurement(View)
*/
public abstract int getDecoratedMeasurementInOther(View view);
/**
* Returns the start position of the layout after the start padding is added.
*
* @return The very first pixel we can draw.
*/
public abstract int getStartAfterPadding();
/**
* Returns the end position of the layout after the end padding is removed.
*
* @return The end boundary for this layout.
*/
public abstract int getEndAfterPadding();
/**
* Returns the end position of the layout without taking padding into account.
*
* @return The end boundary for this layout without considering padding.
*/
public abstract int getEnd();
/**
* Offsets all children's positions by the given amount.
*
* @param amount Value to add to each child's layout parameters
*/
public abstract void offsetChildren(int amount);
/**
* Returns the total space to layout. This number is the difference between
* {@link #getEndAfterPadding()} and {@link #getStartAfterPadding()}.
*
* @return Total space to layout children
*/
public abstract int getTotalSpace();
/**
* Offsets the child in this orientation.
*
* @param view View to offset
* @param offset offset amount
*/
public abstract void offsetChild(View view, int offset);
/**
* Returns the padding at the end of the layout. For horizontal helper, this is the right
* padding and for vertical helper, this is the bottom padding. This method does not check
* whether the layout is RTL or not.
*
* @return The padding at the end of the layout.
*/
public abstract int getEndPadding();
/**
* Creates an OrientationHelper for the given LayoutManager and orientation.
*
* @param layoutManager LayoutManager to attach to
* @param orientation Desired orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}
* @return A new OrientationHelper
*/
public static OrientationHelper createOrientationHelper(
RecyclerView.LayoutManager layoutManager, int orientation) {
switch (orientation) {
case HORIZONTAL:
return createHorizontalHelper(layoutManager);
case VERTICAL:
return createVerticalHelper(layoutManager);
}
throw new IllegalArgumentException("invalid orientation");
}
/**
* Creates a horizontal OrientationHelper for the given LayoutManager.
*
* @param layoutManager The LayoutManager to attach to.
* @return A new OrientationHelper
*/
public static OrientationHelper createHorizontalHelper(
RecyclerView.LayoutManager layoutManager) {
return new OrientationHelper(layoutManager) {
@Override
public int getEndAfterPadding() {
return mLayoutManager.getWidth() - mLayoutManager.getPaddingRight();
}
@Override
public int getEnd() {
return mLayoutManager.getWidth();
}
@Override
public void offsetChildren(int amount) {
mLayoutManager.offsetChildrenHorizontal(amount);
}
@Override
public int getStartAfterPadding() {
return mLayoutManager.getPaddingLeft();
}
@Override
public int getDecoratedMeasurement(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin
+ params.rightMargin;
}
@Override
public int getDecoratedMeasurementInOther(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin
+ params.bottomMargin;
}
@Override
public int getDecoratedEnd(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedRight(view) + params.rightMargin;
}
@Override
public int getDecoratedStart(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedLeft(view) - params.leftMargin;
}
@Override
public int getTotalSpace() {
return mLayoutManager.getWidth() - mLayoutManager.getPaddingLeft()
- mLayoutManager.getPaddingRight();
}
@Override
public void offsetChild(View view, int offset) {
view.offsetLeftAndRight(offset);
}
@Override
public int getEndPadding() {
return mLayoutManager.getPaddingRight();
}
};
}
/**
* Creates a vertical OrientationHelper for the given LayoutManager.
*
* @param layoutManager The LayoutManager to attach to.
* @return A new OrientationHelper
*/
public static OrientationHelper createVerticalHelper(RecyclerView.LayoutManager layoutManager) {
return new OrientationHelper(layoutManager) {
@Override
public int getEndAfterPadding() {
return mLayoutManager.getHeight() - mLayoutManager.getPaddingBottom();
}
@Override
public int getEnd() {
return mLayoutManager.getHeight();
}
@Override
public void offsetChildren(int amount) {
mLayoutManager.offsetChildrenVertical(amount);
}
@Override
public int getStartAfterPadding() {
return mLayoutManager.getPaddingTop();
}
@Override
public int getDecoratedMeasurement(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin
+ params.bottomMargin;
}
@Override
public int getDecoratedMeasurementInOther(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin
+ params.rightMargin;
}
@Override
public int getDecoratedEnd(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedBottom(view) + params.bottomMargin;
}
@Override
public int getDecoratedStart(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedTop(view) - params.topMargin;
}
@Override
public int getTotalSpace() {
return mLayoutManager.getHeight() - mLayoutManager.getPaddingTop()
- mLayoutManager.getPaddingBottom();
}
@Override
public void offsetChild(View view, int offset) {
view.offsetTopAndBottom(offset);
}
@Override
public int getEndPadding() {
return mLayoutManager.getPaddingBottom();
}
};
}
}

View File

@ -1,460 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import java.util.ArrayList;
/**
* Like a SparseArray, but with the ability to offset key ranges for bulk insertions/deletions.
*/
class PositionMap<E> implements Cloneable {
private static final Object DELETED = new Object();
private boolean mGarbage = false;
private int[] mKeys;
private Object[] mValues;
private int mSize;
/**
* Creates a new SparseArray containing no mappings.
*/
public PositionMap() {
this(10);
}
/**
* Creates a new PositionMap containing no mappings that will not
* require any additional memory allocation to store the specified
* number of mappings. If you supply an initial capacity of 0, the
* sparse array will be initialized with a light-weight representation
* not requiring any additional array allocations.
*/
public PositionMap(int initialCapacity) {
if (initialCapacity == 0) {
mKeys = ContainerHelpers.EMPTY_INTS;
mValues = ContainerHelpers.EMPTY_OBJECTS;
} else {
initialCapacity = idealIntArraySize(initialCapacity);
mKeys = new int[initialCapacity];
mValues = new Object[initialCapacity];
}
mSize = 0;
}
@Override
@SuppressWarnings("unchecked")
public PositionMap<E> clone() {
PositionMap<E> clone = null;
try {
clone = (PositionMap<E>) super.clone();
clone.mKeys = mKeys.clone();
clone.mValues = mValues.clone();
} catch (CloneNotSupportedException cnse) {
/* ignore */
}
return clone;
}
/**
* Gets the Object mapped from the specified key, or <code>null</code>
* if no such mapping has been made.
*/
public E get(int key) {
return get(key, null);
}
/**
* Gets the Object mapped from the specified key, or the specified Object
* if no such mapping has been made.
*/
@SuppressWarnings("unchecked")
public E get(int key, E valueIfKeyNotFound) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i < 0 || mValues[i] == DELETED) {
return valueIfKeyNotFound;
} else {
return (E) mValues[i];
}
}
/**
* Removes the mapping from the specified key, if there was any.
*/
public void delete(int key) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
if (mValues[i] != DELETED) {
mValues[i] = DELETED;
mGarbage = true;
}
}
}
/**
* Alias for {@link #delete(int)}.
*/
public void remove(int key) {
delete(key);
}
/**
* Removes the mapping at the specified index.
*/
public void removeAt(int index) {
if (mValues[index] != DELETED) {
mValues[index] = DELETED;
mGarbage = true;
}
}
/**
* Remove a range of mappings as a batch.
*
* @param index Index to begin at
* @param size Number of mappings to remove
*/
public void removeAtRange(int index, int size) {
final int end = Math.min(mSize, index + size);
for (int i = index; i < end; i++) {
removeAt(i);
}
}
public void insertKeyRange(int keyStart, int count) {
}
public void removeKeyRange(ArrayList<E> removedItems, int keyStart, int count) {
}
private void gc() {
// Log.e("SparseArray", "gc start with " + mSize);
int n = mSize;
int o = 0;
int[] keys = mKeys;
Object[] values = mValues;
for (int i = 0; i < n; i++) {
Object val = values[i];
if (val != DELETED) {
if (i != o) {
keys[o] = keys[i];
values[o] = val;
values[i] = null;
}
o++;
}
}
mGarbage = false;
mSize = o;
// Log.e("SparseArray", "gc end with " + mSize);
}
/**
* Adds a mapping from the specified key to the specified value,
* replacing the previous mapping from the specified key if there
* was one.
*/
public void put(int key, E value) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
mValues[i] = value;
} else {
i = ~i;
if (i < mSize && mValues[i] == DELETED) {
mKeys[i] = key;
mValues[i] = value;
return;
}
if (mGarbage && mSize >= mKeys.length) {
gc();
// Search again because indices may have changed.
i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
}
if (mSize >= mKeys.length) {
int n = idealIntArraySize(mSize + 1);
int[] nkeys = new int[n];
Object[] nvalues = new Object[n];
// Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
mKeys = nkeys;
mValues = nvalues;
}
if (mSize - i != 0) {
// Log.e("SparseArray", "move " + (mSize - i));
System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
}
mKeys[i] = key;
mValues[i] = value;
mSize++;
}
}
/**
* Returns the number of key-value mappings that this SparseArray
* currently stores.
*/
public int size() {
if (mGarbage) {
gc();
}
return mSize;
}
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
* SparseArray stores.
*/
public int keyAt(int index) {
if (mGarbage) {
gc();
}
return mKeys[index];
}
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the value from the <code>index</code>th key-value mapping that this
* SparseArray stores.
*/
@SuppressWarnings("unchecked")
public E valueAt(int index) {
if (mGarbage) {
gc();
}
return (E) mValues[index];
}
/**
* Given an index in the range <code>0...size()-1</code>, sets a new
* value for the <code>index</code>th key-value mapping that this
* SparseArray stores.
*/
public void setValueAt(int index, E value) {
if (mGarbage) {
gc();
}
mValues[index] = value;
}
/**
* Returns the index for which {@link #keyAt} would return the
* specified key, or a negative number if the specified
* key is not mapped.
*/
public int indexOfKey(int key) {
if (mGarbage) {
gc();
}
return ContainerHelpers.binarySearch(mKeys, mSize, key);
}
/**
* Returns an index for which {@link #valueAt} would return the
* specified key, or a negative number if no keys map to the
* specified value.
* <p>Beware that this is a linear search, unlike lookups by key,
* and that multiple keys can map to the same value and this will
* find only one of them.
* <p>Note also that unlike most collections' {@code indexOf} methods,
* this method compares values using {@code ==} rather than {@code equals}.
*/
public int indexOfValue(E value) {
if (mGarbage) {
gc();
}
for (int i = 0; i < mSize; i++)
if (mValues[i] == value)
return i;
return -1;
}
/**
* Removes all key-value mappings from this SparseArray.
*/
public void clear() {
int n = mSize;
Object[] values = mValues;
for (int i = 0; i < n; i++) {
values[i] = null;
}
mSize = 0;
mGarbage = false;
}
/**
* Puts a key/value pair into the array, optimizing for the case where
* the key is greater than all existing keys in the array.
*/
public void append(int key, E value) {
if (mSize != 0 && key <= mKeys[mSize - 1]) {
put(key, value);
return;
}
if (mGarbage && mSize >= mKeys.length) {
gc();
}
int pos = mSize;
if (pos >= mKeys.length) {
int n = idealIntArraySize(pos + 1);
int[] nkeys = new int[n];
Object[] nvalues = new Object[n];
// Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
mKeys = nkeys;
mValues = nvalues;
}
mKeys[pos] = key;
mValues[pos] = value;
mSize = pos + 1;
}
/**
* {@inheritDoc}
*
* <p>This implementation composes a string by iterating over its mappings. If
* this map contains itself as a value, the string "(this Map)"
* will appear in its place.
*/
@Override
public String toString() {
if (size() <= 0) {
return "{}";
}
StringBuilder buffer = new StringBuilder(mSize * 28);
buffer.append('{');
for (int i=0; i<mSize; i++) {
if (i > 0) {
buffer.append(", ");
}
int key = keyAt(i);
buffer.append(key);
buffer.append('=');
Object value = valueAt(i);
if (value != this) {
buffer.append(value);
} else {
buffer.append("(this Map)");
}
}
buffer.append('}');
return buffer.toString();
}
static int idealByteArraySize(int need) {
for (int i = 4; i < 32; i++)
if (need <= (1 << i) - 12)
return (1 << i) - 12;
return need;
}
static int idealBooleanArraySize(int need) {
return idealByteArraySize(need);
}
static int idealShortArraySize(int need) {
return idealByteArraySize(need * 2) / 2;
}
static int idealCharArraySize(int need) {
return idealByteArraySize(need * 2) / 2;
}
static int idealIntArraySize(int need) {
return idealByteArraySize(need * 4) / 4;
}
static int idealFloatArraySize(int need) {
return idealByteArraySize(need * 4) / 4;
}
static int idealObjectArraySize(int need) {
return idealByteArraySize(need * 4) / 4;
}
static int idealLongArraySize(int need) {
return idealByteArraySize(need * 8) / 8;
}
static class ContainerHelpers {
static final boolean[] EMPTY_BOOLEANS = new boolean[0];
static final int[] EMPTY_INTS = new int[0];
static final long[] EMPTY_LONGS = new long[0];
static final Object[] EMPTY_OBJECTS = new Object[0];
// This is Arrays.binarySearch(), but doesn't do any argument validation.
static int binarySearch(int[] array, int size, int value) {
int lo = 0;
int hi = size - 1;
while (lo <= hi) {
final int mid = (lo + hi) >>> 1;
final int midVal = array[mid];
if (midVal < value) {
lo = mid + 1;
} else if (midVal > value) {
hi = mid - 1;
} else {
return mid; // value found
}
}
return ~lo; // value not present
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,97 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import android.os.Bundle;
import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
/**
* The AccessibilityDelegate used by RecyclerView.
* <p>
* This class handles basic accessibility actions and delegates them to LayoutManager.
*/
public class RecyclerViewAccessibilityDelegate extends AccessibilityDelegateCompat {
final RecyclerView mRecyclerView;
public RecyclerViewAccessibilityDelegate(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
}
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
if (super.performAccessibilityAction(host, action, args)) {
return true;
}
if (mRecyclerView.getLayoutManager() != null) {
return mRecyclerView.getLayoutManager().performAccessibilityAction(action, args);
}
return false;
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
super.onInitializeAccessibilityNodeInfo(host, info);
info.setClassName(RecyclerView.class.getName());
if (mRecyclerView.getLayoutManager() != null) {
mRecyclerView.getLayoutManager().onInitializeAccessibilityNodeInfo(info);
}
}
@Override
public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(host, event);
event.setClassName(RecyclerView.class.getName());
if (host instanceof RecyclerView) {
RecyclerView rv = (RecyclerView) host;
if (rv.getLayoutManager() != null) {
rv.getLayoutManager().onInitializeAccessibilityEvent(event);
}
}
}
AccessibilityDelegateCompat getItemDelegate() {
return mItemDelegate;
}
final AccessibilityDelegateCompat mItemDelegate = new AccessibilityDelegateCompat() {
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
super.onInitializeAccessibilityNodeInfo(host, info);
if (mRecyclerView.getLayoutManager() != null) {
mRecyclerView.getLayoutManager().
onInitializeAccessibilityNodeInfoForItem(host, info);
}
}
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
if (super.performAccessibilityAction(host, action, args)) {
return true;
}
if (mRecyclerView.getLayoutManager() != null) {
return mRecyclerView.getLayoutManager().
performAccessibilityActionForItem(host, action, args);
}
return false;
}
};
}

View File

@ -1,94 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import android.view.View;
/**
* A helper class to do scroll offset calculations.
*/
class ScrollbarHelper {
/**
* @param startChild View closest to start of the list. (top or left)
* @param endChild View closest to end of the list (bottom or right)
*/
static int computeScrollOffset(RecyclerView.State state, OrientationHelper orientation,
View startChild, View endChild, RecyclerView.LayoutManager lm,
boolean smoothScrollbarEnabled, boolean reverseLayout) {
if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null ||
endChild == null) {
return 0;
}
final int minPosition = Math.min(lm.getPosition(startChild), lm.getPosition(endChild));
final int maxPosition = Math.max(lm.getPosition(startChild), lm.getPosition(endChild));
final int itemsBefore = reverseLayout
? Math.max(0, state.getItemCount() - maxPosition - 1)
: Math.max(0, minPosition - 1);
if (!smoothScrollbarEnabled) {
return itemsBefore;
}
final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild) -
orientation.getDecoratedStart(startChild));
final int itemRange = Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) + 1;
final float avgSizePerRow = (float) laidOutArea / itemRange;
return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding()
- orientation.getDecoratedStart(startChild)));
}
/**
* @param startChild View closest to start of the list. (top or left)
* @param endChild View closest to end of the list (bottom or right)
*/
static int computeScrollExtent(RecyclerView.State state, OrientationHelper orientation,
View startChild, View endChild, RecyclerView.LayoutManager lm,
boolean smoothScrollbarEnabled) {
if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null ||
endChild == null) {
return 0;
}
if (!smoothScrollbarEnabled) {
return Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) + 1;
}
final int extend = orientation.getDecoratedEnd(endChild)
- orientation.getDecoratedStart(startChild);
return Math.min(orientation.getTotalSpace(), extend);
}
/**
* @param startChild View closest to start of the list. (top or left)
* @param endChild View closest to end of the list (bottom or right)
*/
static int computeScrollRange(RecyclerView.State state, OrientationHelper orientation,
View startChild, View endChild, RecyclerView.LayoutManager lm,
boolean smoothScrollbarEnabled) {
if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null ||
endChild == null) {
return 0;
}
if (!smoothScrollbarEnabled) {
return state.getItemCount();
}
// smooth scrollbar enabled. try to estimate better.
final int laidOutArea = orientation.getDecoratedEnd(endChild) -
orientation.getDecoratedStart(startChild);
final int laidOutRange = Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild))
+ 1;
// estimate a size for full list.
return (int) ((float) laidOutArea / laidOutRange * state.getItemCount());
}
}

View File

@ -6,50 +6,48 @@ import android.graphics.Color;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
public class CustomView extends RelativeLayout{
final static String MATERIALDESIGNXML = "http://schemas.android.com/apk/res-auto";
final static String ANDROIDXML = "http://schemas.android.com/apk/res/android";
final int disabledBackgroundColor = Color.parseColor("#E2E2E2");
int beforeBackground;
// Indicate if user touched this view the last time
public boolean isLastTouch = false;
public class CustomView extends RelativeLayout {
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if(enabled)
setBackgroundColor(beforeBackground);
else
setBackgroundColor(disabledBackgroundColor);
invalidate();
}
boolean animation = false;
@Override
protected void onAnimationStart() {
super.onAnimationStart();
animation = true;
}
@Override
protected void onAnimationEnd() {
super.onAnimationEnd();
animation = false;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(animation)
invalidate();
}
final static String MATERIALDESIGNXML = "http://schemas.android.com/apk/res-auto";
final static String ANDROIDXML = "http://schemas.android.com/apk/res/android";
final int disabledBackgroundColor = Color.parseColor("#E2E2E2");
// Indicate if user touched this view the last time
public boolean isLastTouch = false;
int beforeBackground;
boolean animation = false;
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (enabled)
setBackgroundColor(beforeBackground);
else
setBackgroundColor(disabledBackgroundColor);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (animation)
invalidate();
}
@Override
protected void onAnimationStart() {
super.onAnimationStart();
animation = true;
}
@Override
protected void onAnimationEnd() {
super.onAnimationEnd();
animation = false;
}
}

View File

@ -8,176 +8,167 @@ import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
public class ProgressBarCircularIndeterminate extends CustomView {
final static String ANDROIDXML = "http://schemas.android.com/apk/res/android";
final static String ANDROIDXML = "http://schemas.android.com/apk/res/android";
int backgroundColor = Color.parseColor("#1E88E5");
int backgroundColor = Color.parseColor("#1E88E5");
float radius1 = 0;
float radius2 = 0;
int cont = 0;
boolean firstAnimationOver = false;
int arcD = 1;
int arcO = 0;
float rotateAngle = 0;
int limite = 0;
public ProgressBarCircularIndeterminate(Context context, AttributeSet attrs) {
super(context, attrs);
setAttributes(attrs);
public ProgressBarCircularIndeterminate(Context context, AttributeSet attrs) {
super(context, attrs);
setAttributes(attrs);
}
}
// Set atributtes of XML to View
protected void setAttributes(AttributeSet attrs) {
// Set atributtes of XML to View
protected void setAttributes(AttributeSet attrs) {
setMinimumHeight(Utils.dpToPx(32, getResources()));
setMinimumWidth(Utils.dpToPx(32, getResources()));
setMinimumHeight(Utils.dpToPx(32, getResources()));
setMinimumWidth(Utils.dpToPx(32, getResources()));
// Set background Color
// Color by resource
int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML, "background", -1);
if (bacgroundColor != -1) {
setBackgroundColor(ContextCompat.getColor(getContext(), bacgroundColor));
} else {
// Color by hexadecimal
int background = attrs.getAttributeIntValue(ANDROIDXML, "background", -1);
if (background != -1) {
setBackgroundColor(background);
} else {
setBackgroundColor(Color.parseColor("#1E88E5"));
}
}
// Set background Color
// Color by resource
int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML,
"background", -1);
if (bacgroundColor != -1) {
setBackgroundColor(getResources().getColor(bacgroundColor));
} else {
// Color by hexadecimal
int background = attrs.getAttributeIntValue(ANDROIDXML,
"background", -1);
if (background != -1)
setBackgroundColor(background);
else
setBackgroundColor(Color.parseColor("#1E88E5"));
}
setMinimumHeight(Utils.dpToPx(3, getResources()));
setMinimumHeight(Utils.dpToPx(3, getResources()));
}
}
// Set color of background
public void setBackgroundColor(int color) {
super.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
if (isEnabled()) {
beforeBackground = backgroundColor;
}
this.backgroundColor = color;
}
/**
* Make a dark color to ripple effect
*
* @return
*/
protected int makePressColor() {
int r = (this.backgroundColor >> 16) & 0xFF;
int g = (this.backgroundColor >> 8) & 0xFF;
int b = (this.backgroundColor >> 0) & 0xFF;
// r = (r+90 > 245) ? 245 : r+90;
// g = (g+90 > 245) ? 245 : g+90;
// b = (b+90 > 245) ? 245 : b+90;
return Color.argb(128, r, g, b);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!firstAnimationOver) {
drawFirstAnimation(canvas);
}
if (cont > 0) {
drawSecondAnimation(canvas);
}
invalidate();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (firstAnimationOver == false)
drawFirstAnimation(canvas);
if (cont > 0)
drawSecondAnimation(canvas);
invalidate();
}
}
/**
* Draw first animation of view
*
* @param canvas
*/
private void drawFirstAnimation(Canvas canvas) {
if (radius1 < getWidth() / 2) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(makePressColor());
radius1 = (radius1 >= getWidth() / 2) ? (float) getWidth() / 2 : radius1 + 1;
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius1, paint);
} else {
Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas temp = new Canvas(bitmap);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(makePressColor());
temp.drawCircle(getWidth() / 2, getHeight() / 2, getHeight() / 2, paint);
Paint transparentPaint = new Paint();
transparentPaint.setAntiAlias(true);
transparentPaint.setColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
if (cont >= 50) {
radius2 = (radius2 >= getWidth() / 2) ? (float) getWidth() / 2 : radius2 + 1;
} else {
radius2 = (radius2 >= getWidth() / 2 - Utils.dpToPx(4, getResources())) ?
(float) getWidth() / 2 - Utils.dpToPx(4, getResources()) : radius2 + 1;
}
temp.drawCircle(getWidth() / 2, getHeight() / 2, radius2, transparentPaint);
canvas.drawBitmap(bitmap, 0, 0, new Paint());
if (radius2 >= getWidth() / 2 - Utils.dpToPx(4, getResources())) {
cont++;
}
if (radius2 >= getWidth() / 2) {
firstAnimationOver = true;
}
}
}
float radius1 = 0;
float radius2 = 0;
int cont = 0;
boolean firstAnimationOver = false;
/**
* Draw second animation of view
*
* @param canvas
*/
private void drawSecondAnimation(Canvas canvas) {
if (arcO == limite) {
arcD += 6;
}
if (arcD >= 290 || arcO > limite) {
arcO += 6;
arcD -= 6;
}
if (arcO > limite + 290) {
limite = arcO;
arcO = limite;
arcD = 1;
}
rotateAngle += 4;
canvas.rotate(rotateAngle, getWidth() / 2, getHeight() / 2);
/**
* Draw first animation of view
*
* @param canvas
*/
private void drawFirstAnimation(Canvas canvas) {
if (radius1 < getWidth() / 2) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(makePressColor());
radius1 = (radius1 >= getWidth() / 2) ? (float) getWidth() / 2
: radius1 + 1;
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius1, paint);
} else {
Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(),
canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas temp = new Canvas(bitmap);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(makePressColor());
temp.drawCircle(getWidth() / 2, getHeight() / 2, getHeight() / 2,
paint);
Paint transparentPaint = new Paint();
transparentPaint.setAntiAlias(true);
transparentPaint.setColor(getResources().getColor(
android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
if (cont >= 50) {
radius2 = (radius2 >= getWidth() / 2) ? (float) getWidth() / 2
: radius2 + 1;
} else {
radius2 = (radius2 >= getWidth() / 2
- Utils.dpToPx(4, getResources())) ? (float) getWidth()
/ 2 - Utils.dpToPx(4, getResources()) : radius2 + 1;
}
temp.drawCircle(getWidth() / 2, getHeight() / 2, radius2,
transparentPaint);
canvas.drawBitmap(bitmap, 0, 0, new Paint());
if (radius2 >= getWidth() / 2 - Utils.dpToPx(4, getResources()))
cont++;
if (radius2 >= getWidth() / 2)
firstAnimationOver = true;
}
}
Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas temp = new Canvas(bitmap);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(backgroundColor);
// temp.drawARGB(0, 0, 0, 255);
temp.drawArc(new RectF(0, 0, getWidth(), getHeight()), arcO, arcD, true, paint);
Paint transparentPaint = new Paint();
transparentPaint.setAntiAlias(true);
transparentPaint.setColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
temp.drawCircle(getWidth() / 2, getHeight() / 2, (getWidth() / 2)
- Utils.dpToPx(4, getResources()), transparentPaint);
int arcD = 1;
int arcO = 0;
float rotateAngle = 0;
int limite = 0;
canvas.drawBitmap(bitmap, 0, 0, new Paint());
}
/**
* Draw second animation of view
*
* @param canvas
*/
private void drawSecondAnimation(Canvas canvas) {
if (arcO == limite)
arcD += 6;
if (arcD >= 290 || arcO > limite) {
arcO += 6;
arcD -= 6;
}
if (arcO > limite + 290) {
limite = arcO;
arcO = limite;
arcD = 1;
}
rotateAngle += 4;
canvas.rotate(rotateAngle, getWidth() / 2, getHeight() / 2);
Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(),
canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas temp = new Canvas(bitmap);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(backgroundColor);
// temp.drawARGB(0, 0, 0, 255);
temp.drawArc(new RectF(0, 0, getWidth(), getHeight()), arcO, arcD,
true, paint);
Paint transparentPaint = new Paint();
transparentPaint.setAntiAlias(true);
transparentPaint.setColor(getResources().getColor(
android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
temp.drawCircle(getWidth() / 2, getHeight() / 2, (getWidth() / 2)
- Utils.dpToPx(4, getResources()), transparentPaint);
canvas.drawBitmap(bitmap, 0, 0, new Paint());
}
// Set color of background
public void setBackgroundColor(int color) {
super.setBackgroundColor(getResources().getColor(
android.R.color.transparent));
if (isEnabled())
beforeBackground = backgroundColor;
this.backgroundColor = color;
}
/**
* Make a dark color to ripple effect
*
* @return
*/
protected int makePressColor() {
int r = (this.backgroundColor >> 16) & 0xFF;
int g = (this.backgroundColor >> 8) & 0xFF;
int b = (this.backgroundColor >> 0) & 0xFF;
// r = (r+90 > 245) ? 245 : r+90;
// g = (g+90 > 245) ? 245 : g+90;
// b = (b+90 > 245) ? 245 : b+90;
return Color.argb(128, r, g, b);
}
}

View File

@ -5,30 +5,30 @@ import android.util.TypedValue;
import android.view.View;
public class Utils {
/**
* Convert Dp to Pixel
*/
public static int dpToPx(float dp, Resources resources){
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.getDisplayMetrics());
return (int) px;
}
public static int getRelativeTop(View myView) {
/**
* Convert Dp to Pixel
*/
public static int dpToPx(float dp, Resources resources) {
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.getDisplayMetrics());
return (int) px;
}
public static int getRelativeTop(View myView) {
// if (myView.getParent() == myView.getRootView())
if(myView.getId() == android.R.id.content)
return myView.getTop();
else
return myView.getTop() + getRelativeTop((View) myView.getParent());
}
public static int getRelativeLeft(View myView) {
if (myView.getId() == android.R.id.content)
return myView.getTop();
else
return myView.getTop() + getRelativeTop((View) myView.getParent());
}
public static int getRelativeLeft(View myView) {
// if (myView.getParent() == myView.getRootView())
if(myView.getId() == android.R.id.content)
return myView.getLeft();
else
return myView.getLeft() + getRelativeLeft((View) myView.getParent());
}
if (myView.getId() == android.R.id.content)
return myView.getLeft();
else
return myView.getLeft() + getRelativeLeft((View) myView.getParent());
}
}

View File

@ -1,238 +0,0 @@
package com.gh.base;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.Application;
import android.content.Context;
import android.os.Process;
import android.support.v4.util.ArrayMap;
import android.util.Log;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.gh.common.util.DataUtils;
import com.gh.common.util.HttpsUtils;
import com.gh.common.util.TokenUtils;
import com.gh.common.util.Utils;
import com.umeng.message.IUmengRegisterCallback;
import com.umeng.message.PushAgent;
import com.umeng.message.UTrack;
import com.xiaomi.channel.commonutils.logger.LoggerInterface;
import com.xiaomi.mipush.sdk.Logger;
import com.xiaomi.mipush.sdk.MiPushClient;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class AppController extends Application {
//public class AppController extends TinkerApplication {
public static final String TAG = AppController.class.getSimpleName();
// TODO xiaomi push appid 2882303761517352993
public static final String APP_ID = "2882303761517564447";
// TODO xiaomi push appkey 5451735292993
public static final String APP_KEY = "5761756481447";
private static AppController mInstance;
private static ArrayMap<String, Object> objectMap = new ArrayMap<>();
private ArrayList<Activity> list = new ArrayList<>();
private boolean isFinish = false;
//快传文件发送单线程
public static Executor FILE_SENDER_EXECUTOR = Executors.newSingleThreadExecutor();
//快传文件发送主要的线程池
public static Executor MAIN_EXECUTOR = Executors.newFixedThreadPool(5);
// public AppController() {
// super(ShareConstants.TINKER_ENABLE_ALL, "com.gh.base.AppControllerLike",
// "com.tencent.tinker.loader.TinkerLoader", false);
// }
@Override
public void onCreate() {
super.onCreate();
//初始化Fresco
Fresco.initialize(this);
DataUtils.init(this);
HttpsUtils.initHttpsUrlConnection(this);
AppUncaHandler uncaHandler = new AppUncaHandler(this);
Thread.setDefaultUncaughtExceptionHandler(uncaHandler);
mInstance = this;
// 注册push服务注册成功后会向GHPushMessageReceiver发送广播
// 可以从GHPushMessageReceiver的onCommandResult方法中MiPushCommandMessage对象参数中获取注册信息
if (shouldInit()) {
MiPushClient.registerPush(this, APP_ID, APP_KEY);
}
LoggerInterface newLogger = new LoggerInterface() {
@Override
public void setTag(String tag) {
// ignore
}
@Override
public void log(String content, Throwable t) {
Log.d(TAG, content, t);
}
@Override
public void log(String content) {
Log.d(TAG, content);
}
};
Logger.setLogger(this, newLogger);
//友盟推送
final PushAgent mPushAgent = PushAgent.getInstance(this);
//注册推送服务每次调用register方法都会回调该接口
mPushAgent.register(new IUmengRegisterCallback() {
@Override
public void onSuccess(String deviceToken) {
//注册成功会返回device token
Utils.log("deviceToken::" + deviceToken);
//设置别名
mPushAgent.addExclusiveAlias(TokenUtils.getDeviceId(getApplicationContext())
, "GHDID", new UTrack.ICallBack() {
@Override
public void onMessage(boolean b, String s) {
Utils.log("ExclusiveAlias::" + b + "==" + s);
}
});
}
@Override
public void onFailure(String s, String s1) {
Utils.log("deviceToken::" + "注册失败");
}
});
// 友盟推送数据处理
mPushAgent.setNotificationClickHandler(new GHUmengNotificationClickHandler());
// // 监听屏幕状态广播
// if (shouldInit()) {
// UnlockScreenReceiver unlockScreenReceiver = new UnlockScreenReceiver();
// IntentFilter intentFilter = new IntentFilter();
// intentFilter.addAction(Intent.ACTION_SCREEN_ON);
// intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
// registerReceiver(unlockScreenReceiver, intentFilter);
//
// // 用户App运行数据统计服务
// Intent intent = new Intent(getApplicationContext(), AppStaticService.class);
// startService(intent);
//
// AppRunTimeDao dao = new AppRunTimeDao(getApplicationContext());
// for (AppRunTimeInfo appRunTimeInfo : dao.getAll()) {
// Utils.log(appRunTimeInfo.getPackageName() + "====1111=====" + appRunTimeInfo.getRunTime());
// }
// }
}
public static void put(String key, Object object) {
if (objectMap == null) {
objectMap = new ArrayMap<>();
}
objectMap.put(key, object);
}
public static Object get(String key, boolean isRemove) {
if (objectMap == null) {
return null;
}
if (isRemove) {
return objectMap.remove(key);
} else {
return objectMap.get(key);
}
}
public static void remove(String key) {
if (objectMap == null) {
return;
}
objectMap.remove(key);
}
/**
* Activity关闭时删除Activity列表中的Activity对象
*/
public void removeActivity(Activity a) {
if (!isFinish) {
list.remove(a);
Utils.log("remove = " + a.getClass().getSimpleName());
}
}
/**
* 向Activity列表中添加Activity对象
*/
public void addActivity(Activity a) {
Utils.log("add = " + a.getClass().getSimpleName());
list.add(a);
}
/**
* 关闭Activity列表中的所有Activity
*/
public void finishActivity() {
isFinish = true;
for (int i = list.size() - 1; i >= 0; i--) {
Activity activity = list.get(i);
if (null != activity) {
Utils.log("finish = " + activity.getClass().getSimpleName());
activity.finish();
}
}
// 杀死该应用进程
Process.killProcess(Process.myPid());
}
public static String getProcessName(Context cxt, int pid) {
ActivityManager am = (ActivityManager) cxt
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
if (runningApps == null) {
return null;
}
for (RunningAppProcessInfo procInfo : runningApps) {
if (procInfo.pid == pid) {
return procInfo.processName;
}
}
return null;
}
public static synchronized AppController getInstance() {
return mInstance;
}
private boolean shouldInit() {
ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
List<RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
String mainProcessName = getPackageName();
Log.d(TAG, mainProcessName);
int myPid = Process.myPid();
for (RunningAppProcessInfo info : processInfos) {
if (info.pid == myPid && mainProcessName.equals(info.processName)) {
return true;
}
}
return false;
}
}

View File

@ -1,51 +0,0 @@
//package com.gh.base;
//
//
//import android.annotation.TargetApi;
//import android.app.Application;
//import android.content.Context;
//import android.content.Intent;
//import android.os.Build;
//import android.support.multidex.MultiDex;
//
//import com.tencent.tinker.lib.listener.DefaultPatchListener;
//import com.tencent.tinker.lib.listener.PatchListener;
//import com.tencent.tinker.lib.patch.AbstractPatch;
//import com.tencent.tinker.lib.patch.UpgradePatch;
//import com.tencent.tinker.lib.reporter.DefaultLoadReporter;
//import com.tencent.tinker.lib.reporter.DefaultPatchReporter;
//import com.tencent.tinker.lib.reporter.LoadReporter;
//import com.tencent.tinker.lib.reporter.PatchReporter;
//import com.tencent.tinker.lib.tinker.TinkerInstaller;
//import com.tencent.tinker.loader.app.DefaultApplicationLike;
//
//public class AppControllerLike extends DefaultApplicationLike {
//
// public AppControllerLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag,
// long applicationStartElapsedTime, long applicationStartMillisTime,
// Intent tinkerResultIntent) {
// super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime,
// applicationStartMillisTime, tinkerResultIntent);
// }
//
// @Override
// public void onBaseContextAttached(Context base) {
// super.onBaseContextAttached(base);
// MultiDex.install(base);
//
// LoadReporter loadReporter = new DefaultLoadReporter(getApplication());
// PatchReporter patchReporter = new DefaultPatchReporter(getApplication());
// PatchListener patchListener = new DefaultPatchListener(getApplication());
// AbstractPatch upgradePatchProcessor = new UpgradePatch();
//
// TinkerInstaller.install(this, loadReporter, patchReporter, patchListener,
// AppTinkerResultService.class, upgradePatchProcessor);
//// TinkerInstaller.install(this);
// }
//
// @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
// public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) {
// getApplication().registerActivityLifecycleCallbacks(callback);
// }
//
//}

View File

@ -1,29 +0,0 @@
//package com.gh.base;
//
//import com.gh.common.util.Utils;
//import com.tencent.tinker.lib.service.DefaultTinkerResultService;
//import com.tencent.tinker.lib.service.PatchResult;
//import com.tencent.tinker.lib.util.TinkerServiceInternals;
//
//import java.io.File;
//
//
//public class AppTinkerResultService extends DefaultTinkerResultService {
//
// @Override
// public void onPatchResult(PatchResult result) {
// if (result == null) {
// return;
// }
// Utils.log(result);
//
// //first, we want to kill the recover process
// TinkerServiceInternals.killTinkerPatchServiceProcess(getApplicationContext());
//
// if (result.isSuccess) {
// Utils.log("Tinkder Success");
// deleteRawPatchFile(new File(result.rawPatchFilePath));
// }
// }
//
//}

View File

@ -1,128 +0,0 @@
package com.gh.base;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import com.gh.common.constant.Config;
import com.gh.common.util.DataCollectionUtils;
import com.gh.common.util.FileUtils;
import com.gh.gamecenter.SplashScreenActivity;
import com.tencent.stat.StatService;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class AppUncaHandler implements UncaughtExceptionHandler {
private UncaughtExceptionHandler mDefaultHandler;
private AppController appController;
public AppUncaHandler(AppController appController) {
// 获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
this.appController = appController;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(appController.getApplicationContext(),
"\"光环助手\"发生错误", Toast.LENGTH_SHORT).show();
Looper.loop();
}
}.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 防止重复奔溃导致助手一直重启20秒内不做处理
SharedPreferences sp = appController.getApplicationContext().getSharedPreferences(
Config.PREFERENCE, Context.MODE_PRIVATE);
long time = sp.getLong("last_restart_time", 0);
if (System.currentTimeMillis() - time > 20 * 1000) {
sp.edit().putLong("last_restart_time", System.currentTimeMillis()).apply();
Intent intent = new Intent(appController.getApplicationContext(),
SplashScreenActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent restartIntent = PendingIntent.getActivity(
appController.getApplicationContext(), 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 退出程序并重启
AlarmManager mgr = (AlarmManager) appController
.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,
restartIntent); // 1秒钟后重启应用
}
appController.finishActivity();
}
}
// 保存log到本地
private void saveLog(Throwable ex) {
String errorMsg = Log.getStackTraceString(ex);
// MTA主动上传错误
StatService.reportError(appController.getApplicationContext(), errorMsg);
// 上传错误数据
DataCollectionUtils.uploadError(appController.getApplicationContext(), errorMsg);
// 保存到本地
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
File file = new File(FileUtils.getLogPath(appController.getApplicationContext(),
format.format(new Date()) + "_gh_assist" + ".log"));
FileWriter writer = null;
try {
file.createNewFile();
writer = new FileWriter(file);
writer.write(errorMsg);
writer.flush();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
*
* @param ex
* @return true:如果处理了该异常信息;否则返回false.
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
saveLog(ex);
return true;
}
}

View File

@ -0,0 +1,141 @@
package com.gh.base;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.util.Log;
import com.gh.common.constant.Config;
import com.gh.common.util.DataCollectionUtils;
import com.gh.gamecenter.SplashScreenActivity;
import com.lightgame.config.CommonDebug;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.AppManager;
import com.lightgame.utils.Utils;
import com.tencent.stat.StatService;
import com.tendcloud.tenddata.TCAgent;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class AppUncaughtHandler implements UncaughtExceptionHandler {
private Context mContext;
public AppUncaughtHandler(Context context) {
// 获取系统默认的UncaughtException处理器
mContext = context;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Utils.toast(mContext.getApplicationContext(), "\"光环助手\"发生错误");
Looper.loop();
}
});
saveLocalLog(mContext, ex);
restart(mContext);
}
public static void restart(final Context context) {
// 防止重复奔溃导致助手一直重启20秒内不做处理
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
long curTime = System.currentTimeMillis();
long time = sp.getLong("last_restart_time", 0);
if (curTime - time > 20 * 1000) {
sp.edit().putLong("last_restart_time", curTime).apply();
Intent intent = new Intent(context, SplashScreenActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 退出程序并重启
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, curTime + 3000, restartIntent); // 1秒钟后重启应用
}
//error restart
// System.exit(2);
AppManager.getInstance().finishAllActivity();
}
// 保存log到本地
public static void saveLocalLog(Context context, Throwable ex) {
String errorMsg = Log.getStackTraceString(ex);
Config.setExceptionMsg(context, errorMsg);
// 保存到本地
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
File file = new File(FileUtils.getLogPath(context.getApplicationContext(),
format.format(new Date()) + "_gh_assist" + ".log"));
FileWriter writer = null;
try {
file.createNewFile();
writer = new FileWriter(file);
writer.write(errorMsg);
writer.flush();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 下次应用启动再上报
*
* @param context
* @param throwable
*/
public static void reportException(Context context, Throwable throwable) {
CommonDebug.logMethodWithParams(context, "ERRMSG", throwable);
// 上传错误数据
try {
DataCollectionUtils.uploadError(context, Log.getStackTraceString(throwable));
} catch (Exception e) {
}
// MTA主动上传错误
try {
StatService.reportException(context, throwable);
} catch (Exception e) {
}
// //bugly 作为默认处理异常的类库,已经上报了,此处不重复上报
// try {
// CrashReport.postCatchedException(throwable);
// } catch (Exception e) {
// }
//talkingdata
try {
TCAgent.onError(context, throwable);
} catch (Exception e) {
}
}
}

View File

@ -1,214 +1,190 @@
package com.gh.base;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.gh.common.constant.Config;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.FileUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.RunningUtils;
import com.gh.common.util.ShareUtils;
import com.gh.common.util.Utils;
import com.gh.download.DownloadManager;
import com.gh.common.util.StringUtils;
import com.gh.gamecenter.LoginActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.eventbus.EBShowDialog;
import com.gh.gamecenter.listener.OnCallBackListener;
import com.gh.gamecenter.manager.SystemBarTintManager;
import com.gh.gamecenter.manager.SystemBarTintManager.SystemBarConfig;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.AppManager;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import butterknife.ButterKnife;
import de.greenrobot.event.EventBus;
import pub.devrel.easypermissions.EasyPermissions;
public class BaseActivity extends Activity implements OnCallBackListener {
import static com.gh.common.util.EntranceUtils.KEY_DATA;
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
private SystemBarTintManager tintManager;
public abstract class BaseActivity extends BaseAppCompatToolBarActivity implements EasyPermissions.PermissionCallbacks{
protected String entrance;
protected String mEntrance;
private boolean mIsPause;
private boolean isPause;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init(mContentView);
AppManager.getInstance().addActivity(this);
EventBus.getDefault().register(this);
mEntrance = getIntent().getStringExtra(KEY_ENTRANCE);
if (getIntent().getBundleExtra(KEY_DATA) != null) {
mEntrance = getIntent().getBundleExtra(KEY_DATA).getString(KEY_ENTRANCE);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Utils.log(this.getClass().getSimpleName());
AppController.getInstance().addActivity(this);
EventBus.getDefault().register(this);
entrance = getIntent().getStringExtra("entrance");
if (getIntent().getBundleExtra("data") != null) {
entrance = getIntent().getBundleExtra("data").getString("entrance");
}
}
@Override
protected boolean onNavigationIconClicked() {
return false;
}
protected void init(View contentView, String title) {
init(contentView);
TextView actionbar_tv_title = (TextView) findViewById(R.id.actionbar_tv_title);
actionbar_tv_title.setText(title);
}
private void init(View contentView) {
setContentView(contentView);
protected void init(View contentView) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
setTheme(R.style.AppTheme);
setTranslucentStatus(true);
tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
tintManager.setStatusBarTintColor(Color.BLACK);
SystemBarConfig config = tintManager.getConfig();
contentView.setPadding(0, config.getPixelInsetTop(false), 0,
config.getPixelInsetBottom());
}
ButterKnife.bind(this);
setContentView(contentView);
View back = findViewById(R.id.actionbar_rl_back);
if (back != null)
back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
ButterKnife.bind(this);
protected void initTitle(String title) {
TextView actionbar_tv_title = (TextView) findViewById(R.id.actionbar_tv_title);
actionbar_tv_title.setText(title);
// setNavigationTitle(title);
}
int actionbar_height = getSharedPreferences(Config.PREFERENCE,
Context.MODE_PRIVATE).getInt("actionbar_height",
DisplayUtils.dip2px(getApplicationContext(), 55));
public void toast(String msg) {
Utils.toast(this, msg);
}
RelativeLayout reuse_actionbar = (RelativeLayout) findViewById(R.id.reuse_actionbar);
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, actionbar_height);
reuse_actionbar.setLayoutParams(lparams);
public void toast(int msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
findViewById(R.id.actionbar_rl_back).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
//如果是游戏分享newsTitle默认为空
public void showShare(String url, String gameName, String icon, String newsTitle, ArrayList<String> tag, boolean isToolsBox) {
protected SystemBarTintManager getTintManager() {
return tintManager;
}
//判断是否是官方版
boolean isPlugin = false;
if (tag != null) {
for (String s : tag) {
if (!"官方版".equals(s)) {
isPlugin = true;
}
}
}
@Override
public void finish() {
super.finish();
AppController.getInstance().removeActivity(this);
}
ShareUtils.getInstance(this).showShareWindows(getWindow().getDecorView(), url, gameName, icon, newsTitle, isPlugin, true, isToolsBox);
public void toast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
public void toast(int msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
@TargetApi(19)
protected void setTranslucentStatus(boolean status) {
Window window = getWindow();
WindowManager.LayoutParams winParams = window.getAttributes();
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if (status) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
window.setAttributes(winParams);
}
//如果是游戏分享newsTitle默认为空
public void showShare(String url, String gameName, String icon, String newsTitle, ArrayList<String> tag) {
//判断是否是官方版
boolean isPlugin = false;
if (tag != null){
for (String s : tag) {
if (!"官方版".equals(s)){
isPlugin = true;
}
}
}
ShareUtils.getInstance(this).showShareWindows(new View(this), url, gameName, icon, newsTitle, isPlugin, true);
if (newsTitle == null) {
DataUtils.onEvent(this, "内容分享", gameName);
} else {
DataUtils.onEvent(this, "内容分享", newsTitle);
}
}
if (newsTitle == null) {
DataUtils.onEvent(this, "内容分享", gameName);
} else {
DataUtils.onEvent(this, "内容分享", newsTitle);
}
}
public void onEventMainThread(final EBShowDialog showDialog) {
if (!isPause && this.getClass().getName().equals(RunningUtils.getTopActivity(this))) {
if ("hijack".equals(showDialog.getType())) {
DialogUtils.showQqSessionDialog(this, null);// 建议用户联系客服
} else if ("plugin".equals(showDialog.getType())) {
DialogUtils.showPluginDialog(this, new DialogUtils.ConfiremListener(){
@Override
public void onConfirem() {
if (FileUtils.isEmptyFile(showDialog.getPath())) {
Toast.makeText(BaseActivity.this, "解析包出错(可能被误删了),请重新下载", Toast.LENGTH_SHORT).show();
} else {
startActivity(PackageUtils.getUninstallIntent(BaseActivity.this, showDialog.getPath()));
}
}
});
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Override
protected void onPause() {
super.onPause();
DataUtils.onPause(this);
isPause = true;
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(final EBShowDialog showDialog) {
//TODO 改为缓存到UI可见时才调用参考beier-assist
if (!mIsPause && this.getClass().getName().equals(RunningUtils.getTopActivity(this))) {
if ("hijack".equals(showDialog.getType())) {
DialogUtils.showQqSessionDialog(this, "2586716223");// 建议用户联系客服
} else if ("plugin".equals(showDialog.getType())) {
DialogUtils.showPluginDialog(this, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
if (FileUtils.isEmptyFile(showDialog.getPath())) {
Utils.toast(BaseActivity.this, getString(R.string.install_failure_hint));
} else {
startActivity(PackageUtils.getUninstallIntent(BaseActivity.this, showDialog.getPath()));
}
}
});
} else if ("loginException".equals(showDialog.getType())) {
try {
JSONObject object = new JSONObject(showDialog.getPath());
JSONObject device = object.getJSONObject("device");
String manufacturer = device.getString("manufacturer");
String model = device.getString("model");
DialogUtils.showAlertDialog(this, "你的账号已在另外一台设备登录"
, StringUtils.buildString("", manufacturer, " - ", model, "")
, "知道了", "重新登录"
, null, new DialogUtils.CancelListener() {
@Override
public void onCancel() {
startActivity(LoginActivity.getIntent(BaseActivity.this, false));
}
});
} catch (JSONException e) {
e.printStackTrace();
}
@Override
protected void onResume() {
super.onResume();
DataUtils.onResume(this);
isPause = false;
DownloadManager.getInstance(this).initGameMap();
}
@Override
public void loadDone() {
}
}
}
}
@Override
public void loadDone(Object obj) {
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
AppManager.getInstance().finishActivity(this);
}
}
@Override
protected void onPause() {
super.onPause();
// DataUtils.onPause(this);
mIsPause = true;
}
@Override
public void loadError() {
@Override
protected void onResume() {
super.onResume();
// DataUtils.onResume(this);
mIsPause = false;
// DownloadManager.getInstance(this).initGameMap();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void loadEmpty() {
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
}
}
@Override
public void onPermissionsGranted(int requestCode, List<String> perms) {
}
}

View File

@ -0,0 +1,46 @@
package com.gh.base;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import com.gh.gamecenter.R;
import com.lightgame.BaseAppCompatActivity;
/**
* Created by csheng on 15-10-12.
*/
public abstract class BaseAppCompatToolBarActivity extends BaseAppCompatActivity {
private Toolbar mToolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initToolbar();
}
private void initToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar_navigation);
if (mToolbar != null) {
setSupportActionBar(mToolbar);
mToolbar.addView(View.inflate(this, R.layout.reuse_actionbar, null));
getSupportActionBar().setHomeButtonEnabled(false);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
return onNavigationIconClicked();
}
return super.onOptionsItemSelected(item);
}
protected abstract boolean onNavigationIconClicked();
}

View File

@ -1,392 +0,0 @@
package com.gh.base;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.FileUtils;
import com.gh.common.util.GameUtils;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.ShareUtils;
import com.gh.common.view.DownloadDialog;
import com.gh.download.DataWatcher;
import com.gh.download.DownloadEntity;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.eventbus.EBPackage;
import com.gh.gamecenter.manager.PackageManager;
import com.tencent.tauth.Tencent;
/**
* Created by Administrator on 2016/9/19.
* 游戏详情、新闻详情基类(控制底部下载栏)
*/
public abstract class BaseDetailActivity extends BaseActivity implements View.OnClickListener {
protected TextView actionbar_tv_title;
protected RecyclerView detail_rv_show;
protected LinearLayout detail_ll_bottom;
protected TextView detail_tv_download;
protected ProgressBar detail_pb_progressbar;
protected TextView detail_tv_per;
protected LinearLayout reuse_ll_loading;
protected LinearLayout reuse_no_connection;
protected LinearLayout reuse_none_data;
protected TextView reuse_tv_none_data;
protected ImageView iv_share;
protected GameEntity gameEntity;
protected DownloadEntity mDownloadEntity;
protected String entrance;
protected String name;
protected String title;
protected String downloadAddWord;
protected String downloadOffText;
protected Handler handler = new Handler();
private DataWatcher dataWatcher = new DataWatcher() {
@Override
public void onDataChanged(DownloadEntity downloadEntity) {
if (gameEntity != null && gameEntity.getApk().size() == 1) {
String url = gameEntity.getApk().get(0).getUrl();
if (url.equals(downloadEntity.getUrl())) {
if (!"pause".equals(DownloadManager.getInstance(BaseDetailActivity.this).
getStatus(downloadEntity.getUrl()))) {
mDownloadEntity = downloadEntity;
invalidate();
}
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
entrance = getIntent().getStringExtra("entrance");
if (getIntent().getBundleExtra("data") != null) {
entrance = getIntent().getBundleExtra("data").getString("entrance");
}
View contentView = View.inflate(this, R.layout.activity_detail, null);
// 添加分享图标
iv_share = new ImageView(this);
iv_share.setImageResource(R.drawable.ic_share);
iv_share.setOnClickListener(this);
iv_share.setVisibility(View.GONE);
iv_share.setPadding(DisplayUtils.dip2px(this, 13),DisplayUtils.dip2px(this, 11)
,DisplayUtils.dip2px(this, 11),DisplayUtils.dip2px(this, 13));
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
DisplayUtils.dip2px(this, 48), DisplayUtils.dip2px(this, 48));
params.addRule( RelativeLayout.CENTER_VERTICAL);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT );
RelativeLayout reuse_actionbar = (RelativeLayout) contentView.findViewById(
R.id.reuse_actionbar);
reuse_actionbar.addView(iv_share, params);
init(contentView);
actionbar_tv_title = (TextView) findViewById(R.id.actionbar_tv_title);
detail_rv_show = (RecyclerView) findViewById(R.id.detail_rv_show);
detail_ll_bottom = (LinearLayout) findViewById(R.id.detail_ll_bottom);
detail_tv_download = (TextView) findViewById(R.id.detail_tv_download);
detail_pb_progressbar = (ProgressBar) findViewById(R.id.detail_pb_progressbar);
detail_tv_per = (TextView) findViewById(R.id.detail_tv_per);
reuse_ll_loading = (LinearLayout) findViewById(R.id.reuse_ll_loading);
reuse_no_connection = (LinearLayout) findViewById(R.id.reuse_no_connection);
reuse_none_data = (LinearLayout) findViewById(R.id.reuse_none_data);
reuse_tv_none_data = (TextView) findViewById(R.id.reuse_tv_none_data);
detail_ll_bottom.setOnClickListener(this);
detail_tv_download.setOnClickListener(this);
detail_pb_progressbar.setOnClickListener(this);
detail_tv_per.setOnClickListener(this);
reuse_no_connection.setOnClickListener(this);
}
//接收QQ或者QQ空间分享回调
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == com.tencent.connect.common.Constants.REQUEST_QQ_SHARE
|| requestCode == com.tencent.connect.common.Constants.REQUEST_QZONE_SHARE) {
Tencent.onActivityResultData(requestCode, resultCode, data, ShareUtils.getInstance(this).QqShareListener);
}
}
@Override
protected void onResume() {
super.onResume();
if (gameEntity != null
&& gameEntity.getApk() != null
&& gameEntity.getApk().size() == 1) {
initDownload(true);
}
DownloadManager.getInstance(this).addObserver(dataWatcher);
}
@Override
protected void onPause() {
super.onPause();
DownloadManager.getInstance(this).removeObserver(dataWatcher);
}
protected void initDownload(boolean isCheck) {
if (Config.isShow(this)) {
detail_ll_bottom.setVisibility(View.VISIBLE);
detail_rv_show.setPadding(0, 0, 0,
DisplayUtils.dip2px(getApplicationContext(), 60));
} else {
detail_ll_bottom.setVisibility(View.GONE);
detail_rv_show.setPadding(0, 0, 0, 0);
}
if (gameEntity != null && "光环助手".equals(gameEntity.getName())) {
detail_ll_bottom.setVisibility(View.GONE);
detail_rv_show.setPadding(0, 0, 0, 0);
} else if (gameEntity == null || gameEntity.getApk().isEmpty()) {
detail_tv_download.setVisibility(View.VISIBLE);
detail_pb_progressbar.setVisibility(View.GONE);
detail_tv_per.setVisibility(View.GONE);
if (TextUtils.isEmpty(downloadOffText)) {
detail_tv_download.setText("暂无下载");
} else {
detail_tv_download.setText(downloadOffText);
}
detail_tv_download.setBackgroundResource(R.drawable.game_item_btn_pause_style);
detail_tv_download.setTextColor(0xFF999999);
detail_tv_download.setClickable(false);
} else {
detail_tv_download.setVisibility(View.VISIBLE);
detail_pb_progressbar.setVisibility(View.GONE);
detail_tv_per.setVisibility(View.GONE);
boolean isInstalled = false;
if (gameEntity.getApk() != null && gameEntity.getApk().size() == 1
&& PackageManager.isInstalled(gameEntity.getApk().get(0).getPackageName())) {
isInstalled = true;
}
if (isInstalled) {
if (PackageManager.isCanUpdate(gameEntity.getId(), gameEntity.getApk().get(0).getPackageName())) {
if (TextUtils.isEmpty(downloadAddWord)) {
detail_tv_download.setBackgroundResource(
R.drawable.game_item_btn_download_style);
detail_tv_download.setText(String.format("更新《%s》",
gameEntity.getName()));
} else {
detail_tv_download.setBackgroundResource(
R.drawable.game_item_btn_download_style);
detail_tv_download.setText(String.format("更新《%s》%s",
gameEntity.getName(), downloadAddWord));
}
} else {
if (gameEntity.getTag() != null && gameEntity.getTag().size() != 0
&& !TextUtils.isEmpty(gameEntity.getApk().get(0).getGhVersion())
&& !PackageUtils.isSignature(this, gameEntity.getApk().get(0).getPackageName())) {
if (TextUtils.isEmpty(downloadAddWord)) {
detail_tv_download.setBackgroundResource(
R.drawable.game_item_btn_plugin_style);
detail_tv_download.setText(String.format("插件化《%s》",
gameEntity.getName()));
} else {
detail_tv_download.setBackgroundResource(
R.drawable.game_item_btn_plugin_style);
detail_tv_download.setText(String.format("插件化《%s》%s",
gameEntity.getName(), downloadAddWord));
}
} else {
if (TextUtils.isEmpty(downloadAddWord)) {
detail_tv_download.setBackgroundResource(
R.drawable.game_item_btn_launch_style);
detail_tv_download.setText(String.format("启动《%s》",
gameEntity.getName()));
} else {
detail_tv_download.setBackgroundResource(
R.drawable.game_item_btn_launch_style);
detail_tv_download.setText(String.format("启动《%s》%s",
gameEntity.getName(), downloadAddWord));
}
}
}
} else {
String status = GameUtils.getDownloadBtnText(this, gameEntity);
if ("插件化".equals(status)) {
detail_tv_download.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else if ("打开".equals(status)) {
detail_tv_download.setBackgroundResource(R.drawable.game_item_btn_launch_style);
} else {
detail_tv_download.setBackgroundResource(R.drawable.game_item_btn_download_style);
}
if (TextUtils.isEmpty(downloadAddWord)) {
detail_tv_download.setText(String.format(status + "《%s》",
gameEntity.getName()));
} else {
detail_tv_download.setText(String.format(status + "《%s》%s",
gameEntity.getName(), downloadAddWord));
}
}
}
if (isCheck && gameEntity != null
&& gameEntity.getApk() != null
&& gameEntity.getApk().size() == 1) {
String url = gameEntity.getApk().get(0).getUrl();
DownloadEntity downloadEntity = DownloadManager.getInstance(getApplicationContext()).get(url);
if (downloadEntity != null) {
mDownloadEntity = downloadEntity;
detail_tv_download.setVisibility(View.GONE);
detail_pb_progressbar.setVisibility(View.VISIBLE);
detail_tv_per.setVisibility(View.VISIBLE);
invalidate();
}
}
}
private void invalidate() {
detail_pb_progressbar.setProgress((int) (mDownloadEntity.getPercent() * 10));
detail_tv_per.setTextColor(0xFFFFFFFF);
switch (mDownloadEntity.getStatus()) {
case downloading:
case pause:
case timeout:
case neterror:
case waiting:
detail_tv_per.setText("下载中");
break;
case done:
detail_tv_per.setText("安装");
if (mDownloadEntity.isPluggable()
&& PackageManager.isInstalled(mDownloadEntity.getPackageName())) {
detail_pb_progressbar.setProgressDrawable(getResources().getDrawable(R.drawable.progressbar_plugin_radius_style));
} else {
detail_pb_progressbar.setProgressDrawable(getResources().getDrawable(R.drawable.progressbar_normal_radius_style));
}
break;
case cancel:
case hijack:
case notfound:
initDownload(false);
break;
default:
break;
}
}
// 接收下载被删除消息
public void onEvent(EBDownloadStatus status) {
if ("delete".equals(status.getStatus())
&& gameEntity != null
&& gameEntity.getApk() != null
&& gameEntity.getApk().size() == 1) {
String url = gameEntity.getApk().get(0).getUrl();
if (url.equals(status.getUrl())) {
initDownload(false);
}
}
}
// 接受安装、卸载消息
public void onEventMainThread(EBPackage busFour) {
if (gameEntity != null
&& gameEntity.getApk() != null
&& gameEntity.getApk().size() == 1) {
String packageName = gameEntity.getApk().get(0).getPackageName();
if (packageName.equals(busFour.getPackageName())) {
initDownload(false);
}
}
}
@Override
public void onClick(View v) {
if (v == detail_tv_download) {
if (gameEntity != null && !gameEntity.getApk().isEmpty()) {
if (gameEntity.getApk().size() == 1) {
if (NetworkUtils.isWifiConnected(this)) {
download();
} else {
DialogUtils.showDownloadDialog(this, new DialogUtils.ConfiremListener() {
@Override
public void onConfirem() {
download();
}
});
}
} else {
DownloadDialog.getInstance(this).showPopupWindow(v, gameEntity, entrance, name + ":" + title);
}
} else {
toast("稍等片刻~!游戏正在上传中...");
}
} else if (v == detail_pb_progressbar || v == detail_tv_per) {
String str = detail_tv_per.getText().toString();
if ("下载中".equals(str)) {
Intent intent = new Intent(this, DownloadManagerActivity.class);
intent.putExtra("currentItem", 1);
intent.putExtra("url", gameEntity.getApk().get(0).getUrl());
intent.putExtra("entrance", entrance + "+(" + name + "[" + title + "])");
startActivity(intent);
} else if ("安装".equals(str)) {
PackageUtils.launchSetup(this, mDownloadEntity.getPath());
}
}
}
private void download() {
String str = detail_tv_download.getText().toString();
if (str.contains("启动")) {
DataUtils.onGameLaunchEvent(this, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), name);
PackageUtils.launchApplicationByPackageName(this, gameEntity.getApk().get(0).getPackageName());
} else {
String method;
if (str.contains("更新")) {
method = "更新";
} else if (str.contains("插件化")) {
method = "插件化";
} else {
method = "下载";
}
ApkEntity apkEntity = gameEntity.getApk().get(0);
String msg = FileUtils.isCanDownload(this, apkEntity.getSize());
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(this, gameEntity.getName(), apkEntity.getPlatform(), entrance, "下载开始");
DownloadManager.createDownload(this, apkEntity, gameEntity, method, entrance, name + ":" + title);
detail_tv_download.setVisibility(View.GONE);
detail_pb_progressbar.setVisibility(View.VISIBLE);
detail_tv_per.setVisibility(View.VISIBLE);
detail_pb_progressbar.setProgress(0);
detail_tv_per.setText("0.0%");
DownloadManager.getInstance(BaseDetailActivity.this).putStatus(apkEntity.getUrl(), "downloading");
} else {
toast(msg);
}
}
}
}

View File

@ -1,93 +0,0 @@
package com.gh.base;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.gh.gamecenter.listener.OnCallBackListener;
import butterknife.ButterKnife;
import de.greenrobot.event.EventBus;
/**
* Created by LGT on 2016/9/4.
* Fragment 基类
*/
public class BaseFragment extends Fragment implements OnCallBackListener {
protected View view;
protected Handler handler = new Handler();
protected boolean isEverpause;
protected void init(int layout) {
view = View.inflate(getActivity(), layout, null);
ButterKnife.bind(this, view);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isEverpause = false;
EventBus.getDefault().register(this);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
if(container != null){
container.removeView(view);
}
return view;
}
public boolean isEverpause() {
return isEverpause;
}
@Override
public void onPause() {
super.onPause();
isEverpause = true;
}
@Override
public void onResume() {
super.onResume();
isEverpause = false;
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Override
public void loadDone() {
}
@Override
public void loadDone(Object obj) {
}
@Override
public void loadError() {
}
@Override
public void loadEmpty() {
}
}

View File

@ -1,186 +0,0 @@
package com.gh.base;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.gh.common.constant.Config;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.FileUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.RunningUtils;
import com.gh.common.util.ShareUtils;
import com.gh.common.util.Utils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.R;
import com.gh.gamecenter.eventbus.EBShowDialog;
import com.gh.gamecenter.manager.SystemBarTintManager;
import com.gh.gamecenter.manager.SystemBarTintManager.SystemBarConfig;
import java.util.ArrayList;
import butterknife.ButterKnife;
import de.greenrobot.event.EventBus;
public class BaseFragmentActivity extends FragmentActivity {
protected String entrance;
private boolean isPause;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Utils.log(this.getClass().getSimpleName());
AppController.getInstance().addActivity(this);
EventBus.getDefault().register(this);
entrance = getIntent().getStringExtra("entrance");
if (getIntent().getBundleExtra("data") != null) {
entrance = getIntent().getBundleExtra("data").getString("entrance");
}
}
public void init(View contentView, String title) {
init(contentView);
TextView actionbar_tv_title = (TextView) findViewById(R.id.actionbar_tv_title);
actionbar_tv_title.setText(title);
}
public void init(View contentView) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
setTheme(R.style.AppTheme);
setTranslucentStatus(true);
SystemBarTintManager tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
tintManager.setStatusBarTintColor(Color.BLACK);
SystemBarConfig config = tintManager.getConfig();
contentView.setPadding(0, config.getPixelInsetTop(false), 0,
config.getPixelInsetBottom());
}
setContentView(contentView);
ButterKnife.bind(this);
int actionbar_height = getSharedPreferences(Config.PREFERENCE,
Context.MODE_PRIVATE).getInt("actionbar_height",
DisplayUtils.dip2px(getApplicationContext(), 48));
RelativeLayout reuse_actionbar = (RelativeLayout) findViewById(R.id.reuse_actionbar);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, actionbar_height);
reuse_actionbar.setLayoutParams(params);
findViewById(R.id.actionbar_rl_back).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
@Override
public void finish() {
super.finish();
AppController.getInstance().removeActivity(this);
}
public void toast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
public void toast(int msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
@TargetApi(19)
protected void setTranslucentStatus(boolean status) {
Window window = getWindow();
WindowManager.LayoutParams winParams = window.getAttributes();
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if (status) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
window.setAttributes(winParams);
}
//如果是游戏分享newsTitle默认为空
public void showShare(String url, String gameName, String icon, String newsTitle, ArrayList<String> tag) {
//判断是否是官方版
boolean isPlugin = false;
if (tag != null){
for (String s : tag) {
if (!"官方版".equals(s)){
isPlugin = true;
}
}
}
ShareUtils.getInstance(this).showShareWindows(new View(this), url, gameName, icon, newsTitle, isPlugin, true);
if (newsTitle == null){
DataUtils.onEvent(this, "内容分享", gameName);
}else {
DataUtils.onEvent(this, "内容分享", newsTitle);
}
}
public void onEventMainThread(final EBShowDialog showDialog) {
if (!isPause && this.getClass().getName().equals(RunningUtils.getTopActivity(this))) {
if ("hijack".equals(showDialog.getType())) {
DialogUtils.showQqSessionDialog(this, null);// 建议用户联系客服
} else if ("plugin".equals(showDialog.getType())) {
DialogUtils.showPluginDialog(this, new DialogUtils.ConfiremListener(){
@Override
public void onConfirem() {
if (FileUtils.isEmptyFile(showDialog.getPath())) {
Toast.makeText(BaseFragmentActivity.this, "解析包出错(可能被误删了),请重新下载", Toast.LENGTH_SHORT).show();
} else {
startActivity(PackageUtils.getUninstallIntent(BaseFragmentActivity.this, showDialog.getPath()));
}
}
});
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Override
protected void onPause() {
super.onPause();
DataUtils.onPause(this);
isPause = true;
}
@Override
protected void onResume() {
super.onResume();
DataUtils.onResume(this);
isPause = false;
DownloadManager.getInstance(this).initGameMap();
}
}

View File

@ -0,0 +1,43 @@
package com.gh.base;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import butterknife.ButterKnife;
/**
* 目前仅提供butterknife bind方法
*
* @author CsHeng
* @Date 16/06/2017
* @Time 9:55 AM
*/
public abstract class BaseRecyclerViewHolder<T> extends RecyclerView.ViewHolder implements View.OnClickListener {
private T data;
private OnListClickListener mListClickListener;
public BaseRecyclerViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
/**
* 具体的设置监听在childViewHolder 设置
* @param itemView
* @param data 一般情况下只传列表数据
* @param listClickListener 列表事件接口
*/
public BaseRecyclerViewHolder(View itemView, T data, OnListClickListener listClickListener) {
this(itemView);
this.data = data;
this.mListClickListener = listClickListener;
}
@Override
public void onClick(View view) {
mListClickListener.onListClick(view, getAdapterPosition(), data);
}
}

View File

@ -0,0 +1,64 @@
package com.gh.base;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;
import com.gh.common.util.DataUtils;
import com.gh.download.DownloadManager;
/**
* 1、写点针对生命周期的统计代码
* 2、写点通用的逻辑
* 3、接口解耦
*
* @author CsHeng
* @Date 09/05/2017
* @Time 6:22 PM
*/
public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallbacks {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
DataUtils.onResume(activity);
try {
// 初始化gameMap
DownloadManager.getInstance(activity).initGameMap();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onActivityPaused(Activity activity) {
DataUtils.onPause(activity);
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}

View File

@ -13,17 +13,17 @@ import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;
import android.util.Log;
import android.widget.RemoteViews;
import com.gh.common.util.ClassUtils;
import com.gh.common.util.FileUtils;
import com.gh.common.util.AppDebugConfig;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.RunningUtils;
import com.gh.common.util.TokenUtils;
import com.gh.common.util.Utils;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SplashScreenActivity;
import com.halo.assistant.HaloApp;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
import com.xiaomi.mipush.sdk.ErrorCode;
import com.xiaomi.mipush.sdk.MiPushClient;
import com.xiaomi.mipush.sdk.MiPushCommandMessage;
@ -41,6 +41,20 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import static com.gh.common.util.EntranceUtils.ENTRANCE_MIPUSH;
import static com.gh.common.util.EntranceUtils.HOST_ARTICLE;
import static com.gh.common.util.EntranceUtils.HOST_GAME;
import static com.gh.common.util.EntranceUtils.HOST_WEB;
import static com.gh.common.util.EntranceUtils.HOST_COLUMN;
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
import static com.gh.common.util.EntranceUtils.KEY_GAMEID;
import static com.gh.common.util.EntranceUtils.KEY_ID;
import static com.gh.common.util.EntranceUtils.KEY_NEWSID;
import static com.gh.common.util.EntranceUtils.KEY_TARGET;
import static com.gh.common.util.EntranceUtils.KEY_TO;
import static com.gh.common.util.EntranceUtils.KEY_TYPE;
import static com.gh.common.util.EntranceUtils.KEY_URL;
/**
* 1、PushMessageReceiver是个抽象类该类继承了BroadcastReceiver。
* 2、需要将自定义的DemoMessageReceiver注册在AndroidManifest.xml文件中 <receiver
@ -59,265 +73,250 @@ import java.util.Locale;
* 6、DemoMessageReceiver的onCommandResult方法用来接收客户端向服务器发送命令后的响应结果
* 7、DemoMessageReceiver的onReceiveRegisterResult方法用来接收客户端向服务器发送注册命令后的响应结果
* 8、以上这些方法运行在非UI线程中
*
*
* @author mayixiang
* //TODO 请勿更改此类路径,若需更改时请注意更改./libraries/MiPush/proguard-library.txt混淆对应配置
*/
public class GHPushMessageReceiver extends PushMessageReceiver {
private String mAlias;
@Override
public void onReceivePassThroughMessage(Context context,
MiPushMessage message) {
// 1判断notifyid是否为4
try {
if (message.getNotifyId() == 4) {
JSONObject jsonObject = new JSONObject(message.getContent());
Utils.log(jsonObject.toString());
String channel = jsonObject.getString("channel");
Utils.log("channel = " + channel);
// 1判断渠道号是否一致或是否为ALL
String TD_CHANNEL_ID = (String) PackageUtils.getMetaData(context, context.getPackageName(), "TD_CHANNEL_ID");
if ("ALL".equals(channel) || channel.equalsIgnoreCase(TD_CHANNEL_ID)) {
String type = jsonObject.getString("type");
Utils.log("type = " + type);
if ("NEWS".equals(type)) {
// 新闻推送
JSONArray jsonArray = jsonObject.getJSONArray("package");
ArrayMap<String, Boolean> map = getInstalledMapFromLocal(context);
for (int i = 0; i < jsonArray.length(); i++) {
Boolean b = map.get(jsonArray.getString(i));
if (b != null) {
// 显示推送的消息
showNotification(context, jsonObject, 0);
break;
}
}
} else if ("PLUGIN_UPDATE".equals(type)) {
// 插件更新推送
JSONArray jsonArray = jsonObject.getJSONArray("apk");
ArrayMap<String, Boolean> map = getInstalledMapFromLocal(context);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject apk = jsonArray.getJSONObject(i);
String packageName = apk.getString("package");
Boolean b = map.get(packageName);
if (b != null) {
// 判断是否gh_version是否相同
String gh_version = (String) PackageUtils
.getMetaData(context, packageName, "gh_version");
if (gh_version != null) {
gh_version = gh_version.substring(2);
// 判断gh_version是否相同
if (gh_version.equals(apk.getString("gh_version"))) {
// 判断version是否相同
String version = PackageUtils.getVersionByPackage(
context, packageName);
if (apk.getString("version").equals(version)) {
// 版本相同,无需显示插件更新,继续查看是否有可更新的游戏包
continue;
}
}
}
// 显示推送的消息
showNotification(context, jsonObject, 1);
break;
}
}
} else if ("NEW_GAME".equals(type)) {
// 新游推送
showNotification(context, jsonObject, 2);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
private String mAlias;
Log.v(AppController.TAG, "onReceivePassThroughMessage is called. " + message.toString());
}
@Override
public void onReceivePassThroughMessage(Context context, MiPushMessage message) {
if (BuildConfig.DEBUG) {
AppDebugConfig.logMethodWithParams(this, message);
}
// 1判断notifyid是否为4
try {
//TODO what is magic number 4?
if (message.getNotifyId() == 4) {
JSONObject jsonObject = new JSONObject(message.getContent());
Utils.log(jsonObject.toString());
String channel = jsonObject.getString("channel");
Utils.log("channel = " + channel);
private void showNotification(Context context, JSONObject jsonObject, int id) throws JSONException {
Intent intent = new Intent();
intent.setAction("com.gh.gamecenter.NOTIFICATION");
intent.putExtra("notifyId", id);
intent.putExtra("notifyData", jsonObject.toString());
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, id,
intent, PendingIntent.FLAG_ONE_SHOT);
// 1判断渠道号是否一致或是否为ALL
String packageChannel = HaloApp.getInstance().getChannel();
if ("ALL".equals(channel) || channel.equalsIgnoreCase(packageChannel)) {
String type = jsonObject.getString(KEY_TYPE);
Utils.log("type = " + type);
JSONArray jsonArray;
ArrayMap<String, Boolean> map;
switch (type) {
case "NEWS":
// 新闻推送
jsonArray = jsonObject.getJSONArray("package");
map = getInstalledMapFromLocal(context);
for (int i = 0; i < jsonArray.length(); i++) {
Boolean b = map.get(jsonArray.getString(i));
if (b != null) {
// 显示推送的消息
showNotification(context, jsonObject, 0);
break;
}
}
break;
case "PLUGIN_UPDATE":
// 插件更新推送
jsonArray = jsonObject.getJSONArray("apk");
map = getInstalledMapFromLocal(context);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject apk = jsonArray.getJSONObject(i);
String packageName = apk.getString("package");
Boolean b = map.get(packageName);
if (b != null) {
// 判断是否gh_version是否相同
String gh_version = (String) PackageUtils
.getMetaData(context, packageName, "gh_version");
if (gh_version != null) {
gh_version = gh_version.substring(2);
// 判断gh_version是否相同
if (gh_version.equals(apk.getString("gh_version"))) {
// 判断version是否相同
String version = PackageUtils.getVersionByPackage(context, packageName);
if (apk.getString("version").equals(version)) {
// 版本相同,无需显示插件更新,继续查看是否有可更新的游戏包
continue;
}
}
}
// 显示推送的消息
showNotification(context, jsonObject, 1);
break;
}
}
break;
case "NEW_GAME":
// 新游推送
showNotification(context, jsonObject, 2);
break;
default:
break;
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
NotificationManager nManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
private ArrayMap<String, Boolean> getInstalledMapFromLocal(Context context) {
ArrayMap<String, Boolean> map = new ArrayMap<>();
ArrayList<String> list = getAllPackageName(context);
for (String str : list) {
map.put(str, true);
}
return map;
}
Notification notification = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.logo)
.setTicker(jsonObject.getString("pushTitle"))
.setContentTitle(jsonObject.getString("pushTitle"))
.setContentText(jsonObject.getString("pushDesc"))
.setContentIntent(pendingIntent).build();
private void showNotification(Context context, JSONObject jsonObject, int id) throws JSONException {
Intent intent = new Intent();
intent.setAction("com.gh.gamecenter.NOTIFICATION");
intent.putExtra("notifyId", id);
intent.putExtra("notifyData", jsonObject.toString());
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, id, intent, PendingIntent.FLAG_ONE_SHOT);
RemoteViews remoteViews = null;
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.MANUFACTURER.equals("Meizu")
&& (Build.MODEL.startsWith("m")
|| Build.MODEL.startsWith("MX"))) {
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.notification_meizu);
SimpleDateFormat format = new SimpleDateFormat("HH:mm",
Locale.getDefault());
remoteViews.setTextViewText(R.id.time, format.format(new Date()));
} else if (Build.MANUFACTURER.equals("Xiaomi")
&& (Build.MODEL.startsWith("MI")
|| Build.MODEL.startsWith("HM")
|| Build.MODEL.startsWith("Redmi"))) {
// 小米系统
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.notification_xiaomi);
SimpleDateFormat format = new SimpleDateFormat("ah:mm",
Locale.getDefault());
remoteViews.setTextViewText(R.id.time, format.format(new Date()));
} else if (Build.MANUFACTURER.equals("HUAWEI")) {
// 华为系统
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.notification_huawei);
}
RemoteViews remoteViews = null;
String url = jsonObject.getString("icon");
String path = context.getCacheDir() + File.separator + url.substring(url.lastIndexOf("/") + 1);
int result = FileUtils.downloadFile(url, path);
if (result != 200) {
// 下载出错使用光环logo
path = null;
}
if (Build.MANUFACTURER.equals("Meizu") &&
(Build.MODEL.startsWith("m") || Build.MODEL.startsWith("MX"))) {
remoteViews = new RemoteViews(context.getPackageName(), R.layout.notification_meizu);
SimpleDateFormat format = new SimpleDateFormat("HH:mm", Locale.getDefault());
remoteViews.setTextViewText(R.id.time, format.format(new Date()));
} else if (Build.MANUFACTURER.equals("Xiaomi") &&
(Build.MODEL.startsWith("MI") || Build.MODEL.startsWith("HM") || Build.MODEL.startsWith("Redmi"))) {
// 小米系统
remoteViews = new RemoteViews(context.getPackageName(), R.layout.notification_xiaomi);
SimpleDateFormat format = new SimpleDateFormat("ah:mm", Locale.getDefault());
remoteViews.setTextViewText(R.id.time, format.format(new Date()));
} else if (Build.MANUFACTURER.equals("HUAWEI")) {
// 华为系统
remoteViews = new RemoteViews(context.getPackageName(), R.layout.notification_huawei);
}
if (remoteViews != null) {
if (path == null) {
remoteViews.setImageViewBitmap(R.id.icon, BitmapFactory.decodeResource(context.getResources(), R.drawable.logo));
} else {
remoteViews.setImageViewBitmap(R.id.icon, BitmapFactory.decodeFile(path));
}
remoteViews.setTextViewText(R.id.title, jsonObject.getString("pushTitle"));
remoteViews.setTextViewText(R.id.intro, jsonObject.getString("pushDesc"));
notification.contentView = remoteViews;
} else {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.logo_black)
.setTicker(jsonObject.getString("pushTitle"))
.setContentTitle(jsonObject.getString("pushTitle"))
.setContentText(jsonObject.getString("pushDesc"))
.setContentIntent(pendingIntent);
if (path == null) {
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.logo));
} else {
builder.setLargeIcon(BitmapFactory.decodeFile(path));
}
notification = builder.build();
}
String url = jsonObject.getString("icon");
String path = context.getCacheDir() + File.separator + url.substring(url.lastIndexOf("/") + 1);
int result = FileUtils.downloadFile(url, path);
if (result != 200) {
// 下载出错使用光环logo
path = null;
}
notification.defaults = Notification.DEFAULT_SOUND;// 添加系统默认声音
notification.flags |= Notification.FLAG_AUTO_CANCEL; // FLAG_AUTO_CANCEL表明当通知被用户点击时通知将被清除。
nManager.notify(((int) System.currentTimeMillis() / 1000), notification);// 通过通知管理器来发起通知。如果id不同则每click在status哪里增加一个提示
}
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setTicker(jsonObject.getString("pushTitle"))
.setContentTitle(jsonObject.getString("pushTitle"))
.setContentText(jsonObject.getString("pushDesc"))
.setContentIntent(pendingIntent)
.setDefaults(Notification.DEFAULT_SOUND) // 添加系统默认声音
.setAutoCancel(true); // FLAG_AUTO_CANCEL表明当通知被用户点击时通知将被清除。
private ArrayMap<String, Boolean> getInstalledMapFromLocal(Context context) {
ArrayMap<String, Boolean> map = new ArrayMap<>();
ArrayList<String> list = getAllPackageName(context);
for (String str : list) {
map.put(str, true);
}
return map;
}
if (remoteViews != null) {
if (path == null) {
remoteViews.setImageViewBitmap(R.id.icon, BitmapFactory.decodeResource(context.getResources(), R.drawable.logo));
} else {
remoteViews.setImageViewBitmap(R.id.icon, BitmapFactory.decodeFile(path));
}
remoteViews.setTextViewText(R.id.title, jsonObject.getString("pushTitle"));
remoteViews.setTextViewText(R.id.intro, jsonObject.getString("pushDesc"));
private ArrayList<String> getAllPackageName(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = context.getPackageManager()
.getInstalledPackages(0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
list.add(packageInfo.packageName);
}
}
return list;
}
builder.setSmallIcon(R.drawable.logo);
builder.setCustomContentView(remoteViews);
@Override
public void onNotificationMessageClicked(Context context, MiPushMessage message) {
Log.v(AppController.TAG, "onNotificationMessageClicked is called. " + message.toString());
} else {
builder.setSmallIcon(R.drawable.logo_black);
if (path == null) {
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.logo));
} else {
builder.setLargeIcon(BitmapFactory.decodeFile(path));
}
}
try {
String content = message.getContent();
JSONObject response = new JSONObject(content);
Bundle bundle = new Bundle();
bundle.putString("entrance", "(小米推送)");
String type = response.getString("type");
if ("article".equals(type)) {
bundle.putString("to", "NewsDetailActivity");
bundle.putString("newsId", response.getString("target"));
} else if ("game".equals(type)) {
bundle.putString("to", "GameDetailActivity");
bundle.putString("gameId", response.getString("target"));
} else if ("column".equals(type)) {
bundle.putString("to", "SubjectActivity");
bundle.putString("id", response.getString("target"));
} else if ("web".equals(type)) {
bundle.putString("to", "WebActivity");
bundle.putString("url", response.getString("target"));
}
if (RunningUtils.isRunning(context)) {
// 应用正在运行,前台或后台
String to = bundle.getString("to");
if (!TextUtils.isEmpty(to)) {
Class<?> clazz = ClassUtils.forName(to);
if (clazz != null) {
Intent intent1 = new Intent(context, clazz);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent1.putExtra("data", bundle);
context.startActivity(intent1);
}
}
} else {
// 应用未在运行
Intent intent1 = new Intent(context, SplashScreenActivity.class);
intent1.setAction(Intent.ACTION_MAIN);
intent1.addCategory(Intent.CATEGORY_LAUNCHER);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent1.putExtra("data", bundle);
context.startActivity(intent1);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
nManager.notify(((int) System.currentTimeMillis() / 1000), builder.build());// 通过通知管理器来发起通知。如果id不同则每click在status哪里增加一个提示
}
@Override
public void onNotificationMessageArrived(Context context,
MiPushMessage message) {
Log.v(AppController.TAG, "onNotificationMessageArrived is called. "
+ message.toString());
}
private ArrayList<String> getAllPackageName(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = context.getPackageManager().getInstalledPackages(0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
list.add(packageInfo.packageName);
}
}
return list;
}
@Override
public void onCommandResult(Context context, MiPushCommandMessage message) {
Log.v(AppController.TAG, "onCommandResult is called. "
+ message.toString());
@Override
public void onNotificationMessageClicked(Context context, MiPushMessage message) {
if (BuildConfig.DEBUG) {
AppDebugConfig.logMethodWithParams(this, message);
}
try {
String content = message.getContent();
JSONObject response = new JSONObject(content);
Bundle bundle = new Bundle();
bundle.putString(KEY_ENTRANCE, ENTRANCE_MIPUSH);
String type = response.getString(KEY_TYPE);
String target = response.getString(KEY_TARGET);
String command = message.getCommand();
List<String> arguments = message.getCommandArguments();
switch (type) {
case HOST_ARTICLE:
bundle.putString(KEY_TO, "NewsDetailActivity");
bundle.putString(KEY_NEWSID, target);
break;
case HOST_GAME:
bundle.putString(KEY_TO, "GameDetailActivity");
bundle.putString(KEY_GAMEID, target);
break;
case HOST_COLUMN:
bundle.putString(KEY_TO, "SubjectActivity");
bundle.putString(KEY_ID, target);
break;
case HOST_WEB:
bundle.putString(KEY_TO, "WebActivity");
bundle.putString(KEY_URL, target);
break;
}
EntranceUtils.jumpActivity(context, bundle);
} catch (JSONException e) {
e.printStackTrace();
}
}
if (MiPushClient.COMMAND_SET_ALIAS.equals(command)) {
if (message.getResultCode() == ErrorCode.SUCCESS) {
mAlias = arguments.get(0);
}
}
@Override
public void onNotificationMessageArrived(Context context, MiPushMessage message) {
if (BuildConfig.DEBUG) {
AppDebugConfig.logMethodWithParams(this, message);
}
}
if (TextUtils.isEmpty(mAlias)) {
//添加别名
MiPushClient.setAlias(context, TokenUtils.getDeviceId(context), null);
}
}
@Override
public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {
if (BuildConfig.DEBUG) {
AppDebugConfig.logMethodWithParams(this, message);
}
}
@Override
public void onReceiveRegisterResult(Context context,
MiPushCommandMessage message) {
Log.v(AppController.TAG, "onReceiveRegisterResult is called. "
+ message.toString());
}
@Override
public void onCommandResult(Context context, MiPushCommandMessage message) {
if (BuildConfig.DEBUG) {
AppDebugConfig.logMethodWithParams(this, message);
}
String command = message.getCommand();
List<String> arguments = message.getCommandArguments();
if (MiPushClient.COMMAND_SET_ALIAS.equals(command)) {
if (message.getResultCode() == ErrorCode.SUCCESS) {
mAlias = arguments.get(0);
}
}
if (TextUtils.isEmpty(mAlias)) {
//添加别名
MiPushClient.setAlias(context, TokenUtils.getDeviceId(context), null);
}
}
}

View File

@ -1,14 +1,9 @@
package com.gh.base;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import com.gh.common.util.ClassUtils;
import com.gh.common.util.RunningUtils;
import com.gh.gamecenter.MainActivity;
import com.gh.gamecenter.SplashScreenActivity;
import com.gh.common.util.EntranceUtils;
import com.umeng.message.UmengNotificationClickHandler;
import com.umeng.message.entity.UMessage;
@ -18,54 +13,39 @@ import org.json.JSONObject;
public class GHUmengNotificationClickHandler extends UmengNotificationClickHandler {
@Override
public void launchApp(Context context, UMessage uMessage) {
@Override
public void launchApp(Context context, UMessage uMessage) {
// super.launchApp(context, uMessage);
try {
String content = uMessage.extra.get("data");
JSONObject response = new JSONObject(content);
Bundle bundle = new Bundle();
bundle.putString("entrance", "(友盟推送)");
String type = response.getString("type");
if ("article".equals(type)) {
bundle.putString("to", "NewsDetailActivity");
bundle.putString("newsId", response.getString("target"));
} else if ("game".equals(type)) {
bundle.putString("to", "GameDetailActivity");
bundle.putString("gameId", response.getString("target"));
} else if ("column".equals(type)) {
bundle.putString("to", "SubjectActivity");
bundle.putString("id", response.getString("target"));
} else if ("web".equals(type)) {
bundle.putString("to", "WebActivity");
bundle.putString("url", response.getString("target"));
}
if (RunningUtils.isRunning(context)
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(context))) {
// 应用正在运行,前台或后台
String to = bundle.getString("to");
if (!TextUtils.isEmpty(to)) {
Class<?> clazz = ClassUtils.forName(to);
if (clazz != null) {
Intent intent1 = new Intent(context, clazz);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent1.putExtra("data", bundle);
context.startActivity(intent1);
}
}
} else {
// 应用未在运行
Intent intent1 = new Intent(context, SplashScreenActivity.class);
intent1.setAction(Intent.ACTION_MAIN);
intent1.addCategory(Intent.CATEGORY_LAUNCHER);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent1.putExtra("data", bundle);
context.startActivity(intent1);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
try {
String content = uMessage.extra.get(EntranceUtils.KEY_DATA);
JSONObject response = new JSONObject(content);
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG);
String type = response.getString(EntranceUtils.KEY_TYPE);
String target = response.getString(EntranceUtils.KEY_TARGET);
switch (type) {
case EntranceUtils.HOST_ARTICLE:
bundle.putString(EntranceUtils.KEY_TO, "NewsDetailActivity");
bundle.putString(EntranceUtils.KEY_NEWSID, target);
break;
case EntranceUtils.HOST_GAME:
bundle.putString(EntranceUtils.KEY_TO, "GameDetailActivity");
bundle.putString(EntranceUtils.KEY_GAMEID, target);
break;
case EntranceUtils.HOST_COLUMN:
bundle.putString(EntranceUtils.KEY_TO, "SubjectActivity");
bundle.putString(EntranceUtils.KEY_ID, target);
break;
case EntranceUtils.HOST_WEB:
bundle.putString(EntranceUtils.KEY_TO, "WebActivity");
bundle.putString(EntranceUtils.KEY_URL, target);
break;
}
EntranceUtils.jumpActivity(context, bundle);
} catch (JSONException e) {
e.printStackTrace();
}
}
}

View File

@ -1,277 +0,0 @@
package com.gh.base;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.common.util.DataCollectionUtils;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.ConcernActivity;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SearchActivity;
import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.manager.PackageManager;
import java.util.ArrayList;
import de.greenrobot.event.EventBus;
/**
* Created by LGT on 2016/9/9.
* 工具栏 搜索控制
*/
public class HomeFragment extends Fragment implements View.OnClickListener {
protected View view;
protected Handler handler = new Handler();
private TextView downloadHint;
private TextView searchHint;
private AlphaAnimation mAlphaAnimation;
private ArrayList<String> hintList;
private int hintIndex;
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (hintList != null && !hintList.isEmpty()) {
outState.putStringArrayList("hint", hintList);
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
hintList = savedInstanceState.getStringArrayList("hint");
}
hintIndex = 0;
view = View.inflate(getActivity(), R.layout.fragment_home, null);
SharedPreferences sp = getActivity().getSharedPreferences(
Config.PREFERENCE, Context.MODE_PRIVATE);
LinearLayout home_actionbar = (LinearLayout) view.findViewById(R.id.home_actionbar);
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,DisplayUtils.dip2px(getActivity(), 55));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
int top = DisplayUtils.getStatusBarHeight(getResources());
home_actionbar.setPadding(0, top, 0, 0);
lparams.height += top;
}
home_actionbar.setLayoutParams(lparams);
initActionBar();
final ScaleAnimation scaleAnimation = new ScaleAnimation(0.4f, 1.0f, 0.4f, 1.0f
, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(500);
mAlphaAnimation = new AlphaAnimation(1f, 0.2f);
mAlphaAnimation.setDuration(300);
mAlphaAnimation.setStartOffset(5000);
scaleAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (mAlphaAnimation != null) {
searchHint.setAnimation(mAlphaAnimation);
mAlphaAnimation.start();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mAlphaAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
// 切换数据
if (hintIndex > hintList.size() - 1) {
hintIndex = 0;
}
searchHint.setHint(hintList.get(hintIndex));
hintIndex ++;
if (scaleAnimation != null) {
searchHint.setAnimation(scaleAnimation);
scaleAnimation.start();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
if (hintList != null && hintList.size() > 0) {
if (hintList.size() > 1) {
searchHint.setAnimation(mAlphaAnimation);
} else {
String hint = hintList.get(0);
searchHint.setHint(hint);
}
}
EventBus.getDefault().register(this);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
if (container != null) {
container.removeView(view);
}
return view;
}
private void initActionBar() {
view.findViewById(R.id.actionbar_rl_download).setOnClickListener(this);
view.findViewById(R.id.actionbar_iv_search).setOnClickListener(this);
view.findViewById(R.id.actionbar_notification).setOnClickListener(this);
view.findViewById(R.id.actionbar_search_rl).setOnClickListener(this);
if (Config.isShow(getActivity())) {
view.findViewById(R.id.actionbar_rl_download).setVisibility(View.VISIBLE);
} else {
view.findViewById(R.id.actionbar_rl_download).setVisibility(View.GONE);
}
downloadHint = (TextView) view.findViewById(R.id.action_tip);
int updateSize = PackageManager.getUpdateListSize();
int downloadSize = DownloadManager.getInstance(getActivity()).getAll().size();
if (downloadSize != 0) {
downloadHint.setVisibility(View.VISIBLE);
downloadHint.setText(String.valueOf(downloadSize));
} else if (updateSize != 0) {
downloadHint.setVisibility(View.VISIBLE);
downloadHint.setText(String.valueOf(updateSize));
} else {
downloadHint.setVisibility(View.GONE);
}
searchHint = (TextView) view.findViewById(R.id.actionbar_search_input);
searchHint.setOnClickListener(this);
}
@Override
public void onClick(View v) {
final int id = v.getId();
if (id == R.id.actionbar_rl_download) {
DataUtils.onEvent(getActivity(), "主页", "下载图标");
DataCollectionUtils.uploadClick(getActivity(), "下载图标", "主页");
Intent intent = new Intent(getActivity(), DownloadManagerActivity.class);
intent.putExtra("entrance", "(工具栏)");
intent.putExtra("currentItem", 0);
startActivity(intent);
} else if (id == R.id.actionbar_iv_search) {
DataUtils.onEvent(getActivity(), "主页", "搜索图标");
DataCollectionUtils.uploadClick(getActivity(), "搜索图标", "主页");
Intent intent = new Intent(getActivity(), SearchActivity.class);
intent.putExtra("clicked", true);
intent.putExtra("hint", searchHint.getHint().toString());
intent.putExtra("entrance", "(工具栏)");
startActivity(intent);
} else if (id == R.id.actionbar_search_input || id == R.id.actionbar_search_rl) {
DataUtils.onEvent(getActivity(), "主页", "搜索框");
DataCollectionUtils.uploadClick(getActivity(), "搜索框", "主页");
Intent intent = new Intent(getActivity(), SearchActivity.class);
intent.putExtra("clicked", false);
intent.putExtra("hint", searchHint.getHint().toString());
intent.putExtra("entrance", "(工具栏)");
startActivity(intent);
} else if (id == R.id.actionbar_notification) {
DataUtils.onEvent(getActivity(), "主页", "关注图标");
DataCollectionUtils.uploadClick(getActivity(), "关注图标", "主页");
Intent intent = new Intent(getActivity(), ConcernActivity.class);
intent.putExtra("entrance", "(工具栏)");
startActivity(intent);
}
}
// 打开下载按钮事件
public void onEventMainThread(EBReuse reuse) {
if ("Refresh".equals(reuse.getType())) {
if (Config.isShow(getActivity())) {
view.findViewById(R.id.actionbar_rl_download).setVisibility(View.VISIBLE);
} else {
view.findViewById(R.id.actionbar_rl_download).setVisibility(View.GONE);
}
}
}
public void setHint(ArrayList<String> hint) {
if (hint != null && hint.size() > 0) {
hintList = hint;
if (hint.size() == 1 && searchHint != null) {
searchHint.setHint(hintList.get(0));
} else if (mAlphaAnimation != null && searchHint != null) {
searchHint.setAnimation(mAlphaAnimation);
}
}
}
public void onEventMainThread(EBDownloadStatus status) {
int updateSize = PackageManager.getUpdateListSize();
int downloadSize = DownloadManager.getInstance(getActivity()).getAll().size();
if (downloadSize != 0) {
downloadHint.setVisibility(View.VISIBLE);
downloadHint.setText(String.valueOf(downloadSize));
} else if (updateSize != 0) {
downloadHint.setVisibility(View.VISIBLE);
downloadHint.setText(String.valueOf(updateSize));
} else {
downloadHint.setVisibility(View.GONE);
}
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}

View File

@ -0,0 +1,19 @@
package com.gh.base;
import android.view.View;
/**
* Created by khy on 26/09/17.
*/
public interface OnListClickListener {
/**
*
* @param view
* @param position list position
* @param data list data (直接强转 如果列表传入不同数据类型 请做好判断)
* @param <T>
*/
<T> void onListClick(View view, int position, T data);
}

View File

@ -1,13 +1,16 @@
package com.gh.gamecenter.listener;
package com.gh.base;
/**
* Created by Administrator on 2016/9/8.
*/
public interface OnCallBackListener {
public interface OnRequestCallBackListener<T> {
void loadDone();
void loadDone(Object obj);
void loadDone(T obj);
void loadError();
void loadEmpty();
}

View File

@ -0,0 +1,13 @@
package com.gh.base;
import java.util.ArrayList;
/**
* @author CsHeng
* @Date 05/05/2017
* @Time 4:52 PM
*/
public interface SearchBarHint {
void setHint(ArrayList<String> hintList);
}

View File

@ -0,0 +1,48 @@
//package com.gh.base;
//
//import java.io.Serializable;
//
//public enum SuggestionType implements Serializable {
//
// FEEDBACK("普通反馈", 1),
// SUGGESTION("功能建议", 2),
// CRASH("发生闪退", 3),
// GAME("游戏问题", 4),
// COLLECT("游戏收录", 5),
// POST("文章投稿", 6);
//
// private String mName;
// private int mIndex;
//
// private SuggestionType(String name, int index) {
// mName = name;
// mIndex = index;
// }
//
// public static String getName(int index) {
// for (SuggestionType c : SuggestionType.values()) {
// if (c.mIndex == index) {
// return c.mName;
// }
// }
// return "";
// }
//
// public static int getIndex(String name) {
// for (SuggestionType c : SuggestionType.values()) {
// if (c.mName == name) {
// return c.mIndex;
// }
// }
// return -1;
// }
//
// public int getIndex() {
// return mIndex;
// }
//
// public String getName() {
// return mName;
// }
//
//}

View File

@ -0,0 +1,32 @@
package com.gh.base.adapter;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import java.util.List;
/**
* Created by LGT on 2016/11/17.
* ViewPager FragmentAdapter
*/
public class FragmentAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragmentList;
public FragmentAdapter(FragmentManager fm, List<Fragment> fragmentList) {
super(fm);
this.mFragmentList = fragmentList;
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
}

View File

@ -0,0 +1,152 @@
package com.gh.base.fragment;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.gh.base.OnListClickListener;
import com.gh.base.OnRequestCallBackListener;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.eventbus.EBMiPush;
import com.lightgame.utils.RuntimeUtils;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import butterknife.ButterKnife;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Created by LGT on 2016/9/4.
* Fragment 基类
*/
public abstract class BaseFragment<T> extends Fragment implements OnRequestCallBackListener<T>,
View.OnClickListener, OnListClickListener{
// TODO private view
protected View view;
protected boolean isEverPause;
protected String mEntrance;
@LayoutRes
protected abstract int getLayoutId();
/**
* 责任链谁处理了就返回true否则返回super.handleOnClick(View view)
*
* @return
*/
protected boolean handleOnClick(View view) {
return true;
}
@Override
public void onClick(View v) {
handleOnClick(v);
}
protected void initView(View view) {
}
protected void postRunnable(Runnable runnable) {
RuntimeUtils.getInstance().runOnUiThread(runnable);
}
// 定时任务全部改用这个方法, 在onDestroy做统一取消定时
protected void postDelayedRunnable(Runnable runnable, long delayMillis) {
RuntimeUtils.getInstance().runOnUiThread(runnable, delayMillis);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mEntrance = getActivity().getIntent().getStringExtra(EntranceUtils.KEY_ENTRANCE);
isEverPause = false;
EventBus.getDefault().register(this);
view = View.inflate(getContext(), getLayoutId(), null);
ButterKnife.bind(this, view);
initView(view);
}
//TODO 尴尬必须的有subscribe才能register
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onDummyEvent(EBMiPush push) {
//
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (container != null) {
container.removeView(view);
}
return view;
}
@Override
public void onResume() {
super.onResume();
isEverPause = false;
}
@Override
public void onPause() {
super.onPause();
isEverPause = true;
}
@Override
public void onDestroy() {
super.onDestroy();
RuntimeUtils.getInstance().removeRunnable();
EventBus.getDefault().unregister(this);
}
public void toast(String msg) {
Utils.toast(getContext(), msg);
}
public boolean isEverPause() {
return isEverPause;
}
@Override
public void loadDone() {
}
@Override
public void loadDone(Object obj) {
}
@Override
public void loadError() {
}
@Override
public void loadEmpty() {
}
@Override
public <T> void onListClick(View view, int position, T data) {
}
protected <K> Observable<K> asyncCall(Observable<K> observable) {
return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
}

View File

@ -0,0 +1,125 @@
/**
* project: OPlay
* <p/>
* <p/>
* ========================================================================
* amend date amend user amend reason
* 2013-3-6 CsHeng
*/
package com.gh.base.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import com.lightgame.adapter.BaseFragmentPagerAdapter;
import com.lightgame.config.CommonDebug;
import com.lightgame.view.DoubleTapTextView;
import java.util.ArrayList;
import java.util.List;
/**
* ViewPager 配合RadioGroup实现双切换<br/>
* 记得自己控制onCreateView返回和radioGroup里面radiobutton个数,Viewpager的布局<br/>
*
* @author CsHeng
* @date 2013-3-6
*/
public abstract class BaseFragment_ViewPager extends BaseFragment implements DoubleTapTextView.OnDoubleTapListener {
protected static final String ARGS_INDEX = "index";
protected int mCheckedIndex = 0;
protected PagerAdapter mAdapter;
protected List<Fragment> mFragmentsList;
protected ViewPager mViewPager;
@LayoutRes
protected abstract int getLayoutId();
@IdRes
protected abstract int getViewPagerId();
protected abstract void initFragmentList(List<Fragment> fragments);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFragmentsList = new ArrayList<>();
initFragmentList(mFragmentsList);
mAdapter = BaseFragmentPagerAdapter.newInstance(getChildFragmentManager(), mFragmentsList);
final Bundle args = getArguments();
if (args != null) {
mCheckedIndex = args.getInt(ARGS_INDEX);
}
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mViewPager = (ViewPager) view.findViewById(getViewPagerId());
mViewPager.setOffscreenPageLimit(mFragmentsList.size());
mViewPager.setAdapter(mAdapter);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mCheckedIndex < mFragmentsList.size()) {
mViewPager.setCurrentItem(mCheckedIndex, false);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (getArguments() != null) {
getArguments().putInt(ARGS_INDEX, mCheckedIndex);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (mViewPager != null) {
mViewPager.setAdapter(null);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mFragmentsList != null) {
mFragmentsList.clear();
}
}
@Override
public boolean onDoubleTap() {
final Fragment fragment = mFragmentsList.get(mViewPager.getCurrentItem());
return fragment instanceof DoubleTapTextView.OnDoubleTapListener && ((DoubleTapTextView.OnDoubleTapListener)
fragment).onDoubleTap();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (CommonDebug.IS_DEBUG) {
CommonDebug.logMethodWithParams(this, requestCode, resultCode, data);
}
List<Fragment> fragments = getChildFragmentManager().getFragments();
if (fragments != null) {
Fragment curFragment = fragments.get(mViewPager.getCurrentItem());
curFragment.onActivityResult(requestCode, resultCode, data);
}
}
}

View File

@ -0,0 +1,109 @@
/**
* project: OPlay
* <p/>
* <p/>
* ========================================================================
* amend date amend user amend reason
* 2013-3-6 CsHeng
*/
package com.gh.base.fragment;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Checkable;
/**
* ViewPager 配合ViewGroup Checkable实现双切换<br/>
* 记得自己控制onCreateView返回和ViewGroup里面Checkable个数,ViewPager的布局<br/>
*
* @author CsHeng
* @date 2013-3-6
* @update 2014-09-29
*/
public abstract class BaseFragment_ViewPager_Checkable extends BaseFragment_ViewPager implements
ViewPager.OnPageChangeListener {
protected ViewGroup mCheckableGroup;
@IdRes
protected abstract int getCheckableGroupId();
protected boolean getSmoothScroll() {
return false;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mCheckableGroup = (ViewGroup) view.findViewById(getCheckableGroupId());
for (int i = 0, size = mCheckableGroup.getChildCount(); i < size; i++) {
mCheckableGroup.getChildAt(i).setOnClickListener(this);
}
mViewPager.addOnPageChangeListener(this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
mViewPager.removeOnPageChangeListener(this);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
checkIndex(mCheckedIndex);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int index) {
onPageChanged(index);
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override
protected boolean handleOnClick(View view) {
final int toCheck = mCheckableGroup.indexOfChild(view);
if (toCheck != -1) {
mViewPager.setCurrentItem(toCheck, getSmoothScroll());
return true;
}
return super.handleOnClick(view);
}
protected void checkIndex(int index) {
final int childCount = mCheckableGroup.getChildCount();
if (index < childCount && mCheckedIndex < childCount) {
final View toChecked = mCheckableGroup.getChildAt(index);
if (toChecked instanceof Checkable) {
((Checkable) toChecked).setChecked(true);
}
if (index != mCheckedIndex) {
final View checkedChild = mCheckableGroup.getChildAt(mCheckedIndex);
if (checkedChild instanceof Checkable) {
((Checkable) checkedChild).setChecked(false);
}
}
mCheckedIndex = index;
}
}
protected void onPageChanged(int index) {
checkIndex(index);
}
}

View File

@ -3,19 +3,57 @@ package com.gh.common.constant;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.gh.gamecenter.BuildConfig;
public class Config {
public static final String HOST = "http://dev.api2.ghzhushou.com/v2d5/";
public static final String USER_HOST = "http://dev.user2.ghzhushou.com/v1d2/";
public static final String COMMENT_HOST = "http://dev.comment2.ghzhushou.com/v1d2/";
public static final String DATA_HOST = "http://data.ghzhushou.com/";
public static final String LIBAO_HOST = "http://dev.libao2.ghzhushou.com/v1d2/";
public static final String PREFERENCE = "ghzhushou";
public static final String API_HOST = BuildConfig.API_HOST;
public static final String USER_HOST = BuildConfig.USER_HOST;
public static final String COMMENT_HOST = BuildConfig.COMMENT_HOST;
public static final String DATA_HOST = BuildConfig.DATA_HOST;
public static final String LIBAO_HOST = BuildConfig.LIBAO_HOST;
public static final String MESSAGE_HOST = BuildConfig.MESSAGE_HOST;
public static final String USERSEA_HOST = BuildConfig.USERSEA_HOST;
public static boolean isShow(Context context) {
SharedPreferences sp = context.getSharedPreferences(Config.PREFERENCE, Context.MODE_PRIVATE);
return sp.getBoolean("isShow", true);
}
/**
* 需要配置的请使用{@link PreferenceManager#getDefaultSharedPreferences(Context)}
*/
// @Deprecated
// public static final String PREFERENCE = "ghzhushou";
// Third-Party confs
public static final String WECHAT_APPID = BuildConfig.WECHAT_APPID;
public static final String WECHAT_SECRET = BuildConfig.WECHAT_SECRET;
public static final String TENCENT_APPID = BuildConfig.TENCENT_APPID;
public static final String WEIBO_APPKEY = BuildConfig.WEIBO_APPKEY;
public static final String MIPUSH_APPID = BuildConfig.MIPUSH_APPID;
public static final String MIPUSH_APPKEY = BuildConfig.MIPUSH_APPKEY;
public static final String MTA_APPKEY = BuildConfig.MTA_APPKEY;
public static final String TALKINGDATA_APPID = BuildConfig.TD_APPID;// TalkingData
public static final String UMENG_APPKEY = BuildConfig.UMENG_APPKEY;
public static final String UMENG_MESSAGE_SECRET = BuildConfig.UMENG_MESSAGE_SECRET;
public static final String USERSEA_APP_ID = BuildConfig.USERSEA_APP_ID; // 登录验证
public static final String USERSEA_APP_SECRET = BuildConfig.USERSEA_APP_SECRET; // 登录验证
public static final String BUGLY_APPID = BuildConfig.BUGLY_APPID;
public static final String PATCH_VERSION_NAME = BuildConfig.PATCH_VERSION_NAME; // 补丁包版本 对应关于->版本号
// http://www.ghzs666.com/article/${articleId}.html
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // TODO ghzs/ghzs666 统一
public static final String PATCHES = "patches";
public static boolean isShow(Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
return sp.getBoolean("isShow", true);
}
public static String getExceptionMsg(Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
return sp.getString("errMsg", null);
}
public static void setExceptionMsg(Context context, String errMsg) {
PreferenceManager.getDefaultSharedPreferences(context).edit().putString("errMsg", errMsg).apply();
}
}

View File

@ -2,41 +2,36 @@ package com.gh.common.constant;
public class Constants {
public static final int CONTINUE_DOWNLOAD_TASK = 0x123;
public static final int PAUSE_DOWNLOAD_TASK = 0x124;
public static final int DOWNLOAD_ROLL = 0x125;
public static final int SEND_NEWS_FEEDBACK = 0x126;
public static final int SEND_COMMENT_FEEDBACK = 0x127;
public static final String KEY_DOWNLOAD_ENTRY = "key_download_entry";
public static final String KEY_DOWNLOAD_ACTION = "key_download_action";
public static final int MAX_DOWNLOAD_THREAD_SIZE = 3;
public static final int MAX_DOWNLOADING_SIZE = 3;
public static final long SPEED_CHECK_INTERVAL = 1000;//速度监测频率
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
public static final String REGEX_ACCOUNT = "^[a-zA-Z_]\\w{5,17}$";
public static final String REGEX_PASSWORD = "^[a-zA-Z]\\w{5,31}$";
//输入规则
public static final String INPUT_RULE = "0123456789abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ_";
//最少需要多少数据才能上传
public static final int DATA_AMOUNT = 20;
//游戏 cd间隔
public static final int GAME_CD = 5 * 60 * 1000;
//新闻 cd间隔
public static final int NEWS_CD = 10 * 60 * 1000;
//platform cd间隔
public static final int PLATFORM_CD = 10 * 60 * 1000;
//update cd间隔
public static final int UPDATE_CD = 5 * 60 * 1000;
//搜索 cd间隔
public static final int SEARCH_CD = 5 * 60 * 1000;
//评论 cd间隔
public static final int COMMENT_CD = 60 * 1000;
public static final int SEND_NEWS_FEEDBACK = 0x126;
public static final int SEND_COMMENT_FEEDBACK = 0x127;
public final static int LIST_FOOTER_ITEM = 1;
public final static int LIST_HEAD_ITEM = 1;
public final static int NOT_NETWORK_CODE = 504; // 没有网络的状态码(应该是这个吧!)
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
public static final String REGEX_ACCOUNT = "^[a-zA-Z_]\\w{5,17}$";
public static final String REGEX_PASSWORD = "^[a-zA-Z]\\w{5,31}$";
//输入规则
public static final String INPUT_RULE = "0123456789abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ_";
//最少需要多少数据才能上传
public static final int DATA_AMOUNT = 20;
//游戏 cd间隔
public static final int GAME_CD = 5 * 60 * 1000;
//新闻 cd间隔
public static final int NEWS_CD = 10 * 60 * 1000;
//platform cd间隔
public static final int PLATFORM_CD = 10 * 60 * 1000;
//update cd间隔
public static final int UPDATE_CD = 5 * 60 * 1000;
//搜索 cd间隔
public static final int SEARCH_CD = 5 * 60 * 1000;
//评论 cd间隔
public static final int COMMENT_CD = 60 * 1000;
}

View File

@ -5,24 +5,23 @@ package com.gh.common.constant;
*/
public class ItemViewType {
public static final int COLUMN_HEADER = 0; // 专题头部布局
public static final int GAME_SLIDE = 1; // 滚动图布局
public static final int GAME_NORMAL = 2; // 正常游戏布局
public static final int GAME_TEST = 3; // 测试游戏布局
public static final int GAME_IMAGE = 4; // 游戏大图布局
public static final int NEWS_HEADER = 5; // 新闻头部布局
public static final int NEWS_TEXT = 6; // 新闻文本布局
public static final int NEWS_IMAGE = 7; // 新闻带图布局
public static final int NEWS_IMAGE1 = 8; // 新闻带一张小图布局
public static final int NEWS_IMAGE2 = 9; // 新闻带三张小图布局
public static final int NEWS_IMAGE3 = 10; // 新闻带一张大图布局
public static final int NEWS_DIGEST = 11; // 新闻摘要布局
public static final int SEARCH_NORMAL = 12; // 搜索正常布局
public static final int SEARCH_DELETE = 13; // 清空历史记录布局
public static final int LOADING = 14; // 加载布局
public static final int LIBAO_NORMAL = 15; // 礼包正常布局
public static final int LIBAO_SKIP_CONCERN = 16; // 跳转关注管理页面布局
public static final int KC_HINT = 16;
public static final int ZIXUNTOP_TOP = 7; // 有料顶部布局
public static final int COLUMN_HEADER = 0; // 专题头部布局
public static final int GAME_SLIDE = 1; // 滚动图布局
public static final int GAME_NORMAL = 2; // 正常游戏布局
public static final int GAME_TEST = 3; // 测试游戏布局
public static final int GAME_IMAGE = 4; // 游戏大图布局
public static final int NEWS_HEADER = 5; // 新闻头部布局
public static final int NEWS_TEXT = 6; // 新闻文本布局
public static final int NEWS_IMAGE = 7; // 新闻带图布局
public static final int NEWS_IMAGE1 = 8; // 新闻带一张小图布局
public static final int NEWS_IMAGE2 = 9; // 新闻带三张小图布局
public static final int NEWS_IMAGE3 = 10; // 新闻带一张大图布局
public static final int NEWS_DIGEST = 11; // 新闻摘要布局
public static final int SEARCH_NORMAL = 12; // 搜索正常布局
public static final int LOADING = 14; // 加载布局
public static final int LIBAO_NORMAL = 15; // 礼包正常布局
public static final int LIBAO_SKIP_CONCERN = 16; // 跳转关注管理页面布局
public static final int KC_HINT = 17;
public static final int GAME_PULGIN = 18; // 游戏插件模块
}

View File

@ -10,11 +10,11 @@ import com.sina.weibo.sdk.auth.Oauth2AccessToken;
* 该类定义了微博授权时所需要的参数。
*/
public class AccessTokenKeeper {
private static final String PREFERENCES_NAME = "com_weibo_sdk_android";
private static final String PREFERENCES_NAME = "com_weibo_sdk_android";
private static final String KEY_UID = "uid";
private static final String KEY_ACCESS_TOKEN = "access_token";
private static final String KEY_EXPIRES_IN = "expires_in";
private static final String KEY_UID = "uid";
private static final String KEY_ACCESS_TOKEN = "access_token";
private static final String KEY_EXPIRES_IN = "expires_in";
private static final String KEY_REFRESH_TOKEN = "refresh_token";
/**
@ -41,7 +41,6 @@ public class AccessTokenKeeper {
* 从 SharedPreferences 读取 Token 信息。
*
* @param context 应用程序上下文环境
*
* @return 返回 Token 对象
*/
public static Oauth2AccessToken readAccessToken(Context context) {

View File

@ -0,0 +1,31 @@
package com.gh.common.util;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.manager.PackageManager;
import java.util.List;
/**
* Created by khy on 10/05/17.
*/
public class ApkActiveUtils {
// 过滤隐藏apk包
public static void filterHideApk(GameEntity gameEntity) {
if (gameEntity == null || gameEntity.getApk() == null
|| gameEntity.getApk().size() == 0) return;
List<ApkEntity> apkList = gameEntity.getApk();
for (int i = 0; i < apkList.size(); i++) {
ApkEntity apkEntity = apkList.get(i);
String packageName = apkEntity.getPackageName();
String id = gameEntity.getId();
if (!apkEntity.isActive() && !PackageManager.isCanPluggable(id, packageName)) {
apkList.remove(i);
i--;
}
}
}
}

View File

@ -0,0 +1,116 @@
package com.gh.common.util;
import android.os.Debug;
import android.util.Log;
import com.gh.gamecenter.BuildConfig;
import java.lang.reflect.Field;
/**
* App的测试配置项
*/
public class AppDebugConfig {
/**
* debug模式发布打包需要置为false可以通过混淆让调试的log文本从代码文件中消除避免被反编译时漏泄相关信息。
*/
public static final boolean IS_DEBUG = BuildConfig.DEBUG;
public static void logMethodName(Object object) {
if (IS_DEBUG) {
try {
Log.v(getLogTag(object), getMethodName());
} catch (Throwable e) {
}
}
}
private static String getLogTag(Object object) {
return object.getClass().getSimpleName() + "[" + object.hashCode() + "]";
}
private static String getMethodName() {
final Thread current = Thread.currentThread();
final StackTraceElement trace = current.getStackTrace()[4];
return trace.getMethodName();
}
public static void logMethodName(Class<?> cls) {
if (IS_DEBUG) {
try {
Log.v(getLogTag(cls), getMethodName());
} catch (Throwable e) {
}
}
}
public static void logParams(String tag, Object... params) {
if (IS_DEBUG) {
for (Object obj : params) {
Log.i(tag, "" + obj);
}
}
}
public static void logNetworkRequest(Object object, String request, String response) {
if (IS_DEBUG) {
Log.i(getLogTag(object), String.format("【Request】:%s", request));
Log.i(getLogTag(object), String.format("【Response】:%s", response));
}
}
public static void logFields(Class<?> classType) {
if (IS_DEBUG) {
try {
final String name = classType.getSimpleName();
final Field[] fs = classType.getDeclaredFields();
for (Field f : fs) {
Log.i(name, "Filed:" + f.getName());
}
} catch (Exception e) {
}
}
}
public static void logMethodWithParams(Object object, Object... params) {
if (IS_DEBUG) {
try {
final StringBuilder sb = new StringBuilder();
sb.append(getMethodName()).append(":");
for (Object obj : params) {
sb.append('[').append(obj).append("], ");
}
Log.v(getLogTag(object), sb.toString());
} catch (Exception e) {
}
}
}
public static void logMemoryInfo() {
if (IS_DEBUG) {
try {
// final ActivityManager activityManager = (ActivityManager) getActivity().getSystemService(Context
// .ACTIVITY_SERVICE);
// activityManager.getMemoryClass();
final String tag = "MM_INFO";
// Log.i(tag, "Class " + activityManager.getMemoryClass());
final long mb = 1024 * 1024;
//Get VM Heap Size by calling:
Log.i(tag, "VM Heap Size:" + Runtime.getRuntime().totalMemory() / mb);
// Get VM Heap Size Limit by calling:
Log.i(tag, "VM Heap Size Limit:" + Runtime.getRuntime().maxMemory() / mb);
// Get Allocated VM Memory by calling:
Log.i(tag, "Allocated VM Memory:" + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime()
.freeMemory()) / mb);
//Get Native Allocated Memory by calling:
Log.i(tag, "Native Allocated Memory:" + Debug.getNativeHeapAllocatedSize() / mb);
} catch (Exception e) {
}
}
}
}

View File

@ -8,6 +8,9 @@ import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
@ -15,102 +18,135 @@ import java.io.IOException;
*/
public class BitmapUtils {
/**
* 根据文件路径返回bitmap
* @param filepath 文件路径
* @param w 宽
* @param h 高
* @return bitmap
*/
public static Bitmap getBitmapByFile(String filepath, int w, int h) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
// 设置为ture只获取图片大小
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
// 返回为空
BitmapFactory.decodeFile(filepath, options);
int width = options.outWidth;
int height = options.outHeight;
float scaleWidth = 0.f, scaleHeight = 0.f;
if (width > w || height > h) {
// 缩放
scaleWidth = ((float) width) / w;
scaleHeight = ((float) height) / h;
}
options.inJustDecodeBounds = false;
int scale = (int) Math.ceil(Math.max(scaleWidth, scaleHeight));
if (scale % 2 == 1) {
scale += 1;
}
options.inSampleSize = scale;
Bitmap bitmap = BitmapFactory.decodeFile(filepath, options);
bitmap = rotatePicture(filepath, bitmap);
if (bitmap != null) {
return bitmap;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 保存图片
*
* @param newPath
* @param filePath
* @return
*/
public static boolean savePicture(String newPath, String filePath) {
BitmapFactory.Options options = new BitmapFactory.Options();
// options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
public static Bitmap rotatePicture(String path, Bitmap bitmap) {
int rotate = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
if (rotate != 0) {
Matrix matrix = new Matrix();
matrix.setRotate(rotate);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
} else {
return bitmap;
}
}
File file = new File(newPath);
int quality = 80;
do {
try {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, bos);
bos.flush();
bos.close();
} catch (IOException e) {
file.delete();
e.printStackTrace();
return false;
}
quality -= 10;
if (quality < 10) {
quality = 10;
}
} while (file.length() > 81920 && quality > 10);
return true;
}
/**
* Drawable转Bitmap
*
*/
public static Bitmap drawableToBitmap(Drawable drawable){
if(drawable == null){
return null;
}
/**
* 根据文件路径返回bitmap
*
* @param filepath 文件路径
* @param w 宽
* @param h 高
* @return bitmap
*/
public static Bitmap getBitmapByFile(String filepath, int w, int h) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
// 设置为ture只获取图片大小
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
// 返回为空
BitmapFactory.decodeFile(filepath, options);
int width = options.outWidth;
int height = options.outHeight;
float scaleWidth = 0.f, scaleHeight = 0.f;
if (width > w || height > h) {
// 缩放
scaleWidth = ((float) width) / w;
scaleHeight = ((float) height) / h;
}
options.inJustDecodeBounds = false;
int scale = (int) Math.ceil(Math.max(scaleWidth, scaleHeight));
if (scale % 2 == 1) {
scale += 1;
}
options.inSampleSize = scale;
Bitmap bitmap = BitmapFactory.decodeFile(filepath, options);
bitmap = rotatePicture(filepath, bitmap);
if (bitmap != null) {
return bitmap;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 取 drawable 的长宽
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
// 取 drawable 的颜色格式
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565;
//建立对应的Bitmap
Bitmap bitmap = Bitmap.createBitmap(w, h, config);
// 建立对应 bitmap 的画布
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
// 把 drawable 内容画到画布中
drawable.draw(canvas);
public static Bitmap rotatePicture(String path, Bitmap bitmap) {
int rotate = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
if (rotate != 0) {
Matrix matrix = new Matrix();
matrix.setRotate(rotate);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
} else {
return bitmap;
}
}
return bitmap;
}
/**
* Drawable转Bitmap
*/
public static Bitmap drawableToBitmap(Drawable drawable) {
if (drawable == null) {
return null;
}
// 取 drawable 的长宽
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
// 取 drawable 的颜色格式
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565;
//建立对应的Bitmap
Bitmap bitmap = Bitmap.createBitmap(w, h, config);
// 建立对应 bitmap 的画布
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
// 把 drawable 内容画到画布中
drawable.draw(canvas);
return bitmap;
}
}

View File

@ -0,0 +1,35 @@
package com.gh.common.util;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import com.gh.gamecenter.LoginActivity;
/**
* Created by khy on 28/06/17.
*/
public class CheckLoginUtils {
public static void checkLogin(final Context context, OnLoggenInListener listener) {
String token = LoginUtils.getToken(context);
if (TextUtils.isEmpty(token)) {
DialogUtils.showWarningDialog(context, "登录提示", "需要登录才能使用该功能喔!", "取消", "快速登录",
new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
Intent intent = LoginActivity.getIntent(context, false);
context.startActivity(intent);
}
}, null);
} else {
listener.onLoggedIn();
}
}
public interface OnLoggenInListener {
void onLoggedIn();
}
}

View File

@ -3,18 +3,18 @@ package com.gh.common.util;
public class ClassUtils {
public static Class<?> forName(String name) {
if ("NewsActivity".equals(name)) {
name = "NewsDetailActivity";
} else if ("GameDetailsActivity".equals(name)) {
name = "GameDetailActivity";
}
try {
return Class.forName("com.gh.gamecenter." + name);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
public static Class<?> forName(String name) {
if ("NewsActivity".equals(name)) {
name = "NewsDetailActivity";
} else if ("GameDetailsActivity".equals(name)) {
name = "GameDetailActivity";
}
try {
return Class.forName("com.gh.gamecenter." + name);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,103 @@
package com.gh.common.util
import android.content.Context
import com.gh.gamecenter.eventbus.EBCollectionChanged
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONObject
import retrofit2.HttpException
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
/**
* Created by khy on 26/07/17.
*/
object CollectionUtils {
enum class CollectionType {
toolkit, article
}
fun postCollection(context: Context, content: String, type: CollectionType, listener: OnCollectionListener) {
val body = RequestBody.create(MediaType.parse("application/json"), content)
val postCollection = when (type) {
CollectionType.article -> RetrofitManager.getInstance(context).getApi().postCollectionArticle(body)
CollectionType.toolkit -> RetrofitManager.getInstance(context).getApi().postCollectionTools(body)
}
postCollection
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
listener.onSuccess()
EventBus.getDefault().post(EBCollectionChanged(JSONObject(content).getString("_id"), true, type))
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
if (e != null) {
try {
val string = e.response()?.errorBody()?.string()
val errorBody = JSONObject(string)
if (errorBody.getInt("status") == 40031) {
listener.onSuccess()
return
}
} catch (e: Exception) {
e.printStackTrace()
}
}
listener.onError()
}
})
}
fun deleteCollection(context: Context, id: String, type: CollectionType, listener: OnCollectionListener) {
val postCollection: Observable<ResponseBody>
when (type) {
CollectionType.article -> postCollection = RetrofitManager.getInstance(context).getApi().deletaCollectionArticle(id)
CollectionType.toolkit -> postCollection = RetrofitManager.getInstance(context).getApi().deleteCollectionTools(id)
}
postCollection
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
listener.onSuccess()
EventBus.getDefault().post(EBCollectionChanged(id, false, type))
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
listener.onError()
}
})
}
fun patchCollection(context: Context, id: String, type: CollectionType) {
val postCollection = when (type) {
CollectionType.article -> RetrofitManager.getInstance(context).getApi().patchCollectionArticle(id)
CollectionType.toolkit -> RetrofitManager.getInstance(context).getApi().patchCollectionTools(id)
}
postCollection
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {})
}
interface OnCollectionListener {
fun onSuccess()
fun onError()
}
}

View File

@ -2,21 +2,24 @@ package com.gh.common.util;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.gh.base.AppController;
import com.gh.gamecenter.CommentDetailActivity;
import com.gh.gamecenter.MessageDetailActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.MessageDetailAdapter;
import com.gh.gamecenter.db.CommentDao;
import com.gh.gamecenter.adapter.OnCommentCallBackListener;
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
import com.gh.gamecenter.entity.CommentEntity;
import com.gh.gamecenter.entity.UserDataEntity;
import com.gh.gamecenter.entity.UserInfoEntity;
import com.lightgame.utils.Utils;
import org.json.JSONException;
import org.json.JSONObject;
@ -28,6 +31,8 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import retrofit2.HttpException;
/**
* Created by khy on 2017/3/22.
*/
@ -39,8 +44,8 @@ public class CommentUtils {
long today = format.parse(format.format(new Date())).getTime();
long day = time * 1000;
if (day >= today && day < today + 86400 * 1000) {
long min = new Date().getTime()/1000 - day/1000;
int hour = (int) (min/ (60 * 60));
long min = new Date().getTime() / 1000 - day / 1000;
int hour = (int) (min / (60 * 60));
if (hour == 0) {
if (min < 60) {
textView.setText("刚刚");
@ -64,21 +69,19 @@ public class CommentUtils {
}
}
public static void showReportDialog(final CommentEntity commentEntity, final Context mContext
, final MessageDetailAdapter.OnCommentCallBackListener mCallBackListener, final String newsId) {
public static void showReportDialog(final CommentEntity commentEntity, final Context context,
final OnCommentCallBackListener listener, final String newsId) {
CommentDao commentDao = new CommentDao(mContext);
final Dialog dialog = new Dialog(context);
final Dialog dialog = new Dialog(mContext);
LinearLayout container = new LinearLayout(mContext);
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.setBackgroundColor(Color.WHITE);
container.setPadding(0, DisplayUtils.dip2px(mContext, 12), 0, DisplayUtils.dip2px(mContext, 12));
container.setPadding(0, DisplayUtils.dip2px(context, 12), 0, DisplayUtils.dip2px(context, 12));
List<String> dialogType = new ArrayList<>();
if (!commentDao.isMyComment(commentEntity.getId())) {
if (commentEntity.getUserData() == null || !commentEntity.getUserData().isCommentOwn()) {
dialogType.add("回复");
}
@ -90,16 +93,16 @@ public class CommentUtils {
}
for (String s : dialogType) {
final TextView reportTv = new TextView(mContext);
reportTv.setPadding(DisplayUtils.dip2px(mContext, 20), DisplayUtils.dip2px(mContext, 12),
0, DisplayUtils.dip2px(mContext, 12));
final TextView reportTv = new TextView(context);
reportTv.setText(s);
reportTv.setTextSize(17);
reportTv.setTextColor(mContext.getResources().getColor(R.color.title));
reportTv.setTextColor(ContextCompat.getColor(context, R.color.title));
reportTv.setBackgroundResource(R.drawable.textview_white_style);
int widthPixels = mContext.getResources().getDisplayMetrics().widthPixels;
reportTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9)/10,
int widthPixels = context.getResources().getDisplayMetrics().widthPixels;
reportTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTv.setPadding(DisplayUtils.dip2px(context, 20), DisplayUtils.dip2px(context, 12),
0, DisplayUtils.dip2px(context, 12));
container.addView(reportTv);
reportTv.setOnClickListener(new View.OnClickListener() {
@ -108,34 +111,35 @@ public class CommentUtils {
dialog.cancel();
switch (reportTv.getText().toString()) {
case "回复":
if (mCallBackListener != null) {
mCallBackListener.showSoftInput(commentEntity);
} else if (!TextUtils.isEmpty(newsId)){
Intent intent = new Intent(mContext, MessageDetailActivity.class);
AppController.put("CommentEntity", commentEntity);
intent.putExtra("commentNum", -1);
intent.putExtra("newsId", newsId);
intent.putExtra("openSoftInput", true);
mContext.startActivity(intent);
} else {
Utils.toast(mContext, "缺少关键属性");
}
CheckLoginUtils.checkLogin(context, new CheckLoginUtils.OnLoggenInListener() {
@Override
public void onLoggedIn() {
if (listener != null) {
listener.onCommentCallback(commentEntity);
} else if (!TextUtils.isEmpty(newsId)) {
context.startActivity(MessageDetailActivity.getMessageDetailIntent(context, commentEntity, newsId));
} else {
Utils.toast(context, "缺少关键属性");
}
}
});
break;
case "复制":
LibaoUtils.copyLink(commentEntity.getContent(), mContext);
LibaoUtils.copyLink(commentEntity.getContent(), context);
break;
case "举报":
showReportTypeDialog(commentEntity, mContext);
CheckLoginUtils.checkLogin(context, new CheckLoginUtils.OnLoggenInListener() {
@Override
public void onLoggedIn() {
showReportTypeDialog(commentEntity, context);
}
});
break;
case "查看对话":
Intent intent = new Intent(mContext, CommentDetailActivity.class);
intent.putExtra("commentId", commentEntity.getId());
mContext.startActivity(intent);
context.startActivity(CommentDetailActivity.getCommentDetailIntent(context, commentEntity.getId()));
break;
}
}
});
}
@ -161,9 +165,9 @@ public class CommentUtils {
TextView reportTypeTv = new TextView(mContext);
reportTypeTv.setText(s);
reportTypeTv.setTextSize(17);
reportTypeTv.setTextColor(mContext.getResources().getColor(R.color.title));
reportTypeTv.setTextColor(ContextCompat.getColor(mContext, R.color.title));
reportTypeTv.setBackgroundResource(R.drawable.textview_white_style);
reportTypeTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9)/10,
reportTypeTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTypeTv.setPadding(DisplayUtils.dip2px(mContext, 20), DisplayUtils.dip2px(mContext, 12),
0, DisplayUtils.dip2px(mContext, 12));
@ -180,10 +184,10 @@ public class CommentUtils {
e.printStackTrace();
}
PostCommentUtils.addReportData(mContext, jsonObject.toString(), true,
PostCommentUtils.addReportData(mContext, jsonObject.toString(),
new PostCommentUtils.PostCommentListener() {
@Override
public void postSucced(JSONObject response) {
public void postSuccess(JSONObject response) {
Utils.toast(mContext, "感谢您的举报");
}
@ -202,5 +206,98 @@ public class CommentUtils {
reportTypeDialog.show();
}
public static void postVote(final Context context, final CommentEntity commentEntity,
final TextView commentLikeCountTv, final ImageView commentLikeIv, final OnVoteListener listener) {
CheckLoginUtils.checkLogin(context, new CheckLoginUtils.OnLoggenInListener() {
@Override
public void onLoggedIn() {
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme)) {
Utils.toast(context, "已经点过赞啦!");
return;
}
commentEntity.setVote(commentEntity.getVote() + 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme));
commentLikeIv.setImageResource(R.drawable.ic_like_select);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
commentLikeCountTv.setVisibility(View.VISIBLE);
PostCommentUtils.addCommentVoto(context, commentEntity.getId(),
new PostCommentUtils.PostCommentListener() {
@Override
public void postSuccess(JSONObject response) {
if (listener != null) {
listener.onVote();
}
}
@Override
public void postFailed(Throwable e) {
commentEntity.setVote(commentEntity.getVote() - 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint));
commentLikeIv.setImageResource(R.drawable.ic_like_unselect);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
if (commentEntity.getVote() == 0) {
commentLikeCountTv.setVisibility(View.GONE);
} else {
commentLikeCountTv.setVisibility(View.VISIBLE);
}
if (e instanceof HttpException) {
HttpException exception = (HttpException) e;
if (exception.code() == 403) {
try {
String detail = new JSONObject(exception.response().errorBody().string()).getString("detail");
if ("voted".equals(detail)) {
Utils.toast(context, "已经点过赞啦!");
}
} catch (Exception ex) {
ex.printStackTrace();
}
return;
}
}
Utils.toast(context, "网络异常,点赞失败");
}
});
}
});
}
// 设置评论item 用户相关的view(点赞/头像/用户名)
public static void setCommentUserView(Context mContext, CommentViewHolder holder, CommentEntity entity) {
UserDataEntity userDataEntity = entity.getUserData();
holder.commentLikeCountTv.setTextColor(ContextCompat.getColor(mContext, R.color.hint));
holder.commentLikeIv.setImageResource(R.drawable.ic_like_unselect);
if (entity.getVote() == 0) {
holder.commentLikeCountTv.setVisibility(View.GONE);
} else { // 检查是否已点赞
if (userDataEntity != null && userDataEntity.isCommentVoted()) {
holder.commentLikeCountTv.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
holder.commentLikeIv.setImageResource(R.drawable.ic_like_select);
}
holder.commentLikeCountTv.setVisibility(View.VISIBLE);
holder.commentLikeCountTv.setText(String.valueOf(entity.getVote()));
}
//检查是否是自身评论
UserInfoEntity userInfo = LoginUtils.getUserInfo(mContext);
if (userDataEntity != null && userDataEntity.isCommentOwn() && userInfo != null) {
holder.commentUserNameTv.setText(userInfo.getName());
ImageUtils.Companion.display(holder.commentUserIconDv, userInfo.getIcon());
} else {
holder.commentUserNameTv.setText(entity.getUser().getName());
if (TextUtils.isEmpty(entity.getUser().getIcon())) {
ImageUtils.Companion.display(holder.commentUserIconDv, R.drawable.user_default_icon_comment);
} else {
ImageUtils.Companion.display(holder.commentUserIconDv, entity.getUser().getIcon());
}
}
}
public interface OnVoteListener {
void onVote();
}
}

View File

@ -14,9 +14,8 @@ import java.util.List;
/**
* Created by khy on 2016/11/8.
*
* <p>
* 初始化资讯关注-内容图片
*
**/
public class ConcernContentUtils {
@ -26,75 +25,82 @@ public class ConcernContentUtils {
int index = 0;
for (int i = 0, size = (int) Math.ceil(list.size() / 3.0f); i < size; i++) {
int type = count % 3;
if (type == 0) {
LinearLayout ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.HORIZONTAL);
for (int j = 0; j < 3; j++) {
ll.addView(getImageView(context, list, entrance, index, width, 0));
LinearLayout ll;
switch (type) {
case 0:
ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.HORIZONTAL);
for (int j = 0; j < 3; j++) {
ll.addView(getImageView(context, list, entrance, index, width, 0));
index += 1;
}
linearLayout.addView(ll);
count -= 3;
break;
case 1:
linearLayout.addView(getImageView(context, list, entrance, index, width, 1));
count -= 1;
index += 1;
}
linearLayout.addView(ll);
count -= 3;
} else if (type == 1) {
linearLayout.addView(getImageView(context, list, entrance, index, width, 1));
count -= 1;
index += 1;
} else if (type == 2) {
LinearLayout ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.HORIZONTAL);
for (int j = 0; j < 2; j++) {
ll.addView(getImageView(context, list, entrance, index, width, 2));
index += 1;
}
linearLayout.addView(ll);
count -= 2;
break;
case 2:
ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.HORIZONTAL);
for (int j = 0; j < 2; j++) {
ll.addView(getImageView(context, list, entrance, index, width, 2));
index += 1;
}
linearLayout.addView(ll);
count -= 2;
break;
}
}
}
private static SimpleDraweeView getImageView(final Context context, final List<String> list, final String entrance,
final int position, int width, int type) {
private static SimpleDraweeView getImageView(final Context context, final List<String> list, final String entrance,
final int position, int width, int type) {
SimpleDraweeView imageView;
if (type == 0) {
imageView = new SimpleDraweeView(context);
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
0, width / 3 - DisplayUtils.dip2px(context, 4));
lparams.setMargins(DisplayUtils.dip2px(context, 2), 0,
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
lparams.weight = 1;
imageView.setLayoutParams(lparams);
ImageUtils.getInstance().display(context.getResources(), imageView,
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
} else if (type == 1) {
imageView = new SimpleDraweeView(context);
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(width, width / 2);
lparams.setMargins(DisplayUtils.dip2px(context, 2), 0,
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
imageView.setLayoutParams(lparams);
ImageUtils.getInstance().display(context.getResources(), imageView,
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
} else {
imageView = new SimpleDraweeView(context);
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
0, width / 2 - DisplayUtils.dip2px(context, 4));
lparams.setMargins(DisplayUtils.dip2px(context, 2), 0,
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
lparams.weight = 1;
imageView.setLayoutParams(lparams);
ImageUtils.getInstance().display(context.getResources(), imageView,
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
LinearLayout.LayoutParams lparams;
switch (type) {
case 0:
imageView = new SimpleDraweeView(context);
lparams = new LinearLayout.LayoutParams(
0, width / 3 - DisplayUtils.dip2px(context, 4));
lparams.setMargins(DisplayUtils.dip2px(context, 2), 0,
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
lparams.weight = 1;
imageView.setLayoutParams(lparams);
ImageUtils.Companion.getInstance().display(context.getResources(), imageView,
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
break;
case 1:
imageView = new SimpleDraweeView(context);
lparams = new LinearLayout.LayoutParams(width, width / 2);
lparams.setMargins(DisplayUtils.dip2px(context, 2), 0,
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
imageView.setLayoutParams(lparams);
ImageUtils.Companion.getInstance().display(context.getResources(), imageView,
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
break;
default:
imageView = new SimpleDraweeView(context);
lparams = new LinearLayout.LayoutParams(
0, width / 2 - DisplayUtils.dip2px(context, 4));
lparams.setMargins(DisplayUtils.dip2px(context, 2), 0,
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
lparams.weight = 1;
imageView.setLayoutParams(lparams);
ImageUtils.Companion.getInstance().display(context.getResources(), imageView,
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
break;
}
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent checkIntent = new Intent(context, ViewImageActivity.class);
checkIntent.putExtra("urls", (ArrayList<String>) list);
checkIntent.putExtra("current", position);
checkIntent.putExtra("ScaleType", "FIT_CENTER");
checkIntent.putExtra("entrance", entrance);
Intent checkIntent = ViewImageActivity.getViewImageIntent(context, (ArrayList<String>) list, position, entrance);
context.startActivity(checkIntent);
}
});
return imageView;
}
}

View File

@ -1,81 +0,0 @@
package com.gh.common.util;
import android.content.Context;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import org.json.JSONArray;
import de.greenrobot.event.EventBus;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.adapter.rxjava.HttpException;
import rx.Observable;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
/**
* Created by khy on 2016/8/24.
* croncern 工具类
*/
public class ConcernUtils {
public static void postConcernGameId(final Context context, final String gameId) {
TokenUtils.getToken(context, true)
.flatMap(new Func1<String, Observable<ResponseBody>>() {
@Override
public Observable<ResponseBody> call(String token) {
JSONArray params = new JSONArray();
params.put(gameId);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), params.toString());
return RetrofitManager.getUser().postConcern(token, body);
}
}).subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Response<ResponseBody>());
}
public static void deleteConcernData(final Context context, final String gameId) {
TokenUtils.getToken(context, true)
.flatMap(new Func1<String, Observable<ResponseBody>>() {
@Override
public Observable<ResponseBody> call(String token) {
return RetrofitManager.getUser().deleteConcern(token, gameId);
}
}).subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Response<ResponseBody>());
}
public static void updateConcernData(final Context context, final JSONArray data) {
TokenUtils.getToken(context, true)
.flatMap(new Func1<String, Observable<ResponseBody>>() {
@Override
public Observable<ResponseBody> call(String token) {
RequestBody body = RequestBody.create(MediaType.parse("application/json"),
data.toString());
return RetrofitManager.getUser().putConcern(token, body);
}
})
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Response<ResponseBody>(){
@Override
public void onResponse(ResponseBody response) {
super.onResponse(response);
EventBus.getDefault().post(new EBReuse("UpdateConcernSuccess"));
}
@Override
public void onFailure(HttpException e) {
super.onFailure(e);
EventBus.getDefault().post(new EBReuse("UpdateConcernFailure"));
}
});
}
}

View File

@ -0,0 +1,85 @@
package com.gh.common.util
import android.content.Context
import com.gh.gamecenter.eventbus.EBConcernChanged
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONArray
import retrofit2.HttpException
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
/**
* Created by khy on 2016/8/24.
* croncern 工具类
*/
object ConcernUtils {
fun postConcernGameId(context: Context, gameId: String, listener: onConcernListener?) {
val params = JSONArray()
params.put(gameId)
val body = RequestBody.create(MediaType.parse("application/json"), params.toString())
RetrofitManager.getInstance(context).getApi()
.postConcern(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>(){
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
listener?.onSuccess()
EventBus.getDefault().post(EBConcernChanged(gameId, true))
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
listener?.onError()
}
})
}
fun deleteConcernData(context: Context, gameId: String, listener: onConcernListener?) {
RetrofitManager.getInstance(context).getApi()
.deleteConcern(gameId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>(){
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
listener?.onSuccess()
EventBus.getDefault().post(EBConcernChanged(gameId, false))
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
listener?.onError()
}
})
}
fun updateConcernData(context: Context, data: JSONArray) {
val body = RequestBody.create(MediaType.parse("application/json"),
data.toString())
RetrofitManager.getInstance(context).getApi()
.putConcern(body)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody) {
super.onResponse(response)
EventBus.getDefault().post(EBConcernChanged())
}
})
}
interface onConcernListener {
fun onSuccess()
fun onError()
}
}

View File

@ -3,7 +3,7 @@ package com.gh.common.util;
import android.content.Context;
import android.os.Build;
import com.gh.download.DownloadEntity;
import com.lightgame.download.DownloadEntity;
import com.gh.gamecenter.db.info.ConcernInfo;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.NewsDetailEntity;
@ -11,184 +11,193 @@ import com.gh.gamecenter.manager.ConcernManager;
import com.gh.gamecenter.manager.DataCollectionManager;
import com.gh.gamecenter.manager.PackageManager;
import org.json.JSONArray;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Created by LGT on 2016/12/9.
* 数据收集 工具类data.ghzhushou.com
* 数据收集 工具类data.ghzs666.com
*/
public class DataCollectionUtils {
// 上传助手奔溃数据
public static void uploadError(Context context, String msg) {
Map<String, Object> map = new HashMap<>();
map.put("content", msg);
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));
}
// 上传助手奔溃数据
public static void uploadError(Context context, String msg) {
Map<String, Object> map = new HashMap<>();
map.put("content", msg);
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));
}
// 上传下载数据(开始、完成)
public static void uploadDownload(Context context, DownloadEntity downloadEntity, String status) {
Map<String, Object> map = new HashMap<>();
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
if (downloadEntity.isPluggable()) {
map.put("method", "插件化");
map.put("btn_status", "插件化");
} else if (downloadEntity.isUpdate()) {
map.put("method", "更新");
map.put("btn_status", "更新");
} else {
map.put("method", "正常");
map.put("btn_status", "下载");
}
map.put("platform", PlatformUtils.getInstance(context).getPlatformName(downloadEntity.getPlatform()));
map.put("status", status);
map.put("location", downloadEntity.getLocation());
map.put("entrance", downloadEntity.getEntrance());
map.put("installed", downloadEntity.getInstalled());
map.put("network", NetworkUtils.getConnectedType(context));
DataCollectionManager.onEvent(context, "download", map);
}
// 上传下载数据(开始、完成)
public static void uploadDownload(Context context, DownloadEntity downloadEntity, String status) {
Map<String, Object> map = new HashMap<>();
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
if (downloadEntity.isPluggable()) {
map.put("method", "插件化");
map.put("btn_status", "插件化");
} else if (downloadEntity.isUpdate()) {
map.put("method", "更新");
map.put("btn_status", "更新");
} else {
map.put("method", "正常");
map.put("btn_status", "下载");
}
map.put("platform", PlatformUtils.getInstance(context).getPlatformName(downloadEntity.getPlatform()));
map.put("status", status);
map.put("location", downloadEntity.getLocation());
map.put(EntranceUtils.KEY_ENTRANCE, downloadEntity.getEntrance());
map.put("installed", downloadEntity.getInstalled());
map.put("network", NetworkUtils.getConnectedType(context));
DataCollectionManager.onEvent(context, "download", map);
}
// 上传点击数据
public static void uploadClick(Context context, String... args) {
if (args.length < 2) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("location", args[0]);
map.put("page", args[1]);
if (args.length == 3) {
map.put("title", args[2]);
}
DataCollectionManager.onEvent(context, "click-item", map);
}
// 上传点击数据
public static void uploadClick(Context context, String... args) {
if (args.length < 2) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("location", args[0]);
map.put("page", args[1]);
if (args.length == 3) {
map.put("title", args[2]);
}
DataCollectionManager.onEvent(context, "click-item", map);
}
// 上传游戏数据
public static void uploadGame(Context context, GameEntity gameEntity, int seconds, String from) {
Map<String, Object> map = new HashMap<>();
map.put("game", gameEntity.getName());
map.put("game_id", gameEntity.getId());
map.put("time", seconds);
map.put("from", from);
DataCollectionManager.onEvent(context, "game", map);
}
// 上传游戏数据
public static void uploadGame(Context context, GameEntity gameEntity, int seconds, String from) {
Map<String, Object> map = new HashMap<>();
map.put("game", gameEntity.getName());
map.put("game_id", gameEntity.getId());
map.put("time", seconds);
map.put("from", from);
DataCollectionManager.onEvent(context, "game", map);
}
// 上传新闻数据
public static void uploadNews(Context context, NewsDetailEntity newsDetailEntity,
GameEntity gameEntity, int seconds, String from) {
Map<String, Object> map = new HashMap<>();
map.put("title", newsDetailEntity.getTitle());
map.put("type", newsDetailEntity.getType());
map.put("author", newsDetailEntity.getAuthor());
if (gameEntity != null) {
map.put("game", gameEntity.getName());
map.put("game_id", gameEntity.getId());
}
map.put("time", seconds);
map.put("from", from);
DataCollectionManager.onEvent(context, "news", map);
}
// 上传新闻数据
public static void uploadNews(Context context, NewsDetailEntity newsDetailEntity,
GameEntity gameEntity, int seconds, String from) {
Map<String, Object> map = new HashMap<>();
map.put("title", newsDetailEntity.getTitle());
map.put("type", newsDetailEntity.getType());
map.put("author", newsDetailEntity.getAuthor());
if (gameEntity != null) {
map.put("game", gameEntity.getName());
map.put("game_id", gameEntity.getId());
}
map.put("time", seconds);
map.put("from", from);
DataCollectionManager.onEvent(context, "news", map);
}
// 上传安装或卸载数据
public static void uploadInorunstall(Context context, String type, String packageName) {
Map<String, Object> map = new HashMap<>();
map.put("type", type);
map.put("packageName", packageName);
DataCollectionManager.onEvent(context, "inorunstall", map);
}
// 上传安装或卸载数据
public static void uploadInorunstall(Context context, String type, String packageName) {
Map<String, Object> map = new HashMap<>();
map.put("type", type);
map.put("packageName", packageName);
DataCollectionManager.onEvent(context, "inorunstall", map);
}
// 上传劫持数据
public static void uploadHijack(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("hijack_url", downloadEntity.getError());
DataCollectionManager.onEvent(context, "hijack", map);
}
// 上传劫持数据
public static void uploadHijack(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("hijack_url", downloadEntity.getError());
DataCollectionManager.onEvent(context, "hijack", map);
}
// 上传用户数据
public static void uploadUser(Context context) {
ConcernManager concernManager = new ConcernManager(context);
ArrayList<String> concernList = new ArrayList<>();
for (ConcernInfo entity : concernManager.getAllConcern()) {
if (entity.isConcern()) {
concernList.add(entity.getGameName());
}
}
Map<String, Object> map = new HashMap<>();
map.put("type", Build.MODEL);
map.put("system", Build.VERSION.SDK_INT + "=" + Build.VERSION.RELEASE);
map.put("install", PackageManager.getInstalledList());
map.put("concern", concernList);
DataCollectionManager.upsert(context, "user", map);
}
// 上传用户数据
public static void uploadUser(Context context) {
ConcernManager concernManager = new ConcernManager(context);
ArrayList<String> concernList = new ArrayList<>();
for (ConcernInfo entity : concernManager.getAllConcern()) {
if (entity.isConcern()) {
concernList.add(entity.getGameName());
}
}
Map<String, Object> map = new HashMap<>();
map.put("type", Build.MODEL);
map.put("system", Build.VERSION.SDK_INT + "=" + Build.VERSION.RELEASE);
map.put("install", PackageManager.getInstalledList());
map.put("concern", concernList);
DataCollectionManager.upsert(context, "user", map);
}
// 上传搜索数据
public static void uploadSearch(Context context, String... args) {
if (args.length != 5) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("from", args[2]);
map.put("search_type", args[1]);
map.put("key", args[0]);
map.put("game_id", args[3]);
map.put("game_name", args[4]);
map.put("netword", NetworkUtils.getConnectedType(context));
map.put("type", "search");
map.put("device_type", android.os.Build.MODEL);
map.put("device_system", android.os.Build.VERSION.SDK_INT + "=" + android.os.Build.VERSION.RELEASE);
DataCollectionManager.onEvent(context, "search", map);
}
// 上传搜索数据
public static void uploadSearch(Context context, String... args) {
if (args.length != 5) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("from", args[2]);
map.put("search_type", args[1]);
map.put("key", args[0]);
map.put("game_id", args[3]);
map.put("game_name", args[4]);
map.put("netword", NetworkUtils.getConnectedType(context));
map.put("type", "search");
map.put("device_type", android.os.Build.MODEL);
map.put("device_system", android.os.Build.VERSION.SDK_INT + "=" + android.os.Build.VERSION.RELEASE);
DataCollectionManager.onEvent(context, "search", map);
}
// 上传搜索点击数据
public static void uploadSearchClick(Context context, String... args) {
if (args.length != 5) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("from", args[2]);
map.put("search_type", args[1]);
map.put("key", args[0]);
map.put("game_id", args[3]);
map.put("game_name", args[4]);
map.put("netword", NetworkUtils.getConnectedType(context));
map.put("type", "click");
map.put("device_type", android.os.Build.MODEL);
map.put("device_system", android.os.Build.VERSION.SDK_INT + "=" + android.os.Build.VERSION.RELEASE);
DataCollectionManager.onEvent(context, "search", map);
}
// 上传搜索点击数据
public static void uploadSearchClick(Context context, String... args) {
if (args.length != 5) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("from", args[2]);
map.put("search_type", args[1]);
map.put("key", args[0]);
map.put("game_id", args[3]);
map.put("game_name", args[4]);
map.put("netword", NetworkUtils.getConnectedType(context));
map.put("type", "click");
map.put("device_type", android.os.Build.MODEL);
map.put("device_system", android.os.Build.VERSION.SDK_INT + "=" + android.os.Build.VERSION.RELEASE);
DataCollectionManager.onEvent(context, "search", map);
}
// 上传关注数据
public static void uploadConcern(Context context, String... args) {
if (args.length < 3) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("game", args[0]);
map.put("game_id", args[1]);
map.put("type", args[2]);
DataCollectionManager.onEvent(context, "concern", map);
}
// 上传关注数据
public static void uploadConcern(Context context, String... args) {
if (args.length < 3) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("game", args[0]);
map.put("game_id", args[1]);
map.put("type", args[2]);
DataCollectionManager.onEvent(context, "concern", map);
}
//上传推荐位数据
public static void uploadPosition(Context context, String... args) {
if (args.length < 3) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("page", args[0]);
map.put("location", args[1]);
map.put("name", args[2]);
DataCollectionManager.onEvent(context, "position", map);
}
//上传推荐位数据
public static void uploadPosition(Context context, String... args) {
if (args.length < 3) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("page", args[0]);
map.put("location", args[1]);
map.put("name", args[2]);
DataCollectionManager.onEvent(context, "position", map);
}
//上传应用列表
public static void uploadAppList(Context context, JSONArray applist) {
Map<String, Object> map = new HashMap<>();
map.put("applist", applist);
DataCollectionManager.onEvent(context, "applist", map);
}
}

View File

@ -2,9 +2,11 @@ package com.gh.common.util;
import android.content.Context;
import com.gh.download.DownloadEntity;
import com.halo.assistant.HaloApp;
import com.lightgame.download.DownloadEntity;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.lightgame.utils.Utils;
import org.json.JSONObject;
@ -23,67 +25,67 @@ import rx.schedulers.Schedulers;
*/
public class DataLogUtils {
// 上传日志
public static void uploadLog(Context context, String topic, Map<String, Object> map) {
String version = PackageUtils.getVersionName(context);
String user = Installation.getUUID(context);
String channel = (String) PackageUtils.getMetaData(context, context.getPackageName(), "TD_CHANNEL_ID");
map.put("version", version);
map.put("user", user);
map.put("device_id", TokenUtils.getDeviceId(context));
map.put("channel", channel);
// 轮播图
public static void uploadLunbotuLog(Context context, String type, String title, String location) {
Map<String, Object> map = new HashMap<>();
map.put("location", location);
map.put("type", type);
map.put("title", title);
map.put("form", "click");
uploadLog(context, "lunbotu", map);
}
Map<String, String> params = new HashMap<>();
params.put("topic", topic);
params.put("source", "GH-ASSIST-Client");
params.put("time", String.valueOf(Utils.getTime(context)));
params.put("content", new JSONObject(map).toString());
// 上传日志
public static void uploadLog(Context context, String topic, Map<String, Object> map) {
String version = PackageUtils.getPatchVersionName();
String user = Installation.getUUID(context);
String channel = HaloApp.getInstance().getChannel();
map.put("version", version);
map.put("user", user);
map.put("device_id", TokenUtils.getDeviceId(context));
map.put("channel", channel);
RequestBody body = RequestBody.create(MediaType.parse("application/json"),
new JSONObject(params).toString());
RetrofitManager.getData().postLog(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>());
}
Map<String, String> params = new HashMap<>();
params.put("topic", topic);
params.put("source", "GH-ASSIST-Client");
params.put("time", String.valueOf(Utils.getTime(context)));
params.put("content", new JSONObject(map).toString());
// 轮播图
public static void uploadLunbotuLog(Context context, String type, String title, String location) {
Map<String, Object> map = new HashMap<>();
map.put("location", location);
map.put("type", type);
map.put("title", title);
map.put("form", "click");
uploadLog(context, "lunbotu", map);
}
RequestBody body = RequestBody.create(MediaType.parse("application/json"),
new JSONObject(params).toString());
RetrofitManager.getInstance(context).getData().postLog(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>());
}
// 网络错误
public static void uploadNeterrorLog(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("error", downloadEntity.getError());
uploadLog(context, "neterror", map);
}
// 网络错误
public static void uploadNeterrorLog(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("error", downloadEntity.getError());
uploadLog(context, "neterror", map);
}
// 助手更新
public static void uploadUpgradeLog(Context context, String step) {
Map<String, Object> map = new HashMap<>();
map.put("step", step);
uploadLog(context, "upgrade", map);
}
// 助手更新
public static void uploadUpgradeLog(Context context, String step) {
Map<String, Object> map = new HashMap<>();
map.put("step", step);
uploadLog(context, "upgrade", map);
}
// 链接劫持
public static void uploadHijack(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("hijack_url", downloadEntity.getError());
uploadLog(context, "hijack", map);
}
// 链接劫持
public static void uploadHijack(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("hijack_url", downloadEntity.getError());
uploadLog(context, "hijack", map);
}
}

View File

@ -4,10 +4,17 @@ import android.app.Activity;
import android.app.Application;
import android.content.Context;
import com.gh.common.constant.Config;
import com.halo.assistant.TinkerApp;
import com.tencent.bugly.beta.tinker.TinkerManager;
import com.tencent.bugly.crashreport.CrashReport;
import com.tencent.mta.track.StatisticsDataAPI;
import com.tencent.stat.MtaSDkException;
import com.tencent.stat.StatConfig;
import com.tencent.stat.StatCrashReporter;
import com.tencent.stat.StatReportStrategy;
import com.tencent.stat.StatService;
import com.tencent.tinker.lib.tinker.Tinker;
import com.tendcloud.tenddata.TCAgent;
import java.util.HashMap;
@ -20,29 +27,85 @@ import java.util.Properties;
*/
public class DataUtils {
public static void init(Application application) {
/**
* 初始化各种统计工具仅在release build非debug模式启用统计
*
* @param context
* @param debug 是否debug模式
* @param channel
*/
public static void init(final Application context, final boolean debug, String channel) {
//TalkingData
//dubug true release false
TCAgent.LOG_ON = true;
TCAgent.init(application);
TCAgent.setReportUncaughtExceptions(true);
try {
TCAgent.LOG_ON = debug;
TCAgent.init(context, Config.TALKINGDATA_APPID, channel);
/**
*
* 不要启用!!!!不要启用,全部由{@link com.gh.base.AppUncaughtHandler}处理
*/
TCAgent.setReportUncaughtExceptions(false);
} catch (Exception e) {
e.printStackTrace();
}
//MTA
// 打开debug开关可查看mta上报日志或错误
// dubug true release false
StatConfig.setDebugEnable(true);
// 收集未处理的异常
StatConfig.setAutoExceptionCaught(true);
// 设置数据上报策略
StatConfig.setStatSendStrategy(StatReportStrategy.PERIOD);
StatConfig.setSendPeriodMinutes(5);
// 开启收集服务
String TA_APPKEY = (String) PackageUtils.getMetaData(application, application.getPackageName(), "TA_APPKEY");
try {
StatService.startStatService(application, TA_APPKEY, com.tencent.stat.common.StatConstants.VERSION);
/**
*
* 不要启用!!!!全部由{@link com.gh.base.AppUncaughtHandler}处理
*/
StatConfig.setAutoExceptionCaught(false);
StatCrashReporter crashReporter = StatCrashReporter.getStatCrashReporter(context);
crashReporter.setJavaCrashHandlerStatus(false);
// crashReporter.setEnableInstantReporting(true);
StatConfig.setDebugEnable(debug);
// 设置数据上报策略
if (debug) {
StatConfig.setStatSendStrategy(StatReportStrategy.INSTANT);
} else {
StatConfig.setStatSendStrategy(StatReportStrategy.PERIOD);
StatConfig.setSendPeriodMinutes(5);
}
// 设置启用Tlink
StatConfig.setTLinkStatus(true);
// 设置启用可视化埋点
StatisticsDataAPI.instance(context);
StatConfig.init(context);
StatConfig.setInstallChannel(channel);
StatConfig.setAntoActivityLifecycleStat(true);
StatConfig.setAppVersion(PackageUtils.getPatchVersionName());
StatService.setContext(context);
StatService.registerActivityLifecycleCallbacks(context);
// 开启收集服务
StatService.startStatService(context, Config.MTA_APPKEY, com.tencent.stat.common.StatConstants.VERSION);
} catch (MtaSDkException e) {
e.printStackTrace();
}
// init bugly
try {
CrashReport.setIsDevelopmentDevice(context, debug);
CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(context);
strategy.setEnableANRCrashMonitor(false);
strategy.setEnableNativeCrashMonitor(false);
strategy.setAppChannel(channel);
strategy.setAppVersion(PackageUtils.getPatchVersionName());
CrashReport.initCrashReport(context, Config.BUGLY_APPID, debug, strategy);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void onEvent(Context var0, String var1, String var2) {
@ -50,6 +113,24 @@ public class DataUtils {
StatService.trackCustomEvent(var0, var1, var2);
}
public static void onPause(Activity var0) {
TCAgent.onPageEnd(var0, var0.getClass().getSimpleName());
StatService.onPause(var0);
}
public static void onResume(Activity var0) {
TCAgent.onPageStart(var0, var0.getClass().getSimpleName());
StatService.onResume(var0);
}
// 游戏启动
public static void onGameLaunchEvent(Context context, String gameName, String platform, String page) {
Map<String, Object> kv = new HashMap<>();
kv.put("版本", platform);
kv.put("页面", page);
onEvent(context, "游戏启动", gameName, kv);
}
public static void onEvent(Context var0, String var1, String var2, Map<String, Object> var3) {
TCAgent.onEvent(var0, var1, var2, var3);
Properties prop = new Properties();
@ -60,41 +141,23 @@ public class DataUtils {
StatService.trackCustomKVEvent(var0, var1, prop);
}
public static void onPause(Activity var0) {
TCAgent.onPause(var0);
StatService.onPause(var0);
}
public static void onResume(Activity var0) {
TCAgent.onResume(var0);
StatService.onResume(var0);
}
// 游戏启动
public static void onGameLaunchEvent(Context context, String gameName, String platform, String page) {
Map<String, Object> kv = new HashMap<>();
kv.put("版本", platform);
kv.put("页面", page);
onEvent(context, "游戏启动", gameName, kv);
}
// 游戏下载
public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status) {
Map<String, Object> kv = new HashMap<>();
kv.put("版本", platform);
kv.put("状态", status);
DataUtils.onEvent(context, "游戏下载", gameName, kv);
onEvent(context, "游戏下载", gameName, kv);
Map<String, Object> kv2 = new HashMap<>();
kv2.put("版本", platform);
kv2.put("状态", status);
kv2.put("位置", entrance);
DataUtils.onEvent(context, "游戏下载位置", gameName, kv2);
onEvent(context, "游戏下载位置", gameName, kv2);
Map<String, Object> kv3 = new HashMap<>();
kv3.put(entrance, "下载数");
kv3.put(entrance, status);
DataUtils.onEvent(context, "应用数据", gameName, kv3);
onEvent(context, "应用数据", gameName, kv3);
}
// 游戏更新
@ -102,7 +165,7 @@ public class DataUtils {
Map<String, Object> kv = new HashMap<>();
kv.put("版本", paltform);
kv.put("状态", status);
DataUtils.onEvent(context, "游戏更新", gameName, kv);
onEvent(context, "游戏更新", gameName, kv);
}
}

View File

@ -0,0 +1,259 @@
package com.gh.common.util;
import android.content.Intent;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.view.View;
import com.gh.common.constant.Config;
import com.gh.common.view.DownloadDialog;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.DetailViewHolder;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.manager.PackageManager;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
/**
* Created by khy on 27/06/17.
* 详情下载工具类
*/
public class DetailDownloadUtils {
public static void detailInitDownload(DetailViewHolder viewHolder, boolean isCheck) {
if (Config.isShow(viewHolder.context)) {
viewHolder.downloadBottom.setVisibility(View.VISIBLE);
} else {
viewHolder.downloadBottom.setVisibility(View.GONE);
}
if (viewHolder.gameEntity != null && "光环助手".equals(viewHolder.gameEntity.getName())) {
viewHolder.downloadBottom.setVisibility(View.GONE);
} else if (viewHolder.gameEntity == null || viewHolder.gameEntity.getApk().isEmpty()) {
viewHolder.downloadTv.setVisibility(View.VISIBLE);
viewHolder.downloadPb.setVisibility(View.GONE);
viewHolder.downloadPer.setVisibility(View.GONE);
if (TextUtils.isEmpty(viewHolder.downloadOffText)) {
viewHolder.downloadTv.setText("暂无下载");
} else {
viewHolder.downloadTv.setText(viewHolder.downloadOffText);
}
viewHolder.downloadTv.setBackgroundResource(R.drawable.game_item_btn_pause_style);
viewHolder.downloadTv.setTextColor(0xFF999999);
viewHolder.downloadTv.setClickable(false);
} else {
viewHolder.downloadTv.setVisibility(View.VISIBLE);
viewHolder.downloadPb.setVisibility(View.GONE);
viewHolder.downloadPer.setVisibility(View.GONE);
boolean isInstalled = false;
if (viewHolder.gameEntity.getApk().size() == 1
&& PackageManager.isInstalled(viewHolder.gameEntity.getApk().get(0).getPackageName())) {
isInstalled = true;
}
if (isInstalled) {
if (PackageManager.isCanUpdate(viewHolder.gameEntity.getId(), viewHolder.gameEntity.getApk().get(0).getPackageName())) {
if (viewHolder.isNewsDetail) {
viewHolder.downloadTv.setText(R.string.update);
} else if (TextUtils.isEmpty(viewHolder.downloadAddWord)) {
viewHolder.downloadTv.setText(String.format("更新《%s》",
viewHolder.gameEntity.getName()));
} else {
viewHolder.downloadTv.setText(String.format("更新《%s》%s",
viewHolder.gameEntity.getName(), viewHolder.downloadAddWord));
}
viewHolder.downloadTv.setBackgroundResource(
R.drawable.game_item_btn_download_style);
} else {
if (viewHolder.gameEntity.getTag() != null && viewHolder.gameEntity.getTag().size() != 0
&& !TextUtils.isEmpty(viewHolder.gameEntity.getApk().get(0).getGhVersion())
&& !PackageUtils.isSignature(viewHolder.context, viewHolder.gameEntity.getApk().get(0).getPackageName())) {
if (viewHolder.isNewsDetail) {
viewHolder.downloadTv.setText(R.string.pluggable);
} else if (TextUtils.isEmpty(viewHolder.downloadAddWord)) {
viewHolder.downloadTv.setText(String.format("插件化《%s》",
viewHolder.gameEntity.getName()));
} else {
viewHolder.downloadTv.setText(String.format("插件化《%s》%s",
viewHolder.gameEntity.getName(), viewHolder.downloadAddWord));
}
viewHolder.downloadTv.setBackgroundResource(
R.drawable.game_item_btn_plugin_style);
} else {
if (viewHolder.isNewsDetail) {
viewHolder.downloadTv.setText(R.string.launch);
} else if (TextUtils.isEmpty(viewHolder.downloadAddWord)) {
viewHolder.downloadTv.setText(String.format("启动《%s》",
viewHolder.gameEntity.getName()));
} else {
viewHolder.downloadTv.setText(String.format("启动《%s》%s",
viewHolder.gameEntity.getName(), viewHolder.downloadAddWord));
}
viewHolder.downloadTv.setBackgroundResource(
R.drawable.game_item_btn_launch_style);
}
}
} else {
String status = GameUtils.getDownloadBtnText(viewHolder.context, viewHolder.gameEntity);
switch (status) {
case "插件化":
viewHolder.downloadTv.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
break;
case "打开":
viewHolder.downloadTv.setBackgroundResource(R.drawable.game_item_btn_launch_style);
break;
default:
viewHolder.downloadTv.setBackgroundResource(R.drawable.game_item_btn_download_style);
break;
}
if (viewHolder.isNewsDetail) {
viewHolder.downloadTv.setText(status);
} else if (TextUtils.isEmpty(viewHolder.downloadAddWord)) {
viewHolder.downloadTv.setText(String.format(status + "《%s》",
viewHolder.gameEntity.getName()));
} else {
viewHolder.downloadTv.setText(String.format(status + "《%s》%s",
viewHolder.gameEntity.getName(), viewHolder.downloadAddWord));
}
}
}
if (isCheck && viewHolder.gameEntity != null
&& viewHolder.gameEntity.getApk().size() == 1) {
String url = viewHolder.gameEntity.getApk().get(0).getUrl();
DownloadEntity downloadEntity = DownloadManager.getInstance(viewHolder.context).getDownloadEntityByUrl(url);
if (downloadEntity != null) {
viewHolder.downloadEntity = downloadEntity;
viewHolder.downloadTv.setVisibility(View.GONE);
viewHolder.downloadPb.setVisibility(View.VISIBLE);
viewHolder.downloadPer.setVisibility(View.VISIBLE);
detailInvalidate(viewHolder);
}
}
}
public static void detailInvalidate(DetailViewHolder viewHolder) {
viewHolder.downloadPb.setProgress((int) (viewHolder.downloadEntity.getPercent() * 10));
viewHolder.downloadPer.setTextColor(0xFFFFFFFF);
DownloadEntity downloadEntity = viewHolder.downloadEntity;
switch (downloadEntity.getStatus()) {
case downloading:
case pause:
case timeout:
case neterror:
case waiting:
viewHolder.downloadPer.setText(R.string.downloading);
break;
case done:
viewHolder.downloadPer.setText("安装");
if (downloadEntity.isPluggable()
&& PackageManager.isInstalled(downloadEntity.getPackageName())) {
viewHolder.downloadPb.setProgressDrawable(ContextCompat.getDrawable(viewHolder.context, R.drawable.progressbar_plugin_radius_style));
} else {
viewHolder.downloadPb.setProgressDrawable(ContextCompat.getDrawable(viewHolder.context, R.drawable.progressbar_normal_radius_style));
}
break;
case cancel:
case hijack:
case notfound:
detailInitDownload(viewHolder, false);
break;
default:
break;
}
}
public static class OnDetailDownloadClickListener implements View.OnClickListener {
private DetailViewHolder mViewHolder;
private GameEntity mGameEntity;
private DownloadEntity mDownloadEntity;
private String mEntrance;
private String mName;
private String mTitle;
public OnDetailDownloadClickListener(DetailViewHolder viewHolder, String entrance, String name, String title) {
mViewHolder = viewHolder;
mGameEntity = viewHolder.gameEntity;
mDownloadEntity = viewHolder.downloadEntity;
mEntrance = entrance;
mName = name;
mTitle = title;
}
@Override
public void onClick(View v) {
if (v == mViewHolder.downloadTv) {
if (mGameEntity != null && !mGameEntity.getApk().isEmpty()) {
if (mGameEntity.getApk().size() == 1) {
String str = mViewHolder.downloadTv.getText().toString();
if (str.contains("启动")) {
DataUtils.onGameLaunchEvent(mViewHolder.context, mGameEntity.getName(), mGameEntity.getApk().get(0).getPlatform(), mName);
PackageUtils.launchApplicationByPackageName(mViewHolder.context, mGameEntity.getApk().get(0).getPackageName());
} else if (NetworkUtils.isWifiConnected(mViewHolder.context)) {
download();
} else {
DialogUtils.showDownloadDialog(mViewHolder.context, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
download();
}
});
}
} else {
DownloadDialog.getInstance(mViewHolder.context)
.showPopupWindow(v, mGameEntity, StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"), mName + ":" + mTitle);
}
} else {
Utils.toast(mViewHolder.context, "稍等片刻~!游戏正在上传中...");
}
} else if (v == mViewHolder.downloadPb || v == mViewHolder.downloadPer) {
String str = mViewHolder.downloadPer.getText().toString();
if ("下载中".equals(str)) {
Intent intent = DownloadManagerActivity.getDownloadMangerIntent(mViewHolder.context,
mGameEntity.getApk().get(0).getUrl(), StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"));
mViewHolder.context.startActivity(intent);
} else if ("安装".equals(str)) {
if (mDownloadEntity == null) {
mDownloadEntity = DownloadManager.getInstance(mViewHolder.context).getDownloadEntityByUrl(mGameEntity.getApk().get(0).getUrl());
}
if (mDownloadEntity != null) {
PackageUtils.launchSetup(mViewHolder.context, mDownloadEntity.getPath());
}
}
}
}
private void download() {
String str = mViewHolder.downloadTv.getText().toString();
String method;
if (str.contains("更新")) {
method = "更新";
} else if (str.contains("插件化")) {
method = "插件化";
} else {
method = mViewHolder.context.getString(R.string.download);
}
ApkEntity apkEntity = mGameEntity.getApk().get(0);
String msg = FileUtils.isCanDownload(mViewHolder.context, apkEntity.getSize());
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(mViewHolder.context, mGameEntity.getName(), apkEntity.getPlatform(), StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"), "下载开始");
DownloadManager.createDownload(mViewHolder.context, apkEntity, mGameEntity, method, StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"), mName + ":" + mTitle);
mViewHolder.downloadTv.setVisibility(View.GONE);
mViewHolder.downloadPb.setVisibility(View.VISIBLE);
mViewHolder.downloadPer.setVisibility(View.VISIBLE);
mViewHolder.downloadPb.setProgress(0);
mViewHolder.downloadPer.setText("0.0%");
// DownloadManager.getInstance(mViewHolder.context).putStatus(apkEntity.getUrl(), "downloading");
} else {
Utils.toast(mViewHolder.context, msg);
}
}
}
}

View File

@ -0,0 +1,197 @@
package com.gh.common.util;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import com.gh.gamecenter.kuaichuan.WifiMgr;
import com.lightgame.utils.Util_System_Phone_State;
import com.tencent.stat.StatConfig;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import static android.os.Build.MANUFACTURER;
import static android.os.Build.MODEL;
/**
* Created by khy on 2/08/17.
*/
public class DeviceUtils {
public static JSONObject getLoginDevice(Context context) throws JSONException { // device数据
context = context.getApplicationContext();
JSONObject object = new JSONObject();
object.put("os", "Android");
object.put("imei", Util_System_Phone_State.getDeviceId(context));
object.put("mac", getMac(context));
object.put("model", MODEL);
object.put("manufacturer", MANUFACTURER);
object.put("android_id", Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID));
object.put("android_sdk", Build.VERSION.SDK_INT);
object.put("android_version", android.os.Build.VERSION.RELEASE);
object.put("ip", getIPAddress(context));
object.put("network", getNetwork(context));
return object;
}
public static JSONObject getUserDevice(Context context) { // 判断新老用户device数据
JSONObject object = new JSONObject();
try {
object.put("IMEI", Util_System_Phone_State.getDeviceId(context));
object.put("ANDROID_ID", Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID));
object.put("MAC", getMac(context));
object.put("MTA_ID", StatConfig.getMid(context));
object.put("MANUFACTURER", MANUFACTURER);
object.put("MODEL", MODEL);
object.put("ANDROID_SDK", Build.VERSION.SDK_INT);
object.put("ANDROID_VERSION", android.os.Build.VERSION.RELEASE);
} catch (JSONException e) {
e.printStackTrace();
}
return object;
}
private static String getMac(Context context) {
String str = "";
String macSerial = "";
try {
Process pp = Runtime.getRuntime().exec(
"cat /sys/class/net/wlan0/address ");
InputStreamReader ir = new InputStreamReader(pp.getInputStream());
LineNumberReader input = new LineNumberReader(ir);
for (; null != str;) {
str = input.readLine();
if (str != null) {
macSerial = str.trim();// 去空格
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
if ("".equals(macSerial)) {
try {
return loadFileAsString("/sys/class/net/eth0/address")
.toUpperCase().substring(0, 17);
} catch (Exception e) {
e.printStackTrace();
}
}
if (TextUtils.isEmpty(macSerial)) { // 备用方案
macSerial = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE)).getConnectionInfo().getMacAddress();
}
return macSerial;
}
private static String loadFileAsString(String fileName) throws Exception {
FileReader reader = new FileReader(fileName);
String text = loadReaderAsString(reader);
reader.close();
return text;
}
private static String loadReaderAsString(Reader reader) throws Exception {
StringBuilder builder = new StringBuilder();
char[] buffer = new char[4096];
int readLength = reader.read(buffer);
while (readLength >= 0) {
builder.append(buffer, 0, readLength);
readLength = reader.read(buffer);
}
return builder.toString();
}
private static String getIPAddress(Context context) {
NetworkInfo info = ((ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
if (info != null && info.isConnected()) {
if (info.getType() == ConnectivityManager.TYPE_MOBILE) {//当前使用2G/3G/4G网络
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
} else if (info.getType() == ConnectivityManager.TYPE_WIFI) {//当前使用无线网络
return WifiMgr.getInstance(context).getCurrentIpAddress();
}
} else {
//当前无网络连接,请在设置中打开网络
}
return null;
}
private static String getNetwork(Context context) {
NetworkInfo info = ((ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
if (info != null && info.isConnected()) {
int typeMobile = info.getType();
if (typeMobile == ConnectivityManager.TYPE_WIFI) {
return "WIFI";
} else if (typeMobile == ConnectivityManager.TYPE_MOBILE) {
String status;
switch (typeMobile) {
case TelephonyManager.NETWORK_TYPE_GPRS:
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_IDEN:
status = "2G";
break;
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_EHRPD:
case TelephonyManager.NETWORK_TYPE_HSPAP:
status = "3G";
break;
case TelephonyManager.NETWORK_TYPE_LTE:
status = "4G";
break;
default:
status = "未知";
break;
}
return status;
}
}
return null;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -5,64 +5,63 @@ import android.content.res.Resources;
public class DisplayUtils {
/**
* 根据手机的分辨率从 dip(像素) 的单位 转成为 px
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 dip(像素) 的单位 转成为 px
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dip
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dip
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 将px值转换为sp值保证文字大小不变
*
* @param pxValue
* @param pxValue
* DisplayMetrics类中属性scaledDensity
* @return
*/
public static int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
/**
* 将px值转换为sp值保证文字大小不变
*
* @param pxValue
* @param pxValue DisplayMetrics类中属性scaledDensity
* @return
*/
public static int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
/**
* 将sp值转换为px值保证文字大小不变
*
* @param spValue
* @param spValue
* DisplayMetrics类中属性scaledDensity
* @return
*/
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
/**
* 获取状态栏的高度
* @param resources 资源
* @return height
*/
public static int getStatusBarHeight(Resources resources) {
return getInternalDimensionSize(resources, "status_bar_height");
}
/**
* 将sp值转换为px值保证文字大小不变
*
* @param spValue
* @param spValue DisplayMetrics类中属性scaledDensity
* @return
*/
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
/**
* 获取状态栏的高度
*
* @param resources 资源
* @return height
*/
public static int getStatusBarHeight(Resources resources) {
return getInternalDimensionSize(resources, "status_bar_height");
}
public static int getInternalDimensionSize(Resources res, String key) {
int result = 0;
int resourceId = res.getIdentifier(key, "dimen", "android");
if (resourceId > 0) {
result = res.getDimensionPixelSize(resourceId);
}
return result;
}
public static int getInternalDimensionSize(Resources res, String key) {
int result = 0;
int resourceId = res.getIdentifier(key, "dimen", "android");
if (resourceId > 0) {
result = res.getDimensionPixelSize(resourceId);
}
return result;
}
}

View File

@ -1,457 +1,459 @@
package com.gh.common.util;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Message;
import android.support.v4.content.ContextCompat;
import android.support.v4.util.ArrayMap;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import android.widget.Toast;
import com.gh.common.constant.Config;
import com.gh.common.constant.Constants;
import com.gh.common.view.DownloadDialog;
import com.gh.download.DownloadEntity;
import com.gh.download.DownloadManager;
import com.gh.download.DownloadStatus;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.GameViewHolder;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.manager.PackageManager;
import com.lightgame.download.DownloadConfig;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
import java.util.concurrent.LinkedBlockingQueue;
public class DownloadItemUtils {
// 更新下载进度条
public static void processDate(Context context,
GameEntity gameEntity,
DownloadEntity downloadEntity,
RecyclerView.Adapter<RecyclerView.ViewHolder> adapter,
int index) {
// 更新下载进度条
public static void processDate(Context context,
GameEntity gameEntity,
DownloadEntity downloadEntity,
RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter,
int index) {
if (!gameEntity.getId().equals(downloadEntity.getGameId())) {
adapter.notifyItemChanged(index);
return;
}
if (!gameEntity.getId().equals(downloadEntity.getGameId())) {
adapter.notifyItemChanged(index);
return;
}
LinkedBlockingQueue<String> queue = DownloadManager.getInstance(context).getQueue(downloadEntity.getName());
if (queue == null) {
queue = new LinkedBlockingQueue<>();
DownloadManager.getInstance(context).putQueue(downloadEntity.getName(), queue);
}
LinkedBlockingQueue<String> queue = DownloadManager.getInstance(context).getQueue(downloadEntity.getName());
if (queue == null) {
queue = new LinkedBlockingQueue<>();
DownloadManager.getInstance(context).putQueue(downloadEntity.getName(), queue);
}
String platform = downloadEntity.getPlatform();
ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
String platform = downloadEntity.getPlatform();
ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
DownloadStatus status = downloadEntity.getStatus();
if (status.equals(DownloadStatus.pause)
|| status.equals(DownloadStatus.cancel)
|| status.equals(DownloadStatus.done)) {
queue.remove(platform);
if (entryMap == null) {
entryMap = new ArrayMap<>();
gameEntity.setEntryMap(entryMap);
}
entryMap.put(platform, downloadEntity);
if (!"pause".equals(DownloadManager.getInstance(context).getStatus(downloadEntity.getUrl()))) {
adapter.notifyItemChanged(index);
}
} else {
if (!queue.contains(platform)) {
queue.offer(platform);
if (queue.size() == 2) {
Message msg = Message.obtain();
msg.obj = downloadEntity.getName();
msg.what = Constants.DOWNLOAD_ROLL;
DownloadManager.getInstance(context).sendMessageDelayed(msg, 3000);
}
}
if (platform.equals(queue.peek())) {
if (entryMap == null) {
entryMap = new ArrayMap<>();
gameEntity.setEntryMap(entryMap);
}
entryMap.put(platform, downloadEntity);
if (!"pause".equals(DownloadManager.getInstance(context).getStatus(downloadEntity.getUrl()))) {
adapter.notifyItemChanged(index);
}
}
}
}
DownloadStatus status = downloadEntity.getStatus();
if (status.equals(DownloadStatus.pause)
|| status.equals(DownloadStatus.cancel)
|| status.equals(DownloadStatus.done)) {
queue.remove(platform);
if (entryMap == null) {
entryMap = new ArrayMap<>();
gameEntity.setEntryMap(entryMap);
}
entryMap.put(platform, downloadEntity);
if (!"pause".equals(DownloadManager.getInstance(context).getStatus(downloadEntity.getUrl()))) {
adapter.notifyItemChanged(index);
}
} else {
if (!queue.contains(platform)) {
queue.offer(platform);
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(DownloadItemUtils.class, queue.size(), gameEntity.getBrief(), downloadEntity.getPlatform(), index);
}
// 有两个平台同时下载的时候启用
if (queue.size() == 2) {
//TODO fuck this
Message msg = Message.obtain();
msg.obj = downloadEntity.getName();
msg.what = DownloadConfig.DOWNLOAD_ROLL;
DownloadManager.getInstance(context).sendMessageDelayed(msg, 3000);
}
}
if (platform.equals(queue.peek())) {
if (entryMap == null) {
entryMap = new ArrayMap<>();
gameEntity.setEntryMap(entryMap);
}
entryMap.put(platform, downloadEntity);
if (!"pause".equals(DownloadManager.getInstance(context).getStatus(downloadEntity.getUrl()))) {
adapter.notifyItemChanged(index);
}
}
}
}
// 更新正常的条目只有一个apk包
public static void updateNormalItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform) {
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder, boolean isShowPlatform) {
ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
if (entryMap != null && !entryMap.isEmpty()) {
DownloadEntity downloadEntity = entryMap.get(gameEntity.getApk().get(0).getPlatform());
if (downloadEntity != null) {
// 更改进度条和提示文本的状态
changeStatus(context, holder, downloadEntity, isShowPlatform, true);
return;
}
}
// 控制是否显示下载按钮
if (!Config.isShow(context) || context.getString(R.string.app_name).equals(gameEntity.getName())) {
holder.gameDownloadBtn.setVisibility(View.GONE);
} else {
holder.gameDownloadBtn.setVisibility(View.VISIBLE);
}
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
if (gameEntity.isLibaoExists()) {
holder.gameLibaoIcon.setVisibility(View.VISIBLE);
} else {
holder.gameLibaoIcon.setVisibility(View.GONE);
}
holder.gameDownloadBtn.setTextColor(Color.WHITE);
if (gameEntity.isPluggable()) {
holder.gameDownloadBtn.setText("插件化");
DownloadEntity downloadEntity = DownloadManager.getInstance(context).getByPackage(
gameEntity.getApk().get(0).getPackageName());
if (downloadEntity == null
|| downloadEntity.getUrl().equals(gameEntity.getApk().get(0).getUrl())) {
holder.gameDownloadBtn.setClickable(true);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else {
holder.gameDownloadBtn.setClickable(false);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_pause_up);
}
} else if (PackageManager.isInstalled(gameEntity.getApk().get(0).getPackageName())) {
if (PackageManager.isCanUpdate(gameEntity.getId(), gameEntity.getApk().get(0).getPackageName())) {
holder.gameDownloadBtn.setText("更新");
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
} else {
if (gameEntity.getTag() != null && gameEntity.getTag().size() != 0
&& !TextUtils.isEmpty(gameEntity.getApk().get(0).getGhVersion())
&& !PackageUtils.isSignature(context, gameEntity.getApk().get(0).getPackageName())) {
holder.gameDownloadBtn.setText("插件化");
DownloadEntity downloadEntity = DownloadManager.getInstance(context).getByPackage(
gameEntity.getApk().get(0).getPackageName());
if (downloadEntity == null
|| downloadEntity.getUrl().equals(gameEntity.getApk().get(0).getUrl())) {
holder.gameDownloadBtn.setClickable(true);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else {
holder.gameDownloadBtn.setClickable(false);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_pause_up);
}
} else {
holder.gameDownloadBtn.setText("启动");
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_launch_style);
}
}
} else {
holder.gameDownloadBtn.setText("下载");
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
}
}
if (gameEntity.getApk() == null || gameEntity.getApk().isEmpty()) {
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_pause_style);
holder.gameDownloadBtn.setText("暂无");
holder.gameDownloadBtn.setClickable(false);
} else if (gameEntity.getApk().size() == 1) {
updateNormalItem(context, holder, gameEntity, isShowPlatform);
} else {
// updateNormalItem(context, holder, gameEntity, isShowPlatform);
updatePluginItem(context, holder, gameEntity, isShowPlatform);
}
// 更新插件的条目有多个apk包
public static void updatePluginItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform) {
}
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn);
// 更新正常的条目只有一个apk包
static void updateNormalItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform) {
ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
if (entryMap != null && !entryMap.isEmpty()) {
final ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
final ApkEntity apkEntity = gameEntity.getApk().get(0);
DownloadEntity downloadEntity;
if (entryMap != null && !entryMap.isEmpty()) {
DownloadEntity downloadEntity = entryMap.get(apkEntity.getPlatform());
if (downloadEntity != null) {
// 更改进度条和提示文本的状态
changeStatus(context, holder, downloadEntity, isShowPlatform, true);
return;
}
}
LinkedBlockingQueue<String> queue = DownloadManager.getInstance(context).getQueue(gameEntity.getName());
if (queue != null && !queue.isEmpty()) {
downloadEntity = entryMap.get(queue.peek());
} else {
downloadEntity = entryMap.get(entryMap.keyAt(0));
}
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
if (downloadEntity != null) {
// 更改进度条和提示文本的状态
changeStatus(context, holder, downloadEntity, isShowPlatform, false);
return;
}
}
holder.gameDownloadBtn.setTextColor(Color.WHITE);
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
}
final String packageName = apkEntity.getPackageName();
// 更改进度条和提示文本的状态
public static void changeStatus(Context context, GameViewHolder holder, DownloadEntity downloadEntity,
boolean isShowPlatform, boolean isNormal) {
holder.gameDes.setVisibility(View.GONE);
holder.gameProgressbar.setVisibility(View.VISIBLE);
holder.gameInfo.setVisibility(View.VISIBLE);
if (gameEntity.isPluggable()) {
holder.gameDownloadBtn.setText(R.string.pluggable);
setwhat(context, holder, apkEntity, packageName);
} else if (PackageManager.isInstalled(packageName)) {
if (PackageManager.isCanUpdate(gameEntity.getId(), packageName)) {
holder.gameDownloadBtn.setText(R.string.update);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
} else {
if (gameEntity.getTag() != null && gameEntity.getTag().size() != 0
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
&& !PackageUtils.isSignature(context, packageName)) {
holder.gameDownloadBtn.setText(R.string.pluggable);
setwhat(context, holder, apkEntity, packageName);
} else {
holder.gameDownloadBtn.setText(R.string.launch);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_launch_style);
}
}
} else {
holder.gameDownloadBtn.setText(R.string.download);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
}
}
String platform = PlatformUtils.getInstance(context)
.getPlatformName(downloadEntity.getPlatform());
/**
* 这个干什么鬼?
*
* @param context
* @param holder
* @param apkEntity
* @param packageName
*/
public static void setwhat(Context context, GameViewHolder holder, ApkEntity apkEntity, String packageName) {
DownloadEntity downloadEntity = DownloadManager.getInstance(context).getDownloadEntityByPackageName(packageName);
if (downloadEntity == null || downloadEntity.getUrl().equals(apkEntity.getUrl())) {
holder.gameDownloadBtn.setClickable(true);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else {
holder.gameDownloadBtn.setClickable(false);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_pause_up);
}
}
DownloadStatus status = downloadEntity.getStatus();
if (status.equals(DownloadStatus.downloading)) {
if (!"pause".equals(DownloadManager.getInstance(context).getStatus(downloadEntity.getUrl()))) {
holder.gameProgressbar.setProgress((int) (downloadEntity.getPercent() * 10));
if (isShowPlatform && platform != null) {
holder.gameDownloadSpeed.setText(String.format("%s - %s(剩%s)", platform,
SpeedUtils.getSpeed(downloadEntity.getSpeed()),
SpeedUtils.getRemainTime(downloadEntity.getSize(), downloadEntity.getProgress(), downloadEntity.getSpeed() * 1024)));
} else {
holder.gameDownloadSpeed.setText(String.format("%s(剩%s)", SpeedUtils.getSpeed(downloadEntity.getSpeed()),
SpeedUtils.getRemainTime(downloadEntity.getSize(), downloadEntity.getProgress(), downloadEntity.getSpeed() * 1024)));
}
holder.gameDownloadPercentage.setText(downloadEntity.getPercent() + "%");
}
// 更新插件的条目有多个apk包
static void updatePluginItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform) {
if (isNormal) {
holder.gameDownloadBtn.setText("下载中");
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
holder.gameDownloadBtn.setTextColor(context.getResources().getColorStateList(R.color.text_downloading_style));
}
} else if (status.equals(DownloadStatus.waiting)) {
holder.gameProgressbar.setProgress((int) (downloadEntity.getPercent() * 10));
if (isShowPlatform && platform != null) {
holder.gameDownloadSpeed.setText(String.format("%s - 等待", platform));
} else {
holder.gameDownloadSpeed.setText("等待");
}
holder.gameDownloadPercentage.setText(downloadEntity.getPercent() + "%");
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn);
if (isNormal) {
holder.gameDownloadBtn.setText("下载中");
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
holder.gameDownloadBtn.setTextColor(context.getResources().getColorStateList(R.color.text_downloading_style));
}
} else if (status.equals(DownloadStatus.pause)
|| status.equals(DownloadStatus.timeout)
|| status.equals(DownloadStatus.neterror)) {
holder.gameProgressbar.setProgress((int) (downloadEntity.getPercent() * 10));
if (isShowPlatform && platform != null) {
holder.gameDownloadSpeed.setText(String.format("%s - 暂停", platform));
} else {
holder.gameDownloadSpeed.setText("暂停");
}
holder.gameDownloadPercentage.setText(downloadEntity.getPercent() + "%");
ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
if (entryMap != null && !entryMap.isEmpty()) {
if (isNormal) {
holder.gameDownloadBtn.setText("下载中");
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
holder.gameDownloadBtn.setTextColor(context.getResources().getColorStateList(R.color.text_downloading_style));
}
} else if (status.equals(DownloadStatus.done)) {
holder.gameProgressbar.setProgress(1000);
if (isShowPlatform && platform != null) {
holder.gameDownloadSpeed.setText(String.format("%s - 下载完成", platform));
} else {
holder.gameDownloadSpeed.setText("下载完成");
}
holder.gameDownloadPercentage.setText(R.string.hundred_percent);
DownloadEntity downloadEntity;
if (isNormal) {
holder.gameDownloadBtn.setText("安装");
holder.gameDownloadBtn.setTextColor(Color.WHITE);
if (downloadEntity.isPluggable()
&& PackageManager.isInstalled(downloadEntity.getPackageName())) {
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else {
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
}
}
}
}
LinkedBlockingQueue<String> queue = DownloadManager.getInstance(context).getQueue(gameEntity.getName());
if (queue != null && !queue.isEmpty()) {
downloadEntity = entryMap.get(queue.peek());
} else {
downloadEntity = entryMap.get(entryMap.keyAt(0));
}
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder, boolean isShowPlatform) {
if (downloadEntity != null) {
// 更改进度条和提示文本的状态
changeStatus(context, holder, downloadEntity, isShowPlatform, false);
return;
}
}
// 控制是否显示下载按钮
if (!Config.isShow(context) || "光环助手".equals(gameEntity.getName())) {
holder.gameDownloadBtn.setVisibility(View.GONE);
} else {
holder.gameDownloadBtn.setVisibility(View.VISIBLE);
}
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
}
if (gameEntity.isLibaoExists()) {
holder.gameLibaoIcon.setVisibility(View.VISIBLE);
} else {
holder.gameLibaoIcon.setVisibility(View.GONE);
}
// 更改进度条和提示文本的状态
public static void changeStatus(Context context, GameViewHolder holder, DownloadEntity downloadEntity,
boolean isShowPlatform, boolean isNormal) {
holder.gameDes.setVisibility(View.GONE);
holder.gameProgressbar.setVisibility(View.VISIBLE);
holder.gameInfo.setVisibility(View.VISIBLE);
// LibaoDao libaoDao = new LibaoDao(context);
// if (libaoDao.isExist(gameEntity.getId())) {
// holder.gameLibaoIcon.setVisibility(View.VISIBLE);
// } else {
//
// }
String platform = PlatformUtils.getInstance(context).getPlatformName(downloadEntity.getPlatform());
if (gameEntity.getApk() == null || gameEntity.getApk().isEmpty()) {
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_pause_style);
holder.gameDownloadBtn.setText("暂无");
holder.gameDownloadBtn.setClickable(false);
} else if (gameEntity.getApk().size() == 1) {
updateNormalItem(context, holder, gameEntity, isShowPlatform);
} else {
updatePluginItem(context, holder, gameEntity, isShowPlatform);
}
DownloadStatus status = downloadEntity.getStatus();
if (status.equals(DownloadStatus.downloading)) {
if (!"pause".equals(DownloadManager.getInstance(context).getStatus(downloadEntity.getUrl()))) {
holder.gameProgressbar.setProgress((int) (downloadEntity.getPercent() * 10));
if (isShowPlatform && platform != null) {
holder.gameDownloadSpeed.setText(String.format("%s - %s(剩%s)", platform,
SpeedUtils.getSpeed(downloadEntity.getSpeed()),
SpeedUtils.getRemainTime(downloadEntity.getSize(), downloadEntity.getProgress(), downloadEntity.getSpeed() * 1024)));
} else {
holder.gameDownloadSpeed.setText(String.format("%s(剩%s)", SpeedUtils.getSpeed(downloadEntity.getSpeed()),
SpeedUtils.getRemainTime(downloadEntity.getSize(), downloadEntity.getProgress(), downloadEntity.getSpeed() * 1024)));
}
holder.gameDownloadPercentage.setText(downloadEntity.getPercent() + "%");
}
}
if (isNormal) {
holder.gameDownloadBtn.setText(R.string.downloading);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
holder.gameDownloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
}
} else if (status.equals(DownloadStatus.waiting)) {
holder.gameProgressbar.setProgress((int) (downloadEntity.getPercent() * 10));
if (isShowPlatform && platform != null) {
holder.gameDownloadSpeed.setText(String.format("%s - 等待", platform));
} else {
holder.gameDownloadSpeed.setText("等待");
}
holder.gameDownloadPercentage.setText(downloadEntity.getPercent() + "%");
public static void onNormalClick(final Context context,
final TextView downloadBtn,
final GameEntity gameEntity,
final int position,
final RecyclerView.Adapter<RecyclerView.ViewHolder> adapter,
final String entrance,
final String location) {
if (isNormal) {
holder.gameDownloadBtn.setText(R.string.downloading);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
holder.gameDownloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
}
} else if (status.equals(DownloadStatus.pause)
|| status.equals(DownloadStatus.timeout)
|| status.equals(DownloadStatus.neterror)) {
holder.gameProgressbar.setProgress((int) (downloadEntity.getPercent() * 10));
if (isShowPlatform && platform != null) {
holder.gameDownloadSpeed.setText(String.format("%s - 暂停", platform));
} else {
holder.gameDownloadSpeed.setText("暂停");
}
holder.gameDownloadPercentage.setText(downloadEntity.getPercent() + "%");
String str = downloadBtn.getText().toString();
if ("下载".equals(str)) {
if (NetworkUtils.isWifiConnected(context)) {
download(context, gameEntity, downloadBtn, entrance, location);
} else {
DialogUtils.showDownloadDialog(context, new DialogUtils.ConfiremListener() {
@Override
public void onConfirem() {
download(context, gameEntity, downloadBtn, entrance, location);
}
});
}
} else if ("插件化".equals(str)) {
if (NetworkUtils.isWifiConnected(context)) {
plugin(context, gameEntity, downloadBtn, entrance, location);
} else {
DialogUtils.showDownloadDialog(context, new DialogUtils.ConfiremListener() {
@Override
public void onConfirem() {
plugin(context, gameEntity, downloadBtn, entrance, location);
}
});
}
} else if ("安装".equals(str)) {
install(context, gameEntity, position, adapter);
} else if ("启动".equals(str)) {
DataUtils.onGameLaunchEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
if (isNormal) {
holder.gameDownloadBtn.setText(R.string.downloading);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
holder.gameDownloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
}
} else if (status.equals(DownloadStatus.done)) {
holder.gameProgressbar.setProgress(1000);
if (isShowPlatform && platform != null) {
holder.gameDownloadSpeed.setText(String.format("%s - 下载完成", platform));
} else {
holder.gameDownloadSpeed.setText("下载完成");
}
holder.gameDownloadPercentage.setText(R.string.hundred_percent);
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk().get(0).getPackageName());
} else if ("下载中".equals(str)) {
Intent intent = new Intent(context, DownloadManagerActivity.class);
intent.putExtra("currentItem", 1);
intent.putExtra("url", gameEntity.getApk().get(0).getUrl());
intent.putExtra("entrance", entrance + "+(" + location.split(":")[0] + ")");
context.startActivity(intent);
} else if ("更新".equals(str)) {
if (NetworkUtils.isWifiConnected(context)) {
update(context, gameEntity, entrance, location);
} else {
DialogUtils.showDownloadDialog(context, new DialogUtils.ConfiremListener() {
@Override
public void onConfirem() {
update(context, gameEntity, entrance, location);
}
});
}
}
}
if (isNormal) {
holder.gameDownloadBtn.setText("安装");
holder.gameDownloadBtn.setTextColor(Color.WHITE);
if (downloadEntity.isPluggable()
&& PackageManager.isInstalled(downloadEntity.getPackageName())) {
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else {
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
}
}
}
}
public static void setOnClickListener(final Context context,
final TextView downloadBtn,
final GameEntity gameEntity,
final int position,
final RecyclerView.Adapter<RecyclerView.ViewHolder> adapter,
final String entrance,
final String location) {
public static void setOnClickListener(final Context context,
final TextView downloadBtn,
final GameEntity gameEntity,
final int position,
final RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter,
final String entrance,
final String location) {
if (gameEntity.getApk().size() == 1) {
downloadBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location);
}
});
} else {
downloadBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DownloadDialog.getInstance(context).showPopupWindow(v, gameEntity, entrance, location);
}
});
}
if (gameEntity.getApk().size() == 1) {
downloadBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location);
}
});
} else {
downloadBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DownloadDialog.getInstance(context).showPopupWindow(v, gameEntity, entrance, location);
}
});
}
}
}
//更新
private static void update(Context context,
GameEntity gameEntity,
String entrance,
String location) {
DataUtils.onGameUpdateEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), "下载开始");
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location);
}
public static void onNormalClick(final Context context,
final TextView downloadBtn,
final GameEntity gameEntity,
final int position,
final RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter,
final String entrance,
final String location) {
//下载
private static void download(Context context,
GameEntity gameEntity,
TextView downloadBtn,
String entrance,
String location) {
String msg = FileUtils.isCanDownload(context, gameEntity.getApk().get(0).getSize());
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始");
String str = downloadBtn.getText().toString();
switch (str) {
case "下载":
if (NetworkUtils.isWifiConnected(context)) {
download(context, gameEntity, downloadBtn, entrance, location);
} else {
DialogUtils.showDownloadDialog(context, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
download(context, gameEntity, downloadBtn, entrance, location);
}
});
}
break;
case "插件化":
if (NetworkUtils.isWifiConnected(context)) {
plugin(context, gameEntity, downloadBtn, entrance, location);
} else {
DialogUtils.showDownloadDialog(context, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
plugin(context, gameEntity, downloadBtn, entrance, location);
}
});
}
break;
case "安装":
install(context, gameEntity, position, adapter);
break;
case "启动":
DataUtils.onGameLaunchEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
DownloadManager.createDownload(context, gameEntity, "下载", entrance, location);
Toast.makeText(context, gameEntity.getName() + "已加入下载队列", Toast.LENGTH_SHORT).show();
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk().get(0).getPackageName());
break;
case "下载中":
context.startActivity(
DownloadManagerActivity.getDownloadMangerIntent(context, gameEntity.getApk().get(0).getUrl(), entrance + "+(" + location.split(":")[0] + ")"));
break;
case "更新":
if (NetworkUtils.isWifiConnected(context)) {
update(context, gameEntity, entrance, location);
} else {
DialogUtils.showDownloadDialog(context, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
update(context, gameEntity, entrance, location);
}
});
}
break;
}
}
downloadBtn.setText("下载中");
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(context.getResources().getColorStateList(R.color.text_downloading_style));
//下载
private static void download(Context context,
GameEntity gameEntity,
TextView downloadBtn,
String entrance,
String location) {
String msg = FileUtils.isCanDownload(context, gameEntity.getApk().get(0).getSize());
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始");
DownloadManager.getInstance(context).putStatus(gameEntity.getApk().get(0).getUrl(), "downloading");
} else {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
DownloadManager.createDownload(context, gameEntity, context.getString(R.string.download), entrance, location);
Utils.toast(context, gameEntity.getName() + "已加入下载队列");
//插件化
private static void plugin(Context context,
GameEntity gameEntity,
TextView downloadBtn,
String entrance,
String location) {
String msg = FileUtils.isCanDownload(context, gameEntity.getApk().get(0).getSize());
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始");
downloadBtn.setText(R.string.downloading);
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location);
Toast.makeText(context, gameEntity.getName() + "已加入下载队列", Toast.LENGTH_SHORT).show();
// DownloadManager.getInstance(context).putStatus(gameEntity.getApk().get(0).getUrl(), "downloading");
} else {
Utils.toast(context, msg);
}
}
downloadBtn.setText("下载中");
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(context.getResources().getColorStateList(R.color.text_downloading_style));
//插件化
private static void plugin(Context context, GameEntity gameEntity, TextView downloadBtn, String entrance,
String location) {
String msg = FileUtils.isCanDownload(context, gameEntity.getApk().get(0).getSize());
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始");
DownloadManager.getInstance(context).putStatus(gameEntity.getApk().get(0).getUrl(), "downloading");
} else {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location);
Utils.toast(context, gameEntity.getName() + "已加入下载队列");
//安装
private static void install(final Context context,
GameEntity gameEntity,
int position,
RecyclerView.Adapter<RecyclerView.ViewHolder> adapter) {
DownloadEntity downloadEntity = DownloadManager.getInstance(context).get(gameEntity.getApk().get(0).getUrl());
if (downloadEntity != null) {
final String path = downloadEntity.getPath();
if (FileUtils.isEmptyFile(path)) {
Toast.makeText(context, "解析包出错(可能被误删了),请重新下载", Toast.LENGTH_SHORT).show();
DownloadManager.getInstance(context).cancel(downloadEntity.getUrl());
if (gameEntity.getEntryMap() != null) {
gameEntity.getEntryMap().remove(gameEntity.getApk().get(0).getPlatform());
}
adapter.notifyItemChanged(position);
} else {
PackageUtils.launchSetup(context, path);
}
}
}
downloadBtn.setText(R.string.downloading);
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
// DownloadManager.getInstance(context).putStatus(gameEntity.getApk().get(0).getUrl(), "downloading");
} else {
Utils.toast(context, msg);
}
}
//安装
private static void install(final Context context, GameEntity gameEntity, int position,
RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter) {
ApkEntity apkEntity = gameEntity.getApk().get(0);
DownloadEntity downloadEntity = DownloadManager.getInstance(context).getDownloadEntityByUrl(apkEntity.getUrl());
if (downloadEntity != null) {
final String path = downloadEntity.getPath();
if (FileUtils.isEmptyFile(path)) {
Utils.toast(context, context.getString(R.string.install_failure_hint));
DownloadManager.getInstance(context).cancel(downloadEntity.getUrl());
if (gameEntity.getEntryMap() != null) {
gameEntity.getEntryMap().remove(apkEntity.getPlatform());
}
adapter.notifyItemChanged(position);
} else {
PackageUtils.launchSetup(context, path);
}
}
}
//更新
private static void update(Context context, GameEntity gameEntity, String entrance, String location) {
DataUtils.onGameUpdateEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), "下载开始");
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location);
}
}

View File

@ -0,0 +1,82 @@
package com.gh.common.util;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import com.gh.gamecenter.MainActivity;
import com.gh.gamecenter.SplashScreenActivity;
/**
* @author CsHeng
* @Date 2017/4/25
* @Time 16:39
*/
public class EntranceUtils {
public static final String KEY_TO = "to";
public static final String KEY_NEWSID = "newsId";
public static final String KEY_GAMEID = "gameId";
public static final String KEY_ID = "id";
public static final String KEY_URL = "url";
public static final String KEY_GAMENAME = "gameName";
public static final String HOST_ARTICLE = "article";
public static final String HOST_GAME = "game";
public static final String HOST_COLUMN = "column";
public static final String HOST_WEB = "web";
public static final String HOST_DOWNLOAD = "download";
public static final String HOST_SUGGESTION = "suggestion";
public static final String KEY_DATA = "data";
public static final String KEY_TYPE = "type";
public static final String KEY_NAME = "name";
public static final String KEY_ENTRANCE = "entrance";
public static final String KEY_TARGET = "target";
public static final String ENTRANCE_BROWSER = "(浏览器)";
public static final String ENTRANCE_UMENG = "(友盟推送)";
public static final String ENTRANCE_MIPUSH = "(小米推送)";
public static final String ENTRANCE_DOWNLOAD = "(下载跳转)";
public static final String KEY_SUGGEST_HINT_TYPE = "suggestHintType";
public static final String KEY_PACKAGENAME = "packageName";
public static final String KEY_PLATFORM = "platform";
public static final String KEY_GAME_NAME = "game_name";
public static final String KEY_VERSION = "version";
public static final String KEY_CONTENT = "content";
public static final String KEY_PLUGIN = "plugin";
public static final String KEY_CURRENTITEM = "currentItem";
public static final String KEY_COMMENTID = "commentId";
public static final String KEY_PATH = "path";
public static final String KEY_OLDERUSER = "isOldUser";
public static final String KEY_SEARCHKEY = "searchKey";
public static final String KEY_HINT = "hint";
public static final String KEY_GAME_ICON_URL = "gameIconUrl";
public static final String KEY_SHARECONTENT = "shareContent";
public static final String KEY_SUGGESTTYPE = "suggestType";
public static final String KEY_PROLIST = "provinceList";
public static final String KEY_ORDER = "order";
public static final String KEY_TAGTYPE = "tagType";
public static void jumpActivity(Context context, Bundle bundle) {
//TODO 把其他类似的跳转启动逻辑也处理掉
if (RunningUtils.isRunning(context)
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(context))) {
// 应用正在运行,前台或后台
String to = bundle.getString(KEY_TO);
if (!TextUtils.isEmpty(to)) {
Class<?> clazz = ClassUtils.forName(to);
if (clazz != null) {
Intent intent1 = new Intent(context, clazz);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent1.putExtra(KEY_DATA, bundle);
context.startActivity(intent1);
}
}
} else {
// 应用未在运行
context.startActivity(SplashScreenActivity.getSplashScreenIntent(context, bundle));
}
}
}

View File

@ -1,384 +0,0 @@
package com.gh.common.util;
import android.content.Context;
import android.os.Environment;
import android.os.StatFs;
import android.os.StrictMode;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.UUID;
/**
*
* @author guanchao wen
* @email shuwoom.wgc@gmail.com
* @modify hzh 2016/03/16
* @update 2015-7-29下午2:26:02
*/
public class FileUtils {
private final static String TEST_FILE_NAME = System.currentTimeMillis() + ".log";
public static String getDownloadDir(Context context) {
String dir = null;
if (isMounted()) {
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
dir = checkDir(baseDir + File.separator + "gh-download");
File file = new File(dir + File.separator + TEST_FILE_NAME);
if (!file.exists()) {
try {
if (!file.createNewFile()) {
// cannot create file
Utils.log("cannot create file");
dir = null;
}
} catch (IOException e) {
e.printStackTrace();
// cannot create file
Utils.log("cannot create file");
dir = null;
}
}
}
if (dir == null) {
String baseDir = context.getFilesDir().getAbsolutePath();
dir = checkDir(baseDir + File.separator + "gh-download");
try {
Runtime.getRuntime().exec("chmod 755 " + dir);
} catch (IOException e) {
e.printStackTrace();
}
}
return dir;
}
public static String getDownloadPath(Context context, String name) {
return getDownloadDir(context) + File.separator + name;
}
public static String getLogPath(Context context, String name) {
return checkDir(getDir(context, "log")) + File.separator + name;
}
public static String getPlatformPicDir(Context context) {
return checkDir(getDir(context, "PlatformPic"));
}
private static String checkDir(String dir) {
File directory = new File(dir);
if (directory.exists() && !directory.isDirectory()) {
directory.delete();
}
if (!directory.exists()) {
directory.mkdirs();
}
return dir;
}
public static void deleteFile(String savePath) {
File file = new File(savePath);
if (file.exists()) {
file.delete();
}
}
public static void deleteFolder(File folder) {
if (folder != null) {
if (folder.isDirectory()) {
for (File file : folder.listFiles()) {
if (file.isDirectory()) {
deleteFolder(file);
} else {
file.delete();
}
}
}
folder.delete();
}
}
public static boolean isEmptyFile(String path) {
File file = new File(path);
return !(file.exists() && file.length() != 0);
}
public static boolean isMounted() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
public static String getDir(Context context, String dir) {
if (isMounted()) {
// /storage/emulated/0/Android/data/包名/files
File file = context.getExternalFilesDir(null);
if (file != null) {
return file.getAbsolutePath() + File.separator + dir;
}
}
// /data/data/包名/files
return context.getFilesDir().getAbsolutePath() + File.separator + dir;
}
// 返回剩余空间 单位MB
@SuppressWarnings("deprecation")
public static float getFreeSpaceByPath(String path) {
StatFs statfs = new StatFs(path);
long blockSize = statfs.getBlockSize();
long availableBlocks = statfs.getAvailableBlocks();
return availableBlocks * blockSize / 1024f / 1024f;
}
public static String isCanDownload(Context context, String size) {
String msg = null;
String packageSizeStr = "";
for (int i = 0; i < size.length(); i++) {
if ((size.charAt(i) >= 48 && size.charAt(i) <= 57) || size.charAt(i) == 46) {
packageSizeStr += size.charAt(i);
}
}
float packageSize = 0;
if (packageSizeStr.length() != 0) {
packageSize = Float.valueOf(packageSizeStr);
}
float freeSpace = getFreeSpaceByPath(getDownloadDir(context));
if (freeSpace < packageSize) {
msg = "手机存储空间不足,无法进行下载!";
}
return msg;
}
// 下载文件
public static int downloadFile(String url, String savePath) {
DataInputStream dis = null;
FileOutputStream fos = null;
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5 * 1000);
connection.setReadTimeout(5 * 1000);
connection.connect();
int code = connection.getResponseCode();
if (code == 200) {
dis = new DataInputStream(connection.getInputStream());
File file = new File(savePath);
if (file.exists()) {
file.delete();
}
file.createNewFile();
fos = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int len;
while ((len = dis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.flush();
}
return code;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dis != null) {
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return -1;
}
// 上传文件
public static JSONObject uploadFile(String url, String filePath, String token) {
String end = "\r\n";
String twoHyphens = "--";
String boundary = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
/*
* Output to the connection. Default is false, set to true because
* post method must write something to the connection
*/
connection.setDoOutput(true);
// Read from the connection. Default is true.
connection.setDoInput(true);
// Post cannot use caches
connection.setUseCaches(false);
// Set the post method. Default is GET
connection.setRequestMethod("POST");
connection.setConnectTimeout(5 * 1000);
connection.setReadTimeout(5 * 1000);
// 设置请求属性
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Charset", "UTF-8");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
if (token != null) {
connection.setRequestProperty("TOKEN", token);
}
// 设置StrictMode 否则HTTPURLConnection连接失败因为这是在主进程中进行网络连接
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads().detectDiskWrites().detectNetwork()
.penaltyLog().build());
File file = new File(filePath);
if (file.exists()) {
Utils.log("name = " + file.getName());
Utils.log("length = " + file.length());
}
// 设置DataOutputStreamgetOutputStream中默认调用connect()
DataOutputStream dos = new DataOutputStream(connection.getOutputStream()); // output
// to the connection
dos.writeBytes(twoHyphens + boundary + end);
dos.writeBytes("Content-Disposition: form-data; "
+ "name=\"Filedata\";filename=\"" + file.getName() + "\"" + end);
dos.writeBytes(end);
// 取得文件的FileInputStream
FileInputStream fStream = new FileInputStream(file);
// 设置每次写入8192bytes
int bufferSize = 8192;
byte[] buffer = new byte[bufferSize]; // 8k
int length;
// 从文件读取数据至缓冲区
while ((length = fStream.read(buffer)) != -1) {
// 将资料写入DataOutputStream中
dos.write(buffer, 0, length);
}
dos.writeBytes(end);
dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
// 关闭流写入的东西自动生成Http正文
fStream.close();
// 关闭DataOutputStream
dos.flush();
dos.close();
InputStream inputStream;
try {
inputStream = connection.getInputStream();
} catch (IOException ioe) {
inputStream = connection.getErrorStream();
}
int ch;
StringBuffer b = new StringBuffer();
while ((ch = inputStream.read()) != -1) {
b.append((char) ch);
}
// 显示网页响应内容
Utils.log("content = " + b.toString().trim());
int statusCode = connection.getResponseCode();
Utils.log("statusCode = " + statusCode);
if (statusCode == 200) {
// {"icon":"http:\/\/gh-test-1.oss-cn-qingdao.aliyuncs.com\/pic\/57e4f4d58a3200042d29492f.jpg"}
JSONObject response = new JSONObject(b.toString().trim());
response.put("statusCode", 200);
return response;
} else if (statusCode == 403) {
JSONObject response = new JSONObject(b.toString().trim());
response.put("statusCode", 403);
return response;
} else if (statusCode == 401) {
JSONObject response = new JSONObject();
response.put("statusCode", 401);
return response;
}
} catch (Exception e) {
// 显示异常信息
e.printStackTrace();
Utils.log("Fail:" + e);
}
return null;
}
// 读取文件返回byte[]
public static byte[] readFile(File file) {
if (file == null) {
return null;
}
FileInputStream fis = null;
ByteArrayOutputStream bos = null;
try {
fis = new FileInputStream(file);
bos = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int len;
while ((len = fis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.flush();
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
// 根据byte[],保存文件
public static void saveFile(File file, byte[] data) {
if (file == null || data == null) {
return;
}
ByteArrayInputStream bis = null;
FileOutputStream fos = null;
try {
bis = new ByteArrayInputStream(data);
fos = new FileOutputStream(file);
byte[] buffer = new byte[2048];
int len;
while ((len = bis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

View File

@ -1,151 +1,129 @@
package com.gh.common.util;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.text.TextUtils;
import android.widget.TextView;
import com.gh.base.AppController;
import com.gh.download.DownloadEntity;
import com.gh.download.DownloadManager;
import com.gh.download.DownloadStatus;
import com.gh.gamecenter.GameDetailActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.manager.PackageManager;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
import java.util.List;
public class GameUtils {
/**
* 去除与重复sourceList相同的数据
*/
public static List<GameEntity> removeDuplicateData(List<GameEntity> sourceList, List<GameEntity> rawList) {
if (sourceList == null || sourceList.isEmpty()
|| rawList == null || rawList.isEmpty()) {
return rawList;
}
String id;
for (int i = 0; i < rawList.size(); i++) {
id = rawList.get(i).getId();
for (GameEntity gameEntity : sourceList) {
if (id.equals(gameEntity.getId())) {
rawList.remove(i);
i--;
break;
}
}
}
return rawList;
}
/**
* 去除与重复sourceList相同的数据
*/
public static List<GameEntity> removeDuplicateData(List<GameEntity> sourceList, List<GameEntity> rawList) {
if (sourceList == null || sourceList.isEmpty()
|| rawList == null || rawList.isEmpty()) {
return rawList;
}
String id;
for (int i = 0; i < rawList.size(); i++) {
id = rawList.get(i).getId();
for (GameEntity gameEntity : sourceList) {
if (id.equals(gameEntity.getId())) {
rawList.remove(i);
i--;
break;
}
}
}
return rawList;
}
/**
* 启动游戏详情页面
*/
public static void startGameDetailActivity(Context context, GameEntity gameEntity, String entrance) {
AppController.put("GameEntity", gameEntity);
Intent intent = new Intent(context, GameDetailActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("entrance", entrance);
context.startActivity(intent);
}
/**
* 设置下载按钮状态
*/
public static void setDownloadBtnStatus(Context context, GameEntity gameEntity, TextView downloadBtn) {
String status = getDownloadBtnText(context, gameEntity);
downloadBtn.setTextColor(Color.WHITE);
downloadBtn.setText(status);
if ("插件化".equals(status)) {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else if ("打开".equals(status)) {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_launch_style);
} else {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
}
}
/**
* 启动游戏详情页面
*/
public static void startGameDetailActivity(Context context, String gameId, String entrance) {
Intent intent = new Intent(context, GameDetailActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("gameId", gameId);
intent.putExtra("entrance", entrance);
context.startActivity(intent);
}
/**
* 获取下载按钮文案
*/
public static String getDownloadBtnText(Context context, GameEntity gameEntity) {
int doneCount = 0; // 下载完成数量
int pluginCount = 0; // 可插件化数量
int updateCount = 0; // 可更新数量
int installCount = 0; // 已安装数量
DownloadEntity downloadEntity;
Object gh_id;
for (ApkEntity apkEntity : gameEntity.getApk()) {
downloadEntity = DownloadManager.getInstance(context).getDownloadEntityByUrl(apkEntity.getUrl());
if (downloadEntity != null) {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
doneCount++;
} else if (downloadEntity.isPluggable()) {
pluginCount++;
} else if (downloadEntity.isUpdate()) {
updateCount++;
}
}
if (PackageManager.isCanUpdate(gameEntity.getId(), apkEntity.getPackageName())) {
updateCount++;
}
if (PackageManager.isInstalled(apkEntity.getPackageName())) {
gh_id = PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_id");
if (gameEntity.getTag() != null && gameEntity.getTag().size() != 0
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
&& !PackageUtils.isSignature(context, apkEntity.getPackageName())) {
pluginCount++;
} else if (gh_id == null || gh_id.equals(gameEntity.getId())) {
installCount++;
}
}
}
if (doneCount != 0) {
return "安装";
} else if (pluginCount != 0) {
return "插件化";
} else if (updateCount != 0) {
return "更新";
} else if (installCount != 0) {
return "打开";
} else {
return "下载";
}
}
/**
* 设置下载按钮状态
*/
public static void setDownloadBtnStatus(Context context, GameEntity gameEntity, TextView downloadBtn) {
String status = getDownloadBtnText(context, gameEntity);
downloadBtn.setTextColor(Color.WHITE);
downloadBtn.setText(status);
if ("插件化".equals(status)) {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else if ("打开".equals(status)) {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_launch_style);
} else {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
}
}
/**
* 获取下载按钮文案
*/
public static String getDownloadBtnText(Context context, GameEntity gameEntity) {
int doneCount = 0; // 下载完成数量
int pluginCount = 0; // 可插件化数量
int updateCount = 0; // 可更新数量
int installCount = 0; // 已安装数量
DownloadEntity downloadEntity;
Object gh_id;
for (ApkEntity apkEntity : gameEntity.getApk()) {
downloadEntity = DownloadManager.getInstance(context).get(apkEntity.getUrl());
if (downloadEntity != null) {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
doneCount++;
} else if (downloadEntity.isPluggable()) {
pluginCount++;
} else if (downloadEntity.isUpdate()) {
updateCount++;
}
}
if (PackageManager.isCanUpdate(gameEntity.getId(), apkEntity.getPackageName())) {
updateCount++;
}
if (PackageManager.isInstalled(apkEntity.getPackageName())) {
gh_id = PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_id");
if (!PackageUtils.isSignature(context, apkEntity.getPackageName())) {
pluginCount++;
} else if (gh_id == null || gh_id.equals(gameEntity.getId())) {
installCount++;
}
}
}
if (doneCount != 0) {
return "安装";
} else if (pluginCount != 0) {
return "插件化";
} else if (updateCount != 0) {
return "更新";
} else if (installCount != 0) {
return "打开";
} else {
return "下载";
}
}
/**
* 获取GameUpdateEntity
*/
public static GameUpdateEntity getGameUpdateEntity(GameEntity gameEntity, ApkEntity apkEntity) {
GameUpdateEntity gameUpdateEntity = new GameUpdateEntity();
gameUpdateEntity.setId(gameEntity.getId());
gameUpdateEntity.setIcon(gameEntity.getIcon());
gameUpdateEntity.setName(gameEntity.getName());
gameUpdateEntity.setPackageName(apkEntity.getPackageName());
gameUpdateEntity.setSize(apkEntity.getSize());
gameUpdateEntity.setVersion(apkEntity.getVersion());
gameUpdateEntity.setGhVersion(apkEntity.getGhVersion());
gameUpdateEntity.setUrl(apkEntity.getUrl());
gameUpdateEntity.setPlatform(apkEntity.getPlatform());
gameUpdateEntity.setEtag(apkEntity.getEtag());
gameUpdateEntity.setPluggable(true);
gameUpdateEntity.setTag(gameEntity.getTag());
gameUpdateEntity.setBrief(gameEntity.getBrief());
return gameUpdateEntity;
}
/**
* 获取GameUpdateEntity
*/
public static GameUpdateEntity getGameUpdateEntity(GameEntity gameEntity, ApkEntity apkEntity) {
GameUpdateEntity gameUpdateEntity = new GameUpdateEntity();
gameUpdateEntity.setId(gameEntity.getId());
gameUpdateEntity.setIcon(gameEntity.getIcon());
gameUpdateEntity.setName(gameEntity.getName());
gameUpdateEntity.setPackageName(apkEntity.getPackageName());
gameUpdateEntity.setSize(apkEntity.getSize());
gameUpdateEntity.setVersion(apkEntity.getVersion());
gameUpdateEntity.setGhVersion(apkEntity.getGhVersion());
gameUpdateEntity.setUrl(apkEntity.getUrl());
gameUpdateEntity.setPlatform(apkEntity.getPlatform());
gameUpdateEntity.setEtag(apkEntity.getEtag());
gameUpdateEntity.setPluggable(true);
gameUpdateEntity.setTag(gameEntity.getTag());
gameUpdateEntity.setBrief(gameEntity.getBrief());
return gameUpdateEntity;
}
}

View File

@ -3,6 +3,8 @@ package com.gh.common.util;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.View;
import android.widget.LinearLayout;
@ -20,7 +22,6 @@ import java.util.Locale;
import java.util.TimeZone;
/**
*
* @author 温冠超
* @email 294299195@qq.com
* @date 2015-8-14
@ -29,100 +30,104 @@ import java.util.TimeZone;
*/
public class GameViewUtils {
public static void setLabelList(Context context, LinearLayout labelLayout, List<String> tag) {
labelLayout.removeAllViews();
if (tag == null || tag.isEmpty()) {
labelLayout.addView(getGameTagView(context, "官方版", 0));
} else {
for (int i = 0, size = tag.size(); i < size; i++) {
View view;
if (i == size - 1) {
view = getGameTagView(context, tag.get(i), 0);
} else {
view = getGameTagView(context, tag.get(i), DisplayUtils.dip2px(context, 6));
}
if (view != null) {
labelLayout.addView(view);
}
if (labelLayout.getChildCount() == 3) {
break;
}
}
}
}
public static void setLabelList(Context context, LinearLayout labelLayout, List<String> tag, String tagType) {
labelLayout.removeAllViews();
if (tag == null || tag.isEmpty()) {
labelLayout.addView(getGameTagView(context, "官方版", 0, tagType));
} else {
for (int i = 0, size = tag.size(); i < size; i++) {
View view;
if (i == size - 1) {
view = getGameTagView(context, tag.get(i), 0, tagType);
} else {
view = getGameTagView(context, tag.get(i), DisplayUtils.dip2px(context, 6), tagType);
}
if (view != null) {
labelLayout.addView(view);
}
if (labelLayout.getChildCount() == 3) {
break;
}
}
}
}
private static TextView getGameTagView(Context context, String tagStr, int rightMargin) {
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lparams.rightMargin = rightMargin;
TextView tag = new TextView(context);
tag.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
tag.setSingleLine(true);
tag.setText(tagStr);
if ("官方版".equals(tagStr) || "已关注".equals(tagStr)) {
tag.setBackgroundResource(R.drawable.border_green_bg);
tag.setTextColor(context.getResources().getColor(R.color.tag_green));
} else {
String colorStr = TagUtils.getInstance(context).getColor(tagStr);
if (colorStr == null) {
return null;
}
int color = Color.parseColor(colorStr);
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.TRANSPARENT);
gradientDrawable.setStroke(DisplayUtils.dip2px(context, 0.6f), color);
tag.setBackgroundDrawable(gradientDrawable);
private static TextView getGameTagView(Context context, String tagStr, int rightMargin, String tagType) {
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lparams.rightMargin = rightMargin;
TextView tag = new TextView(context);
tag.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
tag.setSingleLine(true);
tag.setText(tagStr);
if ("官方版".equals(tagStr) || "已关注".equals(tagStr)) {
tag.setBackgroundResource(R.drawable.border_green_bg);
tag.setTextColor(ContextCompat.getColor(context, R.color.tag_green));
} else {
String colorStr;
if (!TextUtils.isEmpty(tagType) && "type".equals(tagType)) { // 游戏标签
colorStr = "#ff6a28";
} else {
colorStr = TagUtils.getInstance(context).getColor(tagStr);
}
if (colorStr == null) {
return null;
}
int color = Color.parseColor(colorStr);
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.TRANSPARENT);
gradientDrawable.setStroke(DisplayUtils.dip2px(context, 0.6f), color);
tag.setBackgroundDrawable(gradientDrawable);
// tag.setBackgroundResource(R.drawable.border_blue_bg);
tag.setTextColor(color);
}
tag.setLayoutParams(lparams);
tag.setPadding(DisplayUtils.dip2px(context, 3),
0,
DisplayUtils.dip2px(context, 3),
DisplayUtils.dip2px(context, 1));
return tag;
}
tag.setTextColor(color);
}
tag.setLayoutParams(lparams);
tag.setPadding(DisplayUtils.dip2px(context, 3),
0,
DisplayUtils.dip2px(context, 3),
DisplayUtils.dip2px(context, 1));
return tag;
}
public static String getGameTestDate(long testTime) {
public static String getGameTestDate(long testTime) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
format.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
format.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
String testDate;
try {
long today = format.parse(format.format(new Date())).getTime();
long day = Long.parseLong(testTime + "000");
Calendar calendar = Calendar.getInstance(TimeZone
.getTimeZone("Asia/Shanghai"));
calendar.setTimeInMillis(day);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
if (day >= today && day < today + 86400 * 1000) {
testDate = "今天" + hour + "";
} else if (day >= today + 86400 * 1000
&& day < today + 86400 * 1000 * 2) {
testDate = "明天" + hour + "";
} else if (day >= today + 86400 * 1000 * 2
&& day < today + 86400 * 1000 * 3) {
testDate = "后天" + hour + "";
} else if (day >= today - 86400 * 1000 && day < today) {
testDate = "昨天" + hour + "";
} else {
format = new SimpleDateFormat("MM-dd", Locale.CHINA);
testDate = format.format(day) + " " + hour + "";
}
return testDate;
} catch (ParseException e) {
e.printStackTrace();
long day = Long.parseLong(testTime + "000");
Calendar calendar = Calendar.getInstance(TimeZone
.getTimeZone("Asia/Shanghai"));
calendar.setTimeInMillis(day);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
format = new SimpleDateFormat("MM-dd", Locale.CHINA);
testDate = format.format(day) + " " + hour + "";
return testDate;
}
String testDate;
try {
long today = format.parse(format.format(new Date())).getTime();
long day = Long.parseLong(testTime + "000");
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.CHINA);
String time = timeFormat.format(day);
}
if (day >= today && day < today + 86400 * 1000) {
testDate = "今天 " + time;
} else if (day >= today + 86400 * 1000
&& day < today + 86400 * 1000 * 2) {
testDate = "明天 " + time;
} else if (day >= today + 86400 * 1000 * 2
&& day < today + 86400 * 1000 * 3) {
testDate = "后天 " + time;
} else if (day >= today - 86400 * 1000 && day < today) {
testDate = "昨天 " + time;
} else {
testDate = new SimpleDateFormat("MM-dd HH:mm", Locale.CHINA).format(day);
}
return testDate;
} catch (ParseException e) {
e.printStackTrace();
long day = Long.parseLong(testTime + "000");
Calendar calendar = Calendar.getInstance(TimeZone
.getTimeZone("Asia/Shanghai"));
calendar.setTimeInMillis(day);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
format = new SimpleDateFormat("MM-dd", Locale.CHINA);
testDate = format.format(day) + " " + hour + "";
return testDate;
}
}
}

View File

@ -0,0 +1,299 @@
package com.gh.common.util;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import com.gh.common.constant.Config;
import com.lightgame.utils.RuntimeUtils;
import com.lightgame.utils.Utils;
import com.sina.weibo.sdk.WbSdk;
import com.sina.weibo.sdk.auth.AuthInfo;
import com.sina.weibo.sdk.auth.Oauth2AccessToken;
import com.sina.weibo.sdk.auth.WbAuthListener;
import com.sina.weibo.sdk.auth.WbConnectErrorMessage;
import com.sina.weibo.sdk.auth.sso.SsoHandler;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.SendAuth;
import com.tencent.mm.sdk.openapi.WXAPIFactory;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
/**
* Created by khy on 14/06/17.
* <p>
* 获取第三方登录数据
*/
public class GetLoginDataUtils {
private static GetLoginDataUtils instance;
private Context mContext;
private OnLoginDataListener mLoginListener; //登录成功回调
private Tencent mTencent;
private IWXAPI mIWXAPI;
private SsoHandler mSsoHandler;
private Oauth2AccessToken mAccessToken; // weibo
public static final String SCOPE =
"email,direct_messages_read,direct_messages_write,"
+ "friendships_groups_read,friendships_groups_write,statuses_to_me_read,"
+ "follow_app_official_microblog," + "invitation_write"; // weiboCode
private GetLoginDataUtils(Context context) {
mContext = context.getApplicationContext();
mTencent = Tencent.createInstance(Config.TENCENT_APPID, mContext); //初始化QQ分享
mIWXAPI = WXAPIFactory.createWXAPI(mContext, Config.WECHAT_APPID, true); //初始化微信分享
WbSdk.install(context, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", SCOPE));
Utils.log(GetLoginDataUtils.class.getSimpleName(), "initLogin");
}
public static GetLoginDataUtils getInstance(Context context) {
if (instance == null) {
instance = new GetLoginDataUtils(context);
}
return instance;
}
//QQ登录回调处理
public IUiListener QqLoginListener = new IUiListener() {
@Override
public void onComplete(Object o) {
Utils.log(GetLoginDataUtils.class.getSimpleName(), "QQ 登录成功");
if (o instanceof JSONObject) {
JSONObject jsonObject = (JSONObject) o;
String s = jsonObject.toString();
Utils.log(GetLoginDataUtils.class.getSimpleName(), "QQLoginComplete::" + s);
try {
mTencent.setOpenId(jsonObject.getString("openid"));
mTencent.setAccessToken(jsonObject.getString("access_token"), jsonObject.getString("expires_in"));
JSONObject content = new JSONObject();
content.put("openid", jsonObject.getString("openid"));
content.put("access_token_expire", Utils.getTime(mContext) + jsonObject.getLong("expires_in"));
content.put("access_token", jsonObject.getString("access_token"));
if (mLoginListener != null) {
mLoginListener.OnLoginData(content, LoginUtils.LoginTag.qq);// QQ 登录回调
}
} catch (JSONException e) {
Utils.log(GetLoginDataUtils.class.getSimpleName(), "QQ登录数据回调异常" + e.toString());
e.printStackTrace();
}
}
// QQToken qqToken = mTencent.getQQToken();
// UserInfo userInfo = new UserInfo(mContext, qqToken);
// userInfo.getUserInfo(new IUiListener() { // 获取QQ用户信息
// @Override
// public void onComplete(Object o) {
// Utils.log(GetLoginDataUtils.class.getSimpleName(), "QQUserInfo::" + o.toString());
// }
//
// @Override
// public void onError(UiError uiError) {
// Utils.log(GetLoginDataUtils.class.getSimpleName(), "QQUserInfoUiError::" + uiError.errorDetail + "==" + uiError.errorMessage + "==" + uiError.errorCode);
// }
//
// @Override
// public void onCancel() {
// Utils.log(GetLoginDataUtils.class.getSimpleName(), "QQUserInfoonCancel");
// }
// });
}
@Override
public void onError(UiError uiError) {
Utils.toast(mContext, "登录失败");
Utils.log(GetLoginDataUtils.class.getSimpleName(), "QQ 登录失败");
}
@Override
public void onCancel() {
Utils.toast(mContext, "登录取消");
Utils.log(GetLoginDataUtils.class.getSimpleName(), "QQ 登录取消");
}
};
public void onQQCallback(int requestCode, int resultCode, Intent data) {
Tencent.onActivityResultData(requestCode, resultCode, data, QqLoginListener);
}
// QQ登录
public void QQLogin(OnLoginDataListener listener, Activity activity) {
mLoginListener = listener;
if (mTencent != null && !mTencent.isSessionValid()) {
Utils.log(GetLoginDataUtils.class.getSimpleName(), "QQLogin");
mTencent.login(activity, "all", QqLoginListener);
}
}
public void QQLogout() {
if (mTencent != null && mTencent.isSessionValid()) {
mTencent.logout(mContext);
}
}
// 微信登录
public void WCLogin(OnLoginDataListener listener) {
mLoginListener = listener;
if (mIWXAPI != null) {
boolean register = mIWXAPI.registerApp(Config.WECHAT_APPID);
SendAuth.Req req = new SendAuth.Req();
req.scope = "snsapi_userinfo";
req.state = "光环助手";
boolean b = mIWXAPI.sendReq(req);
Utils.log(GetLoginDataUtils.class.getSimpleName(), "微信注册状态::" + register + "\n 发送状态::" + b);
if (!register || !b) {
Utils.toast(mContext, "请检查是否安装微信客户端");
}
}
}
public void WCLofinCallBack(JSONObject content) {
mLoginListener.OnLoginData(content, LoginUtils.LoginTag.wechat);
}
public void onWeiboCallback(int requestCode, int resultCode, Intent data) {
if (mSsoHandler != null) {
mSsoHandler.authorizeCallBack(requestCode, resultCode, data);
}
}
// 微博登录
public void WeiBoLogin(OnLoginDataListener listener, Activity context) {
mSsoHandler = new SsoHandler(context);
mLoginListener = listener;
mSsoHandler.authorizeClientSso(new SelfWbAuthListener());
// 第一次启动本应用AccessToken 不可用
mAccessToken = AccessTokenKeeper.readAccessToken(mContext);
// if (mAccessToken.isSessionValid()) {
// updateTokenView(true);
// }
}
// 微博登录回调处理
private class SelfWbAuthListener implements WbAuthListener {
@Override
public void onSuccess(final Oauth2AccessToken token) {
RuntimeUtils.getInstance().runOnUiThread(new Runnable() {
@Override
public void run() {
mAccessToken = token;
if (mAccessToken.isSessionValid()) {
// 显示 Token
// updateTokenView(false);
// 保存 Token 到 SharedPreferences
AccessTokenKeeper.writeAccessToken(mContext, mAccessToken);
Toast.makeText(mContext, "授权成功", Toast.LENGTH_SHORT).show();
}
}
});
JSONObject content = new JSONObject();
try {
content.put("uid", token.getUid());
content.put("access_token", token.getToken());
content.put("access_token_expire", Utils.getTime(mContext) + token.getExpiresTime());
content.put("refresh_token", token.getRefreshToken());
// content.put("refresh_token_expire", Utils.getTime(mContext) + 86400 * 30); // refresh_token 有效期30天
if (mLoginListener != null) {
mLoginListener.OnLoginData(content, LoginUtils.LoginTag.weibo);// 微博 登录回调
}
} catch (JSONException e) {
e.printStackTrace();
}
// AppController.MAIN_EXECUTOR.execute(new Runnable() {
// @Override
// public void run() {
// getWeiBoUserInfo(token.getToken(), token.getUid());
// }
// });
}
@Override
public void cancel() {
Utils.toast(mContext, "取消授权");
}
@Override
public void onFailure(WbConnectErrorMessage errorMessage) {
Utils.toast(mContext, "微博登录需要客户端支持,请先安装微博");
}
}
//微博 获取用户信息
private void getWeiBoUserInfo(String accessToken, String uid) {
String path = "https://api.weibo.com/2/users/show.json?access_token=" + accessToken + "&uid=" + uid;
Utils.log(GetLoginDataUtils.class.getSimpleName(), "getWeiBoUserInfo-url::" + path);
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
conn.setDoInput(true);
int code = conn.getResponseCode();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
Utils.log(GetLoginDataUtils.class.getSimpleName(), "getWeiBoUserInfo-RequestCode::" + code);
if (code == 200) {
InputStream is = conn.getInputStream();
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
String str = new String(baos.toByteArray());
Utils.log(GetLoginDataUtils.class.getSimpleName(), "getWeiBoUserInfo-Body::" + str);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 微博显示当前 Token 信息。
*
* @param hasExisted 配置文件中是否已存在 token 信息并且合法
*/
private void updateTokenView(boolean hasExisted) {
String date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(
new java.util.Date(mAccessToken.getExpiresTime()));
String format = "Token%1$s \\n有效期%2$s";
String token = String.format(format, mAccessToken.getToken(), date);
Utils.log(GetLoginDataUtils.class.getSimpleName(), "::WB_TOKEN::" + token);
String message = String.format(format, mAccessToken.getToken(), date);
if (hasExisted) {
message = "Token 仍在有效期内,无需再次登录。" + "\n" + message;
}
Utils.log(GetLoginDataUtils.class.getSimpleName(), "::WB_MESSAGE::" + message);
}
// 登录成功回调
public interface OnLoginDataListener {
void OnLoginData(JSONObject content, LoginUtils.LoginTag loginTag);
}
}

View File

@ -0,0 +1,35 @@
package com.gh.common.util
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
/**
* Created by khy on 11/10/17.
*/
class GsonUtils private constructor() {
val mGson: Gson = Gson()
companion object {
fun getInstance(): GsonUtils {
return Inner.anotherSingle
}
private object Inner {
val anotherSingle = GsonUtils()
}
}
fun <T> fromJsonBean(json: String, t: Class<T>): T {
return mGson.fromJson(json, t)
}
fun <T> fromJsonList(json: String, t: Class<T>): T {
val type = object : TypeToken<List<T>>() {}.type
return mGson.fromJson(json, type)
}
fun toJson(any: Any): String {
return mGson.toJson(any)
}
}

View File

@ -10,105 +10,105 @@ import java.util.zip.GZIPOutputStream;
public class GzipUtils {
private final static int BUFFER = 1024;
private final static int BUFFER = 1024;
/*
* 数据压缩
*/
public static void compress(InputStream is, OutputStream os) throws IOException {
GZIPOutputStream gos = null;
try {
gos = new GZIPOutputStream(os);
int count;
byte data[] = new byte[BUFFER];
while ((count = is.read(data, 0, BUFFER)) != -1) {
gos.write(data, 0, count);
}
gos.flush();
gos.finish();
gos.close();
} finally {
if (gos != null) {
gos.close();
}
}
}
public static byte[] compressBytes(byte[] compressed) {
ByteArrayInputStream bais = null;
ByteArrayOutputStream baos = null;
try {
bais = new ByteArrayInputStream(compressed);
baos = new ByteArrayOutputStream();
compress(bais, baos);
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return compressed;
} finally {
if (bais != null) {
try {
bais.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
* 数据压缩
*/
public static void decompress(InputStream is, OutputStream os) throws IOException {
GZIPInputStream gis = null;
try {
gis = new GZIPInputStream(is);
int count;
byte data[] = new byte[BUFFER];
while ((count = gis.read(data, 0, BUFFER)) != -1) {
os.write(data, 0, count);
}
} finally {
if (gis != null) {
gis.close();
}
}
}
/*
* 数据压缩
*/
public static void compress(InputStream is, OutputStream os) throws IOException {
GZIPOutputStream gos = null;
try {
gos = new GZIPOutputStream(os);
int count;
byte data[] = new byte[BUFFER];
while ((count = is.read(data, 0, BUFFER)) != -1) {
gos.write(data, 0, count);
}
gos.flush();
gos.finish();
gos.close();
} finally {
if (gos != null) {
gos.close();
}
}
}
public static byte[] compressBytes(byte[] compressed) {
ByteArrayInputStream bais = null;
ByteArrayOutputStream baos = null;
try {
bais = new ByteArrayInputStream(compressed);
baos = new ByteArrayOutputStream();
compress(bais, baos);
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return compressed;
} finally {
if (bais != null) {
try {
bais.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static byte[] decompressBytes(byte[] compressed) {
ByteArrayInputStream bais = null;
ByteArrayOutputStream baos = null;
try {
bais = new ByteArrayInputStream(compressed);
baos = new ByteArrayOutputStream();
decompress(bais, baos);
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return compressed;
} finally {
if (bais != null) {
try {
bais.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static byte[] decompressBytes(byte[] compressed) {
ByteArrayInputStream bais = null;
ByteArrayOutputStream baos = null;
try {
bais = new ByteArrayInputStream(compressed);
baos = new ByteArrayOutputStream();
decompress(bais, baos);
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return compressed;
} finally {
if (bais != null) {
try {
bais.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
* 数据解压缩
*/
public static void decompress(InputStream is, OutputStream os) throws IOException {
GZIPInputStream gis = null;
try {
gis = new GZIPInputStream(is);
int count;
byte data[] = new byte[BUFFER];
while ((count = gis.read(data, 0, BUFFER)) != -1) {
os.write(data, 0, count);
}
} finally {
if (gis != null) {
gis.close();
}
}
}
}

View File

@ -0,0 +1,36 @@
package com.gh.common.util;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class HMACUtils {
public static String encrypt(String data, String key) {
try {
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
return byte2hex(mac.doFinal(data.getBytes()));
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
private static String byte2hex(byte[] ciphertext) {
StringBuilder builder = new StringBuilder();
String stmp;
for (int i = 0; ciphertext != null && i < ciphertext.length; i++) {
stmp = Integer.toHexString(ciphertext[i] & 0XFF);
if (stmp.length() == 1) {
builder.append('0');
}
builder.append(stmp);
}
return builder.toString().toLowerCase();
}
}

View File

@ -41,6 +41,27 @@ public final class HotFix {
}
}
private static void injectInAliyunOs(Context context, String patchDexFile, String patchClassName)
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException,
InstantiationException, NoSuchFieldException {
PathClassLoader obj = (PathClassLoader) context.getClassLoader();
String replaceAll = new File(patchDexFile).getName().replaceAll("\\.[a-zA-Z0-9]+", ".lex");
Class cls = Class.forName("dalvik.system.LexClassLoader");
Object newInstance =
cls.getConstructor(new Class[]{String.class, String.class, String.class, ClassLoader.class}).newInstance(
new Object[]{context.getDir("dex", 0).getAbsolutePath() + File.separator + replaceAll,
context.getDir("dex", 0).getAbsolutePath(), patchDexFile, obj});
cls.getMethod("loadClass", new Class[]{String.class}).invoke(newInstance, new Object[]{patchClassName});
setField(obj, PathClassLoader.class, "mPaths",
appendArray(getField(obj, PathClassLoader.class, "mPaths"), getField(newInstance, cls, "mRawDexPath")));
setField(obj, PathClassLoader.class, "mFiles",
combineArray(getField(obj, PathClassLoader.class, "mFiles"), getField(newInstance, cls, "mFiles")));
setField(obj, PathClassLoader.class, "mZips",
combineArray(getField(obj, PathClassLoader.class, "mZips"), getField(newInstance, cls, "mZips")));
setField(obj, PathClassLoader.class, "mLexs",
combineArray(getField(obj, PathClassLoader.class, "mLexs"), getField(newInstance, cls, "mDexs")));
}
private static boolean hasDexClassLoader() {
try {
Class.forName("dalvik.system.BaseDexClassLoader");
@ -50,85 +71,66 @@ public final class HotFix {
}
}
private static void injectInAliyunOs(Context context, String patchDexFile, String patchClassName)
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException,
InstantiationException, NoSuchFieldException {
PathClassLoader obj = (PathClassLoader) context.getClassLoader();
String replaceAll = new File(patchDexFile).getName().replaceAll("\\.[a-zA-Z0-9]+", ".lex");
Class cls = Class.forName("dalvik.system.LexClassLoader");
Object newInstance =
cls.getConstructor(new Class[] {String.class, String.class, String.class, ClassLoader.class}).newInstance(
new Object[] {context.getDir("dex", 0).getAbsolutePath() + File.separator + replaceAll,
context.getDir("dex", 0).getAbsolutePath(), patchDexFile, obj});
cls.getMethod("loadClass", new Class[] {String.class}).invoke(newInstance, new Object[] {patchClassName});
setField(obj, PathClassLoader.class, "mPaths",
appendArray(getField(obj, PathClassLoader.class, "mPaths"), getField(newInstance, cls, "mRawDexPath")));
setField(obj, PathClassLoader.class, "mFiles",
combineArray(getField(obj, PathClassLoader.class, "mFiles"), getField(newInstance, cls, "mFiles")));
setField(obj, PathClassLoader.class, "mZips",
combineArray(getField(obj, PathClassLoader.class, "mZips"), getField(newInstance, cls, "mZips")));
setField(obj, PathClassLoader.class, "mLexs",
combineArray(getField(obj, PathClassLoader.class, "mLexs"), getField(newInstance, cls, "mDexs")));
}
@TargetApi(14)
private static void injectBelowApiLevel14(Context context, String str, String str2)
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
PathClassLoader obj = (PathClassLoader) context.getClassLoader();
DexClassLoader dexClassLoader =
new DexClassLoader(str, context.getDir("dex", 0).getAbsolutePath(), str, context.getClassLoader());
dexClassLoader.loadClass(str2);
setField(obj, PathClassLoader.class, "mPaths",
appendArray(getField(obj, PathClassLoader.class, "mPaths"), getField(dexClassLoader, DexClassLoader.class,
"mRawDexPath")
));
setField(obj, PathClassLoader.class, "mFiles",
combineArray(getField(obj, PathClassLoader.class, "mFiles"), getField(dexClassLoader, DexClassLoader.class,
"mFiles")
));
setField(obj, PathClassLoader.class, "mZips",
combineArray(getField(obj, PathClassLoader.class, "mZips"), getField(dexClassLoader, DexClassLoader.class,
"mZips")));
setField(obj, PathClassLoader.class, "mDexs",
combineArray(getField(obj, PathClassLoader.class, "mDexs"), getField(dexClassLoader, DexClassLoader.class,
"mDexs")));
obj.loadClass(str2);
}
private static void injectAboveEqualApiLevel14(Context context, String str, String str2)
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader();
Object a = combineArray(getDexElements(getPathList(pathClassLoader)),
getDexElements(getPathList(
new DexClassLoader(str, context.getDir("dex", 0).getAbsolutePath(), str, context.getClassLoader()))));
getDexElements(getPathList(
new DexClassLoader(str, context.getDir("dex", 0).getAbsolutePath(), str, context.getClassLoader()))));
Object a2 = getPathList(pathClassLoader);
setField(a2, a2.getClass(), "dexElements", a);
pathClassLoader.loadClass(str2);
}
private static Object getPathList(Object obj) throws ClassNotFoundException, NoSuchFieldException,
IllegalAccessException {
return getField(obj, Class.forName("dalvik.system.BaseDexClassLoader"), "pathList");
}
private static Object getDexElements(Object obj) throws NoSuchFieldException, IllegalAccessException {
return getField(obj, obj.getClass(), "dexElements");
}
private static Object getField(Object obj, Class cls, String str)
throws NoSuchFieldException, IllegalAccessException {
Field declaredField = cls.getDeclaredField(str);
declaredField.setAccessible(true);
return declaredField.get(obj);
@TargetApi(14)
private static void injectBelowApiLevel14(Context context, String str, String str2)
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
PathClassLoader obj = (PathClassLoader) context.getClassLoader();
DexClassLoader dexClassLoader =
new DexClassLoader(str, context.getDir("dex", 0).getAbsolutePath(), str, context.getClassLoader());
dexClassLoader.loadClass(str2);
setField(obj, PathClassLoader.class, "mPaths",
appendArray(getField(obj, PathClassLoader.class, "mPaths"), getField(dexClassLoader, DexClassLoader.class,
"mRawDexPath")
));
setField(obj, PathClassLoader.class, "mFiles",
combineArray(getField(obj, PathClassLoader.class, "mFiles"), getField(dexClassLoader, DexClassLoader.class,
"mFiles")
));
setField(obj, PathClassLoader.class, "mZips",
combineArray(getField(obj, PathClassLoader.class, "mZips"), getField(dexClassLoader, DexClassLoader.class,
"mZips")));
setField(obj, PathClassLoader.class, "mDexs",
combineArray(getField(obj, PathClassLoader.class, "mDexs"), getField(dexClassLoader, DexClassLoader.class,
"mDexs")));
obj.loadClass(str2);
}
private static void setField(Object obj, Class cls, String str, Object obj2)
throws NoSuchFieldException, IllegalAccessException {
throws NoSuchFieldException, IllegalAccessException {
Field declaredField = cls.getDeclaredField(str);
declaredField.setAccessible(true);
declaredField.set(obj, obj2);
}
private static Object appendArray(Object obj, Object obj2) {
Class componentType = obj.getClass().getComponentType();
int length = Array.getLength(obj);
Object newInstance = Array.newInstance(componentType, length + 1);
Array.set(newInstance, 0, obj2);
for (int i = 1; i < length + 1; i++) {
Array.set(newInstance, i, Array.get(obj, i - 1));
}
return newInstance;
}
private static Object getField(Object obj, Class cls, String str)
throws NoSuchFieldException, IllegalAccessException {
Field declaredField = cls.getDeclaredField(str);
declaredField.setAccessible(true);
return declaredField.get(obj);
}
private static Object combineArray(Object obj, Object obj2) {
Class componentType = obj2.getClass().getComponentType();
int length = Array.getLength(obj2);
@ -144,15 +146,13 @@ public final class HotFix {
return newInstance;
}
private static Object appendArray(Object obj, Object obj2) {
Class componentType = obj.getClass().getComponentType();
int length = Array.getLength(obj);
Object newInstance = Array.newInstance(componentType, length + 1);
Array.set(newInstance, 0, obj2);
for (int i = 1; i < length + 1; i++) {
Array.set(newInstance, i, Array.get(obj, i - 1));
}
return newInstance;
private static Object getDexElements(Object obj) throws NoSuchFieldException, IllegalAccessException {
return getField(obj, obj.getClass(), "dexElements");
}
private static Object getPathList(Object obj) throws ClassNotFoundException, NoSuchFieldException,
IllegalAccessException {
return getField(obj, Class.forName("dalvik.system.BaseDexClassLoader"), "pathList");
}
}

View File

@ -1,126 +0,0 @@
package com.gh.common.util;
import android.content.Context;
import com.gh.gamecenter.R;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.internal.tls.OkHostnameVerifier;
/**
* Created by khy on 2016/10/8.
*
*/
public class HttpsUtils {
private static final TrustManager[] TRUST_MANAGERS = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
private static final HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
private static SSLSocketFactory mSSLSocketFactory;
private static HostnameVerifier mHostnameVerifier;
public static void initHttpsUrlConnection(Context context) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyStore keyStore = getHttpsKeyStore(context);
if (keyStore != null) {
String algorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
tmf.init(keyStore);
sslContext.init(null, tmf.getTrustManagers(), null);
mHostnameVerifier = OkHostnameVerifier.INSTANCE;
} else {
sslContext.init(null, TRUST_MANAGERS, null);
mHostnameVerifier = HOSTNAME_VERIFIER;
}
mSSLSocketFactory = sslContext.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
private static KeyStore getHttpsKeyStore(Context context) {
InputStream is = null;
try {
is = context.getResources().openRawResource(R.raw.cacert);
//读取证书
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
certificateFactory.generateCertificate(is);
Certificate certificate = certificateFactory.generateCertificate(is);
//创建一个证书库,并将证书导入证书库
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("trust", certificate);
return keyStore;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static HttpsURLConnection getHttpsURLConnection(URL url) throws Exception {
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
if (mSSLSocketFactory == null || mHostnameVerifier == null) {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, TRUST_MANAGERS, null);
mSSLSocketFactory = sslContext.getSocketFactory();
mHostnameVerifier = HOSTNAME_VERIFIER;
}
httpsURLConnection.setSSLSocketFactory(mSSLSocketFactory);
httpsURLConnection.setHostnameVerifier(mHostnameVerifier);
return httpsURLConnection;
}
}

View File

@ -1,114 +0,0 @@
package com.gh.common.util;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.view.ViewGroup;
import com.facebook.common.executors.CallerThreadExecutor;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.controller.BaseControllerListener;
import com.facebook.drawee.controller.ControllerListener;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.ImageInfo;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.gh.gamecenter.R;
public class ImageUtils {
private static ImageUtils singleton;
public static ImageUtils getInstance() {
if (singleton == null) {
synchronized (ImageUtils.class) {
if (singleton == null) {
singleton = new ImageUtils();
return singleton;
}
}
}
return singleton;
}
public static void display(SimpleDraweeView simpleDraweeView, String url) {
// if (url.startsWith("http://image.ghzhushou.com") && url.endsWith(".jpg")) {
// url = url + "?x-oss-process=image/format,webp";
// }
simpleDraweeView.setImageURI(url);
}
// 自适应图片宽高
public void display(final SimpleDraweeView simpleDraweeView, String url, final int width) {
ControllerListener<ImageInfo> listener = new BaseControllerListener<ImageInfo>(){
@Override
public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) {
if (imageInfo == null){
return;
}
ViewGroup.LayoutParams layoutParams = simpleDraweeView.getLayoutParams();
float scale = (float) imageInfo.getHeight() / (float) imageInfo.getWidth();
layoutParams.height = (int)(width * scale);
simpleDraweeView.setLayoutParams(layoutParams);
}
};
simpleDraweeView.setController(Fresco.newDraweeControllerBuilder()
.setUri(url)
.setControllerListener(listener)
.build());
}
// 设置缩放类型,设置按压状态下的叠加图
public void display(Resources resources, SimpleDraweeView simpleDraweeView,
ScalingUtils.ScaleType scaleType, String url) {
simpleDraweeView.setHierarchy(new GenericDraweeHierarchyBuilder(resources)
.setFadeDuration(500)
.setPressedStateOverlay(new ColorDrawable(resources.getColor(R.color.pressed_bg)))
.setPlaceholderImage(R.drawable.ocupy2, ScalingUtils.ScaleType.CENTER)
.setBackground(new ColorDrawable(resources.getColor(R.color.placeholder_bg)))
.setActualImageScaleType(scaleType)
.build());
// simpleDraweeView.setImageURI(url);
display(simpleDraweeView, url);
}
// 设置占位符
public void display(Resources resources, SimpleDraweeView simpleDraweeView, String url, int placeholderImage) {
simpleDraweeView.setHierarchy(new GenericDraweeHierarchyBuilder(resources)
.setFadeDuration(500)
.setPressedStateOverlay(new ColorDrawable(resources.getColor(R.color.pressed_bg)))
.setBackground(new ColorDrawable(resources.getColor(R.color.placeholder_bg)))
.setPlaceholderImage(placeholderImage)
.build());
// simpleDraweeView.setImageURI(url);
display(simpleDraweeView, url);
}
// 图片下载监听和设置低高分辨率图片
public void display(SimpleDraweeView simpleDraweeView, String url, String lowUrl,
ControllerListener<? super ImageInfo> listener) {
simpleDraweeView.setController(Fresco.newDraweeControllerBuilder()
.setImageRequest(ImageRequest.fromUri(url))
.setControllerListener(listener)
.setLowResImageRequest(ImageRequest.fromUri(lowUrl)) // 低分辨率图片
.build());
}
// 获取bitmap
public void display(Context context, String url, BaseBitmapDataSubscriber dataSubscriber) {
ImageRequest imageRequest = ImageRequestBuilder
.newBuilderWithSource(Uri.parse(url))
.setProgressiveRenderingEnabled(true)
.build();
Fresco.getImagePipeline()
.fetchDecodedImage(imageRequest, context)
.subscribe(dataSubscriber, CallerThreadExecutor.getInstance());
}
}

View File

@ -0,0 +1,116 @@
package com.gh.common.util
import android.content.Context
import android.content.res.Resources
import android.graphics.drawable.Animatable
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.support.annotation.DrawableRes
import android.support.v4.content.ContextCompat
import com.facebook.common.executors.CallerThreadExecutor
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.controller.ControllerListener
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
import com.facebook.imagepipeline.image.ImageInfo
import com.facebook.imagepipeline.request.ImageRequest
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.gh.gamecenter.R
class ImageUtils private constructor() {
// 自适应图片宽高
fun display(simpleDraweeView: SimpleDraweeView, url: String?, width: Int) {
val listener = object : BaseControllerListener<ImageInfo>() {
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
if (imageInfo == null) {
return
}
val layoutParams = simpleDraweeView.layoutParams
val scale = imageInfo.height.toFloat() / imageInfo.width.toFloat()
layoutParams.height = (width * scale).toInt()
simpleDraweeView.layoutParams = layoutParams
}
}
simpleDraweeView.controller = Fresco.newDraweeControllerBuilder()
.setUri(url)
.setControllerListener(listener)
.build()
}
// 设置缩放类型,设置按压状态下的叠加图
fun display(resources: Resources, simpleDraweeView: SimpleDraweeView,
scaleType: ScalingUtils.ScaleType, url: String?) {
val context = simpleDraweeView.context
simpleDraweeView.hierarchy = GenericDraweeHierarchyBuilder(resources)
.setFadeDuration(500)
.setPressedStateOverlay(ColorDrawable(ContextCompat.getColor(context, R.color.pressed_bg)))
.setPlaceholderImage(R.drawable.occupy2, ScalingUtils.ScaleType.CENTER)
.setBackground(ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
.setActualImageScaleType(scaleType)
.build()
// simpleDraweeView.setImageURI(url);
display(simpleDraweeView, url)
}
// 设置占位符
fun display(resources: Resources, simpleDraweeView: SimpleDraweeView, url: String?, placeholderImage: Int) {
val context = simpleDraweeView.context
simpleDraweeView.hierarchy = GenericDraweeHierarchyBuilder(resources)
.setFadeDuration(500)
.setPressedStateOverlay(ColorDrawable(ContextCompat.getColor(context, R.color.pressed_bg)))
.setBackground(ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
.setPlaceholderImage(placeholderImage)
.build()
// simpleDraweeView.setImageURI(url);
display(simpleDraweeView, url)
}
// 图片下载监听和设置低高分辨率图片
fun display(simpleDraweeView: SimpleDraweeView, url: String?, lowUrl: String?,
listener: ControllerListener<in ImageInfo>) {
simpleDraweeView.controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(ImageRequest.fromUri(url))
.setControllerListener(listener)
.setLowResImageRequest(ImageRequest.fromUri(lowUrl)) // 低分辨率图片
.build()
}
// 获取bitmap
fun display(context: Context, url: String?, dataSubscriber: BaseBitmapDataSubscriber) {
val imageRequest = ImageRequestBuilder
.newBuilderWithSource(Uri.parse(url))
.setProgressiveRenderingEnabled(true)
.build()
Fresco.getImagePipeline()
.fetchDecodedImage(imageRequest, context)
.subscribe(dataSubscriber, CallerThreadExecutor.getInstance())
}
companion object {
fun getInstance(): ImageUtils {
return Inner.anotherSingle
}
private object Inner {
val anotherSingle = ImageUtils()
}
fun display(simpleDraweeView: SimpleDraweeView, url: String?) {
// if (url.startsWith("http://image.ghzs666.com") && url.endsWith(".jpg")) {
// url = url + "?x-oss-process=image/format,webp";
// }
simpleDraweeView.setImageURI(url)
}
fun display(draweeView: SimpleDraweeView, @DrawableRes res: Int?) {
draweeView.setImageURI("res:///" + res)
}
}
}

View File

@ -9,7 +9,8 @@ import android.os.Handler;
import android.os.Message;
import com.gh.gamecenter.eventbus.EBPackage;
import com.gh.gamecenter.manager.CommentManager;
import org.greenrobot.eventbus.EventBus;
import java.util.ArrayList;
import java.util.Collections;
@ -17,132 +18,128 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.greenrobot.event.EventBus;
/**
*
* 下载完成跳安装,
*/
public class InstallUtils {
private static final int MAX_TIME = 5 * 60 * 1000;
private static final int MAX_TIME = 5 * 60 * 1000;
private static int INSTALL_WHAT = 20;
private static Map<String, Long> installMap;
private static Map<String, Long> uninstallMap;
private static Map<String, Long> installMap;
private static Map<String, Long> uninstallMap;
private static InstallUtils mInstance;
private static InstallUtils mInstance;
private PackageManager packageManager;
private Handler handler;
private boolean isRunning;
public static InstallUtils getInstance(Context context) {
if (mInstance == null) {
synchronized (CommentManager.class) {
if (mInstance == null) {
mInstance = new InstallUtils(context);
}
}
}
return mInstance;
}
private InstallUtils(Context context) {
isRunning = false;
private PackageManager packageManager;
packageManager = context.getPackageManager();
private Handler handler;
handler = new Handler(context.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what == INSTALL_WHAT && packageManager != null) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
list.add(packageInfo.packageName);
}
}
if (installMap != null && installMap.size() != 0) {
ArrayList<String> keys = new ArrayList<>();
for (String packageName : installMap.keySet()) {
long time = installMap.get(packageName);
if (System.currentTimeMillis() - time >= MAX_TIME) {
keys.add(packageName);
} else if (list.contains(packageName)) {
keys.add(packageName);
EventBus.getDefault().post(new EBPackage("安装", packageName));
}
}
for (String key : keys) {
installMap.remove(key);
}
}
if (uninstallMap != null && uninstallMap.size() != 0) {
ArrayList<String> keys = new ArrayList<>();
for (String packageName : uninstallMap.keySet()) {
long time = uninstallMap.get(packageName);
if (System.currentTimeMillis() - time >= MAX_TIME) {
keys.add(packageName);
} else if (list.contains(packageName)) {
keys.add(packageName);
EventBus.getDefault().post(new EBPackage("卸载", packageName));
}
}
for (String key : keys) {
uninstallMap.remove(key);
}
}
if ((installMap != null && installMap.size() != 0)
|| (uninstallMap != null && uninstallMap.size() != 0)) {
sendEmptyMessageDelayed(INSTALL_WHAT, 3000);
} else {
isRunning = false;
}
}
}
};
}
private boolean isRunning;
public static InstallUtils getInstance(Context context) {
if (mInstance == null) {
synchronized (InstallUtils.class) {
if (mInstance == null) {
mInstance = new InstallUtils(context);
}
}
}
return mInstance;
}
private InstallUtils(Context context) {
isRunning = false;
public void addInstall(String packageName) {
if (installMap == null) {
installMap = Collections.synchronizedMap(new HashMap<String, Long>());
}
installMap.put(packageName, System.currentTimeMillis());
run();
}
packageManager = context.getPackageManager();
public void run() {
if ((installMap == null || installMap.isEmpty()) && (uninstallMap == null || uninstallMap.isEmpty())) {
return;
}
if (isRunning) {
return;
}
isRunning = true;
handler.sendEmptyMessageDelayed(INSTALL_WHAT, 10000);
}
handler = new Handler(context.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x123 && packageManager != null) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
list.add(packageInfo.packageName);
}
}
if (installMap != null && installMap.size() != 0) {
ArrayList<String> keys = new ArrayList<>();
for (String packageName : installMap.keySet()) {
long time = installMap.get(packageName);
if (System.currentTimeMillis() - time >= MAX_TIME) {
keys.add(packageName);
} else if (list.contains(packageName)) {
keys.add(packageName);
EventBus.getDefault().post(new EBPackage("安装", packageName));
}
}
for (String key : keys) {
installMap.remove(key);
}
}
if (uninstallMap != null && uninstallMap.size() != 0) {
ArrayList<String> keys = new ArrayList<>();
for (String packageName : uninstallMap.keySet()) {
long time = uninstallMap.get(packageName);
if (System.currentTimeMillis() - time >= MAX_TIME) {
keys.add(packageName);
} else if (list.contains(packageName)) {
keys.add(packageName);
EventBus.getDefault().post(new EBPackage("卸载", packageName));
}
}
for (String key : keys) {
uninstallMap.remove(key);
}
}
if ((installMap != null && installMap.size() != 0)
|| (uninstallMap != null && uninstallMap.size() != 0)) {
sendEmptyMessageDelayed(0x123, 3000);
} else {
isRunning = false;
}
}
}
};
}
public void removeInstall(String packageName) {
if (installMap != null) {
installMap.remove(packageName);
}
}
public void addInstall(String packageName) {
if (installMap == null) {
installMap = Collections.synchronizedMap(new HashMap<String, Long>());
}
installMap.put(packageName, System.currentTimeMillis());
run();
}
public void addUninstall(String packageName) {
if (uninstallMap == null) {
uninstallMap = Collections.synchronizedMap(new HashMap<String, Long>());
}
uninstallMap.put(packageName, System.currentTimeMillis());
run();
}
public void removeInstall(String packageName) {
if (installMap != null) {
installMap.remove(packageName);
}
}
public void addUninstall(String packageName) {
if (uninstallMap == null) {
uninstallMap = Collections.synchronizedMap(new HashMap<String, Long>());
}
uninstallMap.put(packageName, System.currentTimeMillis());
run();
}
public void removeUninstall(String packageName) {
if (uninstallMap != null) {
uninstallMap.remove(packageName);
}
}
public void run() {
if ((installMap == null || installMap.isEmpty()) && (uninstallMap == null || uninstallMap.isEmpty())) {
return;
}
if (isRunning) {
return;
}
isRunning = true;
handler.sendEmptyMessageDelayed(0x123, 10000);
}
public void removeUninstall(String packageName) {
if (uninstallMap != null) {
uninstallMap.remove(packageName);
}
}
}

View File

@ -2,9 +2,10 @@ package com.gh.common.util;
import android.content.Context;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import com.lightgame.utils.Util_System_Phone_State;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@ -13,47 +14,47 @@ import java.util.UUID;
public class Installation {
private static final String INSTALLATION = "INSTALLATION";
private static final String INSTALLATION = "INSTALLATION";
private static String sID = null;
private static String sID = null;
public synchronized static String getUUID(Context context) {
String imei = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
if (!TextUtils.isEmpty(imei)) {
return imei;
}
String android_id = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
if (!TextUtils.isEmpty(android_id)) {
return android_id;
}
if (sID == null) {
File installation = new File(context.getFilesDir(), INSTALLATION);
try {
if (!installation.exists())
writeInstallationFile(installation);
sID = readInstallationFile(installation);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return sID;
}
public synchronized static String getUUID(Context context) {
String imei = Util_System_Phone_State.getDeviceId(context);
if (!TextUtils.isEmpty(imei)) {
return imei;
}
String android_id = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
if (!TextUtils.isEmpty(android_id)) {
return android_id;
}
if (sID == null) {
File installation = new File(context.getFilesDir(), INSTALLATION);
try {
if (!installation.exists())
writeInstallationFile(installation);
sID = readInstallationFile(installation);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return sID;
}
private static String readInstallationFile(File installation)
throws IOException {
RandomAccessFile f = new RandomAccessFile(installation, "r");
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
f.close();
return new String(bytes);
}
private static void writeInstallationFile(File installation)
throws IOException {
FileOutputStream out = new FileOutputStream(installation);
String id = UUID.randomUUID().toString();
out.write(id.getBytes());
out.close();
}
private static void writeInstallationFile(File installation)
throws IOException {
FileOutputStream out = new FileOutputStream(installation);
String id = UUID.randomUUID().toString();
out.write(id.getBytes());
out.close();
}
private static String readInstallationFile(File installation)
throws IOException {
RandomAccessFile f = new RandomAccessFile(installation, "r");
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
f.close();
return new String(bytes);
}
}

View File

@ -0,0 +1,56 @@
package com.gh.common.util;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
/**
* @author CsHeng
* @Date 17/05/2017
* @Time 5:23 PM
*/
public class IntentUtils {
public static Intent getWifiIntent() {
return new Intent("android.settings.WIFI_SETTINGS");
}
@NonNull
public static Intent getWechatShareIntent(Context context, String picName) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + context.getExternalCacheDir().getPath() + "/ShareImg/" + picName));
intent.setComponent(new ComponentName("com.tencent.mm", "com.tencent.mm.ui.tools.ShareImgUI"));
return intent;
}
@NonNull
public static Intent getSMSIntent(String smsBody) {
Intent sendIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("smsto:"));
sendIntent.putExtra("sms_body", smsBody);
sendIntent.setType("vnd.android-dir/mms-sms");
sendIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return sendIntent;
}
@NonNull
public static Intent getEmailToGHIntent() {
Intent data = new Intent(Intent.ACTION_SENDTO);
data.setData(Uri.parse("mailto:"));
data.putExtra(Intent.EXTRA_SUBJECT, "快来试试光环助手");
data.putExtra(Intent.EXTRA_TEXT, "我用光环助手一段时间了在里面可以下载各种热门卡牌手游的加速版绿色安全超级省心做日常效率提高3-5倍\n" +
"\n" +
"不用肝的感觉真好,快来试试。\n" +
"\n" +
"光环助手官网地址:\n" +
"\n" +
"http://www.ghzs.com/link?source=appshare333");
return data;
}
}

View File

@ -1,77 +1,29 @@
package com.gh.common.util;
import android.graphics.Color;
import android.support.v4.content.ContextCompat;
import android.widget.TextView;
import com.gh.gamecenter.R;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* Created by khy on 2017/3/19.
*/
public class KaiFuUtils {
public static void setKaiFuTime(TextView textView, long time) {
time = time * 1000;
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
try {
long today = format.parse(format.format(new Date())).getTime();
if (time >= today && time < today + 86400 * 1000) {
format.applyPattern("HH:mm");
textView.setText(String.format("今天 %s", format.format(time)));
textView.setBackgroundResource(R.drawable.border_white_bg);
textView.setTextColor(Color.parseColor("#ffb13c"));
} else if (time >= today - 86400 * 1000 && time < today) {
format.applyPattern("HH:mm");
textView.setText(String.format("昨天 %s", format.format(time)));
textView.setBackgroundResource(R.drawable.kaifu_time_tag_gray);
textView.setTextColor(Color.parseColor("#c7c7c7"));
} else if (time > today && time < today + 86400 * 1000 * 2){
format.applyPattern("HH:mm");
textView.setText(String.format("明天 %s", format.format(time)));
textView.setBackgroundResource(R.drawable.border_white_bg);
textView.setTextColor(Color.parseColor("#ffb13c"));
} else if (time >= today - 86400 * 1000 * 2 && time < today){
format.applyPattern("HH:mm");
textView.setText(String.format("前天 %s", format.format(time)));
textView.setBackgroundResource(R.drawable.kaifu_time_tag_gray);
textView.setTextColor(Color.parseColor("#c7c7c7"));
} else if (time > today && time < today + 86400 * 1000 * 3){
format.applyPattern("HH:mm");
textView.setText(String.format("后天 %s", format.format(time)));
textView.setBackgroundResource(R.drawable.kaifu_time_tag_gray);
textView.setTextColor(Color.parseColor("#c7c7c7"));
} else {
format.applyPattern("MM-dd HH:mm");
textView.setText(format.format(time));
textView.setBackgroundResource(R.drawable.kaifu_time_tag_gray);
textView.setTextColor(Color.parseColor("#c7c7c7"));
}
} catch (ParseException e) {
e.printStackTrace();
format.applyPattern("yyyy年MM月dd日 HH:mm");
textView.setText(format.format(time));
}
}
public static void setKaiFuType(TextView textView, String type) {
public static void setKaiFuType(TextView textView, String type) {
textView.setText(type);
switch (type) {
case "不删档内测":
textView.setBackgroundColor(Color.parseColor("#c7c7c7"));
textView.setBackgroundColor(ContextCompat.getColor(textView.getContext(), R.color.content));
break;
case "删档内测":
textView.setBackgroundColor(Color.parseColor("#c7c7c7"));
textView.setBackgroundColor(ContextCompat.getColor(textView.getContext(), R.color.content));
break;
case "公测":
textView.setBackgroundColor(Color.parseColor("#06d0a8"));
textView.setBackgroundColor(ContextCompat.getColor(textView.getContext(), R.color.tag_yellow));
break;
default:
textView.setBackgroundColor(Color.parseColor("#06d0a8"));
textView.setBackgroundColor(ContextCompat.getColor(textView.getContext(), R.color.tag_yellow));
break;
}
}

View File

@ -1,42 +1,46 @@
package com.gh.common.util;
import android.app.Dialog;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.support.v4.content.ContextCompat;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.gh.base.AppController;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.LibaoDetailActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.LibaoDetailAdapter;
import com.gh.gamecenter.db.LibaoDao;
import com.gh.gamecenter.db.info.LibaoInfo;
import com.gh.gamecenter.entity.LibaoEntity;
import com.gh.gamecenter.entity.LibaoStatusEntity;
import com.gh.gamecenter.entity.UserDataEntity;
import com.gh.gamecenter.entity.UserDataLibaoEntity;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.eventbus.EBUISwitch;
import com.gh.gamecenter.geetest.GeetestListener;
import com.gh.gamecenter.geetest.GeetestUtils;
import com.gh.gamecenter.retrofit.JSONObjectResponse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
import de.greenrobot.event.EventBus;
import okhttp3.ResponseBody;
import retrofit2.adapter.rxjava.HttpException;
import retrofit2.HttpException;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
/**
@ -45,6 +49,8 @@ import rx.schedulers.Schedulers;
*/
public class LibaoUtils {
public static final String REFRESH_LIBAO_TIME = "refreshLiBaoTime";
// 礼包去重
public static List<LibaoEntity> removeDuplicateData(List<LibaoEntity> sourceList, List<LibaoEntity> rawList) {
if (sourceList == null || sourceList.isEmpty()
@ -65,59 +71,16 @@ public class LibaoUtils {
return rawList;
}
//初始化存号箱 获取存号箱所有礼包
public static void getCunHaoXiang(final Context context, final boolean isCheck) {
TokenUtils.getToken(context, isCheck)
.flatMap(new Func1<String, Observable<List<LibaoEntity>>>() {
@Override
public Observable<List<LibaoEntity>> call(String token) {
return RetrofitManager.getLibao().getCunHaoXiang(token);
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<List<LibaoEntity>>() {
@Override
public void onResponse(List<LibaoEntity> response) {
LibaoDao libaoDao = new LibaoDao(context);
libaoDao.deleteAll(); // 清空之前所有数据
for (LibaoEntity libaoEntity : response) {
if ("ling".equals(libaoEntity.getStatus())) {
libaoEntity.setStatus("linged");
} else {
libaoEntity.setStatus("taoed");
}
LibaoInfo libaoInfo = LibaoInfo.createLibaoInfo(libaoEntity);
libaoInfo.setActive(libaoEntity.isActive());
libaoDao.add(libaoInfo);
}
EventBus.getDefault().post(new EBReuse("libaoChanged"));
}
@Override
public void onFailure(HttpException e) {
if (e != null && e.code() == 401) {
getCunHaoXiang(context, false);
}
}
});
}
private static void postLibaoLing(final Context context, final String libaoId, final boolean isCheck,
private static void postLibaoLing(final Context context, final String libaoId,
final PostLibaoListener listener, final String captchaCode) {
TokenUtils.getToken(context, isCheck)
.flatMap(new Func1<String, Observable<ResponseBody>>() {
@Override
public Observable<ResponseBody> call(String token) {
if (!TextUtils.isEmpty(captchaCode)) {
return RetrofitManager.getLibao().postLibaoLing(token, captchaCode, libaoId);
} else {
return RetrofitManager.getLibao().postLibaoLing(token, libaoId);
}
}
}).subscribeOn(Schedulers.io())
Observable<ResponseBody> observable;
if (!TextUtils.isEmpty(captchaCode)) {
observable = RetrofitManager.getInstance(context).getApi().postLibaoLing(captchaCode, libaoId);
} else {
observable = RetrofitManager.getInstance(context).getApi().postLibaoLing(libaoId);
}
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new JSONObjectResponse() {
@Override
@ -127,10 +90,7 @@ public class LibaoUtils {
@Override
public void onFailure(HttpException e) {
if (e != null && e.code() == 401) {
postLibaoLing(context, libaoId, false, listener, captchaCode);
return;
} else if (e.code() == 410) { // 该接口已废弃
if (e != null && e.code() == 410) { // 该接口已废弃
Utils.toast(context, "领取失败,请安装最新版本的光环助手");
}
listener.postFailed(e);
@ -138,15 +98,10 @@ public class LibaoUtils {
});
}
private static void postLibaoTao(final Context context, final String libaoId, final boolean isCheck,
private static void postLibaoTao(final Context context, final String libaoId,
final PostLibaoListener listener) {
TokenUtils.getToken(context, isCheck)
.flatMap(new Func1<String, Observable<ResponseBody>>() {
@Override
public Observable<ResponseBody> call(String token) {
return RetrofitManager.getLibao().postLibaoTao(token, libaoId);
}
}).subscribeOn(Schedulers.io())
RetrofitManager.getInstance(context).getApi().postLibaoTao(libaoId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new JSONObjectResponse() {
@Override
@ -156,24 +111,15 @@ public class LibaoUtils {
@Override
public void onFailure(HttpException e) {
if (e != null && e.code() == 401) {
postLibaoTao(context, libaoId, false, listener);
return;
}
listener.postFailed(e);
}
});
}
public static void deleteLibaoCode(final Context context, final String code, final boolean isCheck,
final PostLibaoListener listener) {
TokenUtils.getToken(context, isCheck)
.flatMap(new Func1<String, Observable<ResponseBody>>() {
@Override
public Observable<ResponseBody> call(String token) {
return RetrofitManager.getLibao().deleteLibaoCode(token, code);
}
}).subscribeOn(Schedulers.io())
public static void deleteLibaoCode(final Context context, final String code,
final PostLibaoListener listener) {
RetrofitManager.getInstance(context).getApi().deleteLibaoCode(code)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
@ -183,17 +129,13 @@ public class LibaoUtils {
@Override
public void onFailure(HttpException e) {
if (e != null && e.code() == 401) {
deleteLibaoCode(context, code, false, listener);
return;
}
listener.postFailed(e);
}
});
}
public static void getLibaoStatus(String ids, final PostLibaoListener listener) {
RetrofitManager.getLibao().getLibaoStatus(ids)
public static void getLibaoStatus(Context context, String ids, final PostLibaoListener listener) {
RetrofitManager.getInstance(context).getApi().getLibaoStatus(ids)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<List<LibaoStatusEntity>>() {
@ -209,233 +151,272 @@ public class LibaoUtils {
});
}
public interface PostLibaoListener {
void postSucced(Object response);
void postFailed(Throwable error);
}
public static void initLibaoBtn(final TextView libaoBtn, final LibaoEntity libaoEntity, final LibaoDao libaoDao,
public static void initLibaoBtn(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity,
final boolean isInstallRequired, final LibaoDetailAdapter adapter, final String entrance) {
libaoBtn.setTextColor(Color.WHITE);
String status = libaoEntity.getStatus();
final String status = libaoEntity.getStatus();
if (TextUtils.isEmpty(status)) return;
switch (status) {
case "coming":
libaoBtn.setText("未开抢");
libaoBtn.setText(R.string.libao_coming);
libaoBtn.setBackgroundResource(R.drawable.textview_blue_style);
break;
case "ling":
libaoBtn.setText("领取");
libaoBtn.setText(R.string.libao_ling);
libaoBtn.setBackgroundResource(R.drawable.textview_green_style);
break;
case "tao":
libaoBtn.setText("淘号");
libaoBtn.setText(R.string.libao_tao);
libaoBtn.setBackgroundResource(R.drawable.textview_orange_style);
break;
case "used_up":
libaoBtn.setText("已领光");
libaoBtn.setText(R.string.libao_used_up);
libaoBtn.setBackgroundResource(R.drawable.textview_cancel_up);
break;
case "finish":
libaoBtn.setText("已结束");
libaoBtn.setText(R.string.libao_finish);
libaoBtn.setBackgroundResource(R.drawable.textview_cancel_up);
break;
case "linged":
int[][] states = new int[2][];
states[0] = new int[] { android.R.attr.state_pressed };
states[1] = new int[] {};
int[] colors = new int[] { Color.WHITE,
Color.parseColor("#06D0A8") };
ColorStateList sl = new ColorStateList(states, colors);
libaoBtn.setText("已领取");
libaoBtn.setText(R.string.libao_linged);
libaoBtn.setBackgroundResource(R.drawable.libao_linged_style);
libaoBtn.setTextColor(sl);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_linged_selector));
break;
case "taoed":
int[][] states2 = new int[2][];
states2[0] = new int[] { android.R.attr.state_pressed };
states2[1] = new int[] {};
int[] colors2 = new int[] { Color.WHITE,
Color.parseColor("#ffb13c") };
ColorStateList sl2 = new ColorStateList(states2, colors2);
libaoBtn.setText("已淘号");
libaoBtn.setText(R.string.libao_taoed);
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(sl2);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
break;
case "copy":
libaoBtn.setText("复制");
libaoBtn.setText(R.string.libao_copy);
libaoBtn.setBackgroundResource(R.drawable.textview_blue_style);
break;
case "repeatLing":
libaoBtn.setText(R.string.libao_repeat_ling);
libaoBtn.setBackgroundResource(R.drawable.textview_cancel_up);
break;
case "repeatLinged":
libaoBtn.setText(R.string.libao_repeat_ling);
libaoBtn.setBackgroundResource(R.drawable.textview_green_style);
break;
case "repeatTao":
libaoBtn.setText(R.string.libao_repeat_tao);
libaoBtn.setBackgroundResource(R.drawable.textview_cancel_up);
break;
case "repeatTaoed":
libaoBtn.setText(R.string.libao_repeat_tao);
libaoBtn.setBackgroundResource(R.drawable.textview_orange_style);
break;
case "unshelve":
libaoBtn.setBackgroundResource(R.drawable.textview_cancel_style);
libaoBtn.setText(R.string.libao_unshelve);
break;
default:
libaoBtn.setBackgroundResource(R.drawable.textview_cancel_style);
libaoBtn.setText("异常");
break;
}
libaoBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 领取限制
if ("领取".equals(libaoBtn.getText().toString()) || "淘号".equals(libaoBtn.getText().toString())) {
if (isInstallRequired && !isAppInstalled(libaoBtn.getContext(), libaoEntity.getPackageName())) {
String platform;
if (TextUtils.isEmpty(libaoEntity.getPlatform())) {
platform = "";
} else {
platform = PlatformUtils.getInstance(libaoBtn.getContext())
.getPlatformName(libaoEntity.getPlatform()) + "";
}
DialogUtils.showWarningDialog(libaoBtn.getContext(), "条件不符",
Html.fromHtml("请先"+ "<font color=\"#06D0A8\">"
+ "安装《" + libaoEntity.getGame().getName() + ""
+ platform + "</font>"), "关闭", "立即安装"
, new DialogUtils.ConfiremListener() {
@Override
public void onConfirem() {
adapter.openDownload();
}
}, null);
return;
}
}
switch (libaoBtn.getText().toString()) {
case "未开始":
Utils.toast(libaoBtn.getContext(), "还没到开始领取时间");
break;
case "查看":
AppController.put("libaoEntity", libaoEntity);
Intent intent = new Intent(libaoBtn.getContext(), LibaoDetailActivity.class);
intent.putExtra("entrance", entrance);
libaoBtn.getContext().startActivity(intent);
break;
case "领取":
libaoLing(libaoBtn, libaoEntity, adapter, isInstallRequired, libaoDao, null, entrance);
break;
case "淘号":
postLibaoTao(libaoBtn.getContext(), libaoEntity.getId(), true, new PostLibaoListener() {
@Override
public void postSucced(Object response) {
JSONObject responseBody = (JSONObject) response;
Utils.log("postLibaoTao=====" + responseBody);
String libaoCode = null;
try {
libaoCode = responseBody.getString("code");
} catch (JSONException e) {
e.printStackTrace();
CheckLoginUtils.checkLogin(context, new CheckLoginUtils.OnLoggenInListener() {
@Override
public void onLoggedIn() {
// 领取限制
if ("领取".equals(libaoBtn.getText().toString()) || "淘号".equals(libaoBtn.getText().toString())) {
if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) {
String platform;
if (TextUtils.isEmpty(libaoEntity.getPlatform())) {
platform = "";
} else {
platform = PlatformUtils.getInstance(context)
.getPlatformName(libaoEntity.getPlatform()) + "";
}
if (TextUtils.isEmpty(libaoCode)) {
try {
String detail = responseBody.getString("detail");
if ("maintaining".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "网络状态异常,请稍后再试");
} else if ("fail to compete".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "淘号失败,稍后重试");
} else {
Utils.toast(libaoBtn.getContext(), "淘号异常");
}
} catch (JSONException e) {
e.printStackTrace();
}
return;
}
Utils.toast(libaoBtn.getContext(), "淘号成功");
libaoEntity.setStatus("taoed");
LibaoInfo libaoInfo = LibaoInfo.createLibaoInfo(libaoEntity);
libaoInfo.setCode(libaoCode);
libaoInfo.setTime(Utils.getTime(libaoBtn.getContext()));
libaoDao.add(libaoInfo);
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoDao();
adapter.notifyDataSetChanged();
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(libaoBtn.getContext(), "淘号成功",Html.fromHtml("礼包码:"
+ "<font color=\"#ffb13c\">" + libaoCode + "</font>" +
"<br/>淘号礼包不保证可用,请尽快进入游戏尝试兑换")
, "关闭", " 复制礼包码"
, new DialogUtils.ConfiremListener() {
String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform);
DialogUtils.showWarningDialog(context, "条件不符",
Html.fromHtml(dialogContent), "关闭", "立即安装"
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirem() {
copyLink(finalLibaoCode, libaoBtn.getContext());
if (isInstallRequired) {
libaoBtn.postDelayed(new Runnable() {
@Override
public void run() {
lunningAppDialog(libaoBtn.getContext()
, Html.fromHtml("礼包码:"
+ "<font color=\"#ffb13c\">" + finalLibaoCode + "</font>"
+ " 复制成功"
+"<br/>淘号礼包不保证可用,请尽快进入游戏尝试兑换"), libaoEntity);
}
}, 300);
}
public void onConfirm() {
adapter.openDownload();
}
}, null);
return;
}
}
@Override
public void postFailed(Throwable error) {
Utils.log("---" + error.toString());
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
if (exception.code() == 403) {
try {
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
String detail = errorJson.getString("detail");
Utils.toast(libaoBtn.getContext(), "返回::" + detail);
if ("coming".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "礼包领取时间未开始");
} else if ("finish".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "礼包领取时间已结束");
} else if ("fetched".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "你已领过这个礼包了");
getCunHaoXiang(libaoBtn.getContext(), true);
libaoBtn.setText("复制");
libaoBtn.setBackgroundResource(R.drawable.textview_blue_style);
} else if ("try tao".equals(detail) || "used up".equals(detail)) {
DialogUtils.showHintDialog(libaoBtn.getContext(), "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
} else if ("maintaining".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "网络状态异常,请稍后再试");
} else if ("fail to compete".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "淘号失败,稍后重试");
} else {
Utils.toast(libaoBtn.getContext(), "操作失败");
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(libaoBtn.getContext(),"礼包处理异常"+ ex.toString());
}
return;
}
switch (libaoBtn.getText().toString()) {
case "未开始":
Utils.toast(context, "还没到开始领取时间");
break;
case "查看":
Intent intent = LibaoDetailActivity.getIntent(context, libaoEntity, entrance);
context.startActivity(intent);
break;
case "再领一个":
case "领取":
if ("repeatLing".equals(status)) {
DialogUtils.showWarningDialog(context, "礼包刷新提醒"
, "礼包每天0点刷新换新区或者换新角色需要继续领取礼包的童鞋请于明天0点之后回来即可[再领一个]"
, null, "知道了", null, null);
} else {
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
}
Utils.toast(libaoBtn.getContext(), "发生异常");
}
});
break;
}
break;
case "再淘一个":
case "淘号":
if ("repeatTao".equals(status)) {
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
return;
}
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
@Override
public void postSucced(Object response) {
if (loadingDialog != null) loadingDialog.dismiss();
JSONObject responseBody = (JSONObject) response;
Utils.log("postLibaoTao=====" + responseBody);
String libaoCode = null;
try {
libaoCode = responseBody.getString("code");
} catch (JSONException e) {
e.printStackTrace();
}
if (TextUtils.isEmpty(libaoCode)) {
try {
String detail = responseBody.getString("detail");
switch (detail) {
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "淘号异常");
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
return;
}
Utils.toast(context, "淘号成功");
libaoEntity.setStatus("taoed");
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(context, "淘号成功"
, Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode))
, "关闭", " 复制礼包码"
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(new Runnable() {
@Override
public void run() {
Spanned msg = Html.fromHtml(
context.getString(R.string.taoed_copy_dialog
, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}
}, 300);
}
}
}, null);
}
@Override
public void postFailed(Throwable error) {
Utils.log("---" + error.toString());
if (loadingDialog != null) loadingDialog.dismiss();
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
if (exception.code() == 403) {
try {
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
String detail = errorJson.getString("detail");
// Utils.toast(context, "返回::" + detail);
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
break;
case "finish":
Utils.toast(context, "礼包领取时间已结束");
break;
case "fetched":
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
libaoBtn.setText("已淘号");
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
libaoEntity.setStatus("taoed");
break;
case "try tao":
case "used up":
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "操作失败");
break;
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(context, "礼包处理异常" + ex.toString());
}
return;
}
}
Utils.toast(context, "发生异常");
}
});
break;
}
}
});
}
});
}
private static void libaoLing(final TextView libaoBtn, final LibaoEntity libaoEntity, final LibaoDetailAdapter adapter,
final boolean isInstallRequired, final LibaoDao libaoDao, String captchaCode, final String entrance) {
private static void libaoLing(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity, final LibaoDetailAdapter adapter,
final boolean isInstallRequired, String captchaCode, final String entrance) {
postLibaoLing(libaoBtn.getContext(), libaoEntity.getId(), true, new PostLibaoListener() {
if (BuildConfig.DEBUG) {
Log.e("LIBAO", "context? " + context + libaoBtn.getContext());
}
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "领取中...");
postLibaoLing(context, libaoEntity.getId(), new PostLibaoListener() {
@Override
public void postSucced(Object response) {
if (loadingDialog != null) loadingDialog.dismiss();
JSONObject responseBody = (JSONObject) response;
Utils.log("postLibaoLing=====" + responseBody);
@ -447,40 +428,32 @@ public class LibaoUtils {
}
if (TextUtils.isEmpty(libaoCode)) {
Utils.toast(libaoBtn.getContext(), "领取异常");
Utils.toast(context, "领取异常");
return;
}
libaoEntity.setAvailable(libaoEntity.getAvailable() - 1);
libaoEntity.setStatus("linged");
LibaoInfo libaoInfo = LibaoInfo.createLibaoInfo(libaoEntity);
libaoInfo.setTime(Utils.getTime(libaoBtn.getContext()));
libaoInfo.setCode(libaoCode);
libaoDao.add(libaoInfo);
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoDao();
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "ling", Utils.getTime(context)));
adapter.notifyDataSetChanged();
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(libaoBtn.getContext(), "领取成功", Html.fromHtml("礼包码:"
+ "<font color=\"#00B7FA\">" + libaoCode + "</font>" +
"<br/>请尽快使用礼包码将于60分钟后进入淘号池")
DialogUtils.showWarningDialog(context, "领取成功", Html.fromHtml(context.getString(R.string.linged_dialog, libaoCode))
, "关闭", " 复制礼包码"
, new DialogUtils.ConfiremListener() {
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirem() {
copyLink(finalLibaoCode, libaoBtn.getContext());
public void onConfirm() {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(new Runnable() {
@Override
public void run() {
lunningAppDialog(libaoBtn.getContext()
, Html.fromHtml("礼包码:"
+ "<font color=\"#00B7FA\">" + finalLibaoCode + "</font>"
+ " 复制成功" +"<br/>请尽快进入游戏兑换"), libaoEntity);
Spanned msg = Html.fromHtml(context.getString(R.string.linged_copy_dialog, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}
}, 300);
}
@ -490,7 +463,7 @@ public class LibaoUtils {
@Override
public void postFailed(Throwable error) {
Utils.log("-----" + error.toString());
if (loadingDialog != null) loadingDialog.dismiss();
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
@ -499,46 +472,61 @@ public class LibaoUtils {
String string = exception.response().errorBody().string();
JSONObject errorJson = new JSONObject(string);
String detail = errorJson.getString("detail");
Utils.log("=======detail ::" + errorJson.toString());
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
break;
case "finish":
Utils.toast(context, "礼包领取时间已结束");
break;
case "fetched":
Utils.toast(context, "你已领过这个礼包了");
int countdown = 0;
if (errorJson.toString().contains("countdown")) {
countdown = errorJson.getInt("countdown");
}
if (countdown > 0 && countdown < 60 * 10) {
EventBus.getDefault().post(new EBUISwitch(REFRESH_LIBAO_TIME, countdown));
}
if ("coming".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "礼包领取时间未开始");
} else if ("finish".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "礼包领取时间已结束");
} else if ("fetched".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "你已领过这个礼包了");
getCunHaoXiang(libaoBtn.getContext(), true);
libaoBtn.setText("复制");// TODO
libaoBtn.setBackgroundResource(R.drawable.textview_blue_style);
libaoBtn.setText(R.string.libao_linged);
libaoBtn.setBackgroundResource(R.drawable.libao_linged_style);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_linged_selector));
} else if ("try tao".equals(detail) || "used up".equals(detail)) {
DialogUtils.showHintDialog(libaoBtn.getContext(), "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
libaoEntity.setStatus("used_up");
initLibaoBtn(libaoBtn, libaoEntity, libaoDao, isInstallRequired, adapter, entrance);
} else if ("maintaining".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "网络状态异常,请稍后再试");
} else {
Utils.toast(libaoBtn.getContext(), "操作失败");
libaoEntity.setStatus("linged");
break;
case "try tao":
case "used up":
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
libaoEntity.setStatus("used_up");
initLibaoBtn(context, libaoBtn, libaoEntity, isInstallRequired, adapter, entrance);
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
default:
Utils.toast(context, "操作失败");
break;
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(libaoBtn.getContext(),"礼包处理异常");
Utils.toast(context, "礼包处理异常");
}
return;
} else if (exception.code() == 412) {
// 需要验证
GeetestUtils.getInstance(libaoBtn.getContext())
.showDialog(new GeetestUtils.GeetestListener() {
@Override
public void succed(String response) {
libaoLing(libaoBtn, libaoEntity, adapter, isInstallRequired, libaoDao, response, entrance);
}
});
GeetestUtils.getInstance().showDialog(context, new GeetestListener() {
@Override
public void onVerified(String captcha) {
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, captcha, entrance);
}
});
return;
}
}
Utils.toast(libaoBtn.getContext(), "发生异常");
Utils.toast(context, "发生异常");
}
}, captchaCode);
}
@ -557,16 +545,16 @@ public class LibaoUtils {
return false;
}
public static void lunningAppDialog (final Context context, Spanned msg, final LibaoEntity libaoEntity) {
public static void lunningAppDialog(final Context context, Spanned msg, final LibaoEntity libaoEntity) {
DialogUtils.showWarningDialog(context, "复制成功", msg
, "关闭", "启动游戏"
, new DialogUtils.ConfiremListener() {
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirem() {
public void onConfirm() {
if (LibaoUtils.isAppInstalled(context, libaoEntity.getPackageName())) {
PackageUtils.launchApplicationByPackageName(context, libaoEntity.getPackageName());
} else {
Utils.toast(context, "请安装游戏:" + libaoEntity.getGame().getName()
Utils.toast(context, "请安装游戏:" + libaoEntity.getGame().getName()
+ PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform()) + "");
}
@ -574,12 +562,71 @@ public class LibaoUtils {
}, null);
}
//复制文字
public static void copyLink(String copyContent, Context context) {
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(copyContent);
Utils.toast(context,copyContent + " 复制成功");
Utils.toast(context, copyContent + " 复制成功");
}
// 合并List<LibaoStatusEntity> 和 List<LibaoEntity>
public static void initLiBaoEntity(List<LibaoStatusEntity> statusList,
List<LibaoEntity> libaoEntities) {
for (LibaoEntity libaoEntity : libaoEntities) {
for (LibaoStatusEntity libaoStatusEntity : statusList) {
if (libaoEntity.getId().equals(libaoStatusEntity.getId())) {
libaoEntity.setBeforeStatus(libaoStatusEntity.getStatus());
libaoStatusEntity.setBeforeStatus(libaoStatusEntity.getStatus());
UserDataEntity userData = libaoEntity.getUserData();
if (userData != null && userData.getUserDataLibaoList() != null && userData.getUserDataLibaoList().size() > 0) {
List<UserDataLibaoEntity> userDataLibaoList = userData.getUserDataLibaoList();
UserDataLibaoEntity userDataLibaoEntity = userDataLibaoList.get(userDataLibaoList.size() - 1);
if ("ling".equals(userDataLibaoEntity.getType())) { // 拿最后一次领取的状态判断
libaoEntity.setStatus("linged");
} else {
libaoEntity.setStatus("taoed");
}
} else {
libaoEntity.setStatus(libaoStatusEntity.getStatus());
}
libaoEntity.setAvailable(libaoStatusEntity.getAvailable());
libaoEntity.setTotal(libaoStatusEntity.getTotal());
}
}
}
}
public static void initLiBaoEntity(LibaoStatusEntity libaoStatusEntity,
LibaoEntity libaoEntity) {
if (libaoEntity.getId().equals(libaoStatusEntity.getId())) {
libaoEntity.setBeforeStatus(libaoStatusEntity.getStatus());
libaoStatusEntity.setBeforeStatus(libaoStatusEntity.getStatus());
UserDataEntity userData = libaoEntity.getUserData();
if (userData != null && userData.getUserDataLibaoList() != null && userData.getUserDataLibaoList().size() > 0) {
List<UserDataLibaoEntity> userDataLibaoList = userData.getUserDataLibaoList();
UserDataLibaoEntity userDataLibaoEntity = userDataLibaoList.get(userDataLibaoList.size() - 1);
if ("ling".equals(userDataLibaoEntity.getType())) { // 拿最后一次领取的状态判断
libaoEntity.setStatus("linged");
} else {
libaoEntity.setStatus("taoed");
}
} else {
libaoEntity.setStatus(libaoStatusEntity.getStatus());
}
libaoEntity.setAvailable(libaoStatusEntity.getAvailable());
libaoEntity.setTotal(libaoStatusEntity.getTotal());
}
}
public interface PostLibaoListener {
void postSucced(Object response);
void postFailed(Throwable error);
}
}

View File

@ -0,0 +1,676 @@
package com.gh.common.util;
import android.app.Dialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.LoginResponseEntity;
import com.gh.gamecenter.entity.UserInfoEntity;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.manager.RefreshTokenManager;
import com.gh.gamecenter.personal.PersonalFragment;
import com.gh.gamecenter.retrofit.JSONObjectResponse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.HttpException;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Created by khy on 7/07/17.
*/
public class LoginUtils {
public enum LoginTag {
qq, wechat, weibo, phone, refresh, oldUserPhone
}
public static void checkPhoneNum(final Context context, final String phoneName, final onCaptchaCallBackListener listener) { // 老用户登录检查手机是否登录过
RetrofitManager.getInstance(context).getApi()
.checkPhoneNum(phoneName)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(ResponseBody response) {
super.onResponse(response);
try {
JSONObject content = new JSONObject(response.string());
String status = content.getString("status");
if ("ok".equals(status)) {
getPhoneCaptcha(context, phoneName, listener);
} else {
DialogUtils.showWarningDialog(context, null, "手机号已存在,请使用未登录过的手机号,以保证数据正常同步到新账号上"
, null, "我知道了", null, null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onFailure(HttpException e) {
super.onFailure(e);
if (e == null) {
Utils.toast(context, "请检查网络是否可用");
return;
}
try {
ResponseBody responseBody = e.response().errorBody();
String string = responseBody.string();
JSONObject content = new JSONObject(string);
int code = content.getInt("code");
outputErrorHint(context, code);
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
}
// 获取验证码
public static void getPhoneCaptcha(final Context context, String phoneNum, final onCaptchaCallBackListener listener) {
JSONObject content = new JSONObject();
try {
content.put("mobile", phoneNum);
content.put("device", DeviceUtils.getLoginDevice(context.getApplicationContext()));
} catch (JSONException e) {
e.printStackTrace();
}
RequestBody body = RequestBody.create(MediaType.parse("application/json"), content.toString());
RetrofitManager.getInstance(context)
.getUsersea()
.loginByCaptcha(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new JSONObjectResponse() {
@Override
public void onResponse(JSONObject response) {
super.onResponse(response);
try {
listener.onCaptcha(response.getString("service_id"));
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(HttpException e) {
super.onFailure(e);
if (e == null) {
Utils.toast(context, "无法获取验证码,请检查你的网络状态");
return;
}
try {
ResponseBody responseBody = e.response().errorBody();
String string = responseBody.string();
JSONObject content = new JSONObject(string);
int code = content.getInt("code");
outputErrorHint(context, code);
} catch (Exception e1) {
e1.printStackTrace();
Utils.toast(context, "无法获取验证码,请检查你的网络状态");
}
}
});
}
// 登录前做好body判断
public static void login(final Context context, final JSONObject content, final LoginTag loginTag,
final onLoginCallBackListener listener) {
Observable<LoginResponseEntity> observable = null;
String userToken = null;
try {
JSONObject device = DeviceUtils.getLoginDevice(context.getApplicationContext());
content.put("device", device);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), content.toString());
if (loginTag == LoginTag.weibo) {
userToken = content.getString("uid");
observable = RetrofitManager.getInstance(context).getUsersea().loginByWeibo(body);
} else if (loginTag == LoginTag.qq) {
userToken = content.getString("openid");
observable = RetrofitManager.getInstance(context).getUsersea().loginByQQ(body);
} else if (loginTag == LoginTag.wechat) {
userToken = content.getString("openid");
observable = RetrofitManager.getInstance(context).getUsersea().loginByWechat(body);
} else if (loginTag == LoginTag.phone || loginTag == LoginTag.oldUserPhone) {
userToken = content.getString("mobile");
observable = RetrofitManager.getInstance(context).getUsersea().loginByMobile(body);
} else {
return;
}
} catch (JSONException e) {
e.printStackTrace();
}
if (observable == null) return;
final String finalUserToken = userToken;
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<LoginResponseEntity>() {
@Override
public void onResponse(LoginResponseEntity response) {
super.onResponse(response);
if (loginTag.equals(LoginTag.phone) || loginTag.equals(LoginTag.oldUserPhone)) {
try {
response.setLoginType(content.getString("mobile"));
} catch (JSONException e) {
e.printStackTrace();
}
} else {
response.setLoginType(loginTag.name());
}
response.setUserToken(finalUserToken);
saveLoginToken(context, response);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
String syncDeviceID = sp.getString("syncDeviceID", null);
if (!TextUtils.isEmpty(syncDeviceID)) {
syncUserData(context, syncDeviceID, listener, loginTag);
sp.edit().putString("syncDeviceID", null).apply(); // 清空
} else {
getUserData(context, false, listener, loginTag);
}
}
@Override
public void onFailure(HttpException e) {
super.onFailure(e);
if (listener != null) {
listener.onLoginFailure();
}
try {
ResponseBody responseBody = e.response().errorBody();
String string = responseBody.string();
JSONObject content = new JSONObject(string);
int code = content.getInt("code");
if (loginTag.equals(LoginTag.phone)) {
outputErrorHint(context, code);
} else {
if (loginTag.equals(LoginTag.qq)) {
GetLoginDataUtils.getInstance(context).QQLogout();
}
Utils.toast(context, context.getString(R.string.login_failure_hint));
}
} catch (Exception e1) {
Utils.toast(context, context.getString(R.string.login_failure_hint));
e1.printStackTrace();
}
}
});
}
private static void syncUserData(final Context context, String syncDeviceID,
final onLoginCallBackListener listener,
final LoginTag loginTag) {
String loginType;
if (LoginTag.phone.equals(loginTag)) {
loginType = "mobile";
} else {
loginType = loginTag.toString();
}
HashMap<String, String> map = new HashMap<>();
map.put("device_id", syncDeviceID);
map.put("login_type", loginType);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), new JSONObject(map).toString());
RetrofitManager.getInstance(context).getApi().syncUserData(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(userInfoResponse(context, loginTag, listener));
}
// 注销登录
public static void logout(final Context context, final OnLogoutListener listener) {
RetrofitManager.getInstance(context)
.getUsersea()
.logout()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(ResponseBody response) {
super.onResponse(response);
listener.onCompleted();
}
@Override
public void onFailure(HttpException e) {
super.onFailure(e);
listener.onCompleted();
}
});
}
// 清除本地用户相关信息
public static void cleanUserData(Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = sp.edit();
edit.putString("user_info", null);
edit.putString("login_token", null);
edit.apply();
GetLoginDataUtils.getInstance(context).QQLogout();
EventBus.getDefault().post(new EBReuse(PersonalFragment.LOGOUT_TAG));
}
// 检查本地是否有缓存token,有则马上登录
public static void checkLogin(Context context, onLoginCallBackListener listener) {
LoginResponseEntity loginToken = getLoginToken(context);
if (loginToken != null && loginToken.getAccessToken() != null) {
LoginResponseEntity.AccessToken accessToken = loginToken.getAccessToken();
Long accessExpire = accessToken.getExpire();
if (accessExpire != null && accessExpire > Utils.getTime(context)) {
getUserData(context, false, listener, null);
} else {
LoginResponseEntity.RefreshToken refreshToken = loginToken.getRefreshToken();
Long refreshExpire = refreshToken.getExpire();
if (refreshExpire != null && refreshExpire > Utils.getTime(context)) {
Map<String, String> params = new HashMap<>();
params.put("refresh_token", refreshToken.getValue());
RefreshTokenManager.getInstance().refreshToken(context, false, new JSONObject(params), listener);
} else {
// 重新登录
cleanUserData(context);
}
}
}
}
private static Response<UserInfoEntity> userInfoResponse(final Context context,
final LoginTag loginTag,
final onLoginCallBackListener listener) {
return new Response<UserInfoEntity>() {
@Override
public void onResponse(UserInfoEntity response) {
super.onResponse(response);
saveUserInfo(context, response);
if (listener != null) {
listener.onLogin(response, loginTag);
}
if (loginTag != null && !LoginTag.refresh.equals(loginTag)) {
Utils.toast(context, "登录成功");
}
}
@Override
public void onFailure(HttpException e) {
super.onFailure(e);
if (listener != null) {
listener.onLoginFailure();
}
if (loginTag != null) {
Utils.toast(context, context.getString(R.string.login_failure_hint));
}
if (loginTag != null && loginTag.equals(LoginTag.qq)) {
GetLoginDataUtils.getInstance(context).QQLogout();
}
}
};
}
// 获取用户信息
public static void getUserData(final Context context, boolean isRunMainThread, final onLoginCallBackListener listener, final LoginTag loginTag) {
Observable<UserInfoEntity> observable;
if (isRunMainThread) {
observable = RetrofitManager.getInstance(context)
.getApi()
.getUserInfo();
} else {
observable = RetrofitManager.getInstance(context)
.getApi()
.getUserInfo()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
observable.subscribe(userInfoResponse(context, loginTag, listener));
}
// 获取本地缓存用户信息
public static UserInfoEntity getUserInfo(Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
String loginData = sp.getString("user_info", null);
if (!TextUtils.isEmpty(loginData)) {
Type listType = new TypeToken<UserInfoEntity>() {
}.getType();
return new Gson().fromJson(loginData, listType);
}
return null;
}
// 在本地缓存用户信息
public static void saveUserInfo(Context context, UserInfoEntity entity) {
if (entity != null) {
String region = entity.getRegion();
if (region != null && region.contains("中国")) { // 转换地区格式
String replace = region.replace("中国 ", "");
entity.setRegion(replace);
}
String s = new Gson().toJson(entity);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = sp.edit();
edit.putString("user_info", s);
edit.apply();
}
}
//获取本地缓存用户token
public static LoginResponseEntity getLoginToken(Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
String loginData = sp.getString("login_token", null);
if (!TextUtils.isEmpty(loginData)) {
Type listType = new TypeToken<LoginResponseEntity>() {
}.getType();
return new Gson().fromJson(loginData, listType);
}
return null;
}
//获取本地缓存用户token
public static String getToken(Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
String loginData = sp.getString("login_token", null);
if (!TextUtils.isEmpty(loginData)) {
Type listType = new TypeToken<LoginResponseEntity>() {
}.getType();
LoginResponseEntity entity = new Gson().fromJson(loginData, listType);
if (entity != null && entity.getAccessToken() != null) {
return entity.getAccessToken().getValue();
}
}
return null;
}
// 在本地缓存用户token
public static void saveLoginToken(Context context, LoginResponseEntity entity) {
if (entity != null) {
if (TextUtils.isEmpty(entity.getLoginType())) {
LoginResponseEntity loginToken = getLoginToken(context);
if (loginToken != null) {
entity.setLoginType(loginToken.getLoginType());
}
}
String s = new Gson().toJson(entity);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = sp.edit();
edit.putString("login_token", s);
edit.apply();
}
}
//更改用户信息
public static void changeUserInfo(final onChangeUserInfoListener listener, final Context context,
final String content, final String editType) {
final UserInfoEntity entity = getUserInfo(context);
if (entity == null) {
return;
}
Map<String, String> map = new HashMap<>();
map.put(editType, content);
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "正在修改信息...");
RequestBody body = RequestBody.create(MediaType.parse("application/json"),
new JSONObject(map).toString());
RetrofitManager.getInstance(context)
.getUsersea()
.changeUserInfo(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(ResponseBody response) {
super.onResponse(response);
if (loadingDialog != null) {
loadingDialog.dismiss();
}
switch (editType) {
case "name":
entity.setName(content);
break;
case "contact":
entity.setContact(content);
break;
case "gender":
entity.setGender(content);
break;
case "region":
entity.setRegion(content);
break;
case "icon":
entity.setIcon(content);
break;
default:
return;
}
saveUserInfo(context, entity);
listener.onChange();
}
@Override
public void onFailure(HttpException e) {
super.onFailure(e);
if (loadingDialog != null) {
loadingDialog.dismiss();
}
Utils.toast(context, "修改失败");
if (e == null) {
Utils.toast(context, "请检查网络是否可用");
return;
}
try {
ResponseBody responseBody = e.response().errorBody();
String string = responseBody.string();
JSONObject content = new JSONObject(string);
int code = content.getInt("code");
outputErrorHint(context, code);
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
}
private static void outputErrorHint(Context context, int code) {
switch (code) {
case 40000:
Utils.toast(context, "参数不全");
break;
case 40001:
Utils.toast(context, "验证码获取过快,请稍后重试");// 已经发送过短信
break;
case 40002:
Utils.toast(context, "请求第三方开放平台时发生错误");
break;
case 40003:
Utils.toast(context, "上传用户头像时发生错误");
break;
case 40101:
Utils.toast(context, "缺少参数 app_id");
break;
case 40102:
Utils.toast(context, "缺少签名验证的头信息");
break;
case 40104:
Utils.toast(context, "缺少token");
break;
case 40105:
Utils.toast(context, "缺少手机号码");
break;
case 40106:
Utils.toast(context, "缺少用户名");
break;
case 40107:
Utils.toast(context, "缺少密码参数");
break;
case 40202:
Utils.toast(context, "无效的手机号码");
break;
case 40203:
Utils.toast(context, "无效的用户名");
break;
case 40204:
Utils.toast(context, "无效的头像地址");
break;
case 40205:
Utils.toast(context, "无效的性别参数");
break;
case 40206:
Utils.toast(context, "无效的地区参数");
break;
case 40208:
Utils.toast(context, "无效的密码");
break;
case 40209:
Utils.toast(context, "无效的URL 地址");
break;
case 42000:
Utils.toast(context, "无效的app_id");
break;
case 42001:
Utils.toast(context, "无效的app_secret");
break;
case 42002:
Utils.toast(context, "无效的Union_id");
break;
case 42003:
Utils.toast(context, "无效的设备信息");
break;
case 42004:
Utils.toast(context, "无效的请求");
break;
case 40301:
Utils.toast(context, "签名验证失败");
break;
case 40302:
Utils.toast(context, "验证码错误");
break;
case 40303:
Utils.toast(context, "密码错误");
break;
case 40304:
Utils.toast(context, "不支持该种方式登录");
break;
case 40305:
Utils.toast(context, "错误的状态值(应用只有两种状态: working / stop)");
break;
case 40306:
Utils.toast(context, "传递了无法识别的参数");
break;
case 40401:
Utils.toast(context, "token过期");
break;
case 40402:
Utils.toast(context, "Service_id过期,主要原因是:收到手机短信验证码后长时间没有进行登录操作");
break;
case 40403:
Utils.toast(context, "验证码已过期");
break;
case 40501:
Utils.toast(context, "同名应用已经存在");
break;
case 40502:
Utils.toast(context, "用户名已存在");
break;
case 40503:
Utils.toast(context, "名称已经存在");
break;
case 40601:
Utils.toast(context, "应用不存在");
break;
case 40602:
Utils.toast(context, "用户不存在");
break;
case 40603:
Utils.toast(context, "用户系统不存在");
break;
case 40604:
Utils.toast(context, "用户已被冻结");
break;
case 40605:
Utils.toast(context, "用户没有冻结");
break;
case 40606:
Utils.toast(context, "该应用被停止运行了");
break;
case 40801:
Utils.toast(context, "访问过于频繁");
break;
case 403001:
Utils.toast(context, "设备异常,获取验证码失败,请更换登陆方式或明天再试");
break;
default:
Utils.toast(context, "未知错误");
break;
}
}
// 更改用户信息回调
public interface OnLogoutListener {
void onCompleted();
}
// 更改用户信息回调
public interface onChangeUserInfoListener {
void onChange();
}
// 获取验证码回调
public interface onCaptchaCallBackListener {
void onCaptcha(String serviceId);
}
// 登录回调
public interface onLoginCallBackListener {
void onLogin(UserInfoEntity entity, LoginTag loginTag);
void onLoginFailure();
}
}

View File

@ -6,73 +6,73 @@ import java.security.MessageDigest;
public class MD5Utils {
public static String getUpdateMD5(String url, String content) {
if (url == null && content == null) {
return null;
}
MessageDigest digest = null;
ByteArrayInputStream bais = null;
byte buffer[] = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance("MD5");
bais = new ByteArrayInputStream((url + content).getBytes());
while ((len = bais.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
bais.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
BigInteger bigInt = new BigInteger(1, digest.digest());
return bigInt.toString(16);
}
public static String getUpdateMD5(String url, String content) {
if (url == null && content == null) {
return null;
}
MessageDigest digest;
ByteArrayInputStream bais;
byte buffer[] = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance("MD5");
bais = new ByteArrayInputStream((url + content).getBytes());
while ((len = bais.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
bais.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
BigInteger bigInt = new BigInteger(1, digest.digest());
return bigInt.toString(16);
}
public static String getUrlMD5(String url) {
if (url == null) {
return null;
}
MessageDigest digest = null;
ByteArrayInputStream bais = null;
byte buffer[] = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance("MD5");
bais = new ByteArrayInputStream(url.getBytes());
while ((len = bais.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
bais.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
BigInteger bigInt = new BigInteger(1, digest.digest());
return bigInt.toString(16);
}
public static String getUrlMD5(String url) {
if (url == null) {
return null;
}
MessageDigest digest;
ByteArrayInputStream bais;
byte buffer[] = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance("MD5");
bais = new ByteArrayInputStream(url.getBytes());
while ((len = bais.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
bais.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
BigInteger bigInt = new BigInteger(1, digest.digest());
return bigInt.toString(16);
}
public static String getContentMD5(String content) {
if (content == null) {
return null;
}
MessageDigest digest = null;
ByteArrayInputStream bais = null;
byte buffer[] = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance("MD5");
bais = new ByteArrayInputStream(content.getBytes());
while ((len = bais.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
bais.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
BigInteger bigInt = new BigInteger(1, digest.digest());
return bigInt.toString(16);
}
public static String getContentMD5(String content) {
if (content == null) {
return null;
}
MessageDigest digest;
ByteArrayInputStream bais;
byte buffer[] = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance("MD5");
bais = new ByteArrayInputStream(content.getBytes());
while ((len = bais.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
bais.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
BigInteger bigInt = new BigInteger(1, digest.digest());
return bigInt.toString(16);
}
}

View File

@ -1,63 +0,0 @@
package com.gh.common.util;
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by khy on 2016/8/22.
* RecyclerView 自适应高度
*/
public class MeasureHeightLayoutManager extends LinearLayoutManager {
public MeasureHeightLayoutManager(Context context) {
super(context);
}
private int[] mMeasuredDimension = new int[1];
@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int height = 0;
for (int i = 0; i < getItemCount(); i++) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
height = height + mMeasuredDimension[0];
}
if (height > heightSize){
super.onMeasure(recycler, state, widthSpec, heightSpec);
}else {
setMeasuredDimension(View.MeasureSpec.getSize(widthSpec), height);
}
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
if (view.getVisibility() == View.GONE) {
measuredDimension[0] = 0;
return;
}
super.measureChildWithMargins(view, 0, 0);
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childHeightSpec = ViewGroup.getChildMeasureSpec(
heightSpec,
getPaddingTop() + getPaddingBottom() + getDecoratedTop(view) + getDecoratedBottom(view),
p.height);
view.measure(0, childHeightSpec);
measuredDimension[0] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}

View File

@ -1,7 +1,6 @@
package com.gh.common.util;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
@ -12,11 +11,11 @@ import android.graphics.Matrix;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.KeyEvent;
import android.support.v4.content.*;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@ -25,7 +24,9 @@ import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.gamecenter.R;
import com.lightgame.utils.Utils;
import com.tencent.connect.share.QQShare;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.SendMessageToWX;
@ -50,28 +51,48 @@ import java.util.List;
*/
public class MessageShareUtils {
private static MessageShareUtils instance;
private IWXAPI mIWXAPI;
private Tencent mTencent;
private Bitmap shareBm; //分享截图
private String picName;
private boolean isPlugin = false;
private int[] arrLogo = {
R.drawable.share_wechat_logo,
R.drawable.share_wechatmoments_logo,
R.drawable.share_qq_logo,
R.drawable.share_qzone_logo,
R.drawable.share_save
};
private static IWXAPI api;
private static Tencent mTencent;
private String[] mArrLabel = {"微信好友", "朋友圈", "QQ好友", "QQ空间", "保存"};
private Handler handler;
private PopupWindow mPopupWindow;
private int[] arrLogo = {R.drawable.share_wechat_logo, R.drawable.share_wechatmoments_logo, R.drawable.share_qq_logo
, R.drawable.share_qzone_logo, R.drawable.share_save};
private String[] arrLabel = {"微信好友", "朋友圈", "QQ好友", "QQ空间", "保存"};
private Context mContext;
private PopupWindow popupWindow;
//TODO 干掉activity将context变成applicationcontext
// private Activity activity; // 用来关闭分享页面
//QQ或者QQ空间分享回调处理
public IUiListener QqShareListener = new IUiListener() {
@Override
public void onComplete(Object o) {
// activity.finish();
// activity.overridePendingTransition(0, 0);//禁止退出Activity 动画
Utils.toast(mContext, "分享成功");
}
private Context context;
private Activity activity; // 用来关闭分享页面
@Override
public void onError(UiError uiError) {
Utils.toast(mContext, "分享失败");
}
@Override
public void onCancel() {
// activity.finish();
// activity.overridePendingTransition(0, 0);//禁止退出Activity 动画
Utils.toast(mContext, "分享已取消");
}
};
// 适配快传成绩单分享
private int contentSize;
private int paddTop;
@ -81,21 +102,48 @@ public class MessageShareUtils {
private int marImg;
private int shareType;
private MessageShareUtils(Context context) {
mTencent = Tencent.createInstance(Config.TENCENT_APPID, context); //初始化QQ分享
mIWXAPI = WXAPIFactory.createWXAPI(context, Config.WECHAT_APPID); //初始化微信分享
//TODO changed to application context
mContext = context;
}
public static MessageShareUtils getInstance(Context context) {
if (instance == null) {
instance = new MessageShareUtils();
mTencent = Tencent.createInstance("1104659243", context); //初始化QQ分享
api = WXAPIFactory.createWXAPI(context, "wx3ffd0785fad18396"); //初始化微信分享
instance = new MessageShareUtils(context);
}
instance.context = context;
return instance;
}
public void showShareWindows(View view, Bitmap bitmap, String picName, int shareType){
//检查是否安装手机QQ
public static boolean isQQClientAvailable(Context context) {
final PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
if ("com.tencent.mobileqq".equals(pn)) {
return true;
}
}
}
return false;
}
public IWXAPI getIWXAPI() {
return mIWXAPI;
}
public Tencent getTencent() {
return mTencent;
}
public void showShareWindows(View view, Bitmap bitmap, String picName, int shareType) {
this.shareBm = bitmap;
this.picName = picName;
this.shareType = shareType;
this.activity= (Activity) context;
// this.activity = (Activity) mContext;
if (shareType == 2) {
contentSize = 75;
@ -114,17 +162,18 @@ public class MessageShareUtils {
}
RelativeLayout contentView = new RelativeLayout(context);
RelativeLayout contentView = new RelativeLayout(mContext);
contentView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
contentView.setBackgroundColor(0x8c000000);
contentView.setFocusable(true);
contentView.setFocusableInTouchMode(true);
RecyclerView shareRecyclerView = new RecyclerView(context);
shareRecyclerView.setPadding(DisplayUtils.dip2px(context, 10), DisplayUtils.dip2px(context, paddTop), DisplayUtils.dip2px(context, 10), 0);
RecyclerView shareRecyclerView = new RecyclerView(mContext);
shareRecyclerView.setPadding(DisplayUtils.dip2px(mContext, 10), DisplayUtils.dip2px(mContext, paddTop), DisplayUtils.dip2px(mContext, 10), 0);
shareRecyclerView.setBackgroundColor(Color.WHITE);
//RecyclerView禁止滑动
GridLayoutManager gridLayoutManager = new GridLayoutManager(context, gridCount){
GridLayoutManager gridLayoutManager = new GridLayoutManager(mContext, gridCount) {
@Override
public boolean canScrollVertically() {
return false;
@ -137,25 +186,26 @@ public class MessageShareUtils {
if (shareType == 0 || shareType == 2) {
LinearLayout llBottom = (LinearLayout) view;
ViewGroup.LayoutParams layoutParams = llBottom.getLayoutParams();
layoutParams.height = DisplayUtils.dip2px(context, contentSize);
layoutParams.height = DisplayUtils.dip2px(mContext, contentSize);
shareRecyclerView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
llBottom.addView(shareRecyclerView);
return;
}
RelativeLayout.LayoutParams rlParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT
, DisplayUtils.dip2px(context, 106));
, DisplayUtils.dip2px(mContext, 106));
rlParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
contentView.addView(shareRecyclerView,rlParams);
contentView.addView(shareRecyclerView, rlParams);
popupWindow = new PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT
mPopupWindow = new PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT
, LinearLayout.LayoutParams.MATCH_PARENT, true);
popupWindow.setAnimationStyle(R.style.mypopwindow_anim_style);
popupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0);
mPopupWindow.setAnimationStyle(R.style.mypopwindow_anim_style);
mPopupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0);
contentView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
popupWindow.dismiss();
mPopupWindow.dismiss();
}
});
@ -164,142 +214,54 @@ public class MessageShareUtils {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0 && popupWindow != null
&& popupWindow.isShowing()) {
popupWindow.dismiss();
&& event.getRepeatCount() == 0 && mPopupWindow != null
&& mPopupWindow.isShowing()) {
mPopupWindow.dismiss();
}
return false;
}
});
}
public class ShareRecyclerViewAdapter extends RecyclerView.Adapter<ShareRecyclerViewAdapter.ViewHolder>{
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LinearLayout linearLayout = new LinearLayout(context);
linearLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, DisplayUtils.dip2px(context, itemSize)));
linearLayout.setOrientation(LinearLayout.VERTICAL);
linearLayout.setGravity(Gravity.CENTER_HORIZONTAL);
linearLayout.setBackgroundResource(R.drawable.cardview_item_style);
ImageView shareLogo = new ImageView(context);
LinearLayout.LayoutParams logoParams = new LinearLayout.LayoutParams(DisplayUtils.dip2px(context, picSize), DisplayUtils.dip2px(context, picSize));
logoParams.setMargins(0, DisplayUtils.dip2px(context, 10), 0, 0);
shareLogo.setLayoutParams(logoParams);
TextView shareLabel = new TextView(context);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(0, DisplayUtils.dip2px(context,10), 0, 0);
shareLabel.setLayoutParams(layoutParams);
shareLabel.setGravity(Gravity.CENTER);
shareLabel.setTextColor(Color.parseColor("#3a3a3a"));
shareLabel.setTextSize(marImg);
linearLayout.addView(shareLogo);
linearLayout.addView(shareLabel);
return new ViewHolder(linearLayout);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.shareLogo.setImageResource(arrLogo[position]);
holder.shareLabel.setText(arrLabel[position]);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (holder.getPosition()){
case 0:
wechatSahre();
if (shareType != 2) {
activity.finish();
}
break;
case 1:
wechatMomentsSahre();
if (shareType != 2) {
activity.finish();
}
break;
case 2:
qqSahre();
break;
case 3:
qZoneSahre();
break;
case 4:
String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/ghzhushou/";
writeBitmap(savePath, "gh-" + new Date().getTime() + ".jpg", shareBm, true);
if (popupWindow == null) return;
popupWindow.dismiss();
activity.finish();
break;
}
}
});
}
@Override
public int getItemCount() {
return gridCount;
}
public class ViewHolder extends RecyclerView.ViewHolder{
LinearLayout linearLayout;
TextView shareLabel;
ImageView shareLogo;
public ViewHolder(View itemView) {
super(itemView);
linearLayout = (LinearLayout) itemView;
shareLogo = (ImageView) linearLayout.getChildAt(0);
shareLabel = (TextView) linearLayout.getChildAt(1);
}
}
}
//QQ分享
private void qqSahre(){
Utils.toast(context,"分享跳转中...");
private void qqSahre() {
Utils.toast(mContext, "分享跳转中...");
Bundle params = new Bundle();
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE,
QQShare.SHARE_TO_QQ_TYPE_IMAGE);
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, context.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, "光环助手");
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT,
QQShare.SHARE_TO_QQ_FLAG_QZONE_ITEM_HIDE);
mTencent.shareToQQ(
(Activity) context, params,QqShareListener);
if (popupWindow == null) return;
popupWindow.dismiss();
(Activity) mContext, params, QqShareListener);
if (mPopupWindow == null) return;
mPopupWindow.dismiss();
}
//QQ空间分享
private void qZoneSahre(){
Utils.toast(context,"分享跳转中...");
private void qZoneSahre() {
Utils.toast(mContext, "分享跳转中...");
Bundle params = new Bundle();
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE,
QQShare.SHARE_TO_QQ_TYPE_IMAGE);
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, context.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, "光环助手");
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT,
QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN);
mTencent.shareToQQ(
(Activity) context, params,QqShareListener);
if (popupWindow == null) return;
popupWindow.dismiss();
(Activity) mContext, params, QqShareListener);
if (mPopupWindow == null) return;
mPopupWindow.dismiss();
}
//微信好友分享
private void wechatSahre(){
Utils.toast(context,"分享跳转中...");
private void wechatSahre() {
Utils.toast(mContext, "分享跳转中...");
//官方分享
// WXImageObject imgObj = new WXImageObject();
// imgObj.setImagePath(context.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
// imgObj.setImagePath(mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
// WXMediaMessage msg = new WXMediaMessage();
// msg.mediaObject = imgObj;
//
@ -310,31 +272,26 @@ public class MessageShareUtils {
//
// Bitmap compressBp = compressBitmap(shareBm);
// msg.thumbData = Util.bmpToByteArray(compressBp, true);
// api.sendReq(req);
// mIWXAPI.sendReq(req);
//调用手机系统分享
try {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + context.getExternalCacheDir().getPath() + "/ShareImg/" + picName));
intent.setComponent(new ComponentName("com.tencent.mm", "com.tencent.mm.ui.tools.ShareImgUI"));
context.startActivity(intent);
mContext.startActivity(IntentUtils.getWechatShareIntent(mContext, picName));
} catch (Exception e) {
Utils.toast(context,"分享失败!请检查是否已安装微信");
Utils.toast(mContext, "分享失败!请检查是否已安装微信");
e.printStackTrace();
}
if (popupWindow == null) return;
popupWindow.dismiss();
if (mPopupWindow == null) return;
mPopupWindow.dismiss();
}
//微信朋友圈分享
private void wechatMomentsSahre(){
Utils.toast(context,"分享跳转中...");
private void wechatMomentsSahre() {
Utils.toast(mContext, "分享跳转中...");
WXImageObject imgObj = new WXImageObject();
imgObj.setImagePath(context.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
imgObj.setImagePath(mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;
@ -346,14 +303,12 @@ public class MessageShareUtils {
Bitmap compressBp = compressBitmap(shareBm);
msg.thumbData = Util.bmpToByteArray(compressBp, true);
api.sendReq(req);
mIWXAPI.sendReq(req);
if (popupWindow == null) return;
popupWindow.dismiss();
if (mPopupWindow == null) return;
mPopupWindow.dismiss();
}
private String buildTransaction(final String type) {
return (type == null) ? String.valueOf(System.currentTimeMillis()) : type + System.currentTimeMillis();
}
@ -372,7 +327,7 @@ public class MessageShareUtils {
result.compress(Bitmap.CompressFormat.JPEG, 85, bos);
while(bos.toByteArray().length > 10 * 1024){
while (bos.toByteArray().length > 10 * 1024) {
System.out.println(bos.toByteArray().length);
matrix.setScale(0.9f, 0.9f);
result = Bitmap.createBitmap(result, 0, 0, result.getWidth(), result.getHeight(), matrix, true);
@ -384,42 +339,6 @@ public class MessageShareUtils {
return result;
}
//QQ或者QQ空间分享回调处理
public IUiListener QqShareListener = new IUiListener() {
@Override
public void onComplete(Object o) {
activity.finish();
activity.overridePendingTransition(0, 0);//禁止退出Activity 动画
Utils.toast(context, "分享成功");
}
@Override
public void onError(UiError uiError) {
Utils.toast(context, "分享失败");
}
@Override
public void onCancel() {
activity.finish();
activity.overridePendingTransition(0, 0);//禁止退出Activity 动画
Utils.toast(context, "分享已取消");
}
};
//检查是否安装手机QQ
public static boolean isQQClientAvailable(Context context){
final PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName; if (pn.equals("com.tencent.mobileqq")) {
return true;
}
}
}
return false;
}
//写到存储卡中
public void writeBitmap(String path, String name, Bitmap bitmap, boolean isToast) {
File file = new File(path);
@ -427,7 +346,7 @@ public class MessageShareUtils {
file.mkdirs();
}
File _file = new File(path , name);
File _file = new File(path, name);
if (_file.exists()) {
_file.delete();
}
@ -445,9 +364,9 @@ public class MessageShareUtils {
bitmap.compress(Bitmap.CompressFormat.JPEG, 75, fos);
}
if (isToast) {
Utils.toast(context,"成功保存到相册");
Utils.toast(mContext, "成功保存到相册");
//刷新手机图片库
refreshImage(_file, context);
refreshImage(_file, mContext);
}
}
}
@ -473,4 +392,92 @@ public class MessageShareUtils {
Utils.log("保存分享图片路径:" + _file.getAbsolutePath());
}
class ShareRecyclerViewAdapter extends RecyclerView.Adapter<ShareRecyclerViewAdapter.ViewHolder> {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LinearLayout linearLayout = new LinearLayout(mContext);
linearLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(mContext, itemSize)));
linearLayout.setOrientation(LinearLayout.VERTICAL);
linearLayout.setGravity(Gravity.CENTER_HORIZONTAL);
linearLayout.setBackgroundResource(R.drawable.cardview_item_style);
ImageView shareLogo = new ImageView(mContext);
LinearLayout.LayoutParams logoParams = new LinearLayout.LayoutParams(DisplayUtils.dip2px(mContext, picSize), DisplayUtils.dip2px(mContext, picSize));
logoParams.setMargins(0, DisplayUtils.dip2px(mContext, 10), 0, 0);
shareLogo.setLayoutParams(logoParams);
TextView shareLabel = new TextView(mContext);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(0, DisplayUtils.dip2px(mContext, 10), 0, 0);
shareLabel.setLayoutParams(layoutParams);
shareLabel.setGravity(Gravity.CENTER);
shareLabel.setTextColor(ContextCompat.getColor(mContext, R.color.text_3a3a3a));
shareLabel.setTextSize(marImg);
linearLayout.addView(shareLogo);
linearLayout.addView(shareLabel);
return new ViewHolder(linearLayout);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.shareLogo.setImageResource(arrLogo[position]);
holder.shareLabel.setText(mArrLabel[position]);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (holder.getPosition()) {
case 0:
wechatSahre();
if (shareType != 2) {
// activity.finish();
}
break;
case 1:
wechatMomentsSahre();
if (shareType != 2) {
// activity.finish();
}
break;
case 2:
qqSahre();
break;
case 3:
qZoneSahre();
break;
case 4:
String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/ghzhushou/";
writeBitmap(savePath, "gh-" + new Date().getTime() + ".jpg", shareBm, true);
if (mPopupWindow == null) return;
mPopupWindow.dismiss();
// activity.finish();
break;
}
}
});
}
@Override
public int getItemCount() {
return gridCount;
}
public class ViewHolder extends RecyclerView.ViewHolder {
LinearLayout linearLayout;
TextView shareLabel;
ImageView shareLogo;
public ViewHolder(View itemView) {
super(itemView);
linearLayout = (LinearLayout) itemView;
shareLogo = (ImageView) linearLayout.getChildAt(0);
shareLabel = (TextView) linearLayout.getChildAt(1);
}
}
}
}

View File

@ -6,102 +6,103 @@ import android.net.NetworkInfo;
public class NetworkUtils {
/**
* 判断是否有网络连接
*
* @param context 上下文
* @return true 有网络连接 false 无网络连接
*/
public static boolean isNetworkConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager
.getActiveNetworkInfo();
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable();
}
}
return false;
}
/**
* 判断是否有网络连接
*
* @param context 上下文
* @return true 有网络连接 false 无网络连接
*/
public static boolean isNetworkConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager
.getActiveNetworkInfo();
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable();
}
}
return false;
}
/**
* 判断WIFI网络是否可用
*
* @param context 上下文
* @return true wifi可用 false wifi不可用
*/
public static boolean isWifiConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWiFiNetworkInfo = mConnectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (mWiFiNetworkInfo != null) {
return mWiFiNetworkInfo.isConnected();
}
}
return false;
}
/**
* 判断MOBILE网络是否可用
*
* @param context 上下文
* @return true mobile可用 false mobile不可用
*/
public static boolean isMobileConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mMobileNetworkInfo = mConnectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (mMobileNetworkInfo != null) {
return mMobileNetworkInfo.isAvailable();
}
}
return false;
}
/**
* 判断WIFI网络是否可用
*
* @param context 上下文
* @return true wifi可用 false wifi不可用
*/
public static boolean isWifiConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWiFiNetworkInfo = mConnectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (mWiFiNetworkInfo != null) {
return mWiFiNetworkInfo.isConnected();
}
}
return false;
}
/**
* 获取当前网络连接的类型信息
* @param context 上下文
* @return 当前网络连接的类型信息
*/
public static String getConnectedType(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager
.getActiveNetworkInfo();
if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
switch (mNetworkInfo.getType()) {
case ConnectivityManager.TYPE_BLUETOOTH:
return "BLUETOOTH";
case ConnectivityManager.TYPE_DUMMY:
return "DUMMY";
case ConnectivityManager.TYPE_ETHERNET:
return "ETHERNET";
case ConnectivityManager.TYPE_MOBILE:
return "MOBILE";
case ConnectivityManager.TYPE_MOBILE_DUN:
return "MOBILE_DUN";
case ConnectivityManager.TYPE_MOBILE_HIPRI:
return "MOBILE_HIPRI";
case ConnectivityManager.TYPE_MOBILE_MMS:
return "MOBILE_MMS";
case ConnectivityManager.TYPE_MOBILE_SUPL:
return "MOBILE_SUPL";
case ConnectivityManager.TYPE_WIFI:
return "WIFI";
case ConnectivityManager.TYPE_WIMAX:
return "WIMAX";
default:
break;
}
}
}
return "NONE";
}
/**
* 判断MOBILE网络是否可用
*
* @param context 上下文
* @return true mobile可用 false mobile不可用
*/
public static boolean isMobileConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mMobileNetworkInfo = mConnectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (mMobileNetworkInfo != null) {
return mMobileNetworkInfo.isAvailable();
}
}
return false;
}
/**
* 获取当前网络连接的类型信息
*
* @param context 上下文
* @return 当前网络连接的类型信息
*/
public static String getConnectedType(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager
.getActiveNetworkInfo();
if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
switch (mNetworkInfo.getType()) {
case ConnectivityManager.TYPE_BLUETOOTH:
return "BLUETOOTH";
case ConnectivityManager.TYPE_DUMMY:
return "DUMMY";
case ConnectivityManager.TYPE_ETHERNET:
return "ETHERNET";
case ConnectivityManager.TYPE_MOBILE:
return "MOBILE";
case ConnectivityManager.TYPE_MOBILE_DUN:
return "MOBILE_DUN";
case ConnectivityManager.TYPE_MOBILE_HIPRI:
return "MOBILE_HIPRI";
case ConnectivityManager.TYPE_MOBILE_MMS:
return "MOBILE_MMS";
case ConnectivityManager.TYPE_MOBILE_SUPL:
return "MOBILE_SUPL";
case ConnectivityManager.TYPE_WIFI:
return "WIFI";
case ConnectivityManager.TYPE_WIMAX:
return "WIMAX";
default:
break;
}
}
}
return "NONE";
}
}

View File

@ -1,14 +1,10 @@
package com.gh.common.util;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.text.TextUtils;
import android.widget.TextView;
import com.gh.gamecenter.NewsDetailActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.entity.NewsEntity;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
@ -25,135 +21,121 @@ import rx.schedulers.Schedulers;
public class NewsUtils {
/**
* 根据新闻类型获取标签背景资源
*/
public static int getDrawableIdByType(String type) {
if ("活动".equals(type) || "高阶".equals(type)) {
return R.drawable.textview_red_up;
} else if ("公告".equals(type) || "中期".equals(type)) {
return R.drawable.textview_orange_up;
} else if ("新游".equals(type)) {
return R.drawable.textview_green_up;
} else if ("热门".equals(type) || "置顶".equals(type)) {
return R.drawable.textview_all_red_up;
} else {
return R.drawable.textview_blue_up;
}
}
/**
* 启动新闻详情页面
*/
public static void startNewsDetailActivity(Context context, NewsEntity newsEntity, String entrance) {
if (!TextUtils.isEmpty(newsEntity.getLink())) {
Intent intent = new Intent(context, WebActivity.class);
intent.putExtra("url", newsEntity.getLink());
intent.putExtra("gameName", newsEntity.getGameName());
intent.putExtra("newsId", newsEntity.getId());
intent.putExtra("entrance", entrance + "+(消息详情[" + newsEntity.getGameName() + "])");
context.startActivity(intent);
} else {
Intent intent = new Intent(context, NewsDetailActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("id", newsEntity.getId());
intent.putExtra("title", newsEntity.getTitle());
intent.putExtra("type", newsEntity.getType());
intent.putExtra("entrance", entrance);
context.startActivity(intent);
}
}
/**
* 统计阅读量
/**
* 根据新闻类型获取标签背景资源
*/
public static void statNewsViews(String news_id) {
RetrofitManager.getData().postNewsViews(news_id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>());
}
public static int getDrawableIdByType(String type) {
switch (type) {
case "活动":
case "高阶":
return R.drawable.textview_red_up;
case "公告":
case "中期":
return R.drawable.textview_orange_up;
case "新游":
return R.drawable.textview_green_up;
case "热门":
case "置顶":
return R.drawable.textview_all_red_up;
default:
return R.drawable.textview_blue_up;
}
}
/**
* 去除与重复sourceList相同的数据
*/
public static List<NewsEntity> removeDuplicateData(List<NewsEntity> sourceList, List<NewsEntity> rawList) {
if (sourceList == null || sourceList.isEmpty()
|| rawList == null || rawList.isEmpty()) {
return rawList;
}
String id;
for (int i = 0; i < rawList.size(); i++) {
id = rawList.get(i).getId();
for (NewsEntity newsEntity : sourceList) {
if (id.equals(newsEntity.getId())) {
rawList.remove(i);
i--;
break;
}
}
}
return rawList;
}
/**
* 统计阅读量
*/
public static void statNewsViews(Context context, String news_id) {
RetrofitManager.getInstance(context).getData().postNewsViews(news_id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>());
}
/**
* 设置新闻类型
*/
public static void setNewsType(TextView textView, String type, int priority, int position) {
if (priority != 0) {
if (position == 0) {
textView.setText("置顶");
} else {
textView.setText("热门");
}
} else {
textView.setText(type);
}
/**
* 去除与重复sourceList相同的数据
*/
public static List<NewsEntity> removeDuplicateData(List<NewsEntity> sourceList, List<NewsEntity> rawList) {
if (sourceList == null || sourceList.isEmpty()
|| rawList == null || rawList.isEmpty()) {
return rawList;
}
String id;
for (int i = 0; i < rawList.size(); i++) {
id = rawList.get(i).getId();
for (NewsEntity newsEntity : sourceList) {
if (id.equals(newsEntity.getId())) {
rawList.remove(i);
i--;
break;
}
}
}
return rawList;
}
textView.setTextColor(Color.WHITE);
if ("活动".equals(type)) {
textView.setBackgroundResource(R.drawable.textview_orange_style);
} else if ("公告".equals(type)) {
textView.setBackgroundResource(R.drawable.textview_red_style);
} else if ("评测".equals(type)) {
textView.setBackgroundResource(R.drawable.textview_red_style);
} else if ("杂谈".equals(type)) {
textView.setBackgroundResource(R.drawable.textview_orange_style);
} else if ("专题".equals(type)) {
textView.setBackgroundResource(R.drawable.textview_blue_style);
} else if ("置顶".equals(type)) {
textView.setBackgroundResource(R.drawable.textview_all_red_style);
} else if ("热门".equals(type)){
textView.setBackgroundResource(R.drawable.textview_all_red_style);
} else {
textView.setBackgroundResource(R.drawable.textview_blue_style);
}
}
/**
* 设置新闻类型
*/
public static void setNewsType(TextView textView, String type, int priority, int position) {
if (priority != 0) {
if (position == 0) {
textView.setText(R.string.article_top);
} else {
textView.setText(R.string.article_hot);
}
textView.setBackgroundResource(R.drawable.textview_all_red_style);
return;
} else {
textView.setText(type);
}
/**
* 设置新闻发布时间
*/
public static void setNewsPublishOn(TextView textView, long time) {
time = time * 1000;
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
try {
long today = format.parse(format.format(new Date())).getTime();
if (time >= today && time < today + 86400 * 1000) {
format.applyPattern("HH:mm");
textView.setText(format.format(time));
} else if (time >= today - 86400 * 1000 && time < today) {
format.applyPattern("HH:mm");
textView.setText(String.format("昨天 %s", format.format(time)));
} else {
format.applyPattern("yyyy年MM月dd日 HH:mm");
textView.setText(format.format(time));
}
} catch (ParseException e) {
e.printStackTrace();
format.applyPattern("yyyy年MM月dd日 HH:mm");
textView.setText(format.format(time));
}
}
textView.setTextColor(Color.WHITE);
switch (type) {
case "活动":
textView.setBackgroundResource(R.drawable.textview_orange_style);
break;
case "公告":
textView.setBackgroundResource(R.drawable.textview_red_style);
break;
case "评测":
textView.setBackgroundResource(R.drawable.textview_red_style);
break;
case "杂谈":
textView.setBackgroundResource(R.drawable.textview_orange_style);
break;
case "专题":
textView.setBackgroundResource(R.drawable.textview_blue_style);
break;
default:
textView.setBackgroundResource(R.drawable.textview_blue_style);
break;
}
}
/**
* 设置新闻发布时间
*/
public static void setNewsPublishOn(TextView textView, long time) {
time = time * 1000;
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
try {
long today = format.parse(format.format(new Date())).getTime();
if (time >= today && time < today + 86400 * 1000) {
format.applyPattern("HH:mm");
textView.setText(format.format(time));
} else if (time >= today - 86400 * 1000 && time < today) {
format.applyPattern("HH:mm");
textView.setText(String.format("昨天 %s", format.format(time)));
} else {
format.applyPattern("yyyy年MM月dd日 HH:mm");
textView.setText(format.format(time));
}
} catch (ParseException e) {
e.printStackTrace();
format.applyPattern("yyyy年MM月dd日 HH:mm");
textView.setText(format.format(time));
}
}
}

View File

@ -1,106 +0,0 @@
package com.gh.common.util;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import com.gh.download.DownloadEntity;
import com.gh.download.DownloadManager;
import com.gh.download.DownloadStatus;
import com.gh.gamecenter.R;
/**
* Created by LGT on 2016/10/10.
*/
public class NotificationUtils {
// 快传传输完成消息
public static void showKuaiChuanDoneNotification(Context context, String apkPath, String apkName, String packName) {
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent();
intent.putExtra("path", apkPath);
intent.setAction("com.gh.gamecenter.INSTALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0x321,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
String title = "接收完成,点击立即安装";
String text = apkName;
Notification notification = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.logo)
.setTicker(title)
.setContentTitle(text)
.setContentText(title)
.setContentIntent(pendingIntent).build();
notification.flags |= Notification.FLAG_AUTO_CANCEL; // // FLAG_AUTO_CANCEL表明当通知被用户点击时通知将被清除。
nManager.notify(packName,0x321, notification);
}
public static void showDownloadDoneNotification(Context context, DownloadEntity downloadEntity, int flag) {
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent();
intent.putExtra("path", downloadEntity.getPath());
intent.setAction("com.gh.gamecenter.INSTALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, flag,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
String text;
String title;
if (downloadEntity.isPluggable()) {
title = "下载完成,点击继续插件化";
text = downloadEntity.getName() + " - "
+ PlatformUtils.getInstance(context).getPlatformName(downloadEntity.getPlatform());
} else {
if (downloadEntity.isPlugin()) {
text = downloadEntity.getName()
+ " - " + PlatformUtils.getInstance(context).getPlatformName(downloadEntity.getPlatform());
} else {
text = downloadEntity.getName();
}
title = "下载完成,点击立即安装";
}
Notification notification = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.logo)
.setTicker(title)
.setContentTitle(text)
.setContentText(title)
.setContentIntent(pendingIntent).build();
// notification.defaults = Notification.DEFAULT_SOUND;// 添加系统默认声音
notification.flags |= Notification.FLAG_AUTO_CANCEL; // // FLAG_AUTO_CANCEL表明当通知被用户点击时通知将被清除。
nManager.notify(flag, notification);
}
public static void showDownloadingNotification(Context context) {
int downloadingSize = 0;
for (DownloadEntity entity : DownloadManager.getInstance(context).getAll()) {
if (entity.getStatus().equals(DownloadStatus.downloading)
|| entity.getStatus().equals(DownloadStatus.waiting)
|| entity.getStatus().equals(DownloadStatus.pause)
|| entity.getStatus().equals(DownloadStatus.timeout)
|| entity.getStatus().equals(DownloadStatus.neterror)) {
downloadingSize++;
}
}
if (downloadingSize == 0) {
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nManager.cancel(0x123);
} else {
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent();
intent.setAction("com.gh.gamecenter.DOWNLOAD");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0x123,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.logo)
.setTicker("点击查看详情")
.setContentTitle("你有" + downloadingSize + "个游戏正在下载中" )
.setContentText("点击查看详情")
.setContentIntent(pendingIntent).build();
// notification.defaults = Notification.DEFAULT_SOUND;// 添加系统默认声音
notification.flags |= Notification.FLAG_NO_CLEAR; // 通知无法手动清除
nManager.notify(0x123, notification);
}
}
}

View File

@ -12,7 +12,13 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.widget.Toast;
import com.gh.common.constant.Config;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.lightgame.utils.Utils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.File;
@ -23,272 +29,296 @@ import java.util.ArrayList;
import java.util.List;
public class PackageUtils {
public static final String publicKey = "OpenSSLRSAPublicKey{modulus=a8c4bb5748fec8d5c35db1a7a182d41ba4721a91131a417330af79ef4ddb43f9fa0ff4907b0a613bfe152de0ed8fc1b2e6f94a908aa98a5f7adc1ce814ba7ec919d75d9910bdfd8649b4789da6a90ffb61f0d23ac4f828a78fcd0d6f6120c1c43c1f87f7498a89eb40ca8e32dfc2f9d5c10d612b95192870223674e241e53305abf320d7eed76ded398778576e4db7b17b3bc6a792f13de5e43a6a5fae4276c73e6990ce97f68dff0ec16fc9594f175c8d49cd0d7877340d9de60942ca0efc737e50b6c295dfe0713e4532b4e810e1ea11b702b4a27753e41559cbceb247e7f044ec4e3ab2e8bccd8b9fd71286e63307550bcde86deee95adb8133076269135b,publicExponent=10001}";
/*
* 根据路径获取apk的包名
*/
public static String getPackageNameByPath(Context context, String path) {
PackageManager packageManager = context.getPackageManager();
PackageInfo info = packageManager.getPackageArchiveInfo(path,
PackageManager.GET_ACTIVITIES);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
return appInfo.packageName;
}
return null;
}
public static final String publicKey = "OpenSSLRSAPublicKey{modulus=a8c4bb5748fec8d5c35db1a7a182d41ba4721a91131a417330af79ef4ddb43f9fa0ff4907b0a613bfe152de0ed8fc1b2e6f94a908aa98a5f7adc1ce814ba7ec919d75d9910bdfd8649b4789da6a90ffb61f0d23ac4f828a78fcd0d6f6120c1c43c1f87f7498a89eb40ca8e32dfc2f9d5c10d612b95192870223674e241e53305abf320d7eed76ded398778576e4db7b17b3bc6a792f13de5e43a6a5fae4276c73e6990ce97f68dff0ec16fc9594f175c8d49cd0d7877340d9de60942ca0efc737e50b6c295dfe0713e4532b4e810e1ea11b702b4a27753e41559cbceb247e7f044ec4e3ab2e8bccd8b9fd71286e63307550bcde86deee95adb8133076269135b,publicExponent=10001}";
/*
* 获取meta-data
*/
public static Object getMetaData(Context context, String packageName, String name) {
try {
Bundle metaDate = context.getPackageManager().getApplicationInfo(
packageName, PackageManager.GET_META_DATA).metaData;
if (metaDate != null) {
return metaDate.get(name);
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 判断是否可以更新只判断gh_version的大小
*/
public static boolean isCanUpdate(Context context, GameUpdateEntity gameUpdateEntity) {
// 判断是否gh_version是否存在
String gh_version = (String) PackageUtils.getMetaData(
context, gameUpdateEntity.getPackageName(), "gh_version");
if (gh_version != null) {
gh_version = gh_version.substring(2);
// 判断gh_version的大小
return Long.parseLong(gh_version) < Long.parseLong(gameUpdateEntity.getGhVersion());
} else {
return false;
}
}
/*
* 根据包名获取apk的签名信息
*/
public static String getApkSignatureByPackageName(Context context, String packageName) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
Signature[] signatures = packageInfo.signatures;
return parseSignature(signatures[0].toByteArray())[0];
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 获取meta-data
*/
public static Object getMetaData(Context context, String packageName, String name) {
try {
Bundle metaDate = context.getApplicationContext().getPackageManager().getApplicationInfo(
packageName, PackageManager.GET_META_DATA).metaData;
if (metaDate != null) {
return metaDate.get(name);
}
} catch (NameNotFoundException e) {
// e.printStackTrace();
}
return null;
}
/*
* 判断是否可以更新只判断gh_version的大小
*/
public static boolean isCanUpdate(Context context, GameUpdateEntity gameUpdateEntity) {
// 判断是否gh_version是否存在
String gh_version = (String) PackageUtils.getMetaData(
context, gameUpdateEntity.getPackageName(), "gh_version");
if (gh_version != null) {
gh_version = gh_version.substring(2);
// 判断gh_version的大小
return Long.parseLong(gh_version) < Long.parseLong(gameUpdateEntity.getGhVersion());
} else {
return false;
}
}
/*
* 判断是否是插件包
*/
public static boolean isSignature(Context context, String packageName) {
String signature = getApkSignatureByPackageName(context, packageName);
return publicKey.equals(signature);
}
/*
* 判断是否是插件包
*/
public static boolean isSignature(Context context, String packageName) {
String signature = getApkSignatureByPackageName(context, packageName);
return publicKey.equals(signature);
}
/*
* 根据包名获取apk的签名信息
*/
public static String getApkSignatureByPackageName(Context context, String packageName) {
try {
PackageInfo packageInfo = context.getApplicationContext().getPackageManager()
.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
Signature[] signatures = packageInfo.signatures;
return parseSignature(signatures[0].toByteArray())[0];
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 根据apk路径获取apk包名、签名 根据包名 判断 是否已安装游戏 根据签名 判断 是否一致
*/
public static boolean isCanLaunchSetup(Context context, String path) {
String packageName = getPackageNameByPath(context, path);
/*
* 解析签名
*/
private static String[] parseSignature(byte[] signature) {
String[] ret = null;
try {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(
new ByteArrayInputStream(signature));
ret = new String[]{cert.getPublicKey().toString(), cert.getSerialNumber().toString()};
} catch (CertificateException e) {
e.printStackTrace();
}
return ret;
}
if (TextUtils.isEmpty(packageName)) {
return true;
}
boolean isContain = com.gh.gamecenter.manager.PackageManager.isInstalled(packageName);
if (!isContain) {
return true;
}
/*
* 启动安装应用程序
*/
public static void launchSetup(final Context context, final String path) {
if (isCanLaunchSetup(context, path)) {
context.startActivity(PackageUtils.getInstallIntent(context, path));
} else {
DialogUtils.showPluginDialog(context, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
context.startActivity(PackageUtils.getUninstallIntent(context, path));
}
});
}
}
boolean isInstalled = isInstalled(context, packageName);
if (!isInstalled) {
return true;
}
/*
* 根据apk路径获取apk包名、签名 根据包名 判断 是否已安装游戏 根据签名 判断 是否一致
*/
public static boolean isCanLaunchSetup(Context context, String path) {
String packageName = getPackageNameByPath(context, path);
String signature = getApkSignatureByPackageName(context, packageName);
return publicKey.equals(signature);
}
if (TextUtils.isEmpty(packageName)) {
return true;
}
boolean isContain = com.gh.gamecenter.manager.PackageManager.isInstalled(packageName);
if (!isContain) {
return true;
}
/*
* 启动安装应用程序
*/
public static void launchSetup(final Context context, final String path) {
if (isCanLaunchSetup(context, path)) {
context.startActivity(PackageUtils.getInstallIntent(context, path));
} else {
DialogUtils.showPluginDialog(context, new DialogUtils.ConfiremListener() {
@Override
public void onConfirem() {
context.startActivity(PackageUtils.getUninstallIntent(context, path));
}
});
}
}
boolean isInstalled = isInstalled(context, packageName);
if (!isInstalled) {
return true;
}
/*
* 获取应用第一次安装的时间
*/
public static long getInstalledTime(Context context, String packageName) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(packageName, 0);
return packageInfo.firstInstallTime;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return 0;
}
String signature = getApkSignatureByPackageName(context, packageName);
return publicKey.equals(signature);
}
/*
* 解析签名
*/
private static String[] parseSignature(byte[] signature) {
String[] ret = null;
try {
CertificateFactory certFactory = CertificateFactory
.getInstance("X.509");
X509Certificate cert = (X509Certificate) certFactory
.generateCertificate(new ByteArrayInputStream(signature));
ret = new String[] { cert.getPublicKey().toString(),
cert.getSerialNumber().toString() };
} catch (CertificateException e) {
e.printStackTrace();
}
return ret;
}
/*
* 根据路径,获取安装游戏的意图
*/
public static Intent getInstallIntent(Context context, String path) {
Uri uri = Uri.fromFile(new File(path));
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
InstallUtils.getInstance(context).addInstall(getPackageNameByPath(context, path));
return installIntent;
}
/*
* 返回光环助手的版本信息
*/
public static String getVersionName(Context context) {
try {
PackageInfo pkgInfo = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
return pkgInfo.versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 根据包名,获取卸载游戏的意图
*/
public static Intent getUninstallIntent(Context context, String path) {
Intent uninstallIntent = new Intent();
uninstallIntent.setAction(Intent.ACTION_DELETE);
uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT);
String packageName = getPackageNameByPath(context, path);
uninstallIntent.setData(Uri.parse("package:" + packageName));
InstallUtils.getInstance(context).addUninstall(packageName);
return uninstallIntent;
}
/*
* 返回光环助手的版本code
*/
public static String getVersionCode(Context context) {
try {
PackageInfo pkgInfo = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
return String.valueOf(pkgInfo.versionCode);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 根据路径获取apk的包名
*/
public static String getPackageNameByPath(Context context, String path) {
PackageManager packageManager = context.getApplicationContext().getPackageManager();
PackageInfo info = packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
return appInfo.packageName;
}
return null;
}
/*
* 获取apk的版本
*/
public static String getVersionByPackage(Context context, String packageName) {
try {
return context.getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 根据包名,判断是否已安装该游戏
*/
public static boolean isInstalled(Context context, String packageName) {
Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
return intent != null;
}
/*
* 获取所有已安装的软件的包名、版本(非系统应用)
*/
public static ArrayList<String> getAllPackageName(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = context.getPackageManager().getInstalledPackages(0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
if (!context.getPackageName().equals(packageInfo.packageName)) {
list.add(packageInfo.packageName);
}
}
}
return list;
}
/*
* 获取应用第一次安装的时间
*/
public static long getInstalledTime(Context context, String packageName) {
try {
PackageInfo packageInfo = context.getApplicationContext().getPackageManager()
.getPackageInfo(packageName, 0);
return packageInfo.firstInstallTime;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return 0;
}
/*
* 启动应用
*/
public static void launchApplicationByPackageName(Context context,
String packageName) {
try {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(
packageName);
if (intent != null) {
context.startActivity(intent);
} else {
Toast.makeText(context, "启动失败", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(context, "启动失败", Toast.LENGTH_SHORT).show();
}
}
/**
* 数据统计或反馈用PatchVersionName
* 判断助手是否是第一次启动或版本更新提交的版本号用AppVersionName{@link PackageUtils#getVersionName(Context)}
*
* @return 补丁包版本号
*/
public static String getPatchVersionName() {
return Config.PATCH_VERSION_NAME;
}
/*
* 根据包名,获取软件名称
*/
public static String getNameByPackageName(Context context,
String packageName) {
try {
PackageManager pm = context.getPackageManager();
ApplicationInfo applicationInfo = pm.getApplicationInfo(
packageName, 0);
return applicationInfo.loadLabel(pm).toString();
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 返回光环助手的版本信息
*/
public static String getVersionName(Context context) {
try {
PackageInfo pkgInfo = context.getApplicationContext().getPackageManager().getPackageInfo(
context.getPackageName(), 0);
return pkgInfo.versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 根据包名,判断是否已安装该游戏
*/
public static boolean isInstalled(Context context, String packageName) {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
return intent != null;
}
/*
* 返回光环助手的版本code
*/
public static String getVersionCode(Context context) {
try {
PackageInfo pkgInfo = context.getApplicationContext().getPackageManager().getPackageInfo(
context.getPackageName(), 0);
return String.valueOf(pkgInfo.versionCode);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 根据包名,获取卸载游戏的意图
*/
public static Intent getUninstallIntent(Context context, String path) {
Intent uninstallIntent = new Intent();
uninstallIntent.setAction("android.intent.action.DELETE");
uninstallIntent.addCategory("android.intent.category.DEFAULT");
String packageName = getPackageNameByPath(context, path);
uninstallIntent.setData(Uri.parse("package:" + packageName));
InstallUtils.getInstance(context).addUninstall(packageName);
return uninstallIntent;
}
/*
* 获取apk的版本
*/
public static String getVersionByPackage(Context context, String packageName) {
try {
return context.getApplicationContext().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 根据路径,获取安装游戏的意图
*/
public static Intent getInstallIntent(Context context, String path) {
Uri uri = Uri.fromFile(new File(path));
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
InstallUtils.getInstance(context).addInstall(getPackageNameByPath(context, path));
return installIntent;
}
/*
* 获取所有已安装的软件的包名、版本(非系统应用)
*/
public static ArrayList<String> getAllPackageName(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = context.getApplicationContext().getPackageManager().getInstalledPackages(0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
if (!context.getPackageName().equals(packageInfo.packageName)) {
list.add(packageInfo.packageName);
}
}
}
return list;
}
public static JSONArray getAppList(Context context) {
JSONArray jsonArray = new JSONArray();
try {
PackageManager pm = context.getPackageManager();
List<PackageInfo> packageInfos = pm.getInstalledPackages(0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", pm.getApplicationLabel(packageInfo.applicationInfo).toString());
jsonObject.put("package", packageInfo.packageName);
jsonObject.put("version", packageInfo.versionName);
jsonArray.put(jsonObject);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return jsonArray;
}
/*
* 启动应用
*/
public static void launchApplicationByPackageName(Context context, String packageName) {
try {
Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
if (intent != null) {
context.startActivity(intent);
} else {
Utils.toast(context, "启动失败");
}
} catch (Exception e) {
e.printStackTrace();
Utils.toast(context, "启动失败");
}
}
/*
* 根据包名,获取软件名称
*/
public static String getNameByPackageName(Context context, String packageName) {
try {
PackageManager pm = context.getApplicationContext().getPackageManager();
ApplicationInfo applicationInfo = pm.getApplicationInfo(
packageName, 0);
return applicationInfo.loadLabel(pm).toString();
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
}

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