Compare commits

..

132 Commits
v2.4 ... v2.6

Author SHA1 Message Date
62efcef486 游戏详情修改(应该是2.6最后修改了) 2017-08-01 16:26:16 +08:00
0e10b3e50f Merge branch '2.6' of gitlab.ghzhushou.com:halo/assistant-android into 2.6 2017-07-27 11:21:24 +08:00
1c05b322e4 web新闻评论数同步,游戏插件跳转至光环助手反馈默认选中返回类型 2017-07-27 11:20:12 +08:00
9a6bbc7e43 add debug key 2017-07-24 16:07:46 +08:00
3f0347c2a8 add debug config 2017-07-24 16:06:13 +08:00
01cd24d2ba fix ghzhushou.com host 2017-07-14 17:15:54 +08:00
dbbeff14ae 2.6测试 BUG修改 2017-07-14 16:44:45 +08:00
2631d7136c fix download url check 2017-07-07 16:59:55 +08:00
ee43e522f8 更改域名为ghzs666.com,下载服务那边暂时会多支持一个download/apk/apk2.ghzhushou.com 2017-07-07 15:43:54 +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
4f64325f2b fix conflict 2017-04-21 17:08:36 +08:00
de9c9cbdcb 整理工程结构,library配置未完全抽离出来 2017-04-21 16:59:29 +08:00
khy
1fe9e259b4 消息页面对接数据接口, 礼包重复领取,删除无用文件 2017-04-21 16:32:44 +08:00
6b4f68128b fix gitignore 2017-04-21 14:34:12 +08:00
khy
8b637fbeec ... 2017-04-14 16:36:22 +08:00
khy
7267535ccf Merge remote-tracking branch 'origin/2.5' into 2.5
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.java
2017-04-14 16:15:19 +08:00
khy
8f99987696 游戏求版本功能(未对接接口), 文章详情优化(文章内容跳转未做),消息中心(未接接口),首页资讯改版,跳转意见反馈规则汇总 2017-04-14 16:07:36 +08:00
khy
515473e5dc 新版游戏详情,我的光环, 反馈页面。 专题增加标签 2017-04-02 17:18:00 +08:00
8b83e939ce 搜索数据收集 2017-03-28 16:44:00 +08:00
c71bd36de2 推荐位数据收集 2017-03-28 14:57:51 +08:00
9fdc8f0da3 修改版本为2.5,版本号20 2017-03-28 14:57:08 +08:00
khy
8ba099024e 去卡片化, 开服表, 首页游戏-资讯改版,游戏专题增加标签(还差一个接口) 2017-03-22 15:25:05 +08:00
951 changed files with 59713 additions and 58782 deletions

13
.gitignore vendored
View File

@ -1,9 +1,8 @@
/.idea
.idea/misc.xml
.idea/
*.iml
.gradle
/local.properties
.gradle/
local.properties
# sign.properties
.DS_Store
/build
/captures
/PushSDK/build
captures/
build/

View File

@ -1,147 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.umeng.message.lib"
android:versionCode="1"
android:versionName="1.0">
<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.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.BROADCAST_PACKAGE_ADDED" />
<uses-permission android:name="android.permission.BROADCAST_PACKAGE_CHANGED" />
<uses-permission android:name="android.permission.BROADCAST_PACKAGE_INSTALL" />
<uses-permission android:name="android.permission.BROADCAST_PACKAGE_REPLACED" />
<uses-permission android:name="android.permission.RESTART_PACKAGES" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<application>
<service
android:name="com.taobao.accs.ChannelService"
android:exported="true"
android:process=":channel">
<intent-filter>
<action android:name="com.taobao.accs.intent.action.SERVICE" />
</intent-filter>
<intent-filter>
<action android:name="com.taobao.accs.intent.action.ELECTION" />
</intent-filter>
</service>
<service
android:name="com.taobao.accs.data.MsgDistributeService"
android:exported="true">
<intent-filter>
<action android:name="com.taobao.accs.intent.action.RECEIVE" />
</intent-filter>
</service>
<receiver
android:name="com.taobao.accs.EventReceiver"
android:process=":channel">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
<receiver
android:name="com.taobao.accs.ServiceReceiver"
android:exported="false"
android:process=":channel">
<intent-filter>
<action android:name="com.taobao.accs.intent.action.COMMAND" />
</intent-filter>
<intent-filter>
<action android:name="com.taobao.accs.intent.action.START_FROM_AGOO" />
</intent-filter>
</receiver>
<service
android:name="com.taobao.accs.ChannelService$KernelService"
android:process=":channel">
</service>
<service
android:name="org.android.agoo.accs.AgooService"
android:exported="true">
<intent-filter>
<action android:name="com.taobao.accs.intent.action.RECEIVE" />
</intent-filter>
</service>
<service android:name="com.umeng.message.UmengIntentService"
android:exported="true"
android:process=":channel">
<intent-filter>
<action android:name="org.agoo.android.intent.action.RECEIVE" />
</intent-filter>
</service>
<receiver
android:name="com.taobao.agoo.AgooCommondReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.gh.gamecenter.intent.action.COMMAND" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<receiver
android:name="com.umeng.message.NotificationProxyBroadcastReceiver"
android:exported="false" />
<service
android:name="com.umeng.message.UmengMessageCallbackHandlerService"
android:exported="false">
<intent-filter>
<action android:name="com.umeng.messge.registercallback.action" />
</intent-filter>
<intent-filter>
<action android:name="com.umeng.message.enablecallback.action" />
</intent-filter>
<intent-filter>
<action android:name="com.umeng.message.disablecallback.action" />
</intent-filter>
<intent-filter>
<action android:name="com.umeng.message.message.handler.action" />
</intent-filter>
</service>
<service
android:name="com.umeng.message.UmengDownloadResourceService"
android:exported="false" />
<service
android:name="com.umeng.message.UmengMessageIntentReceiverService"
android:exported="true"
android:process=":channel" >
<intent-filter>
<action android:name="org.android.agoo.client.MessageReceiverService" />
</intent-filter>
</service>
<provider
android:name="com.umeng.message.provider.MessageProvider"
android:authorities="com.gh.gamecenter.umeng.message"
android:exported="false">
<grant-uri-permission android:pathPattern=".*" />
</provider>
</application>
</manifest>

View File

@ -1,51 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 22
buildToolsVersion "23.0.2"
defaultConfig {
minSdkVersion 11
targetSdkVersion 22
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
// Move the tests to tests/java, tests/res, etc...
instrumentTest.setRoot('tests')
// Move the build types to build-types/<type>
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
// This moves them out of them default location under src/<type>/... which would
// conflict with src/ being used by the main source set.
// Adding new build types or product flavors should be accompanied
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@ -1,156 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.umeng.message.lib.test" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="22" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:functionalTest="false"
android:handleProfiling="false"
android:label="Tests for com.umeng.message.lib.test"
android:targetPackage="com.umeng.message.lib.test" />
<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.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.BROADCAST_PACKAGE_ADDED" />
<uses-permission android:name="android.permission.BROADCAST_PACKAGE_CHANGED" />
<uses-permission android:name="android.permission.BROADCAST_PACKAGE_INSTALL" />
<uses-permission android:name="android.permission.BROADCAST_PACKAGE_REPLACED" />
<uses-permission android:name="android.permission.RESTART_PACKAGES" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<application>
<uses-library android:name="android.test.runner" />
<service
android:name="com.taobao.accs.ChannelService"
android:exported="true"
android:process=":channel" >
<intent-filter>
<action android:name="com.taobao.accs.intent.action.SERVICE" />
</intent-filter>
<intent-filter>
<action android:name="com.taobao.accs.intent.action.ELECTION" />
</intent-filter>
</service>
<service
android:name="com.taobao.accs.data.MsgDistributeService"
android:exported="true" >
<intent-filter>
<action android:name="com.taobao.accs.intent.action.RECEIVE" />
</intent-filter>
</service>
<receiver
android:name="com.taobao.accs.EventReceiver"
android:process=":channel" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
<receiver
android:name="com.taobao.accs.ServiceReceiver"
android:exported="false"
android:process=":channel" >
<intent-filter>
<action android:name="com.taobao.accs.intent.action.COMMAND" />
</intent-filter>
<intent-filter>
<action android:name="com.taobao.accs.intent.action.START_FROM_AGOO" />
</intent-filter>
</receiver>
<service
android:name="com.taobao.accs.ChannelService$KernelService"
android:process=":channel" >
</service>
<service
android:name="org.android.agoo.accs.AgooService"
android:exported="true" >
<intent-filter>
<action android:name="com.taobao.accs.intent.action.RECEIVE" />
</intent-filter>
</service>
<service
android:name="com.umeng.message.UmengIntentService"
android:exported="true"
android:process=":channel" >
<intent-filter>
<action android:name="org.agoo.android.intent.action.RECEIVE" />
</intent-filter>
</service>
<receiver
android:name="com.taobao.agoo.AgooCommondReceiver"
android:exported="true" >
<intent-filter>
<action android:name="com.gh.gamecenter.intent.action.COMMAND" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<receiver
android:name="com.umeng.message.NotificationProxyBroadcastReceiver"
android:exported="false" />
<service
android:name="com.umeng.message.UmengMessageCallbackHandlerService"
android:exported="false" >
<intent-filter>
<action android:name="com.umeng.messge.registercallback.action" />
</intent-filter>
<intent-filter>
<action android:name="com.umeng.message.enablecallback.action" />
</intent-filter>
<intent-filter>
<action android:name="com.umeng.message.disablecallback.action" />
</intent-filter>
<intent-filter>
<action android:name="com.umeng.message.message.handler.action" />
</intent-filter>
</service>
<service
android:name="com.umeng.message.UmengDownloadResourceService"
android:exported="false" />
<service
android:name="com.umeng.message.UmengMessageIntentReceiverService"
android:exported="true"
android:process=":channel" >
<intent-filter>
<action android:name="org.android.agoo.client.MessageReceiverService" />
</intent-filter>
</service>
<provider
android:name="com.umeng.message.provider.MessageProvider"
android:authorities="com.gh.gamecenter.umeng.message"
android:exported="false" >
<grant-uri-permission android:pathPattern=".*" />
</provider>
</application>
</manifest>

View File

@ -1,12 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-19
android.library=true

23
README.md Normal file
View File

@ -0,0 +1,23 @@
# 光环助手Android客户端
### 多渠道打包配置
* 使用[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``配置
### Ver 2.5
* 此处写本次更新所做的业务和代码修改

1
app/.gitignore vendored
View File

@ -1 +0,0 @@
/build

View File

@ -1,153 +1,264 @@
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
//tinker插件
//apply plugin: 'com.tencent.tinker.patch'
// apkChannelPackage
apply plugin: 'channel'
android {
compileSdkVersion 21
buildToolsVersion "23.0.3"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
dexOptions {
jumboMode = true
}
/**
* 定位编译出错的图片
*/
aaptOptions.cruncherEnabled = false
aaptOptions.useNewCruncher = false
defaultConfig {
applicationId "com.gh.gamecenter"
minSdkVersion 14
targetSdkVersion 21
versionCode 19
versionName "2.4"
// multiDexEnabled true
javaCompileOptions {
annotationProcessorOptions {
arguments = [ eventBusIndex : 'com.bandeng.MyEventBusIndex' ]
}
}
/**
* 只支持两种架构减少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"
// jackOptions {
// enabled true
// }
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
applicationId rootProject.ext.applicationId
multiDexEnabled true
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}\""
}
/**
* 签名设置
*/
// gradle 2.2以上默认同时启用v1和v2优先用于Android N
signingConfigs {
debug {
v1SigningEnabled true
v2SigningEnabled true
}
release {
storeFile file("gh.keystore")
keyAlias "gh.keystore"
keyPassword "20150318"
storePassword "20150318"
v1SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
debug {
debuggable true
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
zipAlignEnabled false
versionNameSuffix "-debug"
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
debuggable false
minifyEnabled true
zipAlignEnabled true
shrinkResources true
signingConfig signingConfigs.release
}
}
// sourceSets {
// main {
// jniLibs.srcDirs = ['libs']
// }
// }
buildTypes {
debug {
debuggable true
minifyEnabled false
zipAlignEnabled false
versionNameSuffix "-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 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}\""
}
}
/**
* 多渠道打包
* 多渠道打包,渠道请参考"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 {}
// public release host
pub {
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}\""
}
// internal dev host
dev {
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}\""
}
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [CHANNEL_VALUE: name]//命令 gradlew assembleRelease
// 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}'
}
apt {
arguments {
eventBusIndex "com.bandeng.MyEventBusIndex"
}
}
//butterknife
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
rebuildChannel {
// baseDebugApk = 已有Debug APK
// baseReleaseApk = 已有Release APK
// //默认为new File(project.buildDir, "rebuildChannel/debug")
// debugOutputDir = Debug渠道包输出目录
// //默认为new File(project.buildDir, "rebuildChannel/release")
// releaseOutputDir = Release渠道包输出目录
}
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:21.0.0'
// 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'
//添加友盟依赖工程
compile project(':PushSDK')
// 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"
}
testCompile test.junit
compile fileTree(include: '*.jar', dir: 'libs')
compile libs.supportMultidex
compile libs.supportDesign
compile libs.supportAppCompat
compile libs.supportAnnotation
compile libs.supportPercent
compile libs.supportDesign
// 依赖插件脚本
//apply from: 'tinker-support.gradle'
compile libs.switchButton
compile libs.systemBarTint
compile libs.fresco
compile libs.frescoAnimatedGif
compile libs.okHttp
compile libs.okHttpLogInterceptor
compile libs.apkChannelPackage
// debugCompile libs.stetho
// debugCompile libs.stethoWithOkHttp
compile libs.retrofit
compile libs.retrofitWithGson // include gson 2.7
compile libs.retrofitWithRxJava
// compile libs.gson
compile libs.ormliteAndroid
compile libs.ormliteCore
compile libs.butterKnife
apt libs.butterKnifeApt
compile libs.rxJava
compile libs.rxAndroid
compile libs.rxBinding
compile libs.zxing
compile libs.zxingAndroid
compile libs.swipeLayout
compile(libs.autoScrollViewPager) {
exclude module: 'support-v4'
}
// tinker
// provided libs.tinker_anno
// compile libs.tinker_lib
compile libs.eventbus
apt libs.eventbusApt
// 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')
compile project(':libraries:iosched')
}
File propFile = file('sign.properties');
if (propFile.exists()) {
def Properties props = new Properties()
props.load(new FileInputStream(propFile))
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')
}
release {
keyAlias props.get('keyAlias')
keyPassword props.get('keyPassword')
storeFile file(props.get('storeFile'))
storePassword props.get('storePassword')
}
}
} else {
android.buildTypes.release.signingConfig = null
}
} else {
android.buildTypes.release.signingConfig = null
}

Binary file not shown.

Binary file not shown.

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.**

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

@ -0,0 +1,160 @@
# 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
# 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);
}
# 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 ----------

4
app/sign.properties Normal file
View File

@ -0,0 +1,4 @@
storeFile=gh.keystore
storePassword=20150318
keyAlias=gh.keystore
keyPassword=20150318

View File

@ -1,360 +1,244 @@
<?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"/>
<permission
android:name="com.gh.gamecenter.permission.MIPUSH_RECEIVE"
android:protectionLevel="signature" />
<uses-permission android:name = "android.permission.WRITE_SETTINGS" />
<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}"-->
<!-- MTA -->
<meta-data
android:name="TA_APPKEY"
android:value="APV567FTBS7J"/>
<meta-data
android:name="InstallChannel"
android:value="GH_TEST"/>
<!--android:value="${CHANNEL_VALUE}"-->
<!-- 友盟推送 -->
<meta-data
android:name="UMENG_APPKEY"
android:value="585a29fa8f4a9d327600023e">
</meta-data>
<meta-data
android:name="UMENG_MESSAGE_SECRET"
android:value="8bcce6bed547ee624f5c2cc64d39a9e9">
</meta-data>
android:name = "com.gh.base.AppController"
android:allowBackup = "true"
android:icon = "@drawable/logo"
android:label = "@string/app_name"
android:theme = "@style/AppCompatTheme" >
<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.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" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<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"/>
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" />
android:name = "com.gh.gamecenter.DownloadManagerActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.ViewImageActivity"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" />
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:windowSoftInputMode="stateVisible" />
android:name = "com.gh.gamecenter.SearchActivity"
android:configChanges = "keyboardHidden"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.GameDetailActivity"
android:screenOrientation="portrait" />
android:name = "com.gh.gamecenter.NewsDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.NewsDetailActivity"
android:screenOrientation="portrait" />
android:name = "com.gh.gamecenter.SettingActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.SettingActivity"
android:screenOrientation="portrait" />
android:name = "com.gh.gamecenter.ConcernActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.SuggestionActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateVisible" />
android:name = "com.gh.gamecenter.SubjectActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.ConcernActivity"
android:screenOrientation="portrait" />
android:name = "com.gh.gamecenter.PluginActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.SubjectActivity"
android:screenOrientation="portrait" />
android:name = "com.gh.gamecenter.NewsSearchActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode="stateHidden"/>
<activity
android:name="com.gh.gamecenter.PluginActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.GameNewsActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.NewsSearchActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.CropImageActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.GameNewsActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.WebActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.CropImageActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.ShareCardPicActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.WebActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.ShareCardActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.ShareCardPicActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.MessageDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.ShareCardActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.LibaoActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode="stateHidden"/>
<activity
android:name="com.gh.gamecenter.MessageDetailActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.LibaoDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.StrategyActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.ShareGhWfifActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.LibaoActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.ShareGhActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.LibaoDetailActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.CleanApkActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.ShareGhWfifActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.KcSelectGameActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.ShareGhActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.ChooseReceiverActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.CleanApkActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.ReceiverWaitingActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.KcSelectGameActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.FileSenderActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.ChooseReceiverActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.FileReceiverActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.ReceiverWaitingActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.SelectUserIconActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.FileSenderActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.AboutActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.FileReceiverActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.KaiFuActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.SelectUserIconActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.CommentDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.AboutActivity"
android:screenOrientation="portrait"/>
android:name = "com.gh.gamecenter.GameDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name="com.gh.gamecenter.SkipActivity"
android:theme="@android:style/Theme.Translucent">
<intent-filter>
<data android:scheme="ghzhushou"/>
android:name = "com.gh.gamecenter.SuggestSelectActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.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.ToolBoxActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode="stateHidden"/>
<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="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 分享 -->
<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>
<activity
android:name="com.tencent.connect.common.AssistActivity"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="behind"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<!--微博分享-->
<activity
android:name="com.sina.weibo.sdk.component.WeiboSdkBrowser"
android:configChanges="keyboardHidden|orientation"
android:windowSoftInputMode="adjustResize"
android:exported="false" >
</activity>
<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>
<category android:name = "android.intent.category.DEFAULT" />
<action android:name = "android.intent.action.VIEW" />
<category android:name = "android.intent.category.BROWSABLE" />
</intent-filter >
</activity >
<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" />
<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>
<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.download.DownloadService" />
<service
android:name="com.gh.download.DownloadService" />
<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />
<!--<service-->
<!--android:name="com.gh.base.AppTinkerResultService"-->
<!--android:exported="false" />-->
</application >
<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>

View File

Before

Width:  |  Height:  |  Size: 544 KiB

After

Width:  |  Height:  |  Size: 544 KiB

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,128 +1,200 @@
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.multidex.MultiDex;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;
import android.util.Log;
import com.bandeng.MyEventBusIndex;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.gh.common.constant.Config;
import com.gh.common.util.DataUtils;
import com.gh.common.util.HttpsUtils;
import com.gh.common.util.StringUtils;
import com.gh.common.util.TokenUtils;
import com.gh.common.util.Utils;
import com.gh.gamecenter.BuildConfig;
import com.leon.channel.helper.ChannelReaderUtil;
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 com.xiaomi.mipush.sdk.MiPushCommandMessage;
import org.greenrobot.eventbus.EventBus;
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();
// xiaomi push appid
public static final String APP_ID = "2882303761517352993";
// xiaomi push appkey
public static final String APP_KEY = "5451735292993";
public static final String TAG = AppController.class.getSimpleName();
public static final String KEY_FILE_INFO = "FileInfo";
//快传文件发送单线程
public static Executor FILE_SENDER_EXECUTOR = Executors.newSingleThreadExecutor();
//快传文件发送主要的线程池
public static Executor MAIN_EXECUTOR = Executors.newCachedThreadPool();
private static AppController mInstance;
private static ArrayMap<String, Object> objectMap = new ArrayMap<>();
private static AppController mInstance;
private static ArrayMap<String, Object> objectMap = new ArrayMap<>();
private String mChannel;
private ArrayList<Activity> list = new ArrayList<>();
public static void put(String key, Object object) {
if (objectMap == null) {
objectMap = new ArrayMap<>();
}
objectMap.put(key, object);
}
private boolean isFinish = false;
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 Executor FILE_SENDER_EXECUTOR = Executors.newSingleThreadExecutor();
public static void remove(String key) {
if (objectMap == null) {
return;
}
objectMap.remove(key);
}
//快传文件发送主要的线程池
public static Executor MAIN_EXECUTOR = Executors.newFixedThreadPool(5);
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 AppController() {
// super(ShareConstants.TINKER_ENABLE_ALL, "com.gh.base.AppControllerLike",
// "com.tencent.tinker.loader.TinkerLoader", false);
// }
public static synchronized AppController getInstance() {
return mInstance;
}
@Override
public void onCreate() {
super.onCreate();
//初始化Fresco
Fresco.initialize(this);
public String getChannel() {
return mChannel;
}
DataUtils.init(this);
@Override
public void onCreate() {
super.onCreate();
HttpsUtils.initHttpsUrlConnection(this);
MultiDex.install(this);
mInstance = this;
AppUncaHandler uncaHandler = new AppUncaHandler(this);
Thread.setDefaultUncaughtExceptionHandler(uncaHandler);
mInstance = this;
//TODO 强烈不建议开发阶段开启这个Handler必须处理错误
if (!BuildConfig.DEBUG) {
AppUncaughtHandler appUncaughtHandler = new AppUncaughtHandler(this);
Thread.setDefaultUncaughtExceptionHandler(appUncaughtHandler);
}
// 注册push服务注册成功后会向GHPushMessageReceiver发送广播
// 可以从GHPushMessageReceiver的onCommandResult方法中MiPushCommandMessage对象参数中获取注册信息
if (shouldInit()) {
MiPushClient.registerPush(this, APP_ID, APP_KEY);
}
mChannel = ChannelReaderUtil.getChannel(this);
if (TextUtils.isEmpty(mChannel)) {
//默认用Android Studio run时并没有写入channel magic number到apk包里面所以需要fallback
mChannel = "GH_TEST";
}
LoggerInterface newLogger = new LoggerInterface() {
Log.e("CHANNEL_ID", mChannel);
@Override
public void setTag(String tag) {
// ignore
}
//初始化Fresco
Fresco.initialize(this);
@Override
public void log(String content, Throwable t) {
Log.d(TAG, content, t);
}
DataUtils.init(this, BuildConfig.DEBUG, mChannel);
@Override
public void log(String content) {
Log.d(TAG, content);
}
};
Logger.setLogger(this, newLogger);
//测试MTA崩溃的坑爹
// if (BuildConfig.DEBUG) {
// StatConfig.setDebugEnable(true);
// StatConfig.setStatSendStrategy(StatReportStrategy.DEVELOPER);
// throw new RuntimeException("test again");
// }
//友盟推送
final PushAgent mPushAgent = PushAgent.getInstance(this);
HttpsUtils.initHttpsUrlConnection(this);
// if (BuildConfig.DEBUG) {
// Stetho.initializeWithDefaults(this);
// }
//注册推送服务每次调用register方法都会回调该接口
mPushAgent.register(new IUmengRegisterCallback() {
/**
* 注册push服务注册成功后会向{@link GHPushMessageReceiver}发送广播
* 可以从{@link GHPushMessageReceiver#onCommandResult(Context, MiPushCommandMessage)}
* 的{@link MiPushCommandMessage} 对象参数中获取注册信息
*/
if (shouldInit()) {
MiPushClient.registerPush(this, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY);
@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);
if (BuildConfig.DEBUG) {
LoggerInterface newLogger = new LoggerInterface() {
}
});
}
@Override
public void setTag(String tag) {
// ignore
}
@Override
public void onFailure(String s, String s1) {
Utils.log("deviceToken::" + "注册失败");
}
});
@Override
public void log(String content) {
Log.d(TAG, content);
}
// 友盟推送数据处理
mPushAgent.setNotificationClickHandler(new GHUmengNotificationClickHandler());
@Override
public void log(String content, Throwable t) {
Log.d(TAG, content, t);
}
};
Logger.setLogger(this, newLogger);
}
//友盟推送
final PushAgent pushAgent = PushAgent.getInstance(this);
pushAgent.setAppkeyAndSecret(Config.UMENG_APPKEY, Config.UMENG_MESSAGE_SECRET);
//注册推送服务每次调用register方法都会回调该接口
pushAgent.register(new IUmengRegisterCallback() {
@Override
public void onSuccess(String deviceToken) {
//注册成功会返回device token
Utils.log("deviceToken::" + deviceToken);
//设置别名
pushAgent.addExclusiveAlias(TokenUtils.getDeviceId(getApplicationContext()),
"GHDID", new UTrack.ICallBack() {
@Override
public void onMessage(boolean b, String s) {
Utils.log(StringUtils.buildString("ExclusiveAlias::", String.valueOf(b), "==", s));
}
});
}
@Override
public void onFailure(String s, String s1) {
Utils.log("deviceToken::" + "注册失败");
}
});
// 友盟推送数据处理
pushAgent.setNotificationClickHandler(new GHUmengNotificationClickHandler());
// // 监听屏幕状态广播
// if (shouldInit()) {
@ -141,98 +213,23 @@ public class AppController extends Application {
// 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);
}
// 启用EventBus3.0加速功能
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
}
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;
}
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,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,127 @@
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.AppManager;
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 AppUncaughtHandler implements UncaughtExceptionHandler {
private UncaughtExceptionHandler mDefaultHandler;
private AppController mAppController;
public AppUncaughtHandler(AppController appController) {
// 获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
mAppController = appController;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
AppController.MAIN_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mAppController.getApplicationContext(),
"\"光环助手\"发生错误", Toast.LENGTH_SHORT).show();
Looper.loop();
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 防止重复奔溃导致助手一直重启20秒内不做处理
SharedPreferences sp = mAppController.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(mAppController.getApplicationContext(), SplashScreenActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent restartIntent = PendingIntent.getActivity(
mAppController.getApplicationContext(), 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 退出程序并重启
AlarmManager mgr = (AlarmManager) mAppController.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒钟后重启应用
}
AppManager.getInstance().finishAllActivity();
}
}
/**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
*
* @param ex
* @return true:如果处理了该异常信息;否则返回false.
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
saveLog(ex);
return true;
}
// 保存log到本地
private void saveLog(Throwable ex) {
String errorMsg = Log.getStackTraceString(ex);
// MTA主动上传错误
// StatService.reportError(mAppController.getApplicationContext(), errorMsg);
StatService.reportException(mAppController, ex);
// 上传错误数据
DataCollectionUtils.uploadError(mAppController, errorMsg);
// 保存到本地
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
File file = new File(FileUtils.getLogPath(mAppController.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();
}
}
}
}
}

View File

@ -1,21 +1,17 @@
package com.gh.base;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
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.AppManager;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DisplayUtils;
@ -23,191 +19,168 @@ 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.listener.OnCallBackListener;
import com.gh.gamecenter.manager.SystemBarTintManager;
import com.gh.gamecenter.manager.SystemBarTintManager.SystemBarConfig;
import com.readystatesoftware.systembartint.SystemBarTintManager.SystemBarConfig;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import butterknife.ButterKnife;
import de.greenrobot.event.EventBus;
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 OnCallBackListener {
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) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
SystemBarConfig config = getTintManager().getConfig();
contentView.setPadding(0, config.getPixelInsetTop(false), 0, config.getPixelInsetBottom());
}
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.setStatusBarTintResource(R.color.theme);
SystemBarConfig config = tintManager.getConfig();
contentView.setPadding(0, config.getPixelInsetTop(false), 0,
config.getPixelInsetBottom());
}
ButterKnife.bind(this);
setContentView(contentView);
View reuse_actionbar = findViewById(R.id.reuse_actionbar);
if (reuse_actionbar != null) {
int actionbar_height = getSharedPreferences(Config.PREFERENCE, Context.MODE_PRIVATE)
.getInt("actionbar_height", DisplayUtils.dip2px(getApplicationContext(), 55));
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, actionbar_height);
reuse_actionbar.setLayoutParams(lparams);
ButterKnife.bind(this);
findViewById(R.id.actionbar_rl_back).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
}
int actionbar_height = getSharedPreferences(Config.PREFERENCE,
Context.MODE_PRIVATE).getInt("actionbar_height",
DisplayUtils.dip2px(getApplicationContext(), 48));
protected void init(String title) {
TextView actionbar_tv_title = (TextView) findViewById(R.id.actionbar_tv_title);
actionbar_tv_title.setText(title);
// setNavigationTitle(title);
}
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(String 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();
}
});
}
public void toast(int msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
protected SystemBarTintManager getTintManager() {
return tintManager;
}
//如果是游戏分享newsTitle默认为空
public void showShare(String url, String gameName, String icon, String newsTitle, ArrayList<String> tag, boolean isToolsBox) {
@Override
public void finish() {
super.finish();
AppController.getInstance().removeActivity(this);
}
//判断是否是官方版
boolean isPlugin = false;
if (tag != null) {
for (String s : tag) {
if (!"官方版".equals(s)) {
isPlugin = true;
}
}
}
public void toast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
ShareUtils.getInstance(this).showShareWindows(getWindow().getDecorView(), url, gameName, icon, newsTitle, isPlugin, true, isToolsBox);
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) {
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())) {
Toast.makeText(BaseActivity.this, "解析包出错(可能被误删了),请重新下载", Toast.LENGTH_SHORT).show();
} else {
startActivity(PackageUtils.getUninstallIntent(BaseActivity.this, showDialog.getPath()));
}
}
});
}
}
}
@Override
protected void onResume() {
super.onResume();
DataUtils.onResume(this);
isPause = false;
DownloadManager.getInstance(this).initGameMap();
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
AppManager.getInstance().finishActivity(this);
}
@Override
public void loadDone() {
}
@Override
protected void onPause() {
super.onPause();
DataUtils.onPause(this);
mIsPause = true;
}
@Override
public void loadDone(Object obj) {
@Override
protected void onResume() {
super.onResume();
DataUtils.onResume(this);
mIsPause = false;
DownloadManager.getInstance(this).initGameMap();
}
}
@Override
public void loadDone() {
@Override
public void loadError() {
}
}
@Override
public void loadDone(Object obj) {
@Override
public void loadEmpty() {
}
}
@Override
public void loadError() {
}
@Override
public void loadEmpty() {
}
}

View File

@ -0,0 +1,325 @@
package com.gh.base;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import com.gh.common.util.AppDebugConfig;
import com.gh.common.util.AppManager;
import com.gh.common.util.Util_System_Keyboard;
import com.gh.gamecenter.R;
/**
* @author CsHeng
*/
public abstract class BaseAppCompatActivity extends BaseAppCompatActivityLog implements FragmentNavigationDelegate,
OnBackPressedListener {
protected static final String ARGS_FRAGMENT_NAME = "frgName";
protected static final String ARGS_FRAGMENT_BUNDLE = "frgBundle";
protected View mContentView;
protected static Intent clearTop(Context context, Class<? extends Activity> cls) {
final Intent intent = getReorderToFrontIntent(context, cls);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
return intent;
}
protected static Intent getReorderToFrontIntent(Context context, Class<? extends Activity> cls) {
final Intent intent = new Intent(context, cls);
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return intent;
}
protected static void showActivity(Context context, Class<? extends Activity> cls) {
final Intent intent = getReorderToFrontIntent(context, cls);
context.startActivity(intent);
}
protected static void startFragmentForResult(Context context, Class<? extends Activity> activity,
Class<? extends Fragment> fragment, Bundle bundle, int requestCode) {
if (context instanceof Activity) {
((Activity) context).startActivityForResult(getFragmentIntent(context, activity, fragment, bundle),
requestCode);
}
}
/**
* 根据传进来的fragment class和bundle extra来决定跳转到哪一个fragment
*
* @param context
* @param fragment fragment.getCanonicalName()
* @param bundle fragment的构造参数
* @return
*/
protected static Intent getFragmentIntent(Context context, Class<? extends Activity> activity,
Class<? extends Fragment> fragment, Bundle bundle) {
final Intent intent = getReorderToFrontIntent(context, activity);
intent.putExtra(ARGS_FRAGMENT_NAME, fragment.getCanonicalName());
intent.putExtra(ARGS_FRAGMENT_BUNDLE, bundle);
return intent;
}
protected static void startFragment(Context context, Class<? extends Activity> activity,
Class<? extends Fragment> fragment) {
startFragment(context, activity, fragment, null);
}
/**
* 启动Fragment
*
* @param context
* @param fragment
* @param bundle
*/
protected static void startFragment(Context context, Class<? extends Activity> activity,
Class<? extends Fragment> fragment, Bundle bundle) {
context.startActivity(getFragmentIntent(context, activity, fragment, bundle));
}
private void handleRedirectFromUri(Uri uri) {
try {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this, uri, uri.getHost(), uri.getPath(), uri.getEncodedQuery());
}
// switch (uri.getPath()) {
// case SchemeConstants.PATH_OPEN_GAME: {
// /**
// * 对于联运游戏传入的game_id为0game_url为对应的游戏链接aid传联运游戏的aid
// * 对于非联运游戏传入非联运游戏的game_idgame_url不传aid传0
// */
// GameModel game = new GameModel();
// int gameId = Integer.parseInt(uri.getQueryParameter(SchemeConstants.PARAMS_GAMEID));
// game.setId(gameId);
//// if (AppDebugConfig.IS_DEBUG) {
//// int debugId = 1049;
//// game.setId(debugId);
//// }
// if (gameId == 0) {
// // cooperate
// int aid = Integer.parseInt(uri.getQueryParameter(SchemeConstants.PARAMS_AID));
// game.setAid(aid);
// String gameUrl = uri.getQueryParameter(SchemeConstants.PARAMS_GAMEURL);
// game.setUrl(gameUrl);
// }
// ApiRequester.requestGameDetail(this, game);
//
// break;
// }
// case SchemeConstants.PATH_OPEN_ARTICLE: {
//
// String url = uri.getQueryParameter(SchemeConstants.PARAMS_ARTICLE_URL);
// String title = uri.getQueryParameter(SchemeConstants.PARAMS_ARTICLE_TITLE);
//
// if (!TextUtils.isEmpty(url) && !TextUtils.isEmpty(title)) {
// Bundle args = new Bundle();
// args.putString(Fragment_Browser_Web.ARGS_URL, url);
// args.putString(Fragment_Browser_Web.ARGS_TITLE, getString(R.string.title_article_detail));
// CommonActivity.startFragment(this, Fragment_Browser_Web.class, args);
// }
//
// break;
// }
// default:
// break;
// }
} catch (Exception e) {
if (AppDebugConfig.IS_DEBUG) {
// Debug_SDK.e(e);
}
}
}
@Override
public boolean onHandleBackPressed() {
onBackPressed();
return true;
}
protected boolean handleBackPressed() {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this);
}
final Fragment curFragment = getTopFragment();
if (curFragment instanceof OnBackPressedListener &&
((OnBackPressedListener) curFragment).onHandleBackPressed()) {
return true;
}
if (popFragment()) {
return true;
}
return false;
}
public Fragment getTopFragment() {
return getSupportFragmentManager().findFragmentById(R.id.layout_activity_content);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final int layoutId = getLayoutId();
if (layoutId != 0) {
mContentView = getLayoutInflater().inflate(layoutId, null);
setContentView(mContentView);
}
if (savedInstanceState == null) {
handleRedirectIntent(getIntent());
}
AppManager.getInstance().addActivity(this);
}
protected abstract int getLayoutId();
/**
* 1、判断当前是否存在某Fragment例如下载管理器已经在栈中则不重新启动而将其带到最上层 (FindFragmentWithTag)
* 2、支持URI调用
* 是否需要重新导向到其他Activity
*/
protected void handleRedirectIntent(Intent intent) {
try {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this, intent.toUri(Intent.URI_INTENT_SCHEME));
}
// 1、根据从网页抓取到的Intent跳转进来处理custom uri
// final Uri uri = intent.getData();
// if (uri != null && SchemeConstants.SCHEME_FFSS.equals(uri.getScheme())) {
// handleRedirectFromUri(uri);
// return;
// }
//
// // 2、根据序列化的数据来重新构建Fragment实例若没有则是旧的形式来决定传参
// final String fragmentName = intent.getStringExtra(ARGS_FRAGMENT_NAME);
// if (AppDebugConfig.IS_DEBUG) {
// AppDebugConfig.logMethodWithParams(this, fragmentName);
// }
// if (!TextUtils.isEmpty(fragmentName)) {
// final Bundle args = intent.getBundleExtra(ARGS_FRAGMENT_BUNDLE);
// final Fragment fragment = Fragment.instantiate(this, fragmentName, args);
// if (fragment instanceof DialogFragment) {
// ((DialogFragment) fragment).show(getSupportFragmentManager(), fragmentName);
// } else {
// getSupportFragmentManager().beginTransaction().replace(R.id.layout_activity_content, fragment)
// .commitAllowingStateLoss();
// }
// }
} catch (Throwable e) {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this, e);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
AppManager.getInstance().finishActivity(this);
}
@Override
public void addFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction().add(R.id.layout_activity_content, fragment)
.addToBackStack(fragment.toString()).commitAllowingStateLoss();
Util_System_Keyboard.hideSoftKeyboard(this);
}
@Override
public void replaceFragment(Fragment toReplace) {
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.layout_activity_content, toReplace).addToBackStack(toReplace.toString());
ft.commitAllowingStateLoss();
Util_System_Keyboard.hideSoftKeyboard(this);
}
@Override
public void removeFragment(Fragment toRemove) {
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.layout_activity_content, toRemove).addToBackStack(toRemove.toString());
ft.commitAllowingStateLoss();
Util_System_Keyboard.hideSoftKeyboard(this);
}
@Override
public void showFragment(Fragment toShow) {
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.show(toShow).addToBackStack(toShow.toString());
ft.commitAllowingStateLoss();
Util_System_Keyboard.hideSoftKeyboard(this);
}
@Override
public void hideFragment(Fragment toHide) {
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.show(toHide).addToBackStack(toHide.toString());
ft.commitAllowingStateLoss();
Util_System_Keyboard.hideSoftKeyboard(this);
}
@Override
public boolean popFragment() {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this, getSupportFragmentManager().getBackStackEntryCount());
}
final int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
if (backStackCount > 0) {
Util_System_Keyboard.hideSoftKeyboard(this);
getSupportFragmentManager().popBackStack();
return true;
}
return false;
}
@Override
public void popFragmentToBase() {
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
/**
* forward ActivityResultListener to fragments this activity hosts
*
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this, requestCode, resultCode, data);
}
final Fragment fragment = getTopFragment();
if (fragment != null) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
@Override
public void onBackPressed() {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this);
}
if (handleBackPressed()) {
return;
}
// default finish activity
Util_System_Keyboard.hideSoftKeyboard(this);
finish();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
handleRedirectIntent(intent);
}
}

View File

@ -0,0 +1,94 @@
package com.gh.base;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.gh.common.util.AppDebugConfig;
/**
* @author: CsHeng (csheng1204[at]gmail[dot]com)
* Date: 13-7-25
* Time: 下午8:42
*/
public class BaseAppCompatActivityLog extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodName(this);
}
}
@Override
protected void onStop() {
super.onStop();
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodName(this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodName(this);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodName(this);
}
}
@Override
public void onLowMemory() {
super.onLowMemory();
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodName(this);
}
}
@Override
protected void onPause() {
super.onPause();
try {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodName(this);
}
} catch (Throwable e) {
}
}
@Override
protected void onResume() {
super.onResume();
try {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodName(this);
}
} catch (Throwable e) {
}
}
@Override
protected void onStart() {
super.onStart();
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodName(this);
}
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodName(this);
}
}
}

View File

@ -0,0 +1,138 @@
package com.gh.base;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;
import com.gh.gamecenter.R;
import com.readystatesoftware.systembartint.SystemBarTintManager;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* Created by csheng on 15-10-12.
*/
public abstract class BaseAppCompatToolBarActivity extends BaseAppCompatActivity implements ToolbarController {
private Toolbar mToolbar;
private SystemBarTintManager mTintManager;
// TODO 获取沉浸栏管理,要进行版本判断或者判断是否为空
protected SystemBarTintManager getTintManager() {
return mTintManager;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initToolbar();
// Util_Window.initStatusBarColor(getWindow(), ContextCompat.getColor(this, R.color.theme));
initStatusBar();
}
private void initToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar_navigation);
if (mToolbar != null) {
mToolbar.setTitle("");
setSupportActionBar(mToolbar);
}
}
private void initStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
setTranslucentStatus(true);
mTintManager = new SystemBarTintManager(this);
mTintManager.setStatusBarTintEnabled(true);
// mTintManager.setNavigationBarTintEnabled(true);
if (Build.MANUFACTURER.equals("Meizu") || Build.MANUFACTURER.equals("Xiaomi")) {
mTintManager.setStatusBarTintColor(Color.WHITE);
} else {
mTintManager.setStatusBarTintColor(Color.BLACK);
}
switch (Build.MANUFACTURER) {
case "Meizu":
try {
Window window = getWindow();
if (window != null) {
WindowManager.LayoutParams lp = window.getAttributes();
Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
value |= bit;
meizuFlags.setInt(lp, value);
window.setAttributes(lp);
}
} catch (Exception e) {
e.printStackTrace();
}
break;
case "Xiaomi":
try {
Window window = getWindow();
if (window != null) {
Class<?> clazz = window.getClass();
Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
int darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(window, darkModeFlag, darkModeFlag);
}
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
}
}
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);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
return onNavigationIconClicked();
}
return super.onOptionsItemSelected(item);
}
protected abstract boolean onNavigationIconClicked();
@Override
public void setNavigationTitle(int res) {
mToolbar.setTitle(res);
}
@Override
public void setNavigationTitle(CharSequence res) {
mToolbar.setTitle(res);
}
@Override
public Toolbar getToolBar() {
return mToolbar;
}
}

View File

@ -2,7 +2,6 @@ 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;
@ -13,6 +12,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.common.util.ApkActiveUtils;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DisplayUtils;
@ -34,6 +34,9 @@ import com.gh.gamecenter.eventbus.EBPackage;
import com.gh.gamecenter.manager.PackageManager;
import com.tencent.tauth.Tencent;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
/**
* Created by Administrator on 2016/9/19.
* 游戏详情、新闻详情基类(控制底部下载栏)
@ -55,14 +58,11 @@ public abstract class BaseDetailActivity extends BaseActivity implements View.On
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) {
@ -79,33 +79,45 @@ public abstract class BaseDetailActivity extends BaseActivity implements View.On
}
};
@Override
protected int getLayoutId() {
return R.layout.activity_detail;
}
//接收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 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);
// 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));
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(
params.addRule(RelativeLayout.CENTER_VERTICAL);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
RelativeLayout reuse_actionbar = (RelativeLayout) mContentView.findViewById(
R.id.reuse_actionbar);
reuse_actionbar.addView(iv_share, params);
init(contentView);
// init(contentView);
actionbar_tv_title = (TextView) findViewById(R.id.actionbar_tv_title);
detail_rv_show = (RecyclerView) findViewById(R.id.detail_rv_show);
@ -126,16 +138,10 @@ public abstract class BaseDetailActivity extends BaseActivity implements View.On
}
//接收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);
}
protected void onPause() {
super.onPause();
DownloadManager.getInstance(this).removeObserver(dataWatcher);
}
@Override
@ -149,12 +155,6 @@ public abstract class BaseDetailActivity extends BaseActivity implements View.On
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);
@ -295,6 +295,7 @@ public abstract class BaseDetailActivity extends BaseActivity implements View.On
}
// 接收下载被删除消息
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(EBDownloadStatus status) {
if ("delete".equals(status.getStatus())
&& gameEntity != null
@ -308,13 +309,17 @@ public abstract class BaseDetailActivity extends BaseActivity implements View.On
}
// 接受安装、卸载消息
@Subscribe(threadMode = ThreadMode.MAIN)
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);
&& gameEntity.getApk().size() > 0) {
for (ApkEntity apkEntity : gameEntity.getApk()) {
String packageName = apkEntity.getPackageName();
if (packageName.equals(busFour.getPackageName())) {
ApkActiveUtils.filterHideApk(gameEntity);
initDownload(false);
}
}
}
}
@ -327,15 +332,15 @@ public abstract class BaseDetailActivity extends BaseActivity implements View.On
if (NetworkUtils.isWifiConnected(this)) {
download();
} else {
DialogUtils.showDownloadDialog(this, new DialogUtils.ConfiremListener() {
DialogUtils.showDownloadDialog(this, new DialogUtils.ConfirmListener() {
@Override
public void onConfirem() {
public void onConfirm() {
download();
}
});
}
} else {
DownloadDialog.getInstance(this).showPopupWindow(v, gameEntity, entrance, name + ":" + title);
DownloadDialog.getInstance(this).showPopupWindow(v, gameEntity, mEntrance, name + ":" + title);
}
} else {
toast("稍等片刻~!游戏正在上传中...");
@ -343,11 +348,8 @@ public abstract class BaseDetailActivity extends BaseActivity implements View.On
} 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);
DownloadManagerActivity.startDownloadManagerActivity(this, gameEntity.getApk().get(0).getUrl()
, mEntrance + "+(" + name + "[" + title + "])");
} else if ("安装".equals(str)) {
PackageUtils.launchSetup(this, mDownloadEntity.getPath());
}
@ -372,9 +374,9 @@ public abstract class BaseDetailActivity extends BaseActivity implements View.On
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, "下载开始");
DataUtils.onGameDownloadEvent(this, gameEntity.getName(), apkEntity.getPlatform(), mEntrance, "下载开始");
DownloadManager.createDownload(this, apkEntity, gameEntity, method, entrance, name + ":" + title);
DownloadManager.createDownload(this, apkEntity, gameEntity, method, mEntrance, name + ":" + title);
detail_tv_download.setVisibility(View.GONE);
detail_pb_progressbar.setVisibility(View.VISIBLE);

View File

@ -1,17 +1,19 @@
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 android.widget.Toast;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.listener.OnCallBackListener;
import org.greenrobot.eventbus.EventBus;
import butterknife.ButterKnife;
import de.greenrobot.event.EventBus;
/**
* Created by LGT on 2016/9/4.
@ -19,75 +21,80 @@ import de.greenrobot.event.EventBus;
*/
public class BaseFragment extends Fragment implements OnCallBackListener {
protected View view;
protected View view;
protected Handler handler = new Handler();
protected boolean isEverpause;
protected boolean isEverpause;
protected String mEntrance;
protected void init(int layout) {
view = View.inflate(getActivity(), layout, null);
protected void init(int layout) {
view = View.inflate(getActivity(), layout, null);
ButterKnife.bind(this, view);
}
ButterKnife.bind(this, view);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isEverpause = false;
EventBus.getDefault().register(this);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mEntrance = getActivity().getIntent().getStringExtra(EntranceUtils.KEY_ENTRANCE);
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;
}
@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 onResume() {
super.onResume();
isEverpause = false;
}
@Override
public void onPause() {
super.onPause();
isEverpause = true;
}
@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 onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
public void toast(String msg) {
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
}
@Override
public void loadDone() {
public boolean isEverpause() {
return isEverpause;
}
}
@Override
public void loadDone() {
@Override
public void loadDone(Object obj) {
}
}
@Override
public void loadDone(Object obj) {
@Override
public void loadError() {
}
}
@Override
public void loadError() {
@Override
public void loadEmpty() {
}
}
@Override
public void loadEmpty() {
}
}

View File

@ -1,185 +1,206 @@
package com.gh.base;
import android.annotation.TargetApi;
import android.content.Context;
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.setStatusBarTintResource(R.color.theme);
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();
}
}
//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.*;
//import android.view.View.OnClickListener;
//import android.view.ViewGroup.LayoutParams;
//import android.widget.*;
//import butterknife.ButterKnife;
//import com.gh.common.constant.Config;
//import com.gh.common.util.*;
//import com.gh.download.DownloadManager;
//import com.gh.gamecenter.R;
//import com.gh.gamecenter.eventbus.EBShowDialog;
//import com.readystatesoftware.systembartint.SystemBarTintManager;
//import com.readystatesoftware.systembartint.SystemBarTintManager.SystemBarConfig;
//import de.greenrobot.event.EventBus;
//
//import java.lang.reflect.Field;
//import java.lang.reflect.Method;
//import java.util.ArrayList;
//
//public class BaseFragmentActivity extends FragmentActivity {
//
// protected String mEntrance;
//
// private boolean isPause;
//
// @Override
// protected void onCreate(Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
// AppManager.getInstance().addActivity(this);
// EventBus.getDefault().register(this);
// mEntrance = getIntent().getStringExtra("mEntrance");
// if (getIntent().getBundleExtra("data") != null) {
// mEntrance = getIntent().getBundleExtra("data").getString("mEntrance");
// }
// }
//
// 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);
// if (Build.MANUFACTURER.equals("Meizu") || Build.MANUFACTURER.equals("Xiaomi")) {
// tintManager.setStatusBarTintColor(Color.WHITE);
// } else {
// tintManager.setStatusBarTintColor(Color.BLACK);
// }
// SystemBarConfig config = tintManager.getConfig();
// contentView.setPadding(0, config.getPixelInsetTop(false), 0,
// config.getPixelInsetBottom());
//
// if (Build.MANUFACTURER.equals("Meizu")) {
// try {
// Window window = getWindow();
// if (window != null) {
// WindowManager.LayoutParams lp = window.getAttributes();
// Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
// Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
// darkFlag.setAccessible(true);
// meizuFlags.setAccessible(true);
// int bit = darkFlag.getInt(null);
// int value = meizuFlags.getInt(lp);
// value |= bit;
// meizuFlags.setInt(lp, value);
// window.setAttributes(lp);
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// } else if (Build.MANUFACTURER.equals("Xiaomi")) {
// try {
// Window window = getWindow();
// if (window != null) {
// Class<?> clazz = window.getClass();
// Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
// Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
// int darkModeFlag = field.getInt(layoutParams);
// Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
// extraFlagField.invoke(window, darkModeFlag, darkModeFlag);
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// }
//
// 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();
// }
// });
// }
//
// 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.ConfirmListener() {
// @Override
// public void onConfirm() {
// 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);
// AppManager.getInstance().finishActivity(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,26 @@
package com.gh.base;
import android.support.v4.app.Fragment;
/**
* @author CsHeng
* @Date 15-9-29
* @Time 上午10:24
*/
public interface FragmentNavigationDelegate {
void addFragment(Fragment toAdd);
void replaceFragment(Fragment toReplace);
void removeFragment(Fragment toRemove);
void showFragment(Fragment toShow);
void hideFragment(Fragment toHide);
boolean popFragment();
void popFragmentToBase();
}

View File

@ -0,0 +1,54 @@
package com.gh.base;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;
/**
* 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) {
}
@Override
public void onActivityPaused(Activity 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,16 @@ 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.AppDebugConfig;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.FileUtils;
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.xiaomi.mipush.sdk.ErrorCode;
import com.xiaomi.mipush.sdk.MiPushClient;
import com.xiaomi.mipush.sdk.MiPushCommandMessage;
@ -41,6 +40,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 +72,241 @@ 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 = AppController.getInstance().getChannel();
if ("ALL".equals(channel) || channel.equalsIgnoreCase(packageChannel)) {
String type = jsonObject.getString(KEY_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();
}
}
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);
}
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();
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;
}
RemoteViews remoteViews = null;
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();
}
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);
}
notification.defaults = Notification.DEFAULT_SOUND;// 添加系统默认声音
notification.flags |= Notification.FLAG_AUTO_CANCEL; // FLAG_AUTO_CANCEL表明当通知被用户点击时通知将被清除。
nManager.notify(((int) System.currentTimeMillis() / 1000), notification);// 通过通知管理器来发起通知。如果id不同则每click在status哪里增加一个提示
}
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;
}
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"));
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();
}
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;
}
notification.defaults = Notification.DEFAULT_SOUND;// 添加系统默认声音
notification.flags |= Notification.FLAG_AUTO_CANCEL; // FLAG_AUTO_CANCEL表明当通知被用户点击时通知将被清除。
nManager.notify(((int) System.currentTimeMillis() / 1000), notification);// 通过通知管理器来发起通知。如果id不同则每click在status哪里增加一个提示
}
@Override
public void onNotificationMessageClicked(Context context, MiPushMessage message) {
Log.v(AppController.TAG, "onNotificationMessageClicked 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;
}
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();
}
}
@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);
if (HOST_ARTICLE.equals(type)) {
bundle.putString(KEY_TO, "NewsDetailActivity");
bundle.putString(KEY_NEWSID, target);
} else if (HOST_GAME.equals(type)) {
bundle.putString(KEY_TO, "GameDetailActivity");
bundle.putString(KEY_GAMEID, target);
} else if (HOSt_COLUMN.equals(type)) {
bundle.putString(KEY_TO, "SubjectActivity");
bundle.putString(KEY_ID, target);
} else if (HOST_WEB.equals(type)) {
bundle.putString(KEY_TO, "WebActivity");
bundle.putString(KEY_URL, target);
}
EntranceUtils.jumpActivity(context, bundle);
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onNotificationMessageArrived(Context context,
MiPushMessage message) {
Log.v(AppController.TAG, "onNotificationMessageArrived is called. "
+ message.toString());
}
@Override
public void onNotificationMessageArrived(Context context,
MiPushMessage message) {
if (BuildConfig.DEBUG) {
AppDebugConfig.logMethodWithParams(this, message);
}
}
@Override
public void onCommandResult(Context context, MiPushCommandMessage message) {
Log.v(AppController.TAG, "onCommandResult is called. "
+ message.toString());
@Override
public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {
if (BuildConfig.DEBUG) {
AppDebugConfig.logMethodWithParams(this, message);
}
}
String command = message.getCommand();
List<String> arguments = message.getCommandArguments();
@Override
public void onCommandResult(Context context, MiPushCommandMessage message) {
if (BuildConfig.DEBUG) {
AppDebugConfig.logMethodWithParams(this, message);
}
if (MiPushClient.COMMAND_SET_ALIAS.equals(command)) {
if (message.getResultCode() == ErrorCode.SUCCESS) {
mAlias = arguments.get(0);
}
}
String command = message.getCommand();
List<String> arguments = message.getCommandArguments();
if (TextUtils.isEmpty(mAlias)) {
//添加别名
MiPushClient.setAlias(context, TokenUtils.getDeviceId(context), null);
}
}
if (MiPushClient.COMMAND_SET_ALIAS.equals(command)) {
if (message.getResultCode() == ErrorCode.SUCCESS) {
mAlias = arguments.get(0);
}
}
@Override
public void onReceiveRegisterResult(Context context,
MiPushCommandMessage message) {
Log.v(AppController.TAG, "onReceiveRegisterResult is called. "
+ message.toString());
}
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,34 @@ 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);
if (EntranceUtils.HOST_ARTICLE.equals(type)) {
bundle.putString(EntranceUtils.KEY_TO, "NewsDetailActivity");
bundle.putString(EntranceUtils.KEY_NEWSID, target);
} else if (EntranceUtils.HOST_GAME.equals(type)) {
bundle.putString(EntranceUtils.KEY_TO, "GameDetailActivity");
bundle.putString(EntranceUtils.KEY_GAMEID, target);
} else if (EntranceUtils.HOSt_COLUMN.equals(type)) {
bundle.putString(EntranceUtils.KEY_TO, "SubjectActivity");
bundle.putString(EntranceUtils.KEY_ID, target);
} else if (EntranceUtils.HOST_WEB.equals(type)) {
bundle.putString(EntranceUtils.KEY_TO, "WebActivity");
bundle.putString(EntranceUtils.KEY_URL, target);
}
EntranceUtils.jumpActivity(context, bundle);
} catch (JSONException e) {
e.printStackTrace();
}
}
}

View File

@ -1,17 +1,15 @@
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.text.TextUtils;
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;
@ -19,6 +17,7 @@ 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.common.util.EntranceUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.ConcernActivity;
import com.gh.gamecenter.DownloadManagerActivity;
@ -28,178 +27,249 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.manager.PackageManager;
import de.greenrobot.event.EventBus;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
/**
* Created by LGT on 2016/9/9.
* 工具栏 搜索控制
*/
public class HomeFragment extends Fragment implements View.OnClickListener {
public class HomeFragment extends Fragment implements View.OnClickListener, SearchBarHint {
protected View view;
protected View view;
protected Handler handler = new Handler();
private TextView downloadHint;
private TextView searchHint;
private TextView downloadHint;
private TextView searchHint;
private AlphaAnimation mAlphaAnimation;
private String hint;
private ArrayList<String> hintList;
private int hintIndex;
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (!TextUtils.isEmpty(hint)) {
outState.putString("hint", hint);
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
hintList = savedInstanceState.getStringArrayList("hint");
}
if (savedInstanceState != null) {
hint = savedInstanceState.getString("hint");
}
hintIndex = 0;
view = View.inflate(getActivity(), R.layout.fragment_home, null);
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, sp.getInt("actionbar_height",
DisplayUtils.dip2px(getActivity(), 48)));
// 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);
// 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();
initActionBar();
EventBus.getDefault().register(this);
}
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);
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
if (container != null) {
container.removeView(view);
}
return view;
}
mAlphaAnimation = new AlphaAnimation(1f, 0.2f);
mAlphaAnimation.setDuration(300);
mAlphaAnimation.setStartOffset(5000);
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);
scaleAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
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);
}
@Override
public void onAnimationEnd(Animation animation) {
if (mAlphaAnimation != null) {
searchHint.setAnimation(mAlphaAnimation);
mAlphaAnimation.start();
}
}
searchHint = (TextView) view.findViewById(R.id.actionbar_search_input);
searchHint.setOnClickListener(this);
if (!TextUtils.isEmpty(hint)) {
searchHint.setHint(hint);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
@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(), "搜索图标", "主页");
mAlphaAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
Intent intent = new Intent(getActivity(), SearchActivity.class);
intent.putExtra("clicked", true);
intent.putExtra("hint", hint);
intent.putExtra("entrance", "(工具栏)");
startActivity(intent);
} else if (id == R.id.actionbar_search_input) {
DataUtils.onEvent(getActivity(), "主页", "搜索框");
DataCollectionUtils.uploadClick(getActivity(), "搜索框", "主页");
}
Intent intent = new Intent(getActivity(), SearchActivity.class);
intent.putExtra("clicked", false);
intent.putExtra("hint", hint);
intent.putExtra("entrance", "(工具栏)");
startActivity(intent);
} else if (id == R.id.actionbar_notification) {
DataUtils.onEvent(getActivity(), "主页", "关注图标");
DataCollectionUtils.uploadClick(getActivity(), "关注图标", "主页");
@Override
public void onAnimationEnd(Animation animation) {
// 切换数据
if (hintIndex > hintList.size() - 1) {
hintIndex = 0;
}
searchHint.setHint(hintList.get(hintIndex));
hintIndex++;
Intent intent = new Intent(getActivity(), ConcernActivity.class);
intent.putExtra("entrance", "(工具栏)");
startActivity(intent);
}
}
if (scaleAnimation != null) {
searchHint.setAnimation(scaleAnimation);
scaleAnimation.start();
}
}
// 打开下载按钮事件
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);
}
}
}
@Override
public void onAnimationRepeat(Animation animation) {
public void setHint(String hint) {
if (!TextUtils.isEmpty(hint)) {
this.hint = hint;
if (searchHint != null) {
searchHint.setHint(hint);
}
}
}
}
});
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);
}
}
if (hintList != null && hintList.size() > 0) {
if (hintList.size() > 1) {
searchHint.setAnimation(mAlphaAnimation);
} else {
String hint = hintList.get(0);
searchHint.setHint(hint);
}
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
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;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (hintList != null && !hintList.isEmpty()) {
outState.putStringArrayList("hint", hintList);
}
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
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(), "下载图标", "主页");
DownloadManagerActivity.startDownloadManagerActivity(getContext(), null, "(工具栏)");
} 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(EntranceUtils.KEY_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(EntranceUtils.KEY_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(EntranceUtils.KEY_ENTRANCE, "(工具栏)");
startActivity(intent);
}
}
// 打开下载按钮事件
@Subscribe(threadMode = ThreadMode.MAIN)
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);
}
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
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 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);
}
}
}
}

View File

@ -0,0 +1,9 @@
package com.gh.base;
/**
* Forward activity onBackPressed() events to fragment
* (If nested fragments need this, just forward again)
*/
public interface OnBackPressedListener {
public boolean onHandleBackPressed();
}

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,17 @@
package com.gh.base;
import android.support.annotation.StringRes;
import android.support.v7.widget.Toolbar;
/**
* Created by csheng on 15-10-12.
*/
public interface ToolbarController {
void setNavigationTitle(@StringRes int res);
void setNavigationTitle(CharSequence res);
Toolbar getToolBar();
}

View File

@ -4,18 +4,33 @@ package com.gh.common.constant;
import android.content.Context;
import android.content.SharedPreferences;
import com.gh.gamecenter.BuildConfig;
public class Config {
public static final String HOST = "http://api.ghzhushou.com/v2d4/";
public static final String USER_HOST = "http://user.ghzhushou.com/v1d2/";
public static final String COMMENT_HOST = "http://comment.ghzhushou.com/v1d1/";
public static final String DATA_HOST = "http://data.ghzhushou.com/";
public static final String LIBAO_HOST = "http://libao.ghzhushou.com/v1d1/";
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 boolean isShow(Context context) {
SharedPreferences sp = context.getSharedPreferences(Config.PREFERENCE, Context.MODE_PRIVATE);
return sp.getBoolean("isShow", true);
}
public static final String PREFERENCE = "ghzhushou";
// Third-Party confs
public static final String WECHAT_APPID = BuildConfig.WECHAT_APPID;
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 TD_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 boolean isShow(Context context) {
SharedPreferences sp = context.getSharedPreferences(Config.PREFERENCE, Context.MODE_PRIVATE);
return sp.getBoolean("isShow", true);
}
}

View File

@ -2,41 +2,41 @@ 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 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;
}

View File

@ -5,23 +5,22 @@ 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 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 = 16;
}

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

@ -0,0 +1,143 @@
package com.gh.common.util;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
/**
* 应用程序Activity管理类用于Activity和Intent相关的管理
*
* @author CsHeng
* @version 1.0
*/
public class AppManager {
private static AppManager mInstance;
private Stack<Activity> mActivityStack;
private AppManager() {
mActivityStack = new Stack<>();
}
/**
* 单一实例
*/
public static AppManager getInstance() {
if (mInstance == null) {
mInstance = new AppManager();
}
return mInstance;
}
public boolean isEmpty() {
return mActivityStack.isEmpty();
}
/**
* 添加Activity到堆栈
*/
public void addActivity(Activity activity) {
mActivityStack.add(activity);
}
/**
* 获取当前Activity堆栈中最后一个压入的
*/
public Activity currentActivity() {
return mActivityStack.lastElement();
}
/**
* 结束当前Activity堆栈中最后一个压入的
*/
public void finishActivity() {
final Activity activity = mActivityStack.lastElement();
finishActivity(activity);
}
/**
* 结束指定的Activity
*/
public void finishActivity(Activity activity) {
if (activity != null) {
mActivityStack.remove(activity);
activity.finish();
}
}
/**
* 结束指定类名的Activity
*/
public void finishActivity(Class<?> cls) {
for (Activity activity : mActivityStack) {
if (activity.getClass().equals(cls)) {
finishActivity(activity);
}
}
}
public boolean isOnStack(Activity activity) {
return mActivityStack.contains(activity);
}
public Intent[] getStartIntents(Intent... intent) {
List<Intent> intentList = getCurrentIntents();
if (intentList != null) {
Collections.addAll(intentList, intent);
return intentList.toArray(new Intent[intentList.size()]);
}
return intent;
}
public List<Intent> getCurrentIntents() {
List<Intent> intentList = new ArrayList<>();
for (Activity activity : mActivityStack) {
intentList.add(activity.getIntent());
}
return intentList;
}
/**
* 退出应用程序
*/
public void appExit(Context context) {
try {
finishAllActivity();
/* Need Permission */
// ActivityManager activityMgr= (ActivityManager)
// context.getSystemService(Context.ACTIVITY_SERVICE);
// activityMgr.restartPackage(context.getPackageName());
// activityMgr.killBackgroundProcesses(context.getPackageName());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 结束所有Activity
*/
public void finishAllActivity() {
for (Activity activity : mActivityStack) {
activity.finish();
}
mActivityStack.clear();
try {
android.os.Process.killProcess(android.os.Process.myPid());
} catch (Exception e) {
}
}
public void destroy() {
if (mActivityStack != null) {
mActivityStack.clear();
}
mInstance = null;
}
}

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

@ -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,198 @@
package com.gh.common.util;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.LinearLayout;
import android.widget.TextView;
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.entity.CommentEntity;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* Created by khy on 2017/3/22.
*/
public class CommentUtils {
public static void setCommentTime(TextView textView, long time) {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
try {
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));
if (hour == 0) {
if (min < 60) {
textView.setText("刚刚");
} else {
textView.setText(String.format(Locale.getDefault(), "%d分钟前", (int) (min / 60)));
}
} else {
textView.setText(String.format(Locale.getDefault(), "%d小时前", hour));
}
} else if (day >= today - 86400 * 1000 && day < today) {
format.applyPattern("HH:mm");
textView.setText("昨天 ");
} else {
format.applyPattern("yyyy-MM-dd");
textView.setText(format.format(day));
}
} catch (ParseException e) {
e.printStackTrace();
format.applyPattern("yyyy-MM-dd");
textView.setText(format.format(time * 1000));
}
}
public static void showReportDialog(final CommentEntity commentEntity, final Context mContext
, final MessageDetailAdapter.OnCommentCallBackListener mCallBackListener, final String newsId) {
CommentDao commentDao = new CommentDao(mContext);
final Dialog dialog = new Dialog(mContext);
LinearLayout container = new LinearLayout(mContext);
container.setOrientation(LinearLayout.VERTICAL);
container.setBackgroundColor(Color.WHITE);
container.setPadding(0, DisplayUtils.dip2px(mContext, 12), 0, DisplayUtils.dip2px(mContext, 12));
List<String> dialogType = new ArrayList<>();
if (!commentDao.isMyComment(commentEntity.getId())) {
dialogType.add("回复");
}
dialogType.add("复制");
dialogType.add("举报");
if (commentEntity.getParent() != null) {
dialogType.add("查看对话");
}
for (String s : dialogType) {
final TextView reportTv = new TextView(mContext);
reportTv.setText(s);
reportTv.setTextSize(17);
reportTv.setTextColor(ContextCompat.getColor(mContext, R.color.title));
reportTv.setBackgroundResource(R.drawable.textview_white_style);
int widthPixels = mContext.getResources().getDisplayMetrics().widthPixels;
reportTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTv.setPadding(DisplayUtils.dip2px(mContext, 20), DisplayUtils.dip2px(mContext, 12),
0, DisplayUtils.dip2px(mContext, 12));
container.addView(reportTv);
reportTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.cancel();
switch (reportTv.getText().toString()) {
case "回复":
if (mCallBackListener != null) {
mCallBackListener.showSoftInput(commentEntity);
} else if (!TextUtils.isEmpty(newsId)) {
mContext.startActivity(MessageDetailActivity.getMessageDetailIntent(mContext, commentEntity, newsId));
} else {
Utils.toast(mContext, "缺少关键属性");
}
break;
case "复制":
LibaoUtils.copyLink(commentEntity.getContent(), mContext);
break;
case "举报":
showReportTypeDialog(commentEntity, mContext);
break;
case "查看对话":
mContext.startActivity(CommentDetailActivity.getCommentDetailIntent(mContext, commentEntity.getId()));
break;
}
}
});
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(container);
dialog.show();
}
private static void showReportTypeDialog(final CommentEntity commentEntity, final Context mContext) {
final String[] arrReportType = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息",
"违法有害信息", "其它"};
int widthPixels = mContext.getResources().getDisplayMetrics().widthPixels;
final Dialog reportTypeDialog = new Dialog(mContext);
LinearLayout container = new LinearLayout(mContext);
container.setOrientation(LinearLayout.VERTICAL);
container.setPadding(0, DisplayUtils.dip2px(mContext, 12), 0, DisplayUtils.dip2px(mContext, 12));
container.setBackgroundColor(Color.WHITE);
for (final String s : arrReportType) {
TextView reportTypeTv = new TextView(mContext);
reportTypeTv.setText(s);
reportTypeTv.setTextSize(17);
reportTypeTv.setTextColor(ContextCompat.getColor(mContext, R.color.title));
reportTypeTv.setBackgroundResource(R.drawable.textview_white_style);
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));
container.addView(reportTypeTv);
reportTypeTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("comment_id", commentEntity.getId());
jsonObject.put("reason", s);
} catch (JSONException e) {
e.printStackTrace();
}
PostCommentUtils.addReportData(mContext, jsonObject.toString(), true,
new PostCommentUtils.PostCommentListener() {
@Override
public void postSuccess(JSONObject response) {
Utils.toast(mContext, "感谢您的举报");
}
@Override
public void postFailed(Throwable error) {
Utils.toast(mContext, "举报失败,请检查网络设置");
}
});
reportTypeDialog.cancel();
}
});
}
reportTypeDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
reportTypeDialog.setContentView(container);
reportTypeDialog.show();
}
}

View File

@ -14,9 +14,8 @@ import java.util.List;
/**
* Created by khy on 2016/11/8.
*
* <p>
* 初始化资讯关注-内容图片
*
**/
public class ConcernContentUtils {
@ -52,8 +51,8 @@ public class ConcernContentUtils {
}
}
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);
@ -87,14 +86,11 @@ public class ConcernContentUtils {
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

@ -6,13 +6,13 @@ import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONArray;
import de.greenrobot.event.EventBus;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.adapter.rxjava.HttpException;
import retrofit2.HttpException;
import rx.Observable;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
@ -62,7 +62,7 @@ public class ConcernUtils {
})
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Response<ResponseBody>(){
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(ResponseBody response) {
super.onResponse(response);

View File

@ -11,150 +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 < 2) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("key", args[0]);
map.put("from", args[1]);
if (args.length == 3) {
map.put("click", args[2]);
}
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 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 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 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,6 +2,7 @@ package com.gh.common.util;
import android.content.Context;
import com.gh.base.AppController;
import com.gh.download.DownloadEntity;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
@ -23,67 +24,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.getVersionName(context);
String user = Installation.getUUID(context);
String channel = AppController.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.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,8 +4,10 @@ import android.app.Activity;
import android.app.Application;
import android.content.Context;
import com.gh.common.constant.Config;
import com.tencent.stat.MtaSDkException;
import com.tencent.stat.StatConfig;
import com.tencent.stat.StatCrashReporter;
import com.tencent.stat.StatReportStrategy;
import com.tencent.stat.StatService;
import com.tendcloud.tenddata.TCAgent;
@ -20,29 +22,61 @@ 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(Application context, final boolean debug, String channel) {
//TalkingData
//dubug true release false
TCAgent.LOG_ON = true;
TCAgent.init(application);
TCAgent.setReportUncaughtExceptions(true);
TCAgent.LOG_ON = debug;
if (!debug) {
TCAgent.init(context, Config.TD_APPID, channel);
//TODO 去除为了测试MTA的问题这个版本不启用
// TCAgent.setReportUncaughtExceptions(true);
}
// 打开debug开关可查看mta上报日志或错误
// debug true release false
StatConfig.setDebugEnable(debug);
//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);
} catch (MtaSDkException e) {
e.printStackTrace();
if (!debug) {
//TODO 加入账号之后设置用户
// StatConfig.setCustomUserId(context, "userid");
// 收集未处理的异常
StatConfig.setAutoExceptionCaught(true);
StatConfig.setAntoActivityLifecycleStat(true);
// 设置数据上报策略
StatConfig.setStatSendStrategy(StatReportStrategy.PERIOD);
StatConfig.setSendPeriodMinutes(5);
StatConfig.init(context);
StatConfig.setInstallChannel(channel);
StatService.setContext(context);
StatService.registerActivityLifecycleCallbacks(context);
StatCrashReporter crashReporter = StatCrashReporter.getStatCrashReporter(context);
// 开启异常时的实时上报
crashReporter.setEnableInstantReporting(true);
// 开启java异常捕获
crashReporter.setJavaCrashHandlerStatus(true);
try {
// 开启收集服务
StatService.startStatService(context, Config.MTA_APPKEY, com.tencent.stat.common.StatConstants.VERSION);
} catch (MtaSDkException e) {
e.printStackTrace();
}
}
}
public static void onEvent(Context var0, String var1, String var2) {
@ -50,16 +84,6 @@ public class DataUtils {
StatService.trackCustomEvent(var0, var1, var2);
}
public static void onEvent(Context var0, String var1, String var2, Map<String, Object> var3) {
TCAgent.onEvent(var0, var1, var2, var3);
Properties prop = new Properties();
prop.setProperty("label", var2);
for (String key : var3.keySet()) {
prop.setProperty(key, var3.get(key) + "");
}
StatService.trackCustomKVEvent(var0, var1, prop);
}
public static void onPause(Activity var0) {
TCAgent.onPause(var0);
StatService.onPause(var0);
@ -78,23 +102,33 @@ public class DataUtils {
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();
prop.setProperty("label", var2);
for (String key : var3.keySet()) {
prop.setProperty(key, var3.get(key) + "");
}
StatService.trackCustomKVEvent(var0, var1, prop);
}
// 游戏下载
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 +136,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

@ -2,14 +2,11 @@ package com.gh.common.util;
import android.app.Activity;
import android.app.Dialog;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Handler;
import android.text.Html;
import android.text.Spanned;
@ -19,7 +16,6 @@ import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gh.base.AppController;
@ -36,422 +32,414 @@ import java.util.Map;
public class DialogUtils {
public static Dialog showWaitDialog(Context context, String msg) {
Dialog dialog = new Dialog(context);
View view = View.inflate(context, R.layout.set_wait_dialog, null);
TextView message = (TextView) view.findViewById(R.id.set_wait_message);
message.setText(msg);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.setCanceledOnTouchOutside(false);
dialog.show();
return dialog;
}
private static boolean isShow = false;
private static boolean isShow = false;
public static Dialog showWaitDialog(Context context, String msg) {
Dialog dialog = new Dialog(context);
View view = View.inflate(context, R.layout.set_wait_dialog, null);
TextView message = (TextView) view.findViewById(R.id.set_wait_message);
message.setText(msg);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.setCanceledOnTouchOutside(false);
dialog.show();
return dialog;
}
// 快传成绩单
public static void showKuaiChuanResult(final Activity activity, Handler handler, int requestCode, final String picName) {
// 快传成绩单
public static void showKuaiChuanResult(final Activity activity, Handler handler, int requestCode, final String picName) {
AppController.remove("FileInfo");
AppController.remove("FileInfo");
List<Map<String, String>> mapList = (List<Map<String, String>>) AppController.get("sendData", true);
if (mapList == null || mapList.size() == 0) return;
List<Map<String, String>> mapList = (List<Map<String, String>>) AppController.get("sendData", true);
if (mapList == null || mapList.size() == 0) return;
WifiMgr.getInstance(activity).disconnectCurrentNetwork(); // 断开当前WiFi
WifiMgr.getInstance(activity).disconnectCurrentNetwork(); // 断开当前WiFi
// int heightPixels = getContext().getResources().getDisplayMetrics().heightPixels;
// int widthPixels = getContext().getResources().getDisplayMetrics().widthPixels;
int filesCount = mapList.size();
int filesSize = 0;
int sendTime = 0;
int filesCount = mapList.size();
int filesSize = 0;
int sendTime = 0;
View view = View.inflate(activity
, R.layout.dialog_kuaichuan, null);
final LinearLayout mShareLl = (LinearLayout) view.findViewById(R.id.kuaichuan_dialog_ll);
final LinearLayout mShareBottomLl = (LinearLayout) view.findViewById(R.id.kuaichuan_dialog_share_rl);
RelativeLayout content = (RelativeLayout) view.findViewById(R.id.kuaichuan_dialog);
LinearLayout shareIconLl = (LinearLayout) view.findViewById(R.id.kuaichuan_icon_ll);
ImageView qrCode = (ImageView) view.findViewById(R.id.kuaichuan_qrcode);
TextView dateTv = (TextView) view.findViewById(R.id.kuaichuan_dialog_date);
TextView countTv = (TextView) view.findViewById(R.id.kuaichuan_send_count);
TextView sizeTv = (TextView) view.findViewById(R.id.kuaichuan_send_size);
TextView speedTv = (TextView) view.findViewById(R.id.kuaichuan_send_speed);
TextView timeCount = (TextView) view.findViewById(R.id.kuaichuan_time_count);
TextView timeTv = (TextView) view.findViewById(R.id.kuaichuan_time_tv);
TextView sendCountTv = (TextView) view.findViewById(R.id.dialog_send_tv);
ImageView closeIv = (ImageView) view.findViewById(R.id.kuaichuan_dialog_colse);
View view = View.inflate(activity
, R.layout.dialog_kuaichuan, null);
final LinearLayout mShareLl = (LinearLayout) view.findViewById(R.id.kuaichuan_dialog_ll);
final LinearLayout mShareBottomLl = (LinearLayout) view.findViewById(R.id.kuaichuan_dialog_share_rl);
LinearLayout shareIconLl = (LinearLayout) view.findViewById(R.id.kuaichuan_icon_ll);
ImageView qrCode = (ImageView) view.findViewById(R.id.kuaichuan_qrcode);
TextView dateTv = (TextView) view.findViewById(R.id.kuaichuan_dialog_date);
TextView countTv = (TextView) view.findViewById(R.id.kuaichuan_send_count);
TextView sizeTv = (TextView) view.findViewById(R.id.kuaichuan_send_size);
TextView speedTv = (TextView) view.findViewById(R.id.kuaichuan_send_speed);
TextView timeCount = (TextView) view.findViewById(R.id.kuaichuan_time_count);
TextView timeTv = (TextView) view.findViewById(R.id.kuaichuan_time_tv);
TextView sendCountTv = (TextView) view.findViewById(R.id.dialog_send_tv);
ImageView closeIv = (ImageView) view.findViewById(R.id.kuaichuan_dialog_colse);
// content.setLayoutParams(new LinearLayout.LayoutParams((int)(((float)heightPixels)*0.85), (int)((float)widthPixels*0.81)));
final Dialog dialog = new Dialog(activity);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCanceledOnTouchOutside(false);
dialog.setContentView(view);
dialog.show();
final Dialog dialog = new Dialog(activity);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCanceledOnTouchOutside(false);
dialog.setContentView(view);
dialog.show();
Window dialogWindow = dialog.getWindow();
WindowManager m = activity.getWindowManager();
Display d = m.getDefaultDisplay();
WindowManager.LayoutParams p = dialogWindow.getAttributes();
p.height = (int) (d.getHeight() * 0.82);
p.width = (int) (d.getWidth() * 0.80);
dialogWindow.setAttributes(p);
Window dialogWindow = dialog.getWindow();
WindowManager m = activity.getWindowManager();
Display d = m.getDefaultDisplay();
if (dialogWindow != null) {
WindowManager.LayoutParams p = dialogWindow.getAttributes();
p.height = (int) (d.getHeight() * 0.82);
p.width = (int) (d.getWidth() * 0.80);
dialogWindow.setAttributes(p);
}
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日", Locale.getDefault());
dateTv.setText(format.format(new Date().getTime()));
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日", Locale.getDefault());
dateTv.setText(format.format(new Date().getTime()));
for (Map<String, String> map : mapList) {
int size = Integer.parseInt(map.get("apkSize"));
int time = 10;
try {
time = Integer.parseInt(map.get("sendTime"));
} catch (Exception e) {
e.printStackTrace();
}
for (Map<String, String> map : mapList) {
int size = Integer.parseInt(map.get("apkSize"));
int time = 10;
try {
time = Integer.parseInt(map.get("sendTime"));
} catch (Exception e) {
e.printStackTrace();
}
String apkPath = map.get("apkPath");
filesSize = filesSize + size;
sendTime = sendTime + time;
String apkPath = map.get("apkPath");
filesSize = filesSize + size;
sendTime = sendTime + time;
if (shareIconLl.getChildCount() >= 5) continue;
if (shareIconLl.getChildCount() >= 5) continue;
android.content.pm.PackageManager pm = activity.getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(apkPath,
android.content.pm.PackageManager.GET_ACTIVITIES);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
appInfo.sourceDir = apkPath;
appInfo.publicSourceDir = apkPath;
Bitmap bitmap = BitmapUtils.drawableToBitmap(appInfo.loadIcon(pm));
android.content.pm.PackageManager pm = activity.getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(apkPath,
android.content.pm.PackageManager.GET_ACTIVITIES);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
appInfo.sourceDir = apkPath;
appInfo.publicSourceDir = apkPath;
Bitmap bitmap = BitmapUtils.drawableToBitmap(appInfo.loadIcon(pm));
ImageView imageView = new ImageView(activity);
imageView.setLayoutParams(new LinearLayout.LayoutParams(DisplayUtils.dip2px(activity, 25)
, DisplayUtils.dip2px(activity, 24)));
imageView.setImageBitmap(bitmap);
shareIconLl.addView(imageView);
}
}
ImageView imageView = new ImageView(activity);
imageView.setLayoutParams(new LinearLayout.LayoutParams(DisplayUtils.dip2px(activity, 25)
, DisplayUtils.dip2px(activity, 24)));
imageView.setImageBitmap(bitmap);
shareIconLl.addView(imageView);
}
}
if (requestCode == 0x170) { // 发送
qrCode.setImageResource(R.drawable.kc_qrcode_120);
sendCountTv.setText("成功传送游戏");
} else {
qrCode.setImageResource(R.drawable.kc_qrcode_110);
sendCountTv.setText("成功接收游戏");
}
if (requestCode == 0x170) { // 发送
qrCode.setImageResource(R.drawable.kc_qrcode_120);
sendCountTv.setText("成功传送游戏");
} else {
qrCode.setImageResource(R.drawable.kc_qrcode_110);
sendCountTv.setText("成功接收游戏");
}
double size = (((float)filesSize/1024)/1024);
String sizeName;
if (size > 1024) {
DecimalFormat df = new DecimalFormat("#.0");
sizeName = df.format(size/1024) + "GB";
} else {
DecimalFormat df = new DecimalFormat("#.0");
sizeName = df.format(size) + "MB";
}
double size = (((float) filesSize / 1024) / 1024);
String sizeName;
if (size > 1024) {
DecimalFormat df = new DecimalFormat("#.0");
sizeName = df.format(size / 1024) + "GB";
} else {
DecimalFormat df = new DecimalFormat("#.0");
sizeName = df.format(size) + "MB";
}
if (sendTime == 0) {
sendTime = 1;
}
int i = (filesSize / 1024) / (sendTime / 1000);
String speed;
if (i >= 1000) {
float mSpeed = i / 1024f;
DecimalFormat df = new DecimalFormat("#.0");
String str = df.format(mSpeed);
if (str.length() > 4) {
str = str.substring(0, 4);
}
speed = str + "MB/s";
} else {
speed = i + "KB/s";
}
if (sendTime > 60000) {
timeCount.setText(String.valueOf(sendTime / 1000 / 60));
timeTv.setText("分钟传送完成");
} else {
timeCount.setText(String.valueOf(sendTime / 1000));
timeTv.setText("秒传送完成");
}
sizeTv.setText(sizeName);
speedTv.setText(speed);
countTv.setText(filesCount + "");
// 延迟操作,等待截图部分绘制完成
handler.postDelayed(new Runnable() {
@Override
public void run() {
mShareLl.setDrawingCacheEnabled(true);
mShareLl.buildDrawingCache();
Bitmap drawingCache = mShareLl.getDrawingCache();
saveBitmap(drawingCache, activity, picName);
MessageShareUtils.getInstance(activity).showShareWindows(mShareBottomLl, drawingCache, picName, 2);
mShareBottomLl.setVisibility(View.VISIBLE);
}
}, 200);
closeIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.cancel();
}
});
}
public static void saveBitmap(Bitmap bm, Activity activity, String picName) {
File externalCacheDir = activity.getExternalCacheDir();
if (externalCacheDir == null) return;
File file = new File(externalCacheDir.getPath() + "/ShareImg");
if (!file.isDirectory()) {
file.delete();
file.mkdirs();
}
if (!file.exists()) {
file.mkdirs();
}
MessageShareUtils.getInstance(activity).writeBitmap(file.getPath(), picName, bm, false);
}
public static void showInstallHintDialog(Context context, final ConfirmListener cmListener) {
int i = (filesSize / 1024) / (sendTime / 1000);
String speed ;
if (i >= 1000) {
float mSpeed = i / 1024f;
DecimalFormat df = new DecimalFormat("#.0");
String str = df.format(mSpeed);
if (str.length() > 4) {
str = str.substring(0, 4);
}
speed = str + "MB/s";
} else {
speed = i + "KB/s";
}
final Dialog dialog = new Dialog(context);
if (sendTime > 60000) {
timeCount.setText(String.valueOf(sendTime/1000/60));
timeTv.setText("分钟传送完成");
} else {
timeCount.setText(String.valueOf(sendTime/1000));
timeTv.setText("秒传送完成");
}
View view = View.inflate(context, R.layout.dialog_install_hint, null);
sizeTv.setText(sizeName);
speedTv.setText(speed);
countTv.setText(filesCount + "");
// 标题
TextView alertdialog_title = (TextView) view.findViewById(R.id.installhint_title);
alertdialog_title.setText("重要提示");
Spanned content = Html.fromHtml("如果您使用的是" + "<font color=\"#ff0000\">华为</font>" + "" +
"<font color=\"#ff0000\">OPPO</font>" + "手机,安装游戏时请选择“" +
"<font color=\"#ff0000\">继续安装</font>" +
"”(记住不要选择“官方推荐”或“软件商店安装”)");
// 内容
TextView alertdialog_content = (TextView) view.findViewById(R.id.installhint_content);
alertdialog_content.setText(content);
// 延迟操作,等待截图部分绘制完成
handler.postDelayed(new Runnable() {
@Override
public void run() {
mShareLl.setDrawingCacheEnabled(true);
mShareLl.buildDrawingCache();
Bitmap drawingCache = mShareLl.getDrawingCache();
saveBitmap(drawingCache, activity, picName);
MessageShareUtils.getInstance(activity).showShareWindows(mShareBottomLl, drawingCache, picName, 2);
mShareBottomLl.setVisibility(View.VISIBLE);
}
}, 200);
// 确定按钮
TextView installhint_confirm = (TextView) view.findViewById(R.id.installhint_confirm);
installhint_confirm.setText("知道了");
closeIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.cancel();
}
});
}
final ImageView installhint_unselect = (ImageView) view.findViewById(R.id.installhint_unselect);
final ImageView installhint_select = (ImageView) view.findViewById(R.id.installhint_select);
public static void saveBitmap(Bitmap bm, Activity activity, String picName) {
File file = new File(activity.getExternalCacheDir().getPath() + "/ShareImg");
if (!file.isDirectory()) {
file.delete();
file.mkdirs();
}
if (!file.exists()) {
file.mkdirs();
}
MessageShareUtils.getInstance(activity).writeBitmap(file.getPath(), picName, bm, false);
LinearLayout installhint_unselect_ll = (LinearLayout) view.findViewById(R.id.installhint_unselect_ll);
}
installhint_unselect_ll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (installhint_unselect.getVisibility() == View.GONE) {
installhint_unselect.setVisibility(View.VISIBLE);
installhint_select.setVisibility(View.GONE);
} else {
installhint_unselect.setVisibility(View.GONE);
installhint_select.setVisibility(View.VISIBLE);
}
}
});
public static void showWarningDialog(Context context, String title, CharSequence msg, String cancel, String confirm,
final ConfiremListener cmListener, final CancelListener clListener) {
installhint_confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
if (installhint_select.getVisibility() == View.VISIBLE) {
if (cmListener != null) {
cmListener.onConfirm();
}
}
}
});
if (isShow) {
return;
}
isShow = true;
dialog.setOnDismissListener(new Dialog.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
isShow = false;
}
});
final Dialog dialog = new Dialog(context);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.show();
}
View view = View.inflate(context, R.layout.common_alertdialog, null);
public static void showHintDialog(Context context, String title, CharSequence msg, String confirm) {
final Dialog dialog = new Dialog(context);
// 标题
TextView alertdialog_title = (TextView) view.findViewById(R.id.alertdialog_title);
alertdialog_title.setText(title);
View view = View.inflate(context, R.layout.common_hintdialog, null);
// 内容
TextView alertdialog_content = (TextView) view.findViewById(R.id.alertdialog_content);
alertdialog_content.setText(msg);
TextView hintdialog_title = (TextView) view.findViewById(R.id.tv_dialog_hint_title);
hintdialog_title.setText(title);
// 取消按钮
TextView alertdialog_cannel = (TextView) view.findViewById(R.id.alertdialog_cannel);
alertdialog_cannel.setText(cancel);
alertdialog_cannel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
if (clListener != null) {
clListener.onCancel();
}
}
});
// 内容
TextView hintdialog_content = (TextView) view.findViewById(R.id.tv_dialog_hint_content);
hintdialog_content.setText(msg);
// 确定按钮
TextView alertdialog_confirm = (TextView) view.findViewById(R.id.alertdialog_confirm);
alertdialog_confirm.setText(confirm);
alertdialog_confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
if (cmListener != null) {
cmListener.onConfirem();
}
}
});
TextView hintdialog_confirm = (TextView) view.findViewById(R.id.tv_dialog_hint_confirm);
dialog.setOnDismissListener(new Dialog.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
isShow = false;
}
});
hintdialog_confirm.setText(confirm);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.show();
}
hintdialog_confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.cancel();
}
});
public static void showInstallHintDialog(Context context ,final ConfiremListener cmListener) {
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.show();
}
public static void showHijackDialog(final Context context) {
showWarningDialog(context, "警告", "您当前网络环境异常,下载地址已被替换(网络劫持),请更换网络环境进行下载。",
new ConfirmListener() {
@Override
public void onConfirm() {
// 跳转wifi管理界面
context.startActivity(IntentUtils.getWifiIntent());
}
});
}
final Dialog dialog = new Dialog(context);
public static void showWarningDialog(Context context, String title, CharSequence msg, final ConfirmListener listener) {
showWarningDialog(context, title, msg, "取消", "确定", listener, null);
}
View view = View.inflate(context, R.layout.dialog_install_hint, null);
public static void showWarningDialog(Context context, String title, CharSequence msg, String cancel, String confirm,
final ConfirmListener cmListener, final CancelListener clListener) {
// 标题
TextView alertdialog_title = (TextView) view.findViewById(R.id.installhint_title);
alertdialog_title.setText("重要提示");
Spanned content = Html.fromHtml("如果您使用的是"+ "<font color=\"#ff0000\">华为</font>" +""+
"<font color=\"#ff0000\">OPPO</font>" +"手机,安装游戏时请选择“" +
"<font color=\"#ff0000\">继续安装</font>" +
"”(记住不要选择“官方推荐”或“软件商店安装”)");
// 内容
TextView alertdialog_content = (TextView) view.findViewById(R.id.installhint_content);
alertdialog_content.setText(content);
if (isShow) {
return;
}
isShow = true;
// 确定按钮
TextView installhint_confirm = (TextView) view.findViewById(R.id.installhint_confirm);
installhint_confirm.setText("知道了");
final Dialog dialog = new Dialog(context);
final ImageView installhint_unselect = (ImageView) view.findViewById(R.id.installhint_unselect);
final ImageView installhint_select = (ImageView) view.findViewById(R.id.installhint_select);
View view = View.inflate(context, R.layout.common_alertdialog, null);
TextView installhint_cancel = (TextView) view.findViewById(R.id.installhint_cancel);
LinearLayout installhint_unselect_ll = (LinearLayout) view.findViewById(R.id.installhint_unselect_ll);
// 标题
TextView alertdialog_title = (TextView) view.findViewById(R.id.alertdialog_title);
alertdialog_title.setText(title);
installhint_unselect_ll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (installhint_unselect.getVisibility() == View.GONE) {
installhint_unselect.setVisibility(View.VISIBLE);
installhint_select.setVisibility(View.GONE);
} else {
installhint_unselect.setVisibility(View.GONE);
installhint_select.setVisibility(View.VISIBLE);
}
}
});
// 内容
TextView alertdialog_content = (TextView) view.findViewById(R.id.alertdialog_content);
alertdialog_content.setText(msg);
installhint_confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
if (installhint_select.getVisibility() == View.VISIBLE) {
if (cmListener != null) {
cmListener.onConfirem();
}
}
}
});
// 取消按钮
TextView alertdialog_cannel = (TextView) view.findViewById(R.id.alertdialog_cannel);
alertdialog_cannel.setText(cancel);
alertdialog_cannel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
if (clListener != null) {
clListener.onCancel();
}
}
});
dialog.setOnDismissListener(new Dialog.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
isShow = false;
}
});
// 确定按钮
TextView alertdialog_confirm = (TextView) view.findViewById(R.id.alertdialog_confirm);
alertdialog_confirm.setText(confirm);
alertdialog_confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
if (cmListener != null) {
cmListener.onConfirm();
}
}
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.show();
}
dialog.setOnDismissListener(new Dialog.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
isShow = false;
}
});
public static void showHintDialog(Context context, String title, CharSequence msg, String confirm) {
final Dialog dialog = new Dialog(context);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.show();
}
View view = View.inflate(context, R.layout.common_hintdialog, null);
// 网络劫持时 打开QQ客户端创建临时会话
public static void showQqSessionDialog(final Context context, final String qq) {
showWarningDialog(context, "警告", "您当前网络环境异常,下载地址可能被运营商恶意替换(网络劫持)" +
"如多次下载失败请联系客服获取正确的下载地址客服QQ" + qq + ""
, "取消", "前往QQ", new ConfirmListener() {
@Override
public void onConfirm() {
QQUtils.startQQSession(context, qq);
}
}, null);
}
TextView hintdialog_title = (TextView) view.findViewById(R.id.hintdialog_title);
hintdialog_title.setText(title);
public static void showDownloadDialog(Context context, ConfirmListener listener) {
showWarningDialog(context, "下载提示", "您当前使用的网络为2G/3G/4G开始下载将会消耗移动流量确定下载", listener);
}
// 内容
TextView hintdialog_content = (TextView) view.findViewById(R.id.hintdialog_content);
hintdialog_content.setText(msg);
public static void showCancelDialog(Context context, final ConfirmListener listener) {
Spanned content = Html.fromHtml("取消关注游戏后,您将无法及时收到游戏" +
"<font color=\"#ff0000\">攻略</font>、" +
"<font color=\"#ff0000\">资讯</font>等最新动态提醒。");
showWarningDialog(context, "取消关注", content, "暂不取消", "确定取消", listener, null);
}
TextView hintdialog_confirm = (TextView) view.findViewById(R.id.hintdialog_confirm);
public static void showPluginDialog(Context context, final ConfirmListener listener) {
Spanned spanned = Html.fromHtml("您将进行插件化安装以实现插件功能,此过程将"
+ "<font color=\"#ff0000\">卸载</font>" + "当前使用的版本并"
+ "<font color=\"#ff0000\">安装插件版本</font>");
showWarningDialog(context, "插件化安装", spanned, listener);
}
hintdialog_confirm.setText(confirm);
hintdialog_confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.cancel();
}
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.show();
}
public static void showHijackDialog(final Context context) {
showWarningDialog(context, "警告", "您当前网络环境异常,下载地址已被替换(网络劫持),请更换网络环境进行下载。",
new ConfiremListener() {
@Override
public void onConfirem() {
// 跳转wifi管理界面
context.startActivity(new Intent("android.settings.WIFI_SETTINGS"));
}
});
}
// 网络劫持时 打开QQ客户端创建临时会话
public static void showQqSessionDialog(final Context context, String qq) {
if (qq == null) {
qq = "2586716223";// 默认客服QQ
}
final String finalQq = qq;
showWarningDialog(context, "警告", "您当前网络环境异常,下载地址可能被运营商恶意替换(网络劫持)" +
"如多次下载失败请联系客服获取正确的下载地址客服QQ" + qq + ""
, "取消", "前往QQ", new ConfiremListener() {
@Override
public void onConfirem() {
if (ShareUtils.isQQClientAvailable(context)) {
//安装了QQ会直接调用QQ打开手机QQ进行会话 QQ号2586716223
String str = "mqqwpa://im/chat?chat_type=wpa&uin=" + finalQq + "&version=1&src_type=web&web_src=oicqzone.com";
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(str)));
} else {
//没有安装QQ 复制账号
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(finalQq);
Utils.toast(context, "已复制" + finalQq);
}
}
}, null);
}
public static void showWarningDialog(Context context, String title, CharSequence msg, final ConfiremListener listener) {
showWarningDialog(context, title, msg, "取消", "确定", listener, null);
}
public static void showDownloadDialog(Context context, ConfiremListener listener) {
showWarningDialog(context, "下载提示", "您当前使用的网络为2G/3G/4G开始下载将会消耗移动流量确定下载", listener);
}
public static void showCancelDialog(Context context, final ConfiremListener listener) {
Spanned content = Html.fromHtml("取消关注游戏后,您将无法及时收到游戏" +
"<font color=\"#ff0000\">攻略</font>、" +
"<font color=\"#ff0000\">资讯</font>等最新动态提醒。");
showWarningDialog(context, "取消关注", content, "暂不取消", "确定取消", listener, null);
}
public static void showPluginDialog(Context context, final ConfiremListener listener) {
Spanned spanned = Html.fromHtml("您将进行插件化安装以实现插件功能,此过程将"
+ "<font color=\"#ff0000\">卸载</font>" + "当前使用的版本并"
+ "<font color=\"#ff0000\">安装插件版本</font>");
showWarningDialog(context, "插件化安装", spanned, listener);
}
public static void showDisclaimerDialog(Context context, String content) {
final Dialog disclaimerDialog = new Dialog(context);
View view = View.inflate(context, R.layout.dialog_disclaimer, null);
public static void showDisclaimerDialog(Context context, String content) {
final Dialog disclaimerDialog = new Dialog(context);
View view = View.inflate(context, R.layout.dialog_disclaimer, null);
// TextView title = (TextView) view.findViewById(R.id.disclaimer_title);
// title.setText("免责声明");
TextView message = (TextView) view.findViewById(R.id.disclaimer_message);
Spanned spanned = Html.fromHtml(content);
message.setText(spanned);
TextView message = (TextView) view.findViewById(R.id.disclaimer_message);
Spanned spanned = Html.fromHtml(content);
message.setText(spanned);
view.findViewById(R.id.disclaimer_confirm).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
disclaimerDialog.dismiss();
}
});
view.findViewById(R.id.disclaimer_confirm).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
disclaimerDialog.dismiss();
}
});
disclaimerDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
disclaimerDialog.setContentView(view);
disclaimerDialog.show();
}
disclaimerDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
disclaimerDialog.setContentView(view);
disclaimerDialog.show();
}
public interface ConfiremListener{
void onConfirem();
}
public interface ConfirmListener {
void onConfirm();
}
public interface CancelListener{
void onCancel();
}
public interface CancelListener {
void onCancel();
}
}

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,14 +1,12 @@
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.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;
@ -28,250 +26,77 @@ 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 (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);
}
}
}
}
// 更新正常的条目只有一个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) || "光环助手".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);
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);
}
}
// 更新插件的条目有多个apk包
public static void updatePluginItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform) {
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn);
ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
if (entryMap != null && !entryMap.isEmpty()) {
DownloadEntity downloadEntity;
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));
}
if (downloadEntity != null) {
// 更改进度条和提示文本的状态
changeStatus(context, holder, downloadEntity, isShowPlatform, false);
return;
}
}
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.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);
String platform = PlatformUtils.getInstance(context)
.getPlatformName(downloadEntity.getPlatform());
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("下载中");
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() + "%");
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() + "%");
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);
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 updateItem(Context context, GameEntity gameEntity, GameViewHolder holder, boolean isShowPlatform) {
// 控制是否显示下载按钮
if (!Config.isShow(context) || "光环助手".equals(gameEntity.getName())) {
holder.gameDownloadBtn.setVisibility(View.GONE);
} else {
holder.gameDownloadBtn.setVisibility(View.VISIBLE);
}
if (gameEntity.isLibaoExists()) {
holder.gameLibaoIcon.setVisibility(View.VISIBLE);
} else {
holder.gameLibaoIcon.setVisibility(View.GONE);
}
if (gameEntity.isLibaoExists()) {
holder.gameLibaoIcon.setVisibility(View.VISIBLE);
} else {
holder.gameLibaoIcon.setVisibility(View.GONE);
}
// LibaoDao libaoDao = new LibaoDao(context);
// if (libaoDao.isExist(gameEntity.getId())) {
@ -280,198 +105,348 @@ public class DownloadItemUtils {
//
// }
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);
}
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);
}
}
}
private static void setNormalOnClickListener(final Context context,
final TextView downloadBtn,
final GameEntity gameEntity,
final int position,
final RecyclerView.Adapter<RecyclerView.ViewHolder> adapter,
final String entrance,
final String location, final boolean isCloseSoftInput) {
downloadBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isCloseSoftInput) {
InputMethodManager imm = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
// 更新正常的条目只有一个apk包
public static void updateNormalItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform) {
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);
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;
}
}
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);
}
});
}
}
}
});
}
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
private static void setPluginOnClickListener(final Context context,
final TextView downloadBtn,
final GameEntity entity,
final String entrance,
final String location,
final boolean isCloseSoftInput) {
downloadBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
if (isCloseSoftInput) {
InputMethodManager imm = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
DownloadDialog.getInstance(context).showPopupWindow(v, entity, entrance, location);
}
});
}
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);
}
}
public static void setOnClickListener(Context context,
TextView downloadBtn,
GameEntity gameEntity,
int position,
RecyclerView.Adapter<RecyclerView.ViewHolder> adapter,
String entrance,
String location,
boolean isCloseSoftInput) {
// 更新插件的条目有多个apk包
public static void updatePluginItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform) {
if (gameEntity.getApk().size() == 1) {
setNormalOnClickListener(context, downloadBtn, gameEntity, position, adapter, entrance, location, isCloseSoftInput);
} else {
setPluginOnClickListener(context, downloadBtn, gameEntity, entrance, location, isCloseSoftInput);
}
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn);
}
ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
if (entryMap != null && !entryMap.isEmpty()) {
//更新
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);
}
DownloadEntity downloadEntity;
//下载
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, "下载开始");
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));
}
DownloadManager.createDownload(context, gameEntity, "下载", entrance, location);
Toast.makeText(context, gameEntity.getName() + "已加入下载队列", Toast.LENGTH_SHORT).show();
if (downloadEntity != null) {
// 更改进度条和提示文本的状态
changeStatus(context, holder, downloadEntity, isShowPlatform, false);
return;
}
}
downloadBtn.setText("下载中");
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(context.getResources().getColorStateList(R.color.text_downloading_style));
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
}
DownloadManager.getInstance(context).putStatus(gameEntity.getApk().get(0).getUrl(), "downloading");
} else {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
// 更改进度条和提示文本的状态
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);
//插件化
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, "下载开始");
String platform = PlatformUtils.getInstance(context)
.getPlatformName(downloadEntity.getPlatform());
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location);
Toast.makeText(context, gameEntity.getName() + "已加入下载队列", Toast.LENGTH_SHORT).show();
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() + "%");
}
downloadBtn.setText("下载中");
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(context.getResources().getColorStateList(R.color.text_downloading_style));
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() + "%");
DownloadManager.getInstance(context).putStatus(gameEntity.getApk().get(0).getUrl(), "downloading");
} else {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
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() + "%");
//安装
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);
}
}
}
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);
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<? 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);
}
});
}
}
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) {
String str = downloadBtn.getText().toString();
if ("下载".equals(str)) {
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);
}
});
}
} else if ("插件化".equals(str)) {
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);
}
});
}
} else if ("安装".equals(str)) {
install(context, gameEntity, position, adapter);
} else if ("启动".equals(str)) {
DataUtils.onGameLaunchEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk().get(0).getPackageName());
} else if ("下载中".equals(str)) {
context.startActivity(
DownloadManagerActivity.getDownloadMangerIntent(context, gameEntity.getApk().get(0).getUrl(), entrance + "+(" + location.split(":")[0] + ")"));
} else if ("更新".equals(str)) {
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);
}
});
}
}
}
//下载
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.createDownload(context, gameEntity, "下载", entrance, location);
Toast.makeText(context, gameEntity.getName() + "已加入下载队列", Toast.LENGTH_SHORT).show();
downloadBtn.setText("下载中");
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(context.getResources().getColorStateList(R.color.text_downloading_style));
DownloadManager.getInstance(context).putStatus(gameEntity.getApk().get(0).getUrl(), "downloading");
} else {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
//插件化
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.createDownload(context, gameEntity, "插件化", entrance, location);
Toast.makeText(context, gameEntity.getName() + "已加入下载队列", Toast.LENGTH_SHORT).show();
downloadBtn.setText("下载中");
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(context.getResources().getColorStateList(R.color.text_downloading_style));
DownloadManager.getInstance(context).putStatus(gameEntity.getApk().get(0).getUrl(), "downloading");
} else {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
//安装
private static void install(final Context context,
GameEntity gameEntity,
int position,
RecyclerView.Adapter<? extends 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);
}
}
}
//更新
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,70 @@
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 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_CURRENT_ITEM = "currentItem";
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

@ -21,7 +21,6 @@ import java.net.URL;
import java.util.UUID;
/**
*
* @author guanchao wen
* @email shuwoom.wgc@gmail.com
* @modify hzh 2016/03/16
@ -29,356 +28,356 @@ import java.util.UUID;
*/
public class FileUtils {
private final static String TEST_FILE_NAME = System.currentTimeMillis() + ".log";
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 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 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 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 boolean isMounted() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
public static void deleteFile(String savePath) {
File file = new File(savePath);
if (file.exists()) {
file.delete();
}
}
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 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 String getLogPath(Context context, String name) {
return checkDir(getDir(context, "log")) + File.separator + name;
}
public static boolean isEmptyFile(String path) {
File file = new File(path);
return !(file.exists() && file.length() != 0);
}
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;
}
public static boolean isMounted() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
public static String getPlatformPicDir(Context context) {
return checkDir(getDir(context, "PlatformPic"));
}
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;
}
public static void deleteFile(String savePath) {
File file = new File(savePath);
if (file.exists()) {
file.delete();
}
}
// 返回剩余空间 单位MB
@SuppressWarnings("deprecation")
public static float getFreeSpaceByPath(String path) {
StatFs statfs = new StatFs(path);
long blockSize = statfs.getBlockSize();
long availableBlocks = statfs.getAvailableBlocks();
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();
}
}
return availableBlocks * blockSize / 1024f / 1024f;
}
public static boolean isEmptyFile(String path) {
File file = new File(path);
return !(file.exists() && file.length() != 0);
}
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 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;
}
// 返回剩余空间 单位MB
@SuppressWarnings("deprecation")
public static float getFreeSpaceByPath(String path) {
StatFs statfs = new StatFs(path);
long blockSize = statfs.getBlockSize();
long availableBlocks = statfs.getAvailableBlocks();
// 上传文件
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
return availableBlocks * blockSize / 1024f / 1024f;
}
// 下载文件
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();
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());
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;
}
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 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();
}
}
}
}
// 根据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,15 +1,12 @@
package com.gh.common.util;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
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;
@ -21,131 +18,109 @@ 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).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())) { // TODO 外层判断插件化逻辑与多平台弹窗不一致
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,106 @@ 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, 5));
}
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) && tagType.equals("type")) { // 游戏标签
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");
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;
}
}
}
}

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

@ -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

@ -26,11 +26,10 @@ import okhttp3.internal.tls.OkHostnameVerifier;
/**
* Created by khy on 2016/10/8.
*
*/
public class HttpsUtils {
private static final TrustManager[] TRUST_MANAGERS = new TrustManager[] {
private static final TrustManager[] TRUST_MANAGERS = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
@ -109,7 +108,7 @@ public class HttpsUtils {
return null;
}
public static HttpsURLConnection getHttpsURLConnection(URL url) throws Exception {
public static HttpsURLConnection getHttpsURLConnection(URL url) throws Exception {
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
if (mSSLSocketFactory == null || mHostnameVerifier == null) {
SSLContext sslContext = SSLContext.getInstance("TLS");

View File

@ -5,6 +5,7 @@ import android.content.res.Resources;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.support.v4.content.ContextCompat;
import android.view.ViewGroup;
import com.facebook.common.executors.CallerThreadExecutor;
@ -24,91 +25,93 @@ 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 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")) {
// 自适应图片宽高
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) {
final Context context = simpleDraweeView.getContext();
simpleDraweeView.setHierarchy(new GenericDraweeHierarchyBuilder(resources)
.setFadeDuration(500)
.setPressedStateOverlay(new ColorDrawable(ContextCompat.getColor(context, R.color.pressed_bg)))
.setPlaceholderImage(R.drawable.ocupy2, ScalingUtils.ScaleType.CENTER)
.setBackground(new ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
.setActualImageScaleType(scaleType)
.build());
// simpleDraweeView.setImageURI(url);
display(simpleDraweeView, url);
}
public static void display(SimpleDraweeView simpleDraweeView, String url) {
// if (url.startsWith("http://image.ghzs666.com") && url.endsWith(".jpg")) {
// url = url + "?x-oss-process=image/format,webp";
// }
simpleDraweeView.setImageURI(url);
}
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());
// 设置占位符
public void display(Resources resources, SimpleDraweeView simpleDraweeView, String url, int placeholderImage) {
final Context context = simpleDraweeView.getContext();
simpleDraweeView.setHierarchy(new GenericDraweeHierarchyBuilder(resources)
.setFadeDuration(500)
.setPressedStateOverlay(new ColorDrawable(ContextCompat.getColor(context, R.color.pressed_bg)))
.setBackground(new ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
.setPlaceholderImage(placeholderImage)
.build());
// simpleDraweeView.setImageURI(url);
display(simpleDraweeView, 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());
}
// 图片下载监听和设置低高分辨率图片
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();
// 获取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());
}
Fresco.getImagePipeline()
.fetchDecodedImage(imageRequest, context)
.subscribe(dataSubscriber, CallerThreadExecutor.getInstance());
}
}

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,127 @@ 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 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 == 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;
}
}
}
};
}
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(0x123, 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,7 +2,6 @@ package com.gh.common.util;
import android.content.Context;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import java.io.File;
@ -13,47 +12,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.ghzs666.com/link?source=appshare333");
return data;
}
}

View File

@ -0,0 +1,150 @@
package com.gh.common.util;
import android.graphics.Color;
import android.view.View;
import android.widget.TextView;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.KaiFuServerEntity;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* Created by khy on 2017/3/19.
*/
public class KaiFuUtils {
public static void setKaiFuTimeHint(long curTime, long lastTime, GameEntity entity, boolean isTop) {
SimpleDateFormat format = new SimpleDateFormat("dd", Locale.getDefault());
String curDay = format.format(curTime);
String lastDay = format.format(lastTime);
if (!curDay.equals(lastDay)) {
if (isTop) {
entity.setKaifuTimeHint(curTime);
} else {
entity.setKaifuTimeHint(lastTime);
}
}
}
public static void initKaiFuTimeHintView(TextView view, Long time) {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
try {
long today = format.parse(format.format(new Date())).getTime();
if (time >= today && time < today + 86400 * 1000) {
view.setText("↓今天开服");
view.setTextColor(Color.parseColor("#ffb13c"));
} else if (time >= today - 86400 * 1000 && time < today) {
view.setText("↑历史开服");
view.setTextColor(Color.parseColor("#c7c7c7"));
} else if (time > today && time < today + 86400 * 1000 * 2) {
view.setText("↓明天开服");
view.setTextColor(Color.parseColor("#ffb13c"));
} else if (time < today) {
view.setText("↑历史开服");
view.setTextColor(Color.parseColor("#c7c7c7"));
} else if (time > today && time < today + 86400 * 1000 * 3) {
view.setText("↓后天开服");
view.setTextColor(Color.parseColor("#c7c7c7"));
} else {
format.applyPattern("↓M月d日开服");
view.setText(format.format(time));
view.setTextColor(Color.parseColor("#c7c7c7"));
}
} catch (ParseException e) {
e.printStackTrace();
format.applyPattern("M月d日开服");
view.setText(format.format(time));
}
}
public static void setKaiFuTimeHint(TextView top, TextView bottom, List<GameEntity> gameList, int position) {
if (position == 0 || position + 1 >= gameList.size()) return;
GameEntity curGameEntity = gameList.get(position);
GameEntity lastGameEntity = gameList.get(position);
KaiFuServerEntity curServerEntity = curGameEntity.getServerEntity();
KaiFuServerEntity lastServerEntity = lastGameEntity.getServerEntity();
if (curServerEntity == null || lastServerEntity == null) return;
long curTime = curServerEntity.getTime() * 1000;
long lastTime = lastServerEntity.getTime() * 1000;
SimpleDateFormat format = new SimpleDateFormat("dd", Locale.getDefault());
String curDay = format.format(curTime);
String lastDay = format.format(lastTime);
if (!curDay.equals(lastDay)) {
bottom.setVisibility(View.VISIBLE);
} else {
bottom.setVisibility(View.GONE);
}
}
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) {
textView.setText(type);
switch (type) {
case "不删档内测":
textView.setBackgroundColor(Color.parseColor("#c7c7c7"));
break;
case "删档内测":
textView.setBackgroundColor(Color.parseColor("#c7c7c7"));
break;
case "公测":
textView.setBackgroundColor(Color.parseColor("#06d0a8"));
break;
default:
textView.setBackgroundColor(Color.parseColor("#06d0a8"));
break;
}
}
}

View File

@ -1,5 +1,6 @@
package com.gh.common.util;
import android.app.Activity;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
@ -9,10 +10,11 @@ import android.graphics.Color;
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;
@ -21,19 +23,21 @@ import com.gh.gamecenter.db.info.LibaoInfo;
import com.gh.gamecenter.entity.LibaoEntity;
import com.gh.gamecenter.entity.LibaoStatusEntity;
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 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;
@ -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()
@ -79,7 +85,15 @@ public class LibaoUtils {
@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);
@ -122,10 +136,8 @@ public class LibaoUtils {
if (e != null && e.code() == 401) {
postLibaoLing(context, libaoId, false, listener, captchaCode);
return;
} else if (e.code() == 410) { // 该接口已废弃
} else if (e != null && e.code() == 410) { // 该接口已废弃
Utils.toast(context, "领取失败,请安装最新版本的光环助手");
} else if (e.code() == 412) {
//TODO 需要验证码
}
listener.postFailed(e);
}
@ -160,7 +172,7 @@ public class LibaoUtils {
}
public static void deleteLibaoCode(final Context context, final String code, final boolean isCheck,
final PostLibaoListener listener) {
final PostLibaoListener listener) {
TokenUtils.getToken(context, isCheck)
.flatMap(new Func1<String, Observable<ResponseBody>>() {
@Override
@ -203,17 +215,13 @@ 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 Activity activity, final TextView libaoBtn, final LibaoEntity libaoEntity, final LibaoDao libaoDao,
final boolean isInstallRequired, final LibaoDetailAdapter adapter, final String entrance) {
libaoBtn.setTextColor(Color.WHITE);
switch (libaoEntity.getStatus()) {
String status = libaoEntity.getStatus();
if (TextUtils.isEmpty(status)) return;
switch (status) {
case "coming":
libaoBtn.setText("未开抢");
libaoBtn.setBackgroundResource(R.drawable.textview_blue_style);
@ -236,10 +244,10 @@ public class LibaoUtils {
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") };
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.setBackgroundResource(R.drawable.libao_linged_style);
@ -247,10 +255,10 @@ public class LibaoUtils {
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") };
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.setBackgroundResource(R.drawable.libao_taoed_style);
@ -280,12 +288,12 @@ public class LibaoUtils {
}
DialogUtils.showWarningDialog(libaoBtn.getContext(), "条件不符",
Html.fromHtml("请先"+ "<font color=\"#06D0A8\">"
Html.fromHtml("请先" + "<font color=\"#06D0A8\">"
+ "安装《" + libaoEntity.getGame().getName() + ""
+ platform + "</font>"), "关闭", "立即安装"
, new DialogUtils.ConfiremListener() {
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirem() {
public void onConfirm() {
adapter.openDownload();
}
}, null);
@ -298,13 +306,11 @@ public class LibaoUtils {
Utils.toast(libaoBtn.getContext(), "还没到开始领取时间");
break;
case "查看":
AppController.put("libaoEntity", libaoEntity);
Intent intent = new Intent(libaoBtn.getContext(), LibaoDetailActivity.class);
intent.putExtra("entrance", entrance);
Intent intent = LibaoDetailActivity.getLibaoDetailIntent(libaoEntity, libaoBtn, entrance);
libaoBtn.getContext().startActivity(intent);
break;
case "领取":
libaoLing(libaoBtn, libaoEntity, adapter, isInstallRequired, libaoDao, null, entrance);
libaoLing(activity, libaoBtn, libaoEntity, adapter, isInstallRequired, libaoDao, null, entrance);
break;
case "淘号":
postLibaoTao(libaoBtn.getContext(), libaoEntity.getId(), true, new PostLibaoListener() {
@ -321,31 +327,43 @@ public class LibaoUtils {
}
if (TextUtils.isEmpty(libaoCode)) {
Utils.toast(libaoBtn.getContext(), "淘号异常");
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(String.valueOf(new Date().getTime()));
libaoInfo.setTime(Utils.getTime(libaoBtn.getContext()));
libaoDao.add(libaoInfo);
EventBus.getDefault().post(new EBReuse("libaoChanged"));
libaoEntity.setStatus("taoed");
adapter.initLibaoDao();
adapter.notifyDataSetChanged();
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(libaoBtn.getContext(), "淘号成功",Html.fromHtml("礼包码:"
DialogUtils.showWarningDialog(libaoBtn.getContext(), "淘号成功", Html.fromHtml("礼包码:"
+ "<font color=\"#ffb13c\">" + libaoCode + "</font>" +
"<br/>淘号礼包不保证可用,请尽快进入游戏尝试兑换")
"<br/>淘号礼包不保证可用,请尽快进入游戏尝试兑换")
, "关闭", " 复制礼包码"
, new DialogUtils.ConfiremListener() {
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirem() {
public void onConfirm() {
copyLink(finalLibaoCode, libaoBtn.getContext());
if (isInstallRequired) {
@ -354,9 +372,9 @@ public class LibaoUtils {
public void run() {
lunningAppDialog(libaoBtn.getContext()
, Html.fromHtml("礼包码:"
+ "<font color=\"#ffb13c\">" + finalLibaoCode + "</font>"
+ "<font color=\"#ffb13c\">" + finalLibaoCode + "</font>"
+ " 复制成功"
+"<br/>淘号礼包不保证可用,请尽快进入游戏尝试兑换"), libaoEntity);
+ "<br/>淘号礼包不保证可用,请尽快进入游戏尝试兑换"), libaoEntity);
}
}, 300);
}
@ -382,8 +400,17 @@ public class LibaoUtils {
} else if ("fetched".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "你已领过这个礼包了");
getCunHaoXiang(libaoBtn.getContext(), true);
libaoBtn.setText("复制");
libaoBtn.setBackgroundResource(R.drawable.textview_blue_style);
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.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(sl2);
libaoEntity.setStatus("taoed");
} else if ("try tao".equals(detail) || "used up".equals(detail)) {
DialogUtils.showHintDialog(libaoBtn.getContext(), "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
@ -396,7 +423,7 @@ public class LibaoUtils {
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(libaoBtn.getContext(),"礼包处理异常"+ ex.toString());
Utils.toast(libaoBtn.getContext(), "礼包处理异常" + ex.toString());
}
return;
}
@ -410,7 +437,7 @@ public class LibaoUtils {
});
}
private static void libaoLing(final TextView libaoBtn, final LibaoEntity libaoEntity, final LibaoDetailAdapter adapter,
private static void libaoLing(final Activity activity, final TextView libaoBtn, final LibaoEntity libaoEntity, final LibaoDetailAdapter adapter,
final boolean isInstallRequired, final LibaoDao libaoDao, String captchaCode, final String entrance) {
postLibaoLing(libaoBtn.getContext(), libaoEntity.getId(), true, new PostLibaoListener() {
@ -432,13 +459,15 @@ public class LibaoUtils {
}
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"));
libaoEntity.setStatus("linged");
adapter.initLibaoDao();
adapter.notifyDataSetChanged();
@ -447,18 +476,18 @@ public class LibaoUtils {
+ "<font color=\"#00B7FA\">" + libaoCode + "</font>" +
"<br/>请尽快使用礼包码将于60分钟后进入淘号池")
, "关闭", " 复制礼包码"
, new DialogUtils.ConfiremListener() {
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirem() {
public void onConfirm() {
copyLink(finalLibaoCode, libaoBtn.getContext());
if (isInstallRequired) {
libaoBtn.postDelayed(new Runnable() {
@Override
public void run() {
lunningAppDialog(libaoBtn.getContext()
, Html.fromHtml("礼包码:"
, Html.fromHtml("礼包码:"
+ "<font color=\"#00B7FA\">" + finalLibaoCode + "</font>"
+ " 复制成功" +"<br/>请尽快进入游戏兑换"), libaoEntity);
+ " 复制成功" + "<br/>请尽快进入游戏兑换"), libaoEntity);
}
}, 300);
}
@ -484,15 +513,32 @@ public class LibaoUtils {
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);
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));
} else {
getCunHaoXiang(libaoBtn.getContext(), true);
}
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.setBackgroundResource(R.drawable.libao_linged_style);
libaoBtn.setTextColor(sl);
libaoEntity.setStatus("linged");
} 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);
initLibaoBtn(activity, libaoBtn, libaoEntity, libaoDao, isInstallRequired, adapter, entrance);
} else if ("maintaining".equals(detail)) {
Utils.toast(libaoBtn.getContext(), "网络状态异常,请稍后再试");
@ -501,18 +547,22 @@ public class LibaoUtils {
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(libaoBtn.getContext(),"礼包处理异常");
Utils.toast(libaoBtn.getContext(), "礼包处理异常");
}
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);
}
});
if (BuildConfig.DEBUG) {
Log.e("LIBAO", "context? " + libaoBtn.getContext() + activity);
}
GeetestUtils.getInstance().showDialog(activity, new GeetestListener() {
@Override
public void onVerified(String captcha) {
libaoLing(activity, libaoBtn, libaoEntity, adapter, isInstallRequired, libaoDao, captcha, entrance);
}
});
return;
}
}
@ -535,16 +585,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()) + "");
}
@ -552,12 +602,79 @@ 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(LibaoDao libaoDao, List<LibaoStatusEntity> statusList
, List<LibaoEntity> mLibaoList, Context mContext) {
for (LibaoInfo libaoInfo : libaoDao.getAll()) {
for (LibaoStatusEntity libaoStatusEntity : statusList) {
if (TextUtils.isEmpty(libaoInfo.getLibaoId()) || TextUtils.isEmpty(libaoStatusEntity.getId())) {
continue;
}
if (TextUtils.isEmpty(libaoStatusEntity.getBeforeStatus())) {
libaoStatusEntity.setBeforeStatus(libaoStatusEntity.getStatus());
}
if (libaoInfo.getLibaoId().equals(libaoStatusEntity.getId())) {
if ("ling".equals(libaoInfo.getStatus()) || "linged".equals(libaoInfo.getStatus())) {
libaoStatusEntity.setStatus("linged");
} else {
libaoStatusEntity.setStatus("taoed");
}
}
}
}
for (LibaoEntity libaoEntity : mLibaoList) {
for (LibaoStatusEntity libaoStatusEntity : statusList) {
if (libaoEntity.getId().equals(libaoStatusEntity.getId())) {
libaoEntity.setAvailable(libaoStatusEntity.getAvailable());
libaoEntity.setTotal(libaoStatusEntity.getTotal());
String beforeStatus = libaoStatusEntity.getBeforeStatus();
if (TextUtils.isEmpty(beforeStatus)) {
beforeStatus = libaoStatusEntity.getStatus();
}
int repeat = libaoEntity.getRepeat();
if (repeat > 0
&& libaoDao.isCanLing(libaoEntity.getId(), mContext)
&& ("ling".equals(beforeStatus) || "tao".equals(beforeStatus))) { // 判断是否可以重复领取
if ("ling".equals(beforeStatus)) {
if (libaoDao.repeatedLingedCount(libaoStatusEntity.getId()) >= repeat) {
libaoEntity.setStatus(libaoStatusEntity.getStatus());
} else {
libaoEntity.setStatus(beforeStatus);
}
} else {
if (libaoDao.repeatedTaoedCount(libaoStatusEntity.getId()) >= repeat) {
libaoEntity.setStatus(libaoStatusEntity.getStatus());
} else {
libaoEntity.setStatus(beforeStatus);
}
}
} else {
libaoEntity.setStatus(libaoStatusEntity.getStatus());
}
libaoEntity.setBeforeStatus(beforeStatus);
}
}
}
}
public interface PostLibaoListener {
void postSucced(Object response);
void postFailed(Throwable error);
}
}

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

@ -12,12 +12,12 @@ import android.view.ViewGroup;
*/
public class MeasureHeightLayoutManager extends LinearLayoutManager {
private int[] mMeasuredDimension = new int[1];
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) {
@ -26,23 +26,26 @@ public class MeasureHeightLayoutManager extends LinearLayoutManager {
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];
try {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
height = height + mMeasuredDimension[0];
} catch (Exception e) {
e.printStackTrace();
}
}
if (height > heightSize){
if (height > heightSize) {
super.onMeasure(recycler, state, widthSpec, heightSpec);
}else {
} else {
setMeasuredDimension(View.MeasureSpec.getSize(widthSpec), height);
}
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
int heightSpec, int[] measuredDimension) throws Exception {
View view = recycler.getViewForPosition(position);
if (view.getVisibility() == View.GONE) {
measuredDimension[0] = 0;

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,6 +24,7 @@ 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.tencent.connect.share.QQShare;
import com.tencent.mm.sdk.openapi.IWXAPI;
@ -50,28 +50,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 +101,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 (pn.equals("com.tencent.mobileqq")) {
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 +161,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 +185,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 +213,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 +271,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 +302,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 +326,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 +338,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 +345,7 @@ public class MessageShareUtils {
file.mkdirs();
}
File _file = new File(path , name);
File _file = new File(path, name);
if (_file.exists()) {
_file.delete();
}
@ -445,13 +363,9 @@ public class MessageShareUtils {
bitmap.compress(Bitmap.CompressFormat.JPEG, 75, fos);
}
if (isToast) {
Utils.toast(context,"成功保存到相册");
Utils.toast(mContext, "成功保存到相册");
//刷新手机图片库
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(_file);
intent.setData(uri);
context.sendBroadcast(intent);
Utils.log("保存分享图片路径:" + _file.getAbsolutePath());
refreshImage(_file, mContext);
}
}
}
@ -469,4 +383,100 @@ public class MessageShareUtils {
}
}
public static void refreshImage(File _file, Context context) {
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(_file);
intent.setData(uri);
context.sendBroadcast(intent);
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,9 @@
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,120 +20,110 @@ 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 {
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) {
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;
}
}
/**
* 去除与重复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(String news_id) {
RetrofitManager.getData().postNewsViews(news_id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>());
}
/**
* 设置新闻类型
*/
public static void setNewsType(TextView textView, String type) {
textView.setText(type);
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 {
textView.setBackgroundResource(R.drawable.textview_blue_style);
}
}
/**
* 去除与重复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 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));
}
}
/**
* 设置新闻类型
*/
public static void setNewsType(TextView textView, String type, int priority, int position) {
if (priority != 0) {
if (position == 0) {
textView.setText("置顶");
} else {
textView.setText("热门");
}
textView.setBackgroundResource(R.drawable.textview_all_red_style);
return;
} else {
textView.setText(type);
}
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 {
textView.setBackgroundResource(R.drawable.textview_blue_style);
}
}
/**
* 设置新闻发布时间
*/
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

@ -12,95 +12,105 @@ import com.gh.download.DownloadManager;
import com.gh.download.DownloadStatus;
import com.gh.gamecenter.R;
import java.util.List;
/**
* 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;
public static final String ACTION_INSTALL = "com.gh.gamecenter.INSTALL";
public static final String ACTION_DOWNLOAD = "com.gh.gamecenter.DOWNLOAD";
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 showKuaiChuanDoneNotification(Context context, String apkPath, String apkName, String packName) {
NotificationManager manager = getNotificationManager(context);
Intent intent = new Intent();
intent.putExtra("path", apkPath);
intent.setAction(ACTION_INSTALL);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0x321,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
String title = "接收完成,点击立即安装";
String text = apkName;
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 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表明当通知被用户点击时通知将被清除。
manager.notify(packName, 0x321, notification);
}
private static NotificationManager getNotificationManager(Context context) {
return (NotificationManager) context.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
}
public static void showDownloadDoneNotification(Context context, DownloadEntity downloadEntity, int flag) {
NotificationManager manager = getNotificationManager(context);
Intent intent = new Intent();
intent.putExtra("path", downloadEntity.getPath());
intent.setAction(ACTION_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);
}
notification.flags |= Notification.FLAG_AUTO_CANCEL; // // FLAG_AUTO_CANCEL表明当通知被用户点击时通知将被清除。
manager.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();
public static void showDownloadingNotification(Context context) {
NotificationManager manager = getNotificationManager(context);
int downloadingSize = 0;
List<DownloadEntity> all = DownloadManager.getInstance(context).getAll();
if (all != null) {
for (DownloadEntity entity : all) {
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) {
manager.cancel(0x123);
} else {
Intent intent = new Intent();
intent.setAction(ACTION_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);
}
}
notification.flags |= Notification.FLAG_NO_CLEAR; // 通知无法手动清除
manager.notify(0x123, notification);
}
}
}

View File

@ -14,6 +14,10 @@ import android.widget.Toast;
import com.gh.gamecenter.entity.GameUpdateEntity;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.security.cert.CertificateException;
@ -23,267 +27,289 @@ 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("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;
}
/*
* 返回光环助手的版本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) {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(
packageName);
if (intent != null) {
context.startActivity(intent);
} else {
Toast.makeText(context, "启动失败", Toast.LENGTH_SHORT).show();
}
}
/*
* 返回光环助手的版本信息
*/
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 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;
}
/*
* 返回光环助手的版本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 boolean isInstalled(Context context, String packageName) {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
return intent != null;
}
/*
* 获取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 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;
}
/*
* 获取所有已安装的软件的包名、版本(非系统应用)
*/
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 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 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 {
Toast.makeText(context, "启动失败", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(context, "启动失败", Toast.LENGTH_SHORT).show();
}
}
/*
* 根据包名,获取软件名称
*/
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;
}
}

View File

@ -0,0 +1,32 @@
package com.gh.common.util;
import android.util.Patterns;
import java.util.regex.Matcher;
/**
* @author CsHeng
* @Date 17/05/2017
* @Time 2:35 PM
*/
public class PatternUtils {
// public static final Pattern VALID_EMAIL_ADDRESS_REGEX =
// Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
// public static final Pattern VALIDATE_URL_REGEX =
// Pattern.compile("((http://|ftp://|https://|www.))(([a-zA-Z0-9\\._-]+\\.[a-zA-Z]{2,6})|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\\&%_\\./-~-]*)?");
public static boolean isEmailAddress(String emailStr) {
Matcher matcher = Patterns.EMAIL_ADDRESS.matcher(emailStr);
return matcher.matches();
}
public static boolean isUrlAddress(String url) {
Matcher matcher = Patterns.WEB_URL.matcher(url);
return matcher.matches();
}
}

View File

@ -7,12 +7,15 @@ import android.os.Handler;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;
import com.gh.base.AppController;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.PlatformEntity;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
@ -25,268 +28,265 @@ import java.util.Locale;
import java.util.Properties;
import java.util.Set;
import de.greenrobot.event.EventBus;
import retrofit2.adapter.rxjava.HttpException;
import retrofit2.HttpException;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
public class PlatformUtils {
private static PlatformUtils mInstance;
private static PlatformUtils mInstance;
private Context context;
private Context context;
private ArrayMap<String, String> platformMap;
private ArrayMap<String, Integer> platformPicMap;
private ArrayMap<String, String> platformPicUrlMap;
private ArrayMap<String, String> platformColorMap;
private ArrayMap<String, String> platformMap;
private ArrayMap<String, Integer> platformPicMap;
private ArrayMap<String, String> platformPicUrlMap;
private ArrayMap<String, String> platformColorMap;
private boolean isCheck = false;
private boolean isUpdate = false;
private PlatformUtils(Context con) {
this.context = con.getApplicationContext();
initMap();
}
private PlatformUtils(Context con) {
this.context = con.getApplicationContext();
initMap();
}
public static PlatformUtils getInstance(Context context) {
if (mInstance == null) {
mInstance = new PlatformUtils(context);
}
return mInstance;
}
private void initMap() {
ArrayMap<String, Integer> platformPicMap = new ArrayMap<>();
platformPicMap.put("360", R.drawable.platform_360);
platformPicMap.put("37wan", R.drawable.platform_37);
platformPicMap.put("91", R.drawable.platform_91);
platformPicMap.put("9u", R.drawable.platform_9u);
platformPicMap.put("anzhi", R.drawable.platform_anzhi);
platformPicMap.put("baidu", R.drawable.platform_baidu);
platformPicMap.put("dangle", R.drawable.platform_dl);
platformPicMap.put("ewan", R.drawable.platform_ewan);
platformPicMap.put("gf", R.drawable.platform_gf);
platformPicMap.put("gf-w", R.drawable.platform_gfw);
platformPicMap.put("huawei", R.drawable.platform_hw);
platformPicMap.put("mi", R.drawable.platform_mi);
platformPicMap.put("oppo", R.drawable.platform_oppo);
platformPicMap.put("ouwan", R.drawable.platform_ouwan);
platformPicMap.put("pps", R.drawable.platform_pps);
platformPicMap.put("vivo", R.drawable.platform_vivo);
platformPicMap.put("wdj", R.drawable.platform_wdj);
private void initMap() {
ArrayMap<String, Integer> platformPicMap = new ArrayMap<>();
platformPicMap.put("360", R.drawable.platform_360);
platformPicMap.put("37wan", R.drawable.platform_37);
platformPicMap.put("91", R.drawable.platform_91);
platformPicMap.put("9u", R.drawable.platform_9u);
platformPicMap.put("anzhi", R.drawable.platform_anzhi);
platformPicMap.put("baidu", R.drawable.platform_baidu);
platformPicMap.put("dangle", R.drawable.platform_dl);
platformPicMap.put("ewan", R.drawable.platform_ewan);
platformPicMap.put("gf", R.drawable.platform_gf);
platformPicMap.put("gf-w", R.drawable.platform_gfw);
platformPicMap.put("huawei", R.drawable.platform_hw);
platformPicMap.put("mi", R.drawable.platform_mi);
platformPicMap.put("oppo", R.drawable.platform_oppo);
platformPicMap.put("ouwan", R.drawable.platform_ouwan);
platformPicMap.put("pps", R.drawable.platform_pps);
platformPicMap.put("vivo", R.drawable.platform_vivo);
platformPicMap.put("wdj", R.drawable.platform_wdj);
ArrayMap<String, String> platformColorMap = new ArrayMap<>();
platformColorMap.put("360", "#218FA4");
platformColorMap.put("37wan", "#F5BD20");
platformColorMap.put("91", "#6A63CB");
platformColorMap.put("9u", "#E17237");
platformColorMap.put("anzhi", "#58BB3D");
platformColorMap.put("baidu", "#537CB3");
platformColorMap.put("dangle", "#E1842B");
platformColorMap.put("ewan", "#36A3DC");
platformColorMap.put("gf", "#BB3D42");
platformColorMap.put("gf-w", "#BB3D42");
platformColorMap.put("huawei", "#EB2526");
platformColorMap.put("mi", "#DC552B");
platformColorMap.put("oppo", "#2A8A64");
platformColorMap.put("ouwan", "#E6D66D");
platformColorMap.put("pps", "#FF8C27");
platformColorMap.put("vivo", "#3FA5E3");
platformColorMap.put("wdj", "#5ABA3F");
ArrayMap<String, String> platformColorMap = new ArrayMap<>();
platformColorMap.put("360", "#218FA4");
platformColorMap.put("37wan", "#F5BD20");
platformColorMap.put("91", "#6A63CB");
platformColorMap.put("9u", "#E17237");
platformColorMap.put("anzhi", "#58BB3D");
platformColorMap.put("baidu", "#537CB3");
platformColorMap.put("dangle", "#E1842B");
platformColorMap.put("ewan", "#36A3DC");
platformColorMap.put("gf", "#BB3D42");
platformColorMap.put("gf-w", "#BB3D42");
platformColorMap.put("huawei", "#EB2526");
platformColorMap.put("mi", "#DC552B");
platformColorMap.put("oppo", "#2A8A64");
platformColorMap.put("ouwan", "#E6D66D");
platformColorMap.put("pps", "#FF8C27");
platformColorMap.put("vivo", "#3FA5E3");
platformColorMap.put("wdj", "#5ABA3F");
ArrayMap<String, String> platformMap = new ArrayMap<>();
ArrayMap<String, String> platformPicUrlMap = new ArrayMap<>();
ArrayMap<String, String> platformMap = new ArrayMap<>();
ArrayMap<String, String> platformPicUrlMap = new ArrayMap<>();
SharedPreferences sharedPreferences = context.getSharedPreferences(
"gh_platform", Context.MODE_PRIVATE);
Set<String> set = sharedPreferences.getStringSet("platform", null);
if (set == null) {
Properties properties = new Properties();
try {
properties
.load(context.getAssets().open("platform.properties"));
Set<String> pset = new HashSet<>();
for (Object object : properties.keySet()) {
platformMap.put(object.toString(),
(String) properties.get(object));
pset.add(object.toString() + "="
+ (String) properties.get(object) + "=" + "=");
}
Editor editor = sharedPreferences.edit();
editor.putStringSet("platform", pset);
editor.apply();
} catch (IOException e) {
e.printStackTrace();
}
} else {
ArrayList<String> urls = new ArrayList<>();
for (String str : set) {
String[] platform = str.split("=");
platformMap.put(platform[0], platform[1]);
if (platform.length == 4 && !TextUtils.isEmpty(platform[2])) {
platformPicUrlMap.put(platform[0], platform[2]);
urls.add(platform[2]);
}
if (platform.length == 4 && !TextUtils.isEmpty(platform[3])) {
platformColorMap.put(platform[0], platform[3]);
}
}
if (urls.size() != 0) {
checkPlatformPic(urls);
}
}
SharedPreferences sharedPreferences = context.getSharedPreferences(
"gh_platform", Context.MODE_PRIVATE);
Set<String> set = sharedPreferences.getStringSet("platform", null);
if (set == null) {
Properties properties = new Properties();
try {
properties
.load(context.getAssets().open("platform.properties"));
Set<String> pset = new HashSet<>();
for (Object object : properties.keySet()) {
platformMap.put(object.toString(),
(String) properties.get(object));
pset.add(object.toString() + "="
+ (String) properties.get(object) + "=" + "=");
}
Editor editor = sharedPreferences.edit();
editor.putStringSet("platform", pset);
editor.apply();
} catch (IOException e) {
e.printStackTrace();
}
} else {
ArrayList<String> urls = new ArrayList<>();
for (String str : set) {
String[] platform = str.split("=");
platformMap.put(platform[0], platform[1]);
if (platform.length == 4 && !TextUtils.isEmpty(platform[2])) {
platformPicUrlMap.put(platform[0], platform[2]);
urls.add(platform[2]);
}
if (platform.length == 4 && !TextUtils.isEmpty(platform[3])) {
platformColorMap.put(platform[0], platform[3]);
}
}
if (urls.size() != 0) {
checkPlatformPic(urls);
}
}
updataPlatform(platformMap, platformPicMap, platformPicUrlMap,
platformColorMap);
}
updataPlatform(platformMap, platformPicMap, platformPicUrlMap,
platformColorMap);
}
private void checkPlatformPic(final ArrayList<String> urls) {
isCheck = true;
File file = new File(FileUtils.getPlatformPicDir(context));
if (file.isDirectory()) {
for (File f : file.listFiles()) {
for (int i = 0; i < urls.size(); i++) {
String url = urls.get(i);
String filename = url.substring(url.lastIndexOf("/") + 1);
if (f.getName().equals(filename)) {
urls.remove(i);
break;
}
}
}
}
if (urls.size() != 0) {
AppController.MAIN_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
int success = 0;
for (int i = 0; i < urls.size(); i++) {
String url = urls.get(i);
String savePath = FileUtils.getPlatformPicDir(context)
+ File.separator
+ url.substring(url.lastIndexOf("/") + 1);
int code = FileUtils.downloadFile(url, savePath);
if (code == HttpURLConnection.HTTP_OK) {
success++;
}
}
if (success == urls.size()) {
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new EBReuse("PlatformChanged"));
}
});
}
isCheck = false;
}
});
} else {
isCheck = false;
}
}
private boolean isCheck = false;
private void updataPlatform(ArrayMap<String, String> pMap,
ArrayMap<String, Integer> pPMap, ArrayMap<String, String> pUMap,
ArrayMap<String, String> pCMap) {
platformMap = pMap;
platformPicMap = pPMap;
platformPicUrlMap = pUMap;
platformColorMap = pCMap;
}
private void updataPlatform(ArrayMap<String, String> pMap,
ArrayMap<String, Integer> pPMap, ArrayMap<String, String> pUMap,
ArrayMap<String, String> pCMap) {
platformMap = pMap;
platformPicMap = pPMap;
platformPicUrlMap = pUMap;
platformColorMap = pCMap;
}
public static PlatformUtils getInstance(Context context) {
if (mInstance == null) {
mInstance = new PlatformUtils(context);
}
return mInstance;
}
private void checkPlatformPic(final ArrayList<String> urls) {
isCheck = true;
File file = new File(FileUtils.getPlatformPicDir(context));
if (file.isDirectory()) {
for (File f : file.listFiles()) {
for (int i = 0; i < urls.size(); i++) {
String url = urls.get(i);
String filename = url.substring(url.lastIndexOf("/") + 1);
if (f.getName().equals(filename)) {
urls.remove(i);
break;
}
}
}
}
if (urls.size() != 0) {
new Thread() {
@Override
public void run() {
int success =0;
for (int i = 0; i < urls.size(); i++) {
String url = urls.get(i);
String savePath = FileUtils.getPlatformPicDir(context)
+ File.separator
+ url.substring(url.lastIndexOf("/") + 1);
int code = FileUtils.downloadFile(url, savePath);
if (code == HttpURLConnection.HTTP_OK) {
success++;
}
}
if (success == urls.size()) {
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new EBReuse("PlatformChanged"));
}
});
}
isCheck = false;
}
}.start();
} else {
isCheck = false;
}
}
public String getPlatformColor(String platform) {
if ("".equals(platform) || "官方版".equals(platform)) {
return "#BB3D42";
}
String color = platformColorMap.get(platform);
if (color != null) {
return color;
}
return "#00B7FA";
}
public String getPlatformColor(String platform) {
if ("".equals(platform) || "官方版".equals(platform)) {
return "#BB3D42";
}
String color = platformColorMap.get(platform);
if (color != null) {
return color;
}
return "#00B7FA";
}
public int getPlatformPic(String platform) {
if ("".equals(platform) || "官方版".equals(platform)) {
return R.drawable.platform_gf;
}
Integer id = platformPicMap.get(platform);
if (id != null) {
return id;
}
return 0;
}
public int getPlatformPic(String platform) {
if ("".equals(platform) || "官方版".equals(platform)) {
return R.drawable.platform_gf;
}
Integer id = platformPicMap.get(platform);
if (id != null) {
return id;
}
return 0;
}
public String getPlatformPicPath(String platform) {
String path = null;
String url = platformPicUrlMap.get(platform);
if (url != null) {
String fileName = url.substring(url.lastIndexOf("/") + 1);
File file = new File(FileUtils.getPlatformPicDir(context));
if (file.isDirectory()) {
for (File f : file.listFiles()) {
if (f.getName().equals(fileName)) {
path = f.getAbsolutePath();
break;
}
}
}
if (path == null && !isCheck) {
ArrayList<String> urls = new ArrayList<>();
for (String value : platformPicUrlMap.values()) {
urls.add(value);
}
checkPlatformPic(urls);
}
}
return path;
}
public String getPlatformPicPath(String platform) {
String path = null;
String url = platformPicUrlMap.get(platform);
if (url != null) {
String fileName = url.substring(url.lastIndexOf("/") + 1);
File file = new File(FileUtils.getPlatformPicDir(context));
if (file.isDirectory()) {
for (File f : file.listFiles()) {
if (f.getName().equals(fileName)) {
path = f.getAbsolutePath();
break;
}
}
}
if (path == null && !isCheck) {
ArrayList<String> urls = new ArrayList<>();
for (String value : platformPicUrlMap.values()) {
urls.add(value);
}
checkPlatformPic(urls);
}
}
return path;
}
public String getPlatformName(String platform) {
if ("".equals(platform) || "官方版".equals(platform)) {
return "官方版";
}
String platformName = platformMap.get(platform);
if (TextUtils.isEmpty(platformName)) {
getPlatform();
}
return platformName;
}
public String getPlatformName(String platform) {
if ("".equals(platform) || "官方版".equals(platform)) {
return "官方版";
}
String platformName = platformMap.get(platform);
if (TextUtils.isEmpty(platformName)) {
getPlatform();
}
return platformName;
}
public void getPlatform() {
if (isUpdate) {
return;
}
isUpdate = true;
RetrofitManager.getApi().getGamePlatform()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<List<PlatformEntity>>() {
@Override
public void onResponse(List<PlatformEntity> response) {
Set<String> platformSet = new HashSet<>();
for (PlatformEntity platformEntity : response) {
platformSet.add(platformEntity.toString());
}
SharedPreferences sp = context.getSharedPreferences("gh_platform", Context.MODE_PRIVATE);
sp.edit().putStringSet("platform", platformSet).apply();
initMap();
EventBus.getDefault().post(new EBReuse("PlatformChanged"));
private boolean isUpdate = false;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
String today = format.format(new Date());
sp.edit().putString("refresh_time", today).apply();
isUpdate = false;
}
public void getPlatform() {
if (isUpdate) {
return;
}
isUpdate = true;
RetrofitManager.getApi().getGamePlatform()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<List<PlatformEntity>>(){
@Override
public void onResponse(List<PlatformEntity> response) {
Set<String> platformSet = new HashSet<>();
for (PlatformEntity platformEntity : response) {
platformSet.add(platformEntity.toString());
}
SharedPreferences sp = context.getSharedPreferences("gh_platform", Context.MODE_PRIVATE);
sp.edit().putStringSet("platform", platformSet).apply();
initMap();
EventBus.getDefault().post(new EBReuse("PlatformChanged"));
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
String today = format.format(new Date());
sp.edit().putString("refresh_time", today).apply();
isUpdate = false;
}
@Override
public void onFailure(HttpException e) {
isUpdate = false;
}
});
}
@Override
public void onFailure(HttpException e) {
isUpdate = false;
}
});
}
}

View File

@ -2,6 +2,7 @@ package com.gh.common.util;
import android.content.Context;
import com.gh.gamecenter.entity.CommentEntity;
import com.gh.gamecenter.retrofit.JSONObjectResponse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
@ -11,7 +12,7 @@ import org.json.JSONObject;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.adapter.rxjava.HttpException;
import retrofit2.HttpException;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
@ -19,18 +20,23 @@ import rx.schedulers.Schedulers;
/**
* Created by khy on 2016/11/9.
*
*/
public class PostCommentUtils {
public static void addCommentData(final Context context, final String newsId, final String content,
final boolean isCheck, final PostCommentListener listener) {
final boolean isCheck, final CommentEntity commentEntity,
final PostCommentListener listener) {
TokenUtils.getToken(context, isCheck)
.flatMap(new Func1<String, Observable<ResponseBody>>() {
@Override
public Observable<ResponseBody> call(String token) {
RequestBody body = RequestBody.create(MediaType.parse("application/json"), content);
return RetrofitManager.getComment().postNewsComment(token, newsId, body);
if (commentEntity != null) {
return RetrofitManager.getComment().postReplyComment(token, commentEntity.getId(), body);
} else {
return RetrofitManager.getComment().postNewsComment(token, newsId, body);
}
}
})
.subscribeOn(Schedulers.io())
@ -39,21 +45,27 @@ public class PostCommentUtils {
@Override
public void onResponse(JSONObject response) {
if (response.length() != 0) {
if (listener != null){
listener.postSucced(response);
if (listener != null) {
listener.postSuccess(response);
}
} else {
Utils.toast(context, "提交失败,请检查网络设置");
}
}
@Override
public void onError(Throwable e) {
super.onError(e);
Utils.log("======" + e.toString());
}
@Override
public void onFailure(HttpException e) {
if (e != null && e.code() == 401) {
addCommentData(context, newsId, content, false, listener);
addCommentData(context, newsId, content, false, commentEntity, listener);
return;
}
if (listener != null){
if (listener != null) {
listener.postFailed(e);
}
}
@ -75,7 +87,7 @@ public class PostCommentUtils {
@Override
public void onResponse(ResponseBody response) {
if (listener != null) {
listener.postSucced(null);
listener.postSuccess(null);
}
}
@ -93,7 +105,7 @@ public class PostCommentUtils {
}
public static void addReportData(final Context context, final String reportData, boolean isCheck,
final PostCommentListener listener) {
final PostCommentListener listener) {
TokenUtils.getToken(context, isCheck)
.flatMap(new Func1<String, Observable<ResponseBody>>() {
@Override
@ -107,7 +119,7 @@ public class PostCommentUtils {
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(ResponseBody response) {
listener.postSucced(null);
listener.postSuccess(null);
}
@Override
@ -122,7 +134,8 @@ public class PostCommentUtils {
}
public interface PostCommentListener {
void postSucced(JSONObject response);
void postSuccess(JSONObject response);
void postFailed(Throwable error);
}

View File

@ -0,0 +1,42 @@
package com.gh.common.util;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
/**
* Created by khy on 2017/3/30.
*/
public class QQUtils {
public static void startQQSession(Context context, String qq) {
if (TextUtils.isEmpty(qq)) {
qq = "2586716223";
}
if (ShareUtils.isQQClientAvailable(context)) {
//安装了QQ会直接调用QQ打开手机QQ进行会话 QQ号2586716223
String str = "mqqwpa://im/chat?chat_type=wpa&uin=" + qq + "&version=1&src_type=web&web_src=oicqzone.com";
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(str)));
} else {
//没有安装QQ 复制账号
// ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
// cmb.setText(qq);
Util_System_ClipboardManager.setText(context, qq);
Utils.toast(context, "已复制" + qq);
}
}
public static boolean joinQQGroup(Context context, String key) {
Intent intent = new Intent();
intent.setData(Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D" + key));
// 此Flag可根据具体产品需要自定义如设置则在加群界面按返回返回手Q主界面不设置按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
context.startActivity(intent);
return true;
} catch (Exception e) {
// 未安装手Q或安装的版本不支持
return false;
}
}
}

View File

@ -2,7 +2,10 @@ package com.gh.common.util;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
import com.gh.gamecenter.retrofit.Response;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
@ -16,10 +19,40 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Created by khy on 2016/12/1.
*/
public class QRCodeUtils {
public static void setQRCode(final Context context, final String qrBody, final ImageView mShareQrCodeDv) {
Observable
.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
String filePath = context.getExternalCacheDir().getPath() + "/ShareImg/ShareQRCode.jpg";
boolean success = QRCodeUtils.createQRImage(qrBody, 200, 200, filePath, context);
if (success) {
subscriber.onNext(filePath);
}
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<String>() {
@Override
public void onResponse(String response) {
super.onResponse(response);
mShareQrCodeDv.setImageBitmap(BitmapFactory.decodeFile(response));
}
});
}
/**
* 生成二维码Bitmap
*
@ -29,7 +62,7 @@ public class QRCodeUtils {
* @param filePath 用于存储二维码图片的文件路径
* @return 生成二维码及保存文件是否成功
*/
public static boolean createQRImage(String content, int widthPix, int heightPix, String filePath, Context context) {
private static boolean createQRImage(String content, int widthPix, int heightPix, String filePath, Context context) {
try {
if (content == null || "".equals(content)) {
return false;
@ -68,7 +101,6 @@ public class QRCodeUtils {
file.mkdirs();
}
FileOutputStream fileOutputStream = new FileOutputStream(filePath);
//必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的内存消耗巨大
return bitmap != null && bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(filePath));
} catch (WriterException | IOException e) {

View File

@ -15,88 +15,88 @@ import javax.crypto.Cipher;
public class RSEUtils {
/**
* 公钥
*/
private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQConqikyOCl5f/VO/vZ+s6wVOhFJcI7o7hYvaLQ5Lzt5/HXbozTeRrGonKFPJurapf9hzjkg0F4/BNFMGXRVlReVdwh+Px5rbXU/ceikF8Ouf67qxiGAuDVC+4e3eIHh+mH68DlqWFJ78sB80iSLXelflGuHkbTOTtaC5F2l+AgxQIDAQAB";
/**
* 公钥
*/
private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQConqikyOCl5f/VO/vZ+s6wVOhFJcI7o7hYvaLQ5Lzt5/HXbozTeRrGonKFPJurapf9hzjkg0F4/BNFMGXRVlReVdwh+Px5rbXU/ceikF8Ouf67qxiGAuDVC+4e3eIHh+mH68DlqWFJ78sB80iSLXelflGuHkbTOTtaC5F2l+AgxQIDAQAB";
/**
* 加密算法RSA
*/
private static final String KEY_ALGORITHM = "RSA";
/**
* 加密算法RSA
*/
private static final String KEY_ALGORITHM = "RSA";
/**
* 得到公钥
*
* @return PublicKey 公钥
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
private static PublicKey getPublicKeyFromX509() throws Exception {
byte[] decodedKey = Base64.decode(PUBLIC_KEY, Base64.DEFAULT);
X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodedKey);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return keyFactory.generatePublic(x509);
}
/**
* 使用公钥加密
*
* @param content
* @return
*/
public static String encryptByPublic(String content) {
try {
PublicKey pubkey = getPublicKeyFromX509();
/**
* 使用公钥加密
*
* @param content
* @return
*/
public static String encryptByPublic(String content) {
try {
PublicKey pubkey = getPublicKeyFromX509();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubkey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubkey);
byte[] data = content.getBytes("UTF-8");
byte[] output = cipher.doFinal(data);
byte[] data = content.getBytes("UTF-8");
byte[] output = cipher.doFinal(data);
String s = new String(Base64.encode(output, Base64.DEFAULT));
String s = new String(Base64.encode(output, Base64.DEFAULT));
return s;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
return s;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 得到公钥
*
* @return PublicKey 公钥
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
private static PublicKey getPublicKeyFromX509() throws Exception {
byte[] decodedKey = Base64.decode(PUBLIC_KEY, Base64.DEFAULT);
X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodedKey);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return keyFactory.generatePublic(x509);
}
/**
* 使用公钥解密
*
* @param content 密文
* @return 解密后的字符串
*/
public static String decryptByPublic(String content) {
try {
PublicKey pubkey = getPublicKeyFromX509();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, pubkey);
InputStream ins = new ByteArrayInputStream(Base64.decode(content,
Base64.DEFAULT));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[128];
int len;
while ((len = ins.read(buffer)) != -1) {
byte[] block = null;
if (buffer.length == len) {
block = buffer;
} else {
block = new byte[len];
for (int i = 0; i < len; i++) {
block[i] = buffer[i];
}
}
baos.write(cipher.doFinal(block));
}
return new String(baos.toByteArray(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 使用公钥解密
*
* @param content 密文
* @return 解密后的字符串
*/
public static String decryptByPublic(String content) {
try {
PublicKey pubkey = getPublicKeyFromX509();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, pubkey);
InputStream ins = new ByteArrayInputStream(Base64.decode(content,
Base64.DEFAULT));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[128];
int len;
while ((len = ins.read(buffer)) != -1) {
byte[] block;
if (buffer.length == len) {
block = buffer;
} else {
block = new byte[len];
for (int i = 0; i < len; i++) {
block[i] = buffer[i];
}
}
baos.write(cipher.doFinal(block));
}
return new String(baos.toByteArray(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

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