Compare commits

..

1 Commits
v3.0 ... v2.4

Author SHA1 Message Date
khy
fc1dc858e2 修复BUG 2017-03-20 09:28:55 +08:00
1068 changed files with 67515 additions and 64457 deletions

13
.gitignore vendored
View File

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

4
.gitmodules vendored
View File

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

View File

@ -1,8 +0,0 @@
### Ver 3.0
* x
### Ver 2.6
* xx
### Ver 2.5
* 此处写本次更新所做的业务和代码修改

147
PushSDK/AndroidManifest.xml Normal file
View File

@ -0,0 +1,147 @@
<?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>

51
PushSDK/build.gradle Normal file
View File

@ -0,0 +1,51 @@
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

@ -0,0 +1,156 @@
<?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>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,12 @@
# 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

View File

@ -1,27 +0,0 @@
# 光环助手Android客户端
### 多渠道打包配置
* 使用[ApkChannelPackage](https://github.com/ltlovezh/ApkChannelPackage)的方案
* 正式打包命令:请使用./gradlew channelRelease打包渠道包
### 混淆配置
* 配置文件Android默认配置+proguard-rules.txt等
* 参考libraries下每个项目独立的配置文件``proguard-project.txt``
### apk大小优化
* 限制resConfig资源集
* 开启ShrinkResources
* 开启混淆使用minifyEnabled(仅在release开启
* pngquant对png压缩、png/jpg->webp(未尝试)
### 第三方appkey等配置
* 修改``gradle.properties``文件将各种key填入其中实现统一管理
* 通过gradle文件内的resValue/buildConfigField/manifestPlaceHolder方式实现编译期间修改具体情况请参考``./build.gradle``和``./app/build.gradle``配置
### 拉取代码步骤
1. 拉取主项目代码: `git clone -b master git@gitlab.ghzhushou.com:halo/assistant-android.git`
2. 初始化公用类库: `git submodule init && git submodule update`
### submodule管理方式(只拉取master)
* 拉取子模块代码:`git submodule foreach git pull origin master`
* 提交代码需要cd到submodule文件夹去做修改

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -1,250 +1,153 @@
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'kotlin-android' // kotlin
//tinker插件
//apply plugin: 'com.tencent.tinker.patch'
// apkChannelPackage
apply plugin: 'channel'
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
compileSdkVersion 21
buildToolsVersion "23.0.3"
dexOptions {
jumboMode = true
}
/**
* 定位编译出错的图片
*/
aaptOptions.cruncherEnabled = false
aaptOptions.useNewCruncher = false
defaultConfig {
applicationId "com.gh.gamecenter"
minSdkVersion 14
targetSdkVersion 21
versionCode 19
versionName "2.4"
javaCompileOptions {
annotationProcessorOptions {
arguments = [ eventBusIndex : 'com.gh.EventBusIndex' ]
}
}
/**
* 只支持两种架构减少apk大小有疑问请参考
* https://developer.android.com/ndk/guides/abis.html
* http://allenfeng.com/2016/11/06/what-you-should-know-about-android-abi-and-so/
* 为了性能考虑armeabi可以考虑替换成armeabi-v7a[需要先收集用户设备情况]
*/
ndk {
abiFilters "armeabi", "x86"
}
// 由于app只针对中文用户所以仅保留zh资源其他删掉
resConfigs "zh"
// 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}\""
// multiDexEnabled true
}
// gradle 2.2以上默认同时启用v1和v2优先用于Android N
/**
* 签名设置
*/
signingConfigs {
debug {
v1SigningEnabled true
v2SigningEnabled true
}
release {
v1SigningEnabled true
v2SigningEnabled true
storeFile file("gh.keystore")
keyAlias "gh.keystore"
keyPassword "20150318"
storePassword "20150318"
}
}
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}\""
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
debuggable false
minifyEnabled true
zipAlignEnabled true
shrinkResources true
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
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 {
// public release host
pub {
buildConfigField "String", "HOST", "\"${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", "HOST", "\"${DEV_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
// sourceSets {
// main {
// jniLibs.srcDirs = ['libs']
// }
// }
}
// 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.gh.EventBusIndex"
/**
* 多渠道打包
*/
productFlavors {
GH_100 {}
GH_101 {}
GH_102 {}
GH_103 {}
GH_104 {}
GH_106 {}
GH_107 {}
GH_108 {}
GH_109 {}
GH_110 {}
GH_111 {}
GH_113 {}
GH_114 {}
GH_115 {}
GH_116 {}
GH_117 {}
GH_118 {}
GH_119 {}
GH_120 {}
GH_121 {}
GH_123 {}
GH_127 {}
GH_200 {}
GH_201 {}
GH_202 {}
GH_203 {}
GH_204 {}
GH_205 {}
GH_222 {}
GH_307 {}
GH_TEST {}
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [CHANNEL_VALUE: name]//命令 gradlew assembleRelease
}
}
rebuildChannel {
// baseDebugApk = 已有Debug APK
// baseReleaseApk = 已有Release APK
// //默认为new File(project.buildDir, "rebuildChannel/debug")
// debugOutputDir = Debug渠道包输出目录
// //默认为new File(project.buildDir, "rebuildChannel/release")
// releaseOutputDir = Release渠道包输出目录
//butterknife
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
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
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.weiboSDK
compile libs.eventbus
apt libs.eventbusApt
compile project(':libraries:LGLibrary')
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:iosched')
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"
}
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
}
// 依赖插件脚本
//apply from: 'tinker-support.gradle'

BIN
app/libs/EventBus-2.4.0.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
app/libs/mid-sdk-2.3.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

@ -1,11 +1,8 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
# 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
@ -17,4 +14,4 @@
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
#}

View File

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

View File

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

View File

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

View File

@ -1,278 +1,360 @@
<?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="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 小米推送需要的权限 -->
<uses-permission android:name="com.gh.gamecenter.permission.MIPUSH_RECEIVE" />
<!-- 修改系统设置的权限 -->
<uses-permission android:name = "android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<permission
android:name="com.gh.gamecenter.permission.MIPUSH_RECEIVE"
android:protectionLevel="signature" />
<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:allowBackup = "true"
android:icon = "@drawable/logo"
android:label = "@string/app_name"
android:theme = "@style/AppCompatTheme.APP" >
android:name="com.gh.base.AppController"
android:icon="@drawable/logo"
android:label="@string/app_name"
android:theme="@style/AppNormalTheme" >
<!-- TalkingData -->
<meta-data
android:name="TD_APP_ID"
android:value="81DB144D555386A38A70B833537EC256" />
<meta-data
android:name="TD_CHANNEL_ID"
android:value="GH_TEST"/>
<!--android:value="${CHANNEL_VALUE}"-->
<!--android:launchMode = "singleTask"-->
<activity
android:name = "com.gh.gamecenter.SplashScreenActivity"
android:configChanges = "keyboardHidden|orientation|screenSize"
android:noHistory = "true"
android:screenOrientation = "portrait"
android:theme = "@style/AppGuideTheme" >
<intent-filter >
<action android:name = "android.intent.action.MAIN" />
<!-- MTA -->
<meta-data
android:name="TA_APPKEY"
android:value="APV567FTBS7J"/>
<meta-data
android:name="InstallChannel"
android:value="GH_TEST"/>
<!--android:value="${CHANNEL_VALUE}"-->
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter >
</activity >
<!-- 友盟推送 -->
<meta-data
android:name="UMENG_APPKEY"
android:value="585a29fa8f4a9d327600023e">
</meta-data>
<meta-data
android:name="UMENG_MESSAGE_SECRET"
android:value="8bcce6bed547ee624f5c2cc64d39a9e9">
</meta-data>
<activity
android:name = "com.gh.gamecenter.MainActivity"
android:launchMode = "singleTask"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateAlwaysHidden|adjustResize" />
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>
<activity
android:name = "com.gh.gamecenter.DownloadManagerActivity"
android:launchMode = "singleTask"
android:screenOrientation = "portrait" />
android:name="com.gh.gamecenter.MainActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"/>
<activity
android:name="com.gh.gamecenter.DownloadManagerActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.ViewImageActivity"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" />
<activity
android:name="com.gh.gamecenter.SearchActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateVisible" />
<activity
android:name="com.gh.gamecenter.GameDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.NewsDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SettingActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SuggestionActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateVisible" />
<activity
android:name="com.gh.gamecenter.ConcernActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SubjectActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.PluginActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.NewsSearchActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.GameNewsActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.CropImageActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.WebActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ShareCardPicActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ShareCardActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.MessageDetailActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.StrategyActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.LibaoActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.LibaoDetailActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ShareGhWfifActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ShareGhActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.CleanApkActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.KcSelectGameActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ChooseReceiverActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.ReceiverWaitingActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.FileSenderActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.FileReceiverActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.SelectUserIconActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.AboutActivity"
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.SkipActivity"
android:theme="@android:style/Theme.Translucent">
<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.ViewImageActivity"
android:theme = "@android:style/Theme.Black.NoTitleBar.Fullscreen" />
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.gh.gamecenter.SearchActivity"
android:configChanges = "keyboardHidden"
android:screenOrientation = "portrait" />
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.gh.gamecenter.NewsDetailActivity"
android:screenOrientation = "portrait" />
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.gh.gamecenter.SettingActivity"
android:screenOrientation = "portrait" />
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.ConcernActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.SubjectActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.PluginActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.NewsSearchActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
<activity
android:name = "com.gh.gamecenter.GameNewsActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.CropImageActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.WebActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ShareCardPicActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ShareCardActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.MessageDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.LibaoActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
<activity
android:name = "com.gh.gamecenter.LibaoDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ShareGhWfifActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ShareGhActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.CleanApkActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.KcSelectGameActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ChooseReceiverActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.ReceiverWaitingActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.FileSenderActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.FileReceiverActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.SelectUserIconActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.AboutActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.KaiFuActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.CommentDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.GameDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.SuggestSelectActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.SuggestionActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.VoteActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateAlwaysHidden|adjustResize" />
<activity
android:name = "com.gh.gamecenter.ToolBoxActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
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>
<activity
android:name = "com.gh.gamecenter.WeiBoShareActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
<receiver android:name="com.gh.gamecenter.receiver.InstallAndUninstallReceiver" >
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<activity
android:name = "com.gh.gamecenter.InstallActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.LoginActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden" />
<activity
android:name = "com.gh.gamecenter.UserInfoActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.UserAreaActivity"
android:screenOrientation = "portrait" />
<!--非全屏+ScrollView+adjustResize-->
<activity
android:name = "com.gh.gamecenter.UserInfoEditActivity"
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 = ".CommonActivity"
android:screenOrientation = "portrait" />
<receiver android:name = "com.gh.gamecenter.receiver.InstallAndUninstallReceiver" >
<intent-filter >
<action android:name = "android.intent.action.PACKAGE_ADDED" />
<action android:name = "android.intent.action.PACKAGE_REMOVED" />
<action android:name = "android.intent.action.PACKAGE_REPLACED" />
<data android:scheme = "package" />
</intent-filter >
</receiver >
<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.gh.gamecenter.receiver.ActivitySkipReceiver"
android:exported = "true" >
<intent-filter >
<action android:name = "com.gh.gamecenter.ACTIVITYSKIP" />
</intent-filter >
</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" />
<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />
<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>
</application >
<service
android:name="com.gh.download.DownloadService" />
</manifest >
<!--<service-->
<!--android:name="com.gh.base.AppTinkerResultService"-->
<!--android:exported="false" />-->
<service
android:name="com.gh.gamecenter.statistics.AppStaticService" />
<service
android:name="com.xiaomi.push.service.XMJobService"
android:enabled="true"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":pushservice" />
<service
android:name="com.xiaomi.push.service.XMPushService"
android:enabled="true"
android:process=":pushservice" />
<service
android:name="com.xiaomi.mipush.sdk.PushMessageHandler"
android:enabled="true"
android:exported="true" />
<service
android:name="com.xiaomi.mipush.sdk.MessageHandleService"
android:enabled="true" />
</application>
</manifest>

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,24 +46,22 @@ article {
margin-bottom:20%;
}
}
</style>
</style>
</head>
</head>
<body>
<header>
</header>
<header>
</header>
<article>
<img src="http://192.168.43.1:3100/image/gh_icon.png" width="28%">
<p class="title">光环助手</p>
<br class="info">乐于分享的人是最帅的^_^ </p>
<div class="download">
<a href="http://192.168.43.1:3100/download/ghzs.apk">免流量下载</a>
<article>
<img src="http://192.168.43.1:3100/image/gh_icon.png" width="28%">
<p class="title">光环助手</p>
<br class="info">乐于分享的人是最帅的^_^ </p>
<div class="download">
<a href="http://192.168.43.1:3100/download/ghzs.apk">免流量下载</a>
</div>
<p class="title"><font color="#9A9A9A" size="3em">仅限安卓系统 </font></p>
</article>
<p class="title"><font color="#9A9A9A" size="3em">仅限安卓系统 </font></p>
</article>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,699 @@
/*
* 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

@ -0,0 +1,484 @@
/*
* 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

@ -0,0 +1,628 @@
/*
* 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

@ -0,0 +1,816 @@
/*
* 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

@ -0,0 +1,87 @@
/*
* 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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,338 @@
/*
* 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

@ -0,0 +1,238 @@
/*
* 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

@ -0,0 +1,338 @@
/*
* 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

@ -0,0 +1,460 @@
/*
* 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

@ -0,0 +1,97 @@
/*
* 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

@ -0,0 +1,94 @@
/*
* 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());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,48 +6,50 @@ import android.graphics.Color;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
public class CustomView extends 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;
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;
}
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();
}
}

View File

@ -8,167 +8,176 @@ 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");
float radius1 = 0;
float radius2 = 0;
int cont = 0;
boolean firstAnimationOver = false;
int arcD = 1;
int arcO = 0;
float rotateAngle = 0;
int limite = 0;
int backgroundColor = Color.parseColor("#1E88E5");
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) {
}
setMinimumHeight(Utils.dpToPx(32, getResources()));
setMinimumWidth(Utils.dpToPx(32, getResources()));
// Set atributtes of XML to View
protected void setAttributes(AttributeSet attrs) {
// 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"));
}
}
setMinimumHeight(Utils.dpToPx(32, getResources()));
setMinimumWidth(Utils.dpToPx(32, getResources()));
setMinimumHeight(Utils.dpToPx(3, getResources()));
// 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()));
// 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;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!firstAnimationOver) {
drawFirstAnimation(canvas);
}
if (cont > 0) {
drawSecondAnimation(canvas);
}
invalidate();
/**
* 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 == 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;
}
}
}
}
/**
* 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);
float radius1 = 0;
float radius2 = 0;
int cont = 0;
boolean firstAnimationOver = false;
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);
/**
* 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;
}
}
canvas.drawBitmap(bitmap, 0, 0, new Paint());
}
int arcD = 1;
int arcO = 0;
float rotateAngle = 0;
int limite = 0;
/**
* 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);
}
/**
* 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;
}
}

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,195 +1,128 @@
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.facebook.drawee.backends.pipeline.Fresco;
import com.gh.EventBusIndex;
import com.gh.common.constant.Config;
import com.gh.common.util.DataUtils;
import com.gh.common.util.StringUtils;
import com.gh.common.util.HttpsUtils;
import com.gh.common.util.TokenUtils;
import com.gh.gamecenter.BuildConfig;
import com.leon.channel.helper.ChannelReaderUtil;
import com.lightgame.utils.Utils;
import com.gh.common.util.Utils;
import com.umeng.message.IUmengRegisterCallback;
import com.umeng.message.PushAgent;
import com.umeng.message.UTrack;
import com.xiaomi.channel.commonutils.logger.LoggerInterface;
import com.xiaomi.mipush.sdk.Logger;
import com.xiaomi.mipush.sdk.MiPushClient;
import 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();
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<>();
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";
private String mChannel;
private static AppController mInstance;
private static ArrayMap<String, Object> objectMap = new ArrayMap<>();
public static void put(String key, Object object) {
if (objectMap == null) {
objectMap = new ArrayMap<>();
}
objectMap.put(key, object);
}
private ArrayList<Activity> list = new ArrayList<>();
public static Object get(String key, boolean isRemove) {
if (objectMap == null) {
return null;
}
if (isRemove) {
return objectMap.remove(key);
} else {
return objectMap.get(key);
}
}
private boolean isFinish = false;
public static void remove(String key) {
if (objectMap == null) {
return;
}
objectMap.remove(key);
}
//快传文件发送单线程
public static Executor FILE_SENDER_EXECUTOR = Executors.newSingleThreadExecutor();
public static synchronized AppController getInstance() {
return mInstance;
}
//快传文件发送主要的线程池
public static Executor MAIN_EXECUTOR = Executors.newFixedThreadPool(5);
public String getChannel() {
return mChannel;
}
// public AppController() {
// super(ShareConstants.TINKER_ENABLE_ALL, "com.gh.base.AppControllerLike",
// "com.tencent.tinker.loader.TinkerLoader", false);
// }
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
@Override
public void onCreate() {
super.onCreate();
//初始化Fresco
Fresco.initialize(this);
@Override
public void onCreate() {
super.onCreate();
DataUtils.init(this);
mInstance = this;
HttpsUtils.initHttpsUrlConnection(this);
//TODO 强烈不建议开发阶段开启这个Handler必须处理错误
if (!BuildConfig.DEBUG) {
AppUncaughtHandler appUncaughtHandler = new AppUncaughtHandler(this);
Thread.setDefaultUncaughtExceptionHandler(appUncaughtHandler);
}
AppUncaHandler uncaHandler = new AppUncaHandler(this);
Thread.setDefaultUncaughtExceptionHandler(uncaHandler);
mInstance = this;
mChannel = ChannelReaderUtil.getChannel(this);
if (TextUtils.isEmpty(mChannel)) {
//默认用Android Studio run时并没有写入channel magic number到apk包里面所以需要fallback
mChannel = "GH_TEST";
}
// 注册push服务注册成功后会向GHPushMessageReceiver发送广播
// 可以从GHPushMessageReceiver的onCommandResult方法中MiPushCommandMessage对象参数中获取注册信息
if (shouldInit()) {
MiPushClient.registerPush(this, APP_ID, APP_KEY);
}
Log.e("CHANNEL_ID", mChannel);
LoggerInterface newLogger = new LoggerInterface() {
//初始化Fresco
Fresco.initialize(this);
@Override
public void setTag(String tag) {
// ignore
}
DataUtils.init(this, BuildConfig.DEBUG, mChannel);
@Override
public void log(String content, Throwable t) {
Log.d(TAG, content, t);
}
//测试MTA崩溃的坑爹
// if (BuildConfig.DEBUG) {
// StatConfig.setDebugEnable(true);
// StatConfig.setStatSendStrategy(StatReportStrategy.DEVELOPER);
// throw new RuntimeException("test again");
// }
@Override
public void log(String content) {
Log.d(TAG, content);
}
};
Logger.setLogger(this, newLogger);
// if (BuildConfig.DEBUG) {
// Stetho.initializeWithDefaults(this);
// }
//友盟推送
final PushAgent mPushAgent = PushAgent.getInstance(this);
/**
* 注册push服务注册成功后会向{@link GHPushMessageReceiver}发送广播
* 可以从{@link GHPushMessageReceiver#onCommandResult(Context, MiPushCommandMessage)}
* 的{@link MiPushCommandMessage} 对象参数中获取注册信息
*/
try {
if (shouldInit()) {
MiPushClient.registerPush(this, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY);
}
} catch (Exception e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
LoggerInterface newLogger = new LoggerInterface() {
//注册推送服务每次调用register方法都会回调该接口
mPushAgent.register(new IUmengRegisterCallback() {
@Override
public void setTag(String tag) {
// ignore
}
@Override
public void onSuccess(String deviceToken) {
//注册成功会返回device token
Utils.log("deviceToken::" + deviceToken);
@Override
public void log(String content) {
Log.d(TAG, content);
}
//设置别名
mPushAgent.addExclusiveAlias(TokenUtils.getDeviceId(getApplicationContext())
, "GHDID", new UTrack.ICallBack() {
@Override
public void onMessage(boolean b, String s) {
Utils.log("ExclusiveAlias::" + b + "==" + s);
@Override
public void log(String content, Throwable t) {
Log.d(TAG, content, t);
}
};
Logger.setLogger(this, newLogger);
}
}
});
}
try {
//友盟推送
final PushAgent pushAgent = PushAgent.getInstance(this);
pushAgent.setAppkeyAndSecret(Config.UMENG_APPKEY, Config.UMENG_MESSAGE_SECRET);
@Override
public void onFailure(String s, String s1) {
Utils.log("deviceToken::" + "注册失败");
}
});
//注册推送服务每次调用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());
} catch (Exception e) {
e.printStackTrace();
}
// 友盟推送数据处理
mPushAgent.setNotificationClickHandler(new GHUmengNotificationClickHandler());
// // 监听屏幕状态广播
// if (shouldInit()) {
@ -208,37 +141,98 @@ public class AppController extends Application {
// Utils.log(appRunTimeInfo.getPackageName() + "====1111=====" + appRunTimeInfo.getRunTime());
// }
// }
}
// 启用EventBus3.0加速功能
EventBus.builder().addIndex(new EventBusIndex()).installDefaultEventBus();
}
public static void put(String key, Object object) {
if (objectMap == null) {
objectMap = new ArrayMap<>();
}
objectMap.put(key, object);
}
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;
}
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 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 void remove(String key) {
if (objectMap == null) {
return;
}
objectMap.remove(key);
}
/**
* Activity关闭时删除Activity列表中的Activity对象
*/
public void removeActivity(Activity a) {
if (!isFinish) {
list.remove(a);
Utils.log("remove = " + a.getClass().getSimpleName());
}
}
/**
* 向Activity列表中添加Activity对象
*/
public void addActivity(Activity a) {
Utils.log("add = " + a.getClass().getSimpleName());
list.add(a);
}
/**
* 关闭Activity列表中的所有Activity
*/
public void finishActivity() {
isFinish = true;
for (int i = list.size() - 1; i >= 0; i--) {
Activity activity = list.get(i);
if (null != activity) {
Utils.log("finish = " + activity.getClass().getSimpleName());
activity.finish();
}
}
// 杀死该应用进程
Process.killProcess(Process.myPid());
}
public static String getProcessName(Context cxt, int pid) {
ActivityManager am = (ActivityManager) cxt
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
if (runningApps == null) {
return null;
}
for (RunningAppProcessInfo procInfo : runningApps) {
if (procInfo.pid == pid) {
return procInfo.processName;
}
}
return null;
}
public static synchronized AppController getInstance() {
return mInstance;
}
private boolean shouldInit() {
ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
List<RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
String mainProcessName = getPackageName();
Log.d(TAG, mainProcessName);
int myPid = Process.myPid();
for (RunningAppProcessInfo info : processInfos) {
if (info.pid == myPid && mainProcessName.equals(info.processName)) {
return true;
}
}
return false;
}
}

View File

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

View File

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

View File

@ -0,0 +1,128 @@
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

@ -1,123 +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.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import com.gh.common.util.DataCollectionUtils;
import com.gh.gamecenter.SplashScreenActivity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.AppManager;
import com.lightgame.utils.RuntimeUtils;
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 Context mContext;
public AppUncaughtHandler(Context context) {
// 获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
mContext = context;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
RuntimeUtils.getInstance().runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext.getApplicationContext(),
"\"光环助手\"发生错误", Toast.LENGTH_SHORT).show();
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 防止重复奔溃导致助手一直重启20秒内不做处理
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
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(mContext, SplashScreenActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent restartIntent = PendingIntent.getActivity(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 退出程序并重启
AlarmManager mgr = (AlarmManager) mContext.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(mContext.getApplicationContext(), errorMsg);
StatService.reportException(mContext, ex);
// 上传错误数据
DataCollectionUtils.uploadError(mContext, errorMsg);
// 保存到本地
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
File file = new File(FileUtils.getLogPath(mContext.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,153 +1,213 @@
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.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.lightgame.download.FileUtils;
import com.lightgame.utils.AppManager;
import com.readystatesoftware.systembartint.SystemBarTintManager.SystemBarConfig;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import com.gh.gamecenter.listener.OnCallBackListener;
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;
import static com.gh.common.util.EntranceUtils.KEY_DATA;
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
public class BaseActivity extends Activity implements OnCallBackListener {
public abstract class BaseActivity extends BaseAppCompatToolBarActivity {
private SystemBarTintManager tintManager;
protected String mEntrance;
private boolean mIsPause;
protected String entrance;
@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);
}
}
private boolean isPause;
@Override
protected boolean onNavigationIconClicked() {
return false;
}
@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");
}
}
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, String title) {
init(contentView);
TextView actionbar_tv_title = (TextView) findViewById(R.id.actionbar_tv_title);
actionbar_tv_title.setText(title);
}
ButterKnife.bind(this);
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());
}
View back = findViewById(R.id.actionbar_rl_back);
if (back != null)
back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
setContentView(contentView);
protected void initTitle(String title) {
TextView actionbar_tv_title = (TextView) findViewById(R.id.actionbar_tv_title);
actionbar_tv_title.setText(title);
// setNavigationTitle(title);
}
ButterKnife.bind(this);
public void toast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
int actionbar_height = getSharedPreferences(Config.PREFERENCE,
Context.MODE_PRIVATE).getInt("actionbar_height",
DisplayUtils.dip2px(getApplicationContext(), 48));
public void toast(int msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
RelativeLayout reuse_actionbar = (RelativeLayout) findViewById(R.id.reuse_actionbar);
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, actionbar_height);
reuse_actionbar.setLayoutParams(lparams);
//如果是游戏分享newsTitle默认为空
public void showShare(String url, String gameName, String icon, String newsTitle, ArrayList<String> tag, boolean isToolsBox) {
findViewById(R.id.actionbar_rl_back).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
//判断是否是官方版
boolean isPlugin = false;
if (tag != null) {
for (String s : tag) {
if (!"官方版".equals(s)) {
isPlugin = true;
}
}
}
protected SystemBarTintManager getTintManager() {
return tintManager;
}
ShareUtils.getInstance(this).showShareWindows(getWindow().getDecorView(), url, gameName, icon, newsTitle, isPlugin, true, isToolsBox);
@Override
public void finish() {
super.finish();
AppController.getInstance().removeActivity(this);
}
if (newsTitle == null) {
DataUtils.onEvent(this, "内容分享", gameName);
} else {
DataUtils.onEvent(this, "内容分享", newsTitle);
}
}
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);
}
}
@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()));
}
}
});
}
}
}
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;
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
AppManager.getInstance().finishActivity(this);
}
@Override
protected void onResume() {
super.onResume();
DataUtils.onResume(this);
isPause = false;
DownloadManager.getInstance(this).initGameMap();
}
@Override
protected void onPause() {
super.onPause();
DataUtils.onPause(this);
mIsPause = true;
}
@Override
public void loadDone() {
}
@Override
protected void onResume() {
super.onResume();
DataUtils.onResume(this);
mIsPause = false;
DownloadManager.getInstance(this).initGameMap();
}
@Override
public void loadDone(Object obj) {
}
@Override
public void loadError() {
}
@Override
public void loadEmpty() {
}
}

View File

@ -1,154 +0,0 @@
package com.gh.base;
import android.annotation.TargetApi;
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.View;
import android.view.Window;
import android.view.WindowManager;
import com.gh.gamecenter.R;
import com.lightgame.BaseAppCompatActivity;
import com.lightgame.ToolbarContainer;
import com.lightgame.ToolbarController;
import com.readystatesoftware.systembartint.SystemBarTintManager;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* Created by csheng on 15-10-12.
*/
@ToolbarContainer
public abstract class BaseAppCompatToolBarActivity extends BaseAppCompatActivity implements ToolbarController {
private Toolbar mToolbar;
private SystemBarTintManager mTintManager;
// TODO 获取沉浸栏管理,要进行版本判断或者判断是否为空
public 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);
mToolbar.addView(View.inflate(this, R.layout.reuse_actionbar, null));
getSupportActionBar().setHomeButtonEnabled(false);
// getSupportActionBar().setDisplayHomeAsUpEnabled(false);
// getSupportActionBar().setDisplayShowHomeEnabled(false);
// getSupportActionBar().setDisplayOptions();
}
}
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;
}
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
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) {
if (mToolbar != null) {
mToolbar.setTitle(res);
}
}
@Override
public void setNavigationTitle(CharSequence res) {
if (mToolbar != null) {
mToolbar.setTitle(res);
}
}
@Override
public Toolbar getToolBar() {
return mToolbar;
}
}

View File

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

View File

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

View File

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

View File

@ -1,23 +0,0 @@
package com.gh.base;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import butterknife.ButterKnife;
/**
* 目前仅提供butterknife bind方法
*
* @author CsHeng
* @Date 16/06/2017
* @Time 9:55 AM
*/
public abstract class BaseRecyclerViewHolder extends RecyclerView.ViewHolder {
public BaseRecyclerViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}

View File

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

View File

@ -1,9 +1,14 @@
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.EntranceUtils;
import com.gh.common.util.ClassUtils;
import com.gh.common.util.RunningUtils;
import com.gh.gamecenter.MainActivity;
import com.gh.gamecenter.SplashScreenActivity;
import com.umeng.message.UmengNotificationClickHandler;
import com.umeng.message.entity.UMessage;
@ -13,39 +18,54 @@ 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(EntranceUtils.KEY_DATA);
JSONObject response = new JSONObject(content);
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG);
String type = response.getString(EntranceUtils.KEY_TYPE);
String target = response.getString(EntranceUtils.KEY_TARGET);
switch (type) {
case EntranceUtils.HOST_ARTICLE:
bundle.putString(EntranceUtils.KEY_TO, "NewsDetailActivity");
bundle.putString(EntranceUtils.KEY_NEWSID, target);
break;
case EntranceUtils.HOST_GAME:
bundle.putString(EntranceUtils.KEY_TO, "GameDetailActivity");
bundle.putString(EntranceUtils.KEY_GAMEID, target);
break;
case EntranceUtils.HOSt_COLUMN:
bundle.putString(EntranceUtils.KEY_TO, "SubjectActivity");
bundle.putString(EntranceUtils.KEY_ID, target);
break;
case EntranceUtils.HOST_WEB:
bundle.putString(EntranceUtils.KEY_TO, "WebActivity");
bundle.putString(EntranceUtils.KEY_URL, target);
break;
}
EntranceUtils.jumpActivity(context, bundle);
} catch (JSONException e) {
e.printStackTrace();
}
}
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();
}
}
}

View File

@ -0,0 +1,205 @@
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.widget.LinearLayout;
import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.common.util.DataCollectionUtils;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.ConcernActivity;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SearchActivity;
import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.manager.PackageManager;
import de.greenrobot.event.EventBus;
/**
* Created by LGT on 2016/9/9.
* 工具栏 搜索控制
*/
public class HomeFragment extends Fragment implements View.OnClickListener {
protected View view;
protected Handler handler = new Handler();
private TextView downloadHint;
private TextView searchHint;
private String hint;
@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);
if (savedInstanceState != null) {
hint = savedInstanceState.getString("hint");
}
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)));
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();
EventBus.getDefault().register(this);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
if (container != null) {
container.removeView(view);
}
return view;
}
private void initActionBar() {
view.findViewById(R.id.actionbar_rl_download).setOnClickListener(this);
view.findViewById(R.id.actionbar_iv_search).setOnClickListener(this);
view.findViewById(R.id.actionbar_notification).setOnClickListener(this);
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);
if (!TextUtils.isEmpty(hint)) {
searchHint.setHint(hint);
}
}
@Override
public void onClick(View v) {
final int id = v.getId();
if (id == R.id.actionbar_rl_download) {
DataUtils.onEvent(getActivity(), "主页", "下载图标");
DataCollectionUtils.uploadClick(getActivity(), "下载图标", "主页");
Intent intent = new Intent(getActivity(), DownloadManagerActivity.class);
intent.putExtra("entrance", "(工具栏)");
intent.putExtra("currentItem", 0);
startActivity(intent);
} else if (id == R.id.actionbar_iv_search) {
DataUtils.onEvent(getActivity(), "主页", "搜索图标");
DataCollectionUtils.uploadClick(getActivity(), "搜索图标", "主页");
Intent intent = new Intent(getActivity(), SearchActivity.class);
intent.putExtra("clicked", true);
intent.putExtra("hint", 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(), "关注图标", "主页");
Intent intent = new Intent(getActivity(), ConcernActivity.class);
intent.putExtra("entrance", "(工具栏)");
startActivity(intent);
}
}
// 打开下载按钮事件
public void onEventMainThread(EBReuse reuse) {
if ("Refresh".equals(reuse.getType())) {
if (Config.isShow(getActivity())) {
view.findViewById(R.id.actionbar_rl_download).setVisibility(View.VISIBLE);
} else {
view.findViewById(R.id.actionbar_rl_download).setVisibility(View.GONE);
}
}
}
public void setHint(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);
}
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}

View File

@ -1,13 +0,0 @@
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

@ -1,48 +0,0 @@
//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

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

View File

@ -1,162 +0,0 @@
package com.gh.base.fragment;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.gh.base.OnRequestCallBackListener;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.eventbus.EBMiPush;
import com.lightgame.ToolbarController;
import com.lightgame.utils.RuntimeUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import butterknife.ButterKnife;
/**
* Created by LGT on 2016/9/4.
* Fragment 基类
*/
public abstract class BaseFragment<T> extends Fragment implements OnRequestCallBackListener<T>,
View.OnClickListener, ToolbarController {
// TODO private view
protected View view;
protected boolean isEverPause;
protected String mEntrance;
@LayoutRes
protected abstract int getLayoutId();
/**
* 责任链谁处理了就返回true否则返回super.handleOnClick(View view)
*
* @return
*/
protected boolean handleOnClick(View view) {
return true;
}
@Override
public void onClick(View v) {
handleOnClick(v);
}
protected void initView(View view) {
}
protected void postRunnable(Runnable runnable) {
RuntimeUtils.getInstance().runOnUiThread(runnable);
}
protected void postDelayedRunnable(Runnable runnable, long delayMillis) {
RuntimeUtils.getInstance().runOnUiThread(runnable, delayMillis);
}
@Override
public void setNavigationTitle(@StringRes int res) {
if (getActivity() instanceof ToolbarController) {
((ToolbarController) getActivity()).setNavigationTitle(res);
}
}
@Override
public void setNavigationTitle(CharSequence res) {
if (getActivity() instanceof ToolbarController) {
((ToolbarController) getActivity()).setNavigationTitle(res);
}
}
@Override
public Toolbar getToolBar() {
if (getActivity() instanceof ToolbarController) {
return ((ToolbarController) getActivity()).getToolBar();
}
return null;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mEntrance = getActivity().getIntent().getStringExtra(EntranceUtils.KEY_ENTRANCE);
isEverPause = false;
EventBus.getDefault().register(this);
view = View.inflate(getContext(), getLayoutId(), null);
ButterKnife.bind(this, view);
initView(view);
}
//TODO 尴尬必须的有subscribe才能register
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onDummyEvent(EBMiPush push) {
//
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (container != null) {
container.removeView(view);
}
return view;
}
@Override
public void onResume() {
super.onResume();
isEverPause = false;
}
@Override
public void onPause() {
super.onPause();
isEverPause = true;
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
public void toast(String msg) {
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
}
public boolean isEverPause() {
return isEverPause;
}
@Override
public void loadDone() {
}
@Override
public void loadDone(Object obj) {
}
@Override
public void loadError() {
}
@Override
public void loadEmpty() {
}
}

View File

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

View File

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

View File

@ -3,40 +3,19 @@ package com.gh.common.constant;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.gh.gamecenter.BuildConfig;
public class Config {
public static final String HOST = BuildConfig.HOST;
public static final String USER_HOST = BuildConfig.USER_HOST;
public static final String COMMENT_HOST = BuildConfig.COMMENT_HOST;
public static final String DATA_HOST = BuildConfig.DATA_HOST;
public static final String LIBAO_HOST = BuildConfig.LIBAO_HOST;
public static final String MESSAGE_HOST = BuildConfig.MESSAGE_HOST;
public static final String 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";
/**
* 需要配置的请使用{@link PreferenceManager#getDefaultSharedPreferences(Context)}
*/
// @Deprecated
// public static final String PREFERENCE = "ghzhushou";
// Third-Party confs
public static final String WECHAT_APPID = BuildConfig.WECHAT_APPID;
public static final String WECHAT_SECRET = BuildConfig.WECHAT_SECRET;
public static final String TENCENT_APPID = BuildConfig.TENCENT_APPID;
public static final String WEIBO_APPKEY = BuildConfig.WEIBO_APPKEY;
public static final String MIPUSH_APPID = BuildConfig.MIPUSH_APPID;
public static final String MIPUSH_APPKEY = BuildConfig.MIPUSH_APPKEY;
public static final String MTA_APPKEY = BuildConfig.MTA_APPKEY;
public static final String 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 = PreferenceManager.getDefaultSharedPreferences(context);
return sp.getBoolean("isShow", true);
}
public static boolean isShow(Context context) {
SharedPreferences sp = context.getSharedPreferences(Config.PREFERENCE, Context.MODE_PRIVATE);
return sp.getBoolean("isShow", true);
}
}

View File

@ -2,31 +2,41 @@ package com.gh.common.constant;
public class Constants {
public static final int SEND_NEWS_FEEDBACK = 0x126;
public static final int SEND_COMMENT_FEEDBACK = 0x127;
//手机号码匹配规则
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,22 +5,23 @@ package com.gh.common.constant;
*/
public class ItemViewType {
public static final int COLUMN_HEADER = 0; // 专题头部布局
public static final int GAME_SLIDE = 1; // 滚动图布局
public static final int GAME_NORMAL = 2; // 正常游戏布局
public static final int GAME_TEST = 3; // 测试游戏布局
public static final int GAME_IMAGE = 4; // 游戏大图布局
public static final int NEWS_HEADER = 5; // 新闻头部布局
public static final int NEWS_TEXT = 6; // 新闻文本布局
public static final int NEWS_IMAGE = 7; // 新闻带图布局
public static final int NEWS_IMAGE1 = 8; // 新闻带一张小图布局
public static final int NEWS_IMAGE2 = 9; // 新闻带三张小图布局
public static final int NEWS_IMAGE3 = 10; // 新闻带一张大图布局
public static final int NEWS_DIGEST = 11; // 新闻摘要布局
public static final int SEARCH_NORMAL = 12; // 搜索正常布局
public static final int 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 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;
}

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,6 +41,7 @@ public class AccessTokenKeeper {
* 从 SharedPreferences 读取 Token 信息。
*
* @param context 应用程序上下文环境
*
* @return 返回 Token 对象
*/
public static Oauth2AccessToken readAccessToken(Context context) {

View File

@ -1,31 +0,0 @@
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

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

View File

@ -8,9 +8,6 @@ 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;
/**
@ -18,135 +15,102 @@ import java.io.IOException;
*/
public class BitmapUtils {
/**
* 保存图片
*
* @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);
/**
* 根据文件路径返回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;
}
}
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;
}
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;
}
}
/**
* 根据文件路径返回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转Bitmap
*
*/
public static Bitmap drawableToBitmap(Drawable drawable){
if(drawable == null){
return null;
}
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;
}
}
// 取 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);
/**
* 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;
}
return bitmap;
}
}

View File

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

View File

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

View File

@ -1,273 +0,0 @@
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.View;
import android.view.Window;
import android.widget.ImageView;
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.OnCommentCallBackListener;
import com.gh.gamecenter.db.CommentDao;
import com.gh.gamecenter.db.VoteDao;
import com.gh.gamecenter.db.info.VoteInfo;
import com.gh.gamecenter.entity.CommentEntity;
import com.lightgame.utils.Utils;
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;
import retrofit2.HttpException;
/**
* 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 context,
final OnCommentCallBackListener listener, final String newsId) {
CommentDao commentDao = new CommentDao(context);
final Dialog dialog = new Dialog(context);
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.setBackgroundColor(Color.WHITE);
container.setPadding(0, DisplayUtils.dip2px(context, 12), 0, DisplayUtils.dip2px(context, 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(context);
reportTv.setText(s);
reportTv.setTextSize(17);
reportTv.setTextColor(ContextCompat.getColor(context, R.color.title));
reportTv.setBackgroundResource(R.drawable.textview_white_style);
int widthPixels = context.getResources().getDisplayMetrics().widthPixels;
reportTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTv.setPadding(DisplayUtils.dip2px(context, 20), DisplayUtils.dip2px(context, 12),
0, DisplayUtils.dip2px(context, 12));
container.addView(reportTv);
reportTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.cancel();
switch (reportTv.getText().toString()) {
case "回复":
CheckLoginUtils.checkLogin(context, new CheckLoginUtils.OnLoggenInListener() {
@Override
public void onLoggedIn() {
if (listener != null) {
listener.onCommentCallback(commentEntity);
} else if (!TextUtils.isEmpty(newsId)) {
context.startActivity(MessageDetailActivity.getMessageDetailIntent(context, commentEntity, newsId));
} else {
Utils.toast(context, "缺少关键属性");
}
}
});
break;
case "复制":
LibaoUtils.copyLink(commentEntity.getContent(), context);
break;
case "举报":
CheckLoginUtils.checkLogin(context, new CheckLoginUtils.OnLoggenInListener() {
@Override
public void onLoggedIn() {
showReportTypeDialog(commentEntity, context);
}
});
break;
case "查看对话":
context.startActivity(CommentDetailActivity.getCommentDetailIntent(context, 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();
}
public static void initVote(final Context context, final CommentEntity commentEntity, final VoteDao voteDao,
final TextView commentLikeCountTv, final ImageView commentLikeIv, final OnVoteListener listener) {
CheckLoginUtils.checkLogin(context, new CheckLoginUtils.OnLoggenInListener() {
@Override
public void onLoggedIn() {
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme)) {
Utils.toast(context, "已经点过赞啦!");
return;
}
commentEntity.setVote(commentEntity.getVote() + 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme));
commentLikeIv.setImageResource(R.drawable.ic_like_select);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
commentLikeCountTv.setVisibility(View.VISIBLE);
PostCommentUtils.addCommentVoto(context, commentEntity.getId(), true,
new PostCommentUtils.PostCommentListener() {
@Override
public void postSuccess(JSONObject response) {
voteDao.add(new VoteInfo(commentEntity.getId()));
if (listener != null) {
listener.onVote();
}
}
@Override
public void postFailed(Throwable e) {
commentEntity.setVote(commentEntity.getVote() - 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint));
commentLikeIv.setImageResource(R.drawable.ic_like_unselect);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
if (commentEntity.getVote() == 0) {
commentLikeCountTv.setVisibility(View.GONE);
} else {
commentLikeCountTv.setVisibility(View.VISIBLE);
}
if (e instanceof HttpException) {
HttpException exception = (HttpException) e;
if (exception.code() == 403) {
try {
String detail = new JSONObject(exception.response().errorBody().string()).getString("detail");
if (detail.equals("voted")) {
Utils.toast(context, "已经点过赞啦!");
}
} catch (Exception ex) {
ex.printStackTrace();
}
return;
}
}
Utils.toast(context, "网络异常,点赞失败");
}
});
}
});
}
public interface OnVoteListener {
void onVote();
}
}

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@ package com.gh.common.util;
import android.content.Context;
import android.os.Build;
import com.lightgame.download.DownloadEntity;
import com.gh.download.DownloadEntity;
import com.gh.gamecenter.db.info.ConcernInfo;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.NewsDetailEntity;
@ -11,193 +11,150 @@ 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.ghzs666.com
* 数据收集 工具类data.ghzhushou.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(EntranceUtils.KEY_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("entrance", downloadEntity.getEntrance());
map.put("installed", downloadEntity.getInstalled());
map.put("network", NetworkUtils.getConnectedType(context));
DataCollectionManager.onEvent(context, "download", map);
}
// 上传点击数据
public static void uploadClick(Context context, String... args) {
if (args.length < 2) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("location", args[0]);
map.put("page", args[1]);
if (args.length == 3) {
map.put("title", args[2]);
}
DataCollectionManager.onEvent(context, "click-item", map);
}
// 上传点击数据
public static void uploadClick(Context context, String... args) {
if (args.length < 2) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("location", args[0]);
map.put("page", args[1]);
if (args.length == 3) {
map.put("title", args[2]);
}
DataCollectionManager.onEvent(context, "click-item", map);
}
// 上传游戏数据
public static void uploadGame(Context context, GameEntity gameEntity, int seconds, String from) {
Map<String, Object> map = new HashMap<>();
map.put("game", gameEntity.getName());
map.put("game_id", gameEntity.getId());
map.put("time", seconds);
map.put("from", from);
DataCollectionManager.onEvent(context, "game", map);
}
// 上传游戏数据
public static void uploadGame(Context context, GameEntity gameEntity, int seconds, String from) {
Map<String, Object> map = new HashMap<>();
map.put("game", gameEntity.getName());
map.put("game_id", gameEntity.getId());
map.put("time", seconds);
map.put("from", from);
DataCollectionManager.onEvent(context, "game", map);
}
// 上传新闻数据
public static void uploadNews(Context context, NewsDetailEntity newsDetailEntity,
GameEntity gameEntity, int seconds, String from) {
Map<String, Object> map = new HashMap<>();
map.put("title", newsDetailEntity.getTitle());
map.put("type", newsDetailEntity.getType());
map.put("author", newsDetailEntity.getAuthor());
if (gameEntity != null) {
map.put("game", gameEntity.getName());
map.put("game_id", gameEntity.getId());
}
map.put("time", seconds);
map.put("from", from);
DataCollectionManager.onEvent(context, "news", map);
}
// 上传新闻数据
public static void uploadNews(Context context, NewsDetailEntity newsDetailEntity,
GameEntity gameEntity, int seconds, String from) {
Map<String, Object> map = new HashMap<>();
map.put("title", newsDetailEntity.getTitle());
map.put("type", newsDetailEntity.getType());
map.put("author", newsDetailEntity.getAuthor());
if (gameEntity != null) {
map.put("game", gameEntity.getName());
map.put("game_id", gameEntity.getId());
}
map.put("time", seconds);
map.put("from", from);
DataCollectionManager.onEvent(context, "news", map);
}
// 上传安装或卸载数据
public static void uploadInorunstall(Context context, String type, String packageName) {
Map<String, Object> map = new HashMap<>();
map.put("type", type);
map.put("packageName", packageName);
DataCollectionManager.onEvent(context, "inorunstall", map);
}
// 上传安装或卸载数据
public static void uploadInorunstall(Context context, String type, String packageName) {
Map<String, Object> map = new HashMap<>();
map.put("type", type);
map.put("packageName", packageName);
DataCollectionManager.onEvent(context, "inorunstall", map);
}
// 上传劫持数据
public static void uploadHijack(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("hijack_url", downloadEntity.getError());
DataCollectionManager.onEvent(context, "hijack", map);
}
// 上传劫持数据
public static void uploadHijack(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("hijack_url", downloadEntity.getError());
DataCollectionManager.onEvent(context, "hijack", map);
}
// 上传用户数据
public static void uploadUser(Context context) {
ConcernManager concernManager = new ConcernManager(context);
ArrayList<String> concernList = new ArrayList<>();
for (ConcernInfo entity : concernManager.getAllConcern()) {
if (entity.isConcern()) {
concernList.add(entity.getGameName());
}
}
Map<String, Object> map = new HashMap<>();
map.put("type", Build.MODEL);
map.put("system", Build.VERSION.SDK_INT + "=" + Build.VERSION.RELEASE);
map.put("install", PackageManager.getInstalledList());
map.put("concern", concernList);
DataCollectionManager.upsert(context, "user", map);
}
// 上传用户数据
public static void uploadUser(Context context) {
ConcernManager concernManager = new ConcernManager(context);
ArrayList<String> concernList = new ArrayList<>();
for (ConcernInfo entity : concernManager.getAllConcern()) {
if (entity.isConcern()) {
concernList.add(entity.getGameName());
}
}
Map<String, Object> map = new HashMap<>();
map.put("type", Build.MODEL);
map.put("system", Build.VERSION.SDK_INT + "=" + Build.VERSION.RELEASE);
map.put("install", PackageManager.getInstalledList());
map.put("concern", concernList);
DataCollectionManager.upsert(context, "user", map);
}
// 上传搜索数据
public static void uploadSearch(Context context, String... args) {
if (args.length != 5) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("from", args[2]);
map.put("search_type", args[1]);
map.put("key", args[0]);
map.put("game_id", args[3]);
map.put("game_name", args[4]);
map.put("netword", NetworkUtils.getConnectedType(context));
map.put("type", "search");
map.put("device_type", android.os.Build.MODEL);
map.put("device_system", android.os.Build.VERSION.SDK_INT + "=" + android.os.Build.VERSION.RELEASE);
DataCollectionManager.onEvent(context, "search", map);
}
// 上传搜索数据
public static void uploadSearch(Context context, String... args) {
if (args.length < 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 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);
}
// 上传关注数据
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);
}
}

View File

@ -2,11 +2,9 @@ package com.gh.common.util;
import android.content.Context;
import com.gh.base.AppController;
import com.lightgame.download.DownloadEntity;
import com.gh.download.DownloadEntity;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.lightgame.utils.Utils;
import org.json.JSONObject;
@ -25,67 +23,67 @@ import rx.schedulers.Schedulers;
*/
public class DataLogUtils {
// 轮播图
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);
}
// 上传日志
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 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);
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());
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());
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>());
}
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 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);
}
// 网络错误
public static void uploadNeterrorLog(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("error", downloadEntity.getError());
uploadLog(context, "neterror", map);
}
// 网络错误
public static void uploadNeterrorLog(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("error", downloadEntity.getError());
uploadLog(context, "neterror", map);
}
// 助手更新
public static void uploadUpgradeLog(Context context, String step) {
Map<String, Object> map = new HashMap<>();
map.put("step", step);
uploadLog(context, "upgrade", map);
}
// 助手更新
public static void uploadUpgradeLog(Context context, String step) {
Map<String, Object> map = new HashMap<>();
map.put("step", step);
uploadLog(context, "upgrade", map);
}
// 链接劫持
public static void uploadHijack(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("hijack_url", downloadEntity.getError());
uploadLog(context, "hijack", map);
}
// 链接劫持
public static void uploadHijack(Context context, DownloadEntity downloadEntity) {
Map<String, Object> map = new HashMap<>();
map.put("url", downloadEntity.getUrl());
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("platform", downloadEntity.getPlatform());
map.put("hijack_url", downloadEntity.getError());
uploadLog(context, "hijack", map);
}
}

View File

@ -4,10 +4,8 @@ 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;
@ -22,61 +20,29 @@ import java.util.Properties;
*/
public class DataUtils {
/**
* 初始化各种统计工具仅在release build非debug模式启用统计
*
* @param context
* @param debug 是否debug模式
* @param channel
*/
public static void init(Application context, final boolean debug, String channel) {
public static void init(Application application) {
//TalkingData
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);
//dubug true release false
TCAgent.LOG_ON = true;
TCAgent.init(application);
TCAgent.setReportUncaughtExceptions(true);
//MTA
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();
}
// 打开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();
}
}
public static void onEvent(Context var0, String var1, String var2) {
@ -84,6 +50,16 @@ 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);
@ -102,33 +78,23 @@ 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);
onEvent(context, "游戏下载", gameName, kv);
DataUtils.onEvent(context, "游戏下载", gameName, kv);
Map<String, Object> kv2 = new HashMap<>();
kv2.put("版本", platform);
kv2.put("状态", status);
kv2.put("位置", entrance);
onEvent(context, "游戏下载位置", gameName, kv2);
DataUtils.onEvent(context, "游戏下载位置", gameName, kv2);
Map<String, Object> kv3 = new HashMap<>();
kv3.put(entrance, "下载数");
kv3.put(entrance, status);
onEvent(context, "应用数据", gameName, kv3);
DataUtils.onEvent(context, "应用数据", gameName, kv3);
}
// 游戏更新
@ -136,7 +102,7 @@ public class DataUtils {
Map<String, Object> kv = new HashMap<>();
kv.put("版本", paltform);
kv.put("状态", status);
onEvent(context, "游戏更新", gameName, kv);
DataUtils.onEvent(context, "游戏更新", gameName, kv);
}
}

View File

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

View File

@ -2,25 +2,24 @@ 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.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.text.Html;
import android.text.Spanned;
import android.text.TextPaint;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gh.base.AppController;
@ -37,517 +36,422 @@ import java.util.Map;
public class DialogUtils {
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 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;
// 快传成绩单
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);
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);
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);
// 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();
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);
}
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);
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";
}
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) {
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";
}
final Dialog dialog = new Dialog(context);
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";
}
View view = View.inflate(context, R.layout.dialog_install_hint, null);
if (sendTime > 60000) {
timeCount.setText(String.valueOf(sendTime/1000/60));
timeTv.setText("分钟传送完成");
} else {
timeCount.setText(String.valueOf(sendTime/1000));
timeTv.setText("秒传送完成");
}
// 标题
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);
sizeTv.setText(sizeName);
speedTv.setText(speed);
countTv.setText(filesCount + "");
// 确定按钮
TextView installhint_confirm = (TextView) view.findViewById(R.id.installhint_confirm);
installhint_confirm.setText("知道了");
// 延迟操作,等待截图部分绘制完成
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);
final ImageView installhint_unselect = (ImageView) view.findViewById(R.id.installhint_unselect);
final ImageView installhint_select = (ImageView) view.findViewById(R.id.installhint_select);
closeIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.cancel();
}
});
}
LinearLayout installhint_unselect_ll = (LinearLayout) view.findViewById(R.id.installhint_unselect_ll);
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);
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);
}
}
});
}
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();
}
}
}
});
public static void showWarningDialog(Context context, String title, CharSequence msg, String cancel, String confirm,
final ConfiremListener cmListener, final CancelListener clListener) {
dialog.setOnDismissListener(new Dialog.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
isShow = false;
}
});
if (isShow) {
return;
}
isShow = true;
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.show();
}
final Dialog dialog = new Dialog(context);
public static void showHintDialog(Context context, String title, CharSequence msg, String confirm) {
final Dialog dialog = new Dialog(context);
View view = View.inflate(context, R.layout.common_alertdialog, null);
View view = View.inflate(context, R.layout.common_hintdialog, null);
// 标题
TextView alertdialog_title = (TextView) view.findViewById(R.id.alertdialog_title);
alertdialog_title.setText(title);
TextView hintdialog_title = (TextView) view.findViewById(R.id.tv_dialog_hint_title);
hintdialog_title.setText(title);
// 内容
TextView alertdialog_content = (TextView) view.findViewById(R.id.alertdialog_content);
alertdialog_content.setText(msg);
// 内容
TextView hintdialog_content = (TextView) view.findViewById(R.id.tv_dialog_hint_content);
hintdialog_content.setText(msg);
// 取消按钮
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_confirm = (TextView) view.findViewById(R.id.tv_dialog_hint_confirm);
// 确定按钮
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();
}
}
});
hintdialog_confirm.setText(confirm);
dialog.setOnDismissListener(new Dialog.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
isShow = false;
}
});
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();
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.show();
}
public static void showInstallHintDialog(Context context ,final ConfiremListener cmListener) {
public static void showHijackDialog(final Context context) {
showWarningDialog(context, "警告", "您当前网络环境异常,下载地址已被替换(网络劫持),请更换网络环境进行下载。",
new ConfirmListener() {
@Override
public void onConfirm() {
// 跳转wifi管理界面
context.startActivity(IntentUtils.getWifiIntent());
}
});
}
public static void showWarningDialog(Context context, String title, CharSequence msg, final ConfirmListener listener) {
showWarningDialog(context, title, msg, "取消", "确定", listener, null);
}
final Dialog dialog = new Dialog(context);
public static void showWarningDialog(Context context, String title, CharSequence msg, String cancel, String confirm,
final ConfirmListener cmListener, final CancelListener clListener) {
View view = View.inflate(context, R.layout.dialog_install_hint, null);
showAlertDialog(context, title, msg, confirm, cancel, cmListener, clListener);
if (true) return; // TODO TEST
// 标题
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, CancelListener cancelListener){
showWarningDialog(context, "下载提示", "您当前使用的网络为2G/3G/4G开始下载将会消耗移动流量确定下载", "取消", "确定", listener, cancelListener);
}
// 内容
TextView hintdialog_content = (TextView) view.findViewById(R.id.hintdialog_content);
hintdialog_content.setText(msg);
public static void showDownloadDialog(Context context, ConfirmListener listener) {
showWarningDialog(context, "下载提示", "您当前使用的网络为2G/3G/4G开始下载将会消耗移动流量确定下载", listener);
}
TextView hintdialog_confirm = (TextView) view.findViewById(R.id.hintdialog_confirm);
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);
}
hintdialog_confirm.setText(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.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.cancel();
}
});
public static void showDisclaimerDialog(Context context, String content) {
final Dialog disclaimerDialog = new Dialog(context);
View view = View.inflate(context, R.layout.dialog_disclaimer, null);
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);
// 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();
}
/**
* Material Design 风格弹窗
*
* @param context
* @param title 标题
* @param message 内容
* @param positive 确认按钮文本
* @param negative 取消按钮文本
* @param cmListener 确认按钮监听
* @param clListener 取消按钮监听
*/
public interface ConfiremListener{
void onConfirem();
}
public static void showAlertDialog(Context context, String title, CharSequence message
, String positive, String negative, final ConfirmListener cmListener, final CancelListener clListener) {
AlertDialog alertDialog = new AlertDialog.Builder(context, R.style.GhAlertDialog)
.setTitle(title)
.setMessage(message)
.setPositiveButton(positive, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (cmListener != null) {
cmListener.onConfirm();
}
}
})
.setNegativeButton(negative, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (clListener != null) {
clListener.onCancel();
}
}
})
.create();
alertDialog.show();
TextView mesage = (TextView) alertDialog.findViewById(android.R.id.message);
Button positiveBtn = alertDialog.getButton(android.app.AlertDialog.BUTTON_POSITIVE);
Button negativeBtn = alertDialog.getButton(android.app.AlertDialog.BUTTON_NEGATIVE);
positiveBtn.setTextSize(13);
positiveBtn.setTextColor(ContextCompat.getColor(context, R.color.theme));
negativeBtn.setTextSize(13);
negativeBtn.setTextColor(ContextCompat.getColor(context, R.color.theme));
if (mesage != null) {
mesage.setTextSize(13);
mesage.setTextColor(ContextCompat.getColor(context, R.color.title));
}
}
/**
* 特殊:验证手机号码
*/
public static void checkPhoneNumDialog(Context context, CharSequence message, final ConfirmListener cmListener) {
String s = message.toString();
String sub1 = s.substring(0, 3);
String sub2 = s.substring(3, 7);
String sub3 = s.substring(7, 11);
String phoneNum = StringUtils.buildString(sub1, " - ", sub2, " - ", sub3);
AlertDialog alertDialog = new AlertDialog.Builder(context, R.style.GhAlertDialog)
.setTitle("请确定手机号:")
.setMessage(phoneNum)
.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (cmListener != null) {
cmListener.onConfirm();
}
}
})
.setNegativeButton("取消", null)
.create();
alertDialog.show();
TextView mesage = (TextView) alertDialog.findViewById(android.R.id.message);
Button positiveBtn = alertDialog.getButton(android.app.AlertDialog.BUTTON_POSITIVE);
Button negativeBtn = alertDialog.getButton(android.app.AlertDialog.BUTTON_NEGATIVE);
positiveBtn.setTextSize(13);
positiveBtn.setTextColor(ContextCompat.getColor(context, R.color.theme));
negativeBtn.setTextSize(13);
negativeBtn.setTextColor(ContextCompat.getColor(context, R.color.theme));
if (mesage != null) {
mesage.setGravity(Gravity.CENTER);
mesage.setTextSize(24);
mesage.setTextColor(ContextCompat.getColor(context, R.color.title));
TextPaint tp = mesage.getPaint();
tp.setFakeBoldText(true);
}
}
public interface ConfirmListener {
void onConfirm();
}
public interface CancelListener {
void onCancel();
}
public interface CancelListener{
void onCancel();
}
}

View File

@ -5,63 +5,64 @@ 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");
}
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;
}
/**
* 将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;
}
}

View File

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

View File

@ -1,70 +0,0 @@
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

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

View File

@ -1,129 +1,151 @@
package com.gh.common.util;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.text.TextUtils;
import android.widget.TextView;
import com.gh.base.AppController;
import com.gh.download.DownloadEntity;
import com.gh.download.DownloadManager;
import com.gh.download.DownloadStatus;
import com.gh.gamecenter.GameDetailActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.manager.PackageManager;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
import java.util.List;
public class GameUtils {
/**
* 去除与重复sourceList相同的数据
*/
public static List<GameEntity> removeDuplicateData(List<GameEntity> sourceList, List<GameEntity> rawList) {
if (sourceList == null || sourceList.isEmpty()
|| rawList == null || rawList.isEmpty()) {
return rawList;
}
String id;
for (int i = 0; i < rawList.size(); i++) {
id = rawList.get(i).getId();
for (GameEntity gameEntity : sourceList) {
if (id.equals(gameEntity.getId())) {
rawList.remove(i);
i--;
break;
}
}
}
return rawList;
}
/**
* 去除与重复sourceList相同的数据
*/
public static List<GameEntity> removeDuplicateData(List<GameEntity> sourceList, List<GameEntity> rawList) {
if (sourceList == null || sourceList.isEmpty()
|| rawList == null || rawList.isEmpty()) {
return rawList;
}
String id;
for (int i = 0; i < rawList.size(); i++) {
id = rawList.get(i).getId();
for (GameEntity gameEntity : sourceList) {
if (id.equals(gameEntity.getId())) {
rawList.remove(i);
i--;
break;
}
}
}
return rawList;
}
/**
* 设置下载按钮状态
*/
public static void 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, 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 String getDownloadBtnText(Context context, GameEntity gameEntity) {
int doneCount = 0; // 下载完成数量
int pluginCount = 0; // 可插件化数量
int updateCount = 0; // 可更新数量
int installCount = 0; // 已安装数量
DownloadEntity downloadEntity;
Object gh_id;
for (ApkEntity apkEntity : gameEntity.getApk()) {
downloadEntity = DownloadManager.getInstance(context).getDownloadEntityByUrl(apkEntity.getUrl());
if (downloadEntity != null) {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
doneCount++;
} else if (downloadEntity.isPluggable()) {
pluginCount++;
} else if (downloadEntity.isUpdate()) {
updateCount++;
}
}
if (PackageManager.isCanUpdate(gameEntity.getId(), apkEntity.getPackageName())) {
updateCount++;
}
if (PackageManager.isInstalled(apkEntity.getPackageName())) {
gh_id = PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_id");
if (gameEntity.getTag() != null && gameEntity.getTag().size() != 0
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
&& !PackageUtils.isSignature(context, apkEntity.getPackageName())) {
pluginCount++;
} else if (gh_id == null || gh_id.equals(gameEntity.getId())) {
installCount++;
}
}
}
if (doneCount != 0) {
return "安装";
} else if (pluginCount != 0) {
return "插件化";
} else if (updateCount != 0) {
return "更新";
} else if (installCount != 0) {
return "打开";
} else {
return "下载";
}
}
/**
* 启动游戏详情页面
*/
public static void 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);
}
/**
* 获取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;
}
/**
* 设置下载按钮状态
*/
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;
}
}

View File

@ -3,8 +3,6 @@ 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;
@ -22,6 +20,7 @@ import java.util.Locale;
import java.util.TimeZone;
/**
*
* @author 温冠超
* @email 294299195@qq.com
* @date 2015-8-14
@ -30,106 +29,100 @@ import java.util.TimeZone;
*/
public class GameViewUtils {
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;
}
}
}
}
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;
}
}
}
}
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);
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);
// 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;
}
}
}
}

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