├── .gitignore ├── README.md ├── brotlij ├── brotlij.aar └── build.gradle ├── build.gradle ├── candywebcache ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── netease │ │ └── hearttouch │ │ ├── candywebcache │ │ ├── ApplicationTest.java │ │ ├── CandyWebCacheTest.java │ │ ├── WebViewManagerTest.java │ │ └── cachemanager │ │ │ ├── BsdiffPatcherTest.java │ │ │ ├── CacheManagerTest.java │ │ │ ├── DatabaseManagerTest.java │ │ │ └── EnDecryptTest.java │ │ ├── htfiledownloader │ │ ├── ApplicationTest.java │ │ └── DownloadDBHelperTest.java │ │ └── htresourceversionchecker │ │ ├── ApplicationTest.java │ │ └── VersionCheckerTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── netease │ │ │ └── hearttouch │ │ │ ├── candywebcache │ │ │ ├── CacheConfig.java │ │ │ ├── CacheError.java │ │ │ ├── CandyWebCache.java │ │ │ ├── HybridWebviewClient.java │ │ │ ├── ReLinker.java │ │ │ ├── StatisticLogger.java │ │ │ ├── WebViewManager.java │ │ │ ├── WebcacheLog.java │ │ │ └── cachemanager │ │ │ │ ├── Base64.java │ │ │ │ ├── BsdiffPatcher.java │ │ │ │ ├── Cache.java │ │ │ │ ├── CacheDatabaseHelper.java │ │ │ │ ├── CacheManager.java │ │ │ │ ├── CourgettePatcher.java │ │ │ │ ├── DESUtils.java │ │ │ │ ├── DatabaseManager.java │ │ │ │ ├── EnDecryptionUtils.java │ │ │ │ ├── FileInfo.java │ │ │ │ ├── FileUtils.java │ │ │ │ ├── Md5Utils.java │ │ │ │ ├── MemBasedCache.java │ │ │ │ ├── Patcher.java │ │ │ │ └── WebappInfo.java │ │ │ ├── htfiledownloader │ │ │ ├── Constants.java │ │ │ ├── DownloadDBHelper.java │ │ │ ├── DownloadTask.java │ │ │ ├── DownloadTaskState.java │ │ │ ├── FileDownloadManager.java │ │ │ ├── FileDownloadRunnable.java │ │ │ ├── FileDownloaderUtil.java │ │ │ ├── InnerStateChangeListener.java │ │ │ ├── LogUtil.java │ │ │ ├── ProgressInfo.java │ │ │ └── StateChangeListener.java │ │ │ └── htresourceversionchecker │ │ │ ├── Constants.java │ │ │ ├── OnResponseListener.java │ │ │ ├── VersionChecker.java │ │ │ └── model │ │ │ ├── AppInfo.java │ │ │ ├── RequestResInfo.java │ │ │ ├── ResponseResInfo.java │ │ │ ├── VersionCheckResponseData.java │ │ │ └── VersionCheckResponseModel.java │ ├── jni │ │ ├── 3rd │ │ │ ├── bsdiff │ │ │ │ ├── bsdiff.c │ │ │ │ ├── bsdiff.h │ │ │ │ ├── bspatch.c │ │ │ │ ├── bspatch.h │ │ │ │ └── config.h │ │ │ └── bzip2 │ │ │ │ ├── blocksort.c │ │ │ │ ├── bzlib.c │ │ │ │ ├── bzlib.h │ │ │ │ ├── bzlib_private.h │ │ │ │ ├── compress.c │ │ │ │ ├── crctable.c │ │ │ │ ├── decompress.c │ │ │ │ ├── huffman.c │ │ │ │ └── randtable.c │ │ ├── Android.mk │ │ ├── Application.mk │ │ ├── JNIHelper.h │ │ └── PatcherJni.cpp │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── netease │ └── hearttouch │ ├── candywebcache │ ├── CacheConfigTest.java │ └── cachemanager │ │ ├── EnDecryptTest.java │ │ ├── FileUtilsTest.java │ │ ├── Md5UtilsTest.java │ │ └── MemBasedCacheTest.java │ ├── htfiledownloader │ └── ExampleUnitTest.java │ └── htresourceversionchecker │ └── ExampleUnitTest.java ├── candywebcacheplugin ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── readme.md └── src │ └── main │ ├── groovy │ └── com │ │ └── netease │ │ └── hearttouch │ │ ├── PresetExt.groovy │ │ └── PresetResourcePlugin.groovy │ └── resources │ └── META-INF │ └── gradle-plugins │ └── com.netease.hearttouch.PresetResourcePlugin.properties ├── demoapp ├── .gitignore ├── build.gradle ├── plugins │ └── candywebcacheplugin.jar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── netease │ │ └── hearttouch │ │ └── candywebcache │ │ └── demoapp │ │ ├── DemoApplication.java │ │ ├── InfomationActivity.java │ │ ├── LoadResourceActivity.java │ │ ├── MainActivity.java │ │ └── WebviewActivity.java │ └── res │ ├── layout │ ├── activity_infomation.xml │ ├── activity_load_resource.xml │ ├── activity_main.xml │ └── activity_webview.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ └── strings.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .idea/ 3 | build/ 4 | .gradle/ 5 | *.iml 6 | local.properties 7 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CandyWebCache 2 | 3 | CandyWebCache是移动端web资源的本地缓存解决方案,能够拦截webview的请求,并优先使用本地缓存静态资源进行响应,以此来对webview加载页面性能进行优化。 4 | 5 | 特点: 6 | 7 | * 协议层拦截请求,透明替换响应 8 | * 静态资源版本控制及更新策略 9 | * 资源防篡改策略 10 | * 静态资源自动打包到应用,及首次安装解压处理 11 | 12 | ## 客户端集成CandyWebCache 13 | 14 | ### 集成自动打包插件 15 | 集成自动打包脚本可以在发布`Release`版本时,自动获取服务器上的最新`WebApp`版本并预置到`assets`目录下,以`Plugin`形式提供。 16 | 17 | 接入方式如下: 18 | 19 | * 在主`module`的`build.gradle`中加入 20 | ```apply plugin: 'com.netease.hearttouch.PresetResourcePlugin'``` 21 | 22 | * 在主`module`的`build.gradle`中加入 23 | 24 | ``` 25 | buildscript { 26 | repositories { 27 | jcenter() 28 | } 29 | dependencies { 30 | classpath 'com.netease.hearttouch:ht-candywebcacheplugin:0.1.0' 31 | } 32 | } 33 | ``` 34 | * 在主`module`的`build.gradle`中加入 35 | 36 | - `url`:检测版本的`http`请求地址 37 | - `appID`:本应用注册在`CandyWebcache`的`native`应用标识 38 | - `appVersion`:本应用当前的版本号 39 | - `needDownload`:是否需要下载,默认设置为true,如果确定在`assembleRelease`的时候资源包没有更新,可以设置为false,加速打包过程 40 | 41 | 如: 42 | ``` 43 | presetExt{ 44 | url 'http://webcache-sp.kaola.com:8080/api/version_check/webapp' 45 | appID 'kaola' 46 | appVersion getVersion().toString() 47 | needDownload true 48 | } 49 | ``` 50 | 51 | ***注:由于某些Gradle实验版本无法将预置任务加入到`assembleRelease`的依赖中,所以无法实现自动下载,可以单独执行`Task`进行预置,`./gradlew app:presetResourceTask`*** 52 | 53 | ### 集成CandyWebCache 54 | 55 | 添加依赖 56 | ``` 57 | compile 'com.netease.hearttouch:ht-candywebcache:0.2.0' 58 | ``` 59 | 60 | ## CandyWebCache的使用 61 | 62 | (1) CandyWebCache的配置及初始化 63 | 64 | CandyWebCache在访问之前,首先需要进行配置及初始化。配置及初始化的动作通常建议放在包含了WebView,且该WebView访问的WebApp静态资源需由CandyWebCache管理的Activity的onCreate()方法中执行。具体的配置及初始化方法如下面代码所示: 65 | 66 | ``` 67 | @Override 68 | protected void onCreate(Bundle savedInstanceState) { 69 | ...... 70 | CandyWebCache.getsInstance().setDebugEnable(true); 71 | CacheConfig config = buildCacheConfig(); 72 | String versionCheckUrl = "http://10.165.124.46:8080/api/version_check"; 73 | CandyWebCache.getsInstance().init(this, config, "kaola", "3.0.1", versionCheckUrl); 74 | } 75 | 76 | private CacheConfig buildCacheConfig() { 77 | CacheConfig.ConfigBuilder builder = CacheConfig.createCofigBuilder(); 78 | List uncachedType = new ArrayList<>(); 79 | uncachedType.add(".html"); 80 | builder.setUncachedFileTypes(uncachedType); 81 | return builder.build(); 82 | } 83 | ``` 84 | 85 | 首先需要构造`CacheConfig`对象,CandyWebCache使用该类的对象来表述配置项。具体可以进行配置的项目如下: 86 | 87 | * 自动进行版本检查更新的周期(以毫秒为单位) 88 | * 本地缓存的WebApp的保存路径 89 | * CandyWebCache保护文件的保存路径 90 | * 内存缓存的最大大小(以字节为单位) 91 | * 不进行缓存的文件的类型的列表(文件的类型使用后缀名来描述) 92 | 93 | 其次,调用`CandyWebCache.getsInstance()`获取CandyWebCache对象。 94 | 95 | 最后,调用`CandyWebCache`对象的`init()`方法,传入`CacheConfig`对象,本地App的AppID,本地App的版本号,及进行版本检测的URL,对CandyWebCache进行初始化。 96 | 97 | 初始化完成之后,即可通过`CandyWebCache.getsInstance()`获取CandyWebCache对象并对CandyWebCache进行访问。 98 | 99 | (2) 启动webapp的版本检测更新 100 | 101 | 本地App可以在适当的时候,如应用启动、Activity创建,前后台切换等主动触发WebApp的版本检查更新流程。具体的方法如下: 102 | 103 | ``` 104 | CandyWebCache webcache = CandyWebCache.getsInstance(); 105 | long delayMillis = 5; 106 | webcache.startCheckAndUpdate(delayMillis); 107 | ``` 108 | 109 | 通过`CandyWebCache.getsInstance()`获取CandyWebCache对象,传入触发WebApp版本检查更新启动延迟的毫秒数,调用`startCheckAndUpdate()`方法即可。 110 | 111 | (3) 访问资源 112 | 113 | CandyWebCache初始化结束之后,即可对缓存的本地静态资源进行访问,及对本地缓存进行控制了。可通过如下的方法来获取本地缓存的静态资源: 114 | 115 | ``` 116 | @Override 117 | public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { 118 | return CandyWebCache.getsInstance().getResponse(view, request); 119 | } 120 | 121 | @Override 122 | public WebResourceResponse shouldInterceptRequest(WebView view, String url) { 123 | return CandyWebCache.getsInstance().getResponse(view, url); 124 | } 125 | ``` 126 | 127 | 通过`CandyWebCache.getsInstance()`获取CandyWebCache对象,传入请求资源的WebView对象及URL或request,调用`getResponse()`方法,获得资源对应的response。 128 | 129 | (4) 版本检查更新监听回调及资源更新进度监听回调。 130 | 131 | 可以为版本检查及资源下载更新进度设置或添加回调,以便于对版本检查请求在请求发送前,或版本检查的服务端响应在被接收到后做进一步的处理,或实时地获取资源的下载更新进度。 132 | 133 | 通过CandyWebCache的如下方法来设置、添加或移除这些回调: 134 | 135 | ``` 136 | void setVersionCheckListener(CandyWebCache.VersionCheckListener versionCheckListener) 137 | 138 | void addResourceUpdateListener(CandyWebCache.ResourceUpdateListener listener) 139 | 140 | void removeResourceUpdateListener(CandyWebCache.ResourceUpdateListener listener) 141 | ``` 142 | 143 | (5) 完整示例代码 144 | 145 | ``` 146 | package com.netease.hearttouch.candywebcache.demoapp; 147 | 148 | import android.app.Activity; 149 | import android.os.Bundle; 150 | import android.view.View; 151 | import android.webkit.WebResourceRequest; 152 | import android.webkit.WebResourceResponse; 153 | import android.webkit.WebView; 154 | import android.webkit.WebViewClient; 155 | import android.widget.EditText; 156 | 157 | import com.netease.hearttouch.candywebcache.CacheConfig; 158 | import com.netease.hearttouch.candywebcache.CandyWebCache; 159 | 160 | import java.util.ArrayList; 161 | import java.util.List; 162 | 163 | public class LoadResourceActivity extends Activity implements View.OnClickListener{ 164 | private WebView mWebview; 165 | private EditText mUrlEditText; 166 | 167 | @Override 168 | protected void onCreate(Bundle savedInstanceState) { 169 | super.onCreate(savedInstanceState); 170 | setContentView(R.layout.activity_load_resource); 171 | mWebview = (WebView) findViewById(R.id.webview); 172 | if (mWebview != null) { 173 | mWebview.getSettings().setJavaScriptEnabled(true); 174 | mWebview.setWebViewClient(new WebViewClient() { 175 | @Override 176 | public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { 177 | return CandyWebCache.getsInstance().getResponse(view, request); 178 | } 179 | 180 | @Override 181 | public WebResourceResponse shouldInterceptRequest(WebView view, String url) { 182 | return CandyWebCache.getsInstance().getResponse(view, url); 183 | } 184 | }); 185 | } 186 | mUrlEditText = (EditText) findViewById(R.id.et_url); 187 | findViewById(R.id.btn_load).setOnClickListener(this); 188 | 189 | CacheConfig config = buildCacheConfig(); 190 | String versionCheckUrl = "http://10.165.124.46:8080/api/version_check"; 191 | CandyWebCache.getsInstance().init(this, config, "KaoLa", "1.0.1", versionCheckUrl); 192 | } 193 | 194 | private CacheConfig buildCacheConfig() { 195 | CacheConfig.ConfigBuilder builder = CacheConfig.createCofigBuilder(); 196 | List uncachedType = new ArrayList<>(); 197 | uncachedType.add(".html"); 198 | builder.setUncachedFileTypes(uncachedType); 199 | builder.setCacheDirPath("/sdcard/netease/webcache"); 200 | builder.setManifestDirPath("/sdcard/netease/webcache/manifests"); 201 | builder.setMemCacheSize(5 * 1025 * 1024); 202 | return builder.build(); 203 | } 204 | 205 | @Override 206 | public void onClick(View v) { 207 | switch (v.getId()) { 208 | case R.id.btn_load: 209 | mWebview.clearCache(true); 210 | mWebview.loadUrl(mUrlEditText.getText().toString()); 211 | break; 212 | default: 213 | break; 214 | } 215 | } 216 | } 217 | ``` 218 | 219 | ## 调试 220 | 221 | CandyWebCache提供了调试开关,以方便开发者在开发期间获取更多CandyWebCache的运行信息。用户可通过`CandyWebCache`对象的`setDebugEnable()`方法来关闭调试开关,如: 222 | 223 | ``` 224 | CandyWebCache.getsInstance().setDebugEnable(true); 225 | ``` 226 | 227 | ## 系统要求 228 | 229 | 该项目支持最低Android API Level 14。 230 | 231 | ## CandyWebCache客户端SDK对服务器的要求 232 | 233 | 提供给客户端SDK的接口: 234 | 235 | * 版本检测接口,返回信息包括 236 | * 请求的webapp对应的增量包和全量包信息:版本号、下载地址、md5、url、domains 237 | * 请求中不包含的webapp则返回全量包信息:版本号、下载地址、md5、url、domains 238 | 239 | 提供给应用服务器的接口: 240 | 241 | * 更新全量包 242 | * 根据全量包和历史N(N可配置)个版本的包进行diff包计算 243 | * 计算各个资源包的md5,并加密md5值 244 | * 上传增量包和全量包到文件服务,并记录各个包的md5、资源url、版本号信息、domains 245 | 246 | 服务端功能要求: 247 | 248 | * 计算资源包diff包(使用bsdiff) 249 | * 上传资源到文件服务器 250 | * 资源md5计算与加密(加密算法:DES + base64,客户端对称加密秘钥目前是埋在客户端代码中) 251 | * webapp domains的配置 252 | 253 | ## CandyWebCache客户端SDK对打包方式的要求 254 | 255 | * 打包资源包目录路径要跟url能够对应,如 `http://m.kaola.com/public/r/js/core_57384232.js` ,资源的存放路径需要是 `public/r/js/core_57384232.js` 或者 `r/js/core_57384232.js`。 256 | * 资源缓存不支持带“?”的url,如果有版本号信息需要打到文件名中。对于为了解决缓存问题所采用的后缀形式url,如 `http://m.kaola.com/public/r/js/core.js?v=57384232` ,需要调整打包方式,采用文件名来区分版本号。 257 | 258 | 259 | -------------------------------------------------------------------------------- /brotlij/brotlij.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-android/43a30bbced51bddab2dd21477b2043f0b9506722/brotlij/brotlij.aar -------------------------------------------------------------------------------- /brotlij/build.gradle: -------------------------------------------------------------------------------- 1 | configurations.maybeCreate("default") 2 | artifacts.add("default", file('brotlij.aar')) -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.2' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | jcenter() 15 | } 16 | } 17 | 18 | task clean(type: Delete) { 19 | delete rootProject.buildDir 20 | } 21 | -------------------------------------------------------------------------------- /candywebcache/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .idea/ 3 | build/ 4 | .gradle/ 5 | *.iml 6 | .externalNativeBuild/ 7 | -------------------------------------------------------------------------------- /candywebcache/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | apply plugin: 'com.jfrog.bintray' 4 | 5 | android { 6 | compileSdkVersion 21 7 | buildToolsVersion "21.1.2" 8 | 9 | defaultConfig { 10 | minSdkVersion 14 11 | targetSdkVersion 21 12 | versionCode 1 13 | versionName "1.0" 14 | 15 | ndk { 16 | abiFilters 'armeabi', 'armeabi-v7a', 'x86' 17 | } 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles.add(file("proguard-rules.pro")) 24 | } 25 | } 26 | 27 | externalNativeBuild { 28 | ndkBuild { 29 | path "src/main/jni/Android.mk" 30 | } 31 | } 32 | } 33 | 34 | buildscript { 35 | repositories { 36 | jcenter() 37 | } 38 | dependencies { 39 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6' 40 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4' 41 | } 42 | } 43 | 44 | dependencies { 45 | compile fileTree(dir: 'libs', include: ['*.jar']) 46 | testCompile 'junit:junit:4.12' 47 | androidTestCompile 'junit:junit:4.12' 48 | androidTestCompile 'com.android.support.test:runner:0.4' 49 | // Set this dependency to use JUnit 4 rules 50 | androidTestCompile 'com.android.support.test:rules:0.4' 51 | // Set this dependency to build and run Espresso tests 52 | androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1' 53 | 54 | compile project(":brotlij") 55 | } 56 | 57 | def siteUrl = 'https://github.com/NEYouFan/ht-candywebcache-android' // 项目的主页 58 | def gitUrl = 'https://github.com/NEYouFan/ht-candywebcache-android.git' // Git仓库的url 59 | 60 | version = "0.2.0" 61 | group = "com.netease.hearttouch" 62 | archivesBaseName='ht-candywebcache' 63 | 64 | install { 65 | repositories.mavenInstaller { 66 | // This generates POM.xml with proper parameters 67 | pom.artifactId ='ht-candywebcache' 68 | pom.project { 69 | packaging 'aar' 70 | // Add your description here 71 | name 'A mobile web resource cache solution, android SDK.' //项目描述 72 | url siteUrl 73 | // Set your license 74 | licenses { 75 | license { 76 | name 'MIT' 77 | url 'http://www.opensource.org/licenses/mit-license.php' 78 | } 79 | } 80 | developers { 81 | developer { 82 | id 'stone' //填写开发者基本信息 83 | name 'stone' 84 | email 'scu0843041105@163.com' 85 | } 86 | } 87 | scm { 88 | connection gitUrl 89 | developerConnection gitUrl 90 | url siteUrl 91 | } 92 | } 93 | 94 | } 95 | } 96 | task sourcesJar(type: Jar) { 97 | from android.sourceSets.main.java.srcDirs 98 | classifier = 'sources' 99 | } 100 | task javadoc(type: Javadoc) { 101 | source = android.sourceSets.main.java.srcDirs 102 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 103 | failOnError false 104 | } 105 | task javadocJar(type: Jar, dependsOn: javadoc) { 106 | classifier = 'javadoc' 107 | from javadoc.destinationDir 108 | } 109 | 110 | tasks.withType(JavaCompile) { 111 | options.encoding = "UTF-8" 112 | } 113 | 114 | artifacts { 115 | archives javadocJar 116 | archives sourcesJar 117 | } 118 | Properties properties = new Properties() 119 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 120 | bintray { 121 | user = properties.getProperty("bintray.user") 122 | key = properties.getProperty("bintray.apikey") 123 | configurations = ['archives'] 124 | pkg { 125 | repo = "maven" //发布到Bintray的那个仓库里,默认账户有四个库,我们这里上传到maven库 126 | name = "ht-candywebcache" //发布到Bintray上的项目名字 127 | websiteUrl = siteUrl 128 | vcsUrl = gitUrl 129 | licenses = ["MIT"] 130 | publish = true 131 | } 132 | } -------------------------------------------------------------------------------- /candywebcache/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/netease/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /candywebcache/src/androidTest/java/com/netease/hearttouch/candywebcache/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /candywebcache/src/androidTest/java/com/netease/hearttouch/candywebcache/CandyWebCacheTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache; 2 | 3 | import android.content.Context; 4 | import android.support.test.runner.AndroidJUnit4; 5 | import android.test.InstrumentationTestCase; 6 | 7 | import com.netease.hearttouch.candywebcache.cachemanager.FileUtils; 8 | 9 | import org.junit.After; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.junit.runners.Suite; 14 | 15 | import java.io.File; 16 | import java.util.ArrayList; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import static org.junit.Assert.*; 22 | 23 | /** 24 | * Created by netease on 16/6/12. 25 | */ 26 | public class CandyWebCacheTest extends InstrumentationTestCase { 27 | Context mContext; 28 | CandyWebCache mCandyWebCache; 29 | @Before 30 | public void setUp() throws Exception { 31 | mContext = getInstrumentation().getContext(); 32 | mCandyWebCache = CandyWebCache.getsInstance(); 33 | } 34 | 35 | @After 36 | public void tearDown() throws Exception { 37 | 38 | } 39 | 40 | @Test 41 | public void testGetInstance() throws Exception { 42 | assertNotNull(mCandyWebCache); 43 | CandyWebCache webcache = CandyWebCache.getsInstance(); 44 | assertNotNull(webcache); 45 | assertEquals(mCandyWebCache, webcache); 46 | } 47 | 48 | @Test 49 | public void testInitNullCacheConfig() throws Exception { 50 | assertTrue(true); 51 | mCandyWebCache.init(mContext, null, null, "kaola", "20160617", null, null); 52 | Thread.sleep(4000); 53 | File protectedFilesDir = new File(mContext.getFilesDir(), "webcache"); 54 | assertTrue(protectedFilesDir.exists()); 55 | File databaseDir = new File(protectedFilesDir, "database"); 56 | assertTrue(databaseDir.exists()); 57 | File databaseFile = new File(databaseDir, "cache_info.db"); 58 | assertTrue(databaseFile.exists()); 59 | 60 | File cacheFilesDir = new File("/sdcard/netease/webcache/" + mContext.getPackageName() 61 | + File.separator + "webapps"); 62 | assertTrue(cacheFilesDir.exists()); 63 | 64 | File downloadTmpDir = new File("/sdcard/netease/webcache/" + mContext.getPackageName() 65 | + File.separator + "download"); 66 | assertTrue(downloadTmpDir.exists()); 67 | } 68 | 69 | @Test 70 | public void testInit() throws Exception { 71 | assertTrue(FileUtils.deleteDir("/sdcard/kaola")); 72 | CacheConfig.ConfigBuilder builder = CacheConfig.createCofigBuilder(); 73 | 74 | List uncachedFileType = new ArrayList(); 75 | builder.setUncachedFileTypes(uncachedFileType); 76 | 77 | builder.setMemCacheSize(2 * 1024 * 1024); 78 | 79 | String cacheDirPath = "/sdcard/kaola/webcache"; 80 | builder.setCacheDirPath(cacheDirPath); 81 | 82 | long cyclemillis = 100; 83 | builder.setUpdateCycle(cyclemillis); 84 | 85 | String protectedFilesPath = "/sdcard/kaola/manifest"; 86 | builder.setManifestDirPath(protectedFilesPath); 87 | CacheConfig config = builder.build(); 88 | 89 | mCandyWebCache.init(mContext, config, null, "kaola", "20160617", null, null); 90 | Thread.sleep(4000); 91 | 92 | File protectedFilesDir = new File("/sdcard/kaola/manifest"); 93 | assertTrue(protectedFilesDir.exists()); 94 | 95 | File databaseDir = new File("/sdcard/kaola/manifest/database"); 96 | assertTrue(databaseDir.exists()); 97 | File databaseFile = new File("/sdcard/kaola/manifest/database/cache_info.db"); 98 | assertTrue(databaseFile.exists()); 99 | 100 | File cacheFilesDir = new File("/sdcard/kaola/webcache"); 101 | assertTrue(cacheFilesDir.exists()); 102 | 103 | File downloadTmpDir = new File("/sdcard/kaola/webcache/download"); 104 | assertTrue(downloadTmpDir.exists()); 105 | } 106 | 107 | @Test 108 | public void testRecvServerMsg() throws Exception { 109 | assertTrue(true); 110 | } 111 | 112 | public void testUpdateWebapp() { 113 | 114 | } 115 | 116 | @org.junit.Test 117 | public void testConstructUrl() throws Exception { 118 | String url = "http://www.kaola.com/activity/detail/11884.shtml"; 119 | Map params = new HashMap<>(); 120 | params.put("navindex", "5"); 121 | params.put("zn", "top"); 122 | String result = mCandyWebCache.constructUrl(url, params); 123 | assertTrue(result.contains("navindex=5")); 124 | assertTrue(result.contains("zn=top")); 125 | assertTrue(result.indexOf("http://www.kaola.com/activity/detail/11884.shtml?") == 0); 126 | assertTrue(result.indexOf("navindex=5") >= "http://www.kaola.com/activity/detail/11884.shtml?".length()); 127 | assertTrue(result.indexOf("zn=top") >= "http://www.kaola.com/activity/detail/11884.shtml?".length()); 128 | assertEquals(result.length(), "http://www.kaola.com/activity/detail/11884.shtml?".length() 129 | + "navindex=5".length() + "zn=top".length() + 1); 130 | 131 | url = "http://www.kaola.com/activity/detail/11884.shtml?"; 132 | result = mCandyWebCache.constructUrl(url, params); 133 | assertTrue(result.contains("navindex=5")); 134 | assertTrue(result.contains("zn=top")); 135 | assertTrue(result.indexOf("http://www.kaola.com/activity/detail/11884.shtml?") == 0); 136 | assertTrue(result.indexOf("navindex=5") >= "http://www.kaola.com/activity/detail/11884.shtml?".length()); 137 | assertTrue(result.indexOf("zn=top") >= "http://www.kaola.com/activity/detail/11884.shtml?".length()); 138 | assertEquals(result.length(), "http://www.kaola.com/activity/detail/11884.shtml?".length() 139 | + "navindex=5".length() + "zn=top".length() + 1); 140 | 141 | url = "http://www.kaola.com/activity/detail/11884.shtml?navindex=5"; 142 | params = new HashMap<>(); 143 | params.put("zn", "top"); 144 | result = mCandyWebCache.constructUrl(url, params); 145 | assertTrue(result.contains("navindex=5")); 146 | assertTrue(result.contains("zn=top")); 147 | assertTrue(result.indexOf("http://www.kaola.com/activity/detail/11884.shtml?") == 0); 148 | assertTrue(result.indexOf("navindex=5") >= "http://www.kaola.com/activity/detail/11884.shtml?".length()); 149 | assertTrue(result.indexOf("zn=top") >= "http://www.kaola.com/activity/detail/11884.shtml?".length()); 150 | assertEquals(result.length(), "http://www.kaola.com/activity/detail/11884.shtml?".length() 151 | + "navindex=5".length() + "zn=top".length() + 1); 152 | 153 | url = "http://www.kaola.com/activity/detail/11884.shtml?navindex="; 154 | params = new HashMap<>(); 155 | params.put("zn", "top"); 156 | result = mCandyWebCache.constructUrl(url, params); 157 | assertTrue(result.contains("navindex=")); 158 | assertTrue(result.contains("zn=top")); 159 | assertTrue(result.indexOf("http://www.kaola.com/activity/detail/11884.shtml?") == 0); 160 | assertTrue(result.indexOf("navindex=") >= "http://www.kaola.com/activity/detail/11884.shtml?".length()); 161 | assertTrue(result.indexOf("zn=top") >= "http://www.kaola.com/activity/detail/11884.shtml?".length()); 162 | assertEquals(result.length(), "http://www.kaola.com/activity/detail/11884.shtml?".length() 163 | + "navindex=".length() + "zn=top".length() + 1); 164 | 165 | } 166 | } -------------------------------------------------------------------------------- /candywebcache/src/androidTest/java/com/netease/hearttouch/candywebcache/WebViewManagerTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache; 2 | 3 | import android.content.Context; 4 | import android.test.InstrumentationTestCase; 5 | import android.webkit.WebView; 6 | 7 | import org.junit.After; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Created by netease on 16/6/20. 15 | */ 16 | public class WebViewManagerTest extends InstrumentationTestCase { 17 | WebViewManager mWebViewManager; 18 | int mCreateCount; 19 | 20 | @Before 21 | public void setUp() throws Exception { 22 | mWebViewManager = WebViewManager.getsInstance(); 23 | mCreateCount = 0; 24 | } 25 | 26 | @After 27 | public void tearDown() throws Exception { 28 | 29 | } 30 | 31 | @Test 32 | public void testGetsInstance() throws Exception { 33 | assertNotNull(mWebViewManager); 34 | } 35 | 36 | @Test 37 | public void testInit() throws Exception { 38 | mWebViewManager.init(5); 39 | } 40 | 41 | @Test 42 | public void testSetsWebViewFactoryAndGetWebView() throws Exception { 43 | WebViewManager.WebViewFactory factory = new WebViewManager.WebViewFactory() { 44 | @Override 45 | public WebView createWebView(Context context) { 46 | // WebView view = new WebView(context); 47 | ++mCreateCount; 48 | return null; 49 | } 50 | }; 51 | mWebViewManager.setsWebViewFactory(factory); 52 | 53 | WebView view = new WebView(getInstrumentation().getContext()); 54 | assertEquals(view.getContext(), getInstrumentation().getContext()); 55 | 56 | assertEquals(mCreateCount, 0); 57 | 58 | for (int i = 0; i < 15; ++ i) { 59 | mWebViewManager.getWebView(getInstrumentation().getContext()); 60 | } 61 | assertEquals(mCreateCount, 15); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /candywebcache/src/androidTest/java/com/netease/hearttouch/candywebcache/cachemanager/BsdiffPatcherTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | import android.test.InstrumentationTestCase; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import java.io.File; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Created by netease on 16/6/13. 15 | */ 16 | public class BsdiffPatcherTest extends InstrumentationTestCase { 17 | static { 18 | System.loadLibrary("patcher"); 19 | } 20 | @Before 21 | public void setUp() throws Exception { 22 | 23 | } 24 | 25 | @After 26 | public void tearDown() throws Exception { 27 | 28 | } 29 | 30 | @Test 31 | public void testApplyPatch() throws Exception { 32 | BsdiffPatcher patcher = new BsdiffPatcher(); 33 | String oldFilePath = "/sdcard/webcachetestfiles/kaola_20160827.zip"; 34 | assertTrue(Md5Utils.checkFileValidation(oldFilePath, "6e3ace2638be9fc855e7672964cf4d4c")); 35 | 36 | String patchFilePath = "/sdcard/webcachetestfiles/kaola.diff"; 37 | assertTrue(Md5Utils.checkFileValidation(patchFilePath, "836a47fe852fa5352322dbd6f2c9a813")); 38 | 39 | String outFilePath = "/sdcard/webcachetestfiles/kaola.zip"; 40 | String patchedFilePath = patcher.applyPatch(oldFilePath, patchFilePath, outFilePath); 41 | assertNotNull(patchedFilePath); 42 | File file = new File(outFilePath); 43 | assertTrue(file.exists()); 44 | assertTrue(file.isFile()); 45 | assertTrue(Md5Utils.checkFileValidation(patchedFilePath, "3244787f9fe856920a77a807a285e6b5")); 46 | 47 | file.delete(); 48 | assertTrue(!file.exists()); 49 | } 50 | } -------------------------------------------------------------------------------- /candywebcache/src/androidTest/java/com/netease/hearttouch/candywebcache/cachemanager/EnDecryptTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | import android.test.InstrumentationTestCase; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.*; 10 | 11 | /** 12 | * Created by netease on 16/6/27. 13 | */ 14 | public class EnDecryptTest extends InstrumentationTestCase { 15 | @Before 16 | public void setUp() throws Exception { 17 | 18 | } 19 | 20 | @After 21 | public void tearDown() throws Exception { 22 | 23 | } 24 | 25 | @Test 26 | public void testEnDecrypt() throws Exception { 27 | String dataSrc = "20398415cf372481131278f074119188"; 28 | String passwd = "12344321"; 29 | 30 | assertEquals("E13F4ECDDBB54551664F74AC76634BBAD8F5ACB35DFF99CA711C05169E990064996A020A8336A5E0", DESUtils.encrypt(dataSrc, passwd)); 31 | assertEquals("4T9Ozdu1RVFmT3SsdmNLutj1rLNd/5nKcRwFFp6ZAGSZagIKgzal4A==", Base64.encode(DESUtils.encrypt(dataSrc.getBytes(), passwd.getBytes()))); 32 | assertEquals("4T9Ozdu1RVFmT3SsdmNLutj1rLNd/5nKcRwFFp6ZAGSZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 33 | 34 | dataSrc = "cbc2d2376ef405c6c49088706b294275"; 35 | assertEquals("rjNJ5lUmD06tE4rWnohvd3ifijh9lXDkRTGRDzNwrn+ZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 36 | assertEquals(dataSrc, EnDecryptionUtils.decode("rjNJ5lUmD06tE4rWnohvd3ifijh9lXDkRTGRDzNwrn+ZagIKgzal4A==")); 37 | 38 | dataSrc = "a2e4c9b7ae6beb31e68daca9d7ad6f4e"; 39 | assertEquals("lQdR6sBdy+AIakJz7Pi53ZlIPWGEj1IDybvPm0RfGsKZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 40 | assertEquals(dataSrc, EnDecryptionUtils.decode("lQdR6sBdy+AIakJz7Pi53ZlIPWGEj1IDybvPm0RfGsKZagIKgzal4A==")); 41 | 42 | dataSrc = "6e3ace2638be9fc855e7672964cf4d4c"; 43 | assertEquals("kC/KhxC55iM83nDOCXxvtaSeEQ0Qf99pCDYD6+ZUVp+ZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 44 | assertEquals(dataSrc, EnDecryptionUtils.decode("kC/KhxC55iM83nDOCXxvtaSeEQ0Qf99pCDYD6+ZUVp+ZagIKgzal4A==")); 45 | 46 | dataSrc = "32d32a0700b8067d0cc98a770a8a1c61"; 47 | assertEquals("+a8HfZHo5447sQc3uhcGSTa6ZLa+LwXs4DzONPSTNz2ZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 48 | assertEquals(dataSrc, EnDecryptionUtils.decode("+a8HfZHo5447sQc3uhcGSTa6ZLa+LwXs4DzONPSTNz2ZagIKgzal4A==")); 49 | 50 | dataSrc = "3244787f9fe856920a77a807a285e6b5"; 51 | assertEquals("S1zVHQTTe5gDJphM1w9xS7RK+NRoaR42nJsE9o8jkzeZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 52 | assertEquals(dataSrc, EnDecryptionUtils.decode("S1zVHQTTe5gDJphM1w9xS7RK+NRoaR42nJsE9o8jkzeZagIKgzal4A==")); 53 | 54 | String encryptedStr = "4T9Ozdu1RVFmT3SsdmNLutj1rLNd/5nKcRwFFp6ZAGSZagIKgzal4A=="; 55 | assertEquals("e13f4ecddbb54551664f74ac76634bbad8f5acb35dff99ca711c05169e990064996a020a8336a5e0", Md5Utils.toHexString(Base64.decode(encryptedStr))); 56 | byte[] decryptedData = Base64.decode(encryptedStr); 57 | String md5 = new String(DESUtils.decrypt(decryptedData, passwd.getBytes()), "UTF-8"); 58 | assertEquals("20398415cf372481131278f074119188", new String(DESUtils.decrypt(decryptedData, passwd.getBytes()), "UTF-8")); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /candywebcache/src/androidTest/java/com/netease/hearttouch/htfiledownloader/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /candywebcache/src/androidTest/java/com/netease/hearttouch/htfiledownloader/DownloadDBHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | import android.test.InstrumentationTestCase; 4 | 5 | import org.junit.Before; 6 | 7 | import java.io.File; 8 | import java.util.List; 9 | 10 | /** 11 | * Created by DING on 16/7/16. 12 | */ 13 | public class DownloadDBHelperTest extends InstrumentationTestCase { 14 | 15 | @Before 16 | public void setUp() throws Exception { 17 | File file = new File("/sdcard/netease/unit_test/download"); 18 | file.mkdirs(); 19 | DownloadDBHelper.init(getInstrumentation().getContext(),file.getAbsolutePath()); 20 | } 21 | 22 | public void testGetByTaskId() throws Exception { 23 | DownloadTask downloadTask = new DownloadTask.DownloadTaskBuilder() 24 | .setDownloadUrl("https://iterm2.com/downloads/stable/iTerm2-2_1_4.zip") 25 | .build(); 26 | DownloadDBHelper.getInstance().insertOrUpdate(downloadTask.getDownloadTaskData()); 27 | DownloadTask.DownloadTaskData downloadTaskData = DownloadDBHelper.getInstance().getByTaskId(downloadTask.getDownloadTaskData().getTaskId()); 28 | assertNotNull(downloadTaskData); 29 | assertEquals(downloadTask.getDownloadTaskData().getTaskId(), downloadTaskData.getTaskId()); 30 | assertEquals(downloadTask.getDownloadTaskData().getState(),downloadTaskData.getState()); 31 | 32 | } 33 | 34 | public void testInsertOrUpdate() throws Exception { 35 | //这个在上面也就测到了 36 | } 37 | 38 | public void testDeleteByTaskId() throws Exception { 39 | DownloadTask downloadTask = new DownloadTask.DownloadTaskBuilder() 40 | .setDownloadUrl("https://iterm2.com/downloads/stable/iTerm2-2_1_4.zip") 41 | .build(); 42 | DownloadDBHelper.getInstance().insertOrUpdate(downloadTask.getDownloadTaskData()); 43 | DownloadTask.DownloadTaskData downloadTaskData = DownloadDBHelper.getInstance().getByTaskId(downloadTask.getDownloadTaskData().getTaskId()); 44 | assertNotNull(downloadTaskData); 45 | 46 | DownloadDBHelper.getInstance().deleteByTaskId(downloadTask.getDownloadTaskData().getTaskId()); 47 | 48 | downloadTaskData = DownloadDBHelper.getInstance().getByTaskId(downloadTask.getDownloadTaskData().getTaskId()); 49 | assertNull(downloadTaskData); 50 | 51 | } 52 | 53 | public void testGetRemainingTasks() throws Exception { 54 | DownloadTask downloadTask = new DownloadTask.DownloadTaskBuilder() 55 | .setDownloadUrl("https://iterm2.com/downloads/stable/iTerm2-2_1_4.zip") 56 | .build(); 57 | DownloadDBHelper.getInstance().insertOrUpdate(downloadTask.getDownloadTaskData()); 58 | List downloadTaskDatas = DownloadDBHelper.getInstance().getRemainingTasks(); 59 | assertNotNull(downloadTaskDatas); 60 | assertTrue(!downloadTaskDatas.isEmpty()); 61 | 62 | for(DownloadTask.DownloadTaskData downloadTaskData : downloadTaskDatas){ 63 | if(downloadTaskData.getTaskId() == downloadTask.getDownloadTaskData().getTaskId()){ 64 | return; 65 | } 66 | } 67 | throw new Exception("cannot find task in result list..."); 68 | }} -------------------------------------------------------------------------------- /candywebcache/src/androidTest/java/com/netease/hearttouch/htresourceversionchecker/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /candywebcache/src/androidTest/java/com/netease/hearttouch/htresourceversionchecker/VersionCheckerTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker; 2 | 3 | import com.netease.hearttouch.htresourceversionchecker.model.ResponseResInfo; 4 | 5 | import junit.framework.TestCase; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * Created by DING on 16/7/16. 12 | */ 13 | public class VersionCheckerTest extends TestCase { 14 | public void testCheckVersion() throws Exception { 15 | 16 | } 17 | 18 | public void testGetVersionInfo() throws Exception { 19 | String errorJsonStr = "dededawdwefrfa"; 20 | List errorResult = VersionChecker.getVersionInfo(errorJsonStr); 21 | assertTrue(errorResult == null); 22 | 23 | 24 | List expectResult = new ArrayList<>(); 25 | ResponseResInfo responseResInfo1 = new ResponseResInfo(); 26 | ResponseResInfo responseResInfo2 = new ResponseResInfo(); 27 | 28 | String userData = "{\"domains\":[\"www.163.com\",\"www.126.com\"]}"; 29 | 30 | responseResInfo1.setResID("123"); 31 | responseResInfo1.setResVersion("123"); 32 | responseResInfo1.setDiffUrl("testDiffUrl"); 33 | responseResInfo1.setDiffMd5("deafwerf24345fref"); 34 | responseResInfo1.setFullUrl("testFullUrl"); 35 | responseResInfo1.setFullMd5("dewf23k4j546#$5"); 36 | responseResInfo1.setState(1); 37 | responseResInfo1.setUserData(userData); 38 | 39 | 40 | responseResInfo2.setResID("321"); 41 | responseResInfo2.setResVersion("321"); 42 | responseResInfo2.setDiffUrl("testDiffUrl111"); 43 | responseResInfo2.setDiffMd5("deafwerf24345fref1111"); 44 | responseResInfo2.setFullUrl("testFullUrl111"); 45 | responseResInfo2.setFullMd5("dewf23k4j546#$51111"); 46 | responseResInfo2.setState(2); 47 | responseResInfo2.setUserData(userData); 48 | 49 | expectResult.add(responseResInfo1); 50 | expectResult.add(responseResInfo2); 51 | 52 | String jsonStr = "[{\"appId\":\"123\",\"version\":\"123\",\"updateTime\":123456789,\"diffUrl\":\"testDiffUrl\",\"diffMd5\":\"deafwerf24345fref\",\"fullUrl\":\"testFullUrl\",\"fullMd5\":\"dewf23k4j546#$5\",\"statusCode\":1,\"domains\":[\"www.163.com\",\"www.126.com\"]},{\"appId\":\"321\",\"version\":\"321\",\"updateTime\":987654321,\"diffUrl\":\"testDiffUrl111\",\"diffMd5\":\"deafwerf24345fref1111\",\"fullUrl\":\"testFullUrl111\",\"fullMd5\":\"dewf23k4j546#$51111\",\"statusCode\":2,\"domains\":[\"www.163.com\",\"www.126.com\"]}]"; 53 | List result = VersionChecker.getVersionInfo(jsonStr); 54 | assertEquals(expectResult.toString(), result.toString()); 55 | 56 | } 57 | } -------------------------------------------------------------------------------- /candywebcache/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/CacheConfig.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by netease on 16/6/3. 8 | */ 9 | public class CacheConfig { 10 | private long mUpdateCheckCycle; 11 | private String mCacheDirPath; 12 | private String mManifestDirPath; 13 | private int mMemCacheSize; 14 | private List mUncachedFileType; 15 | private List mDefaultDomains; 16 | 17 | public static class ConfigBuilder { 18 | private long mUpdateCheckCycle; 19 | private String mCacheDirPath; 20 | private String mManifestDirPath; 21 | private int mMemCacheSize; 22 | private List mUncachedFileType; 23 | private List mDefaultDomains; 24 | 25 | private ConfigBuilder() { 26 | } 27 | 28 | public ConfigBuilder setUpdateCycle(long millis) { 29 | mUpdateCheckCycle = millis; 30 | return this; 31 | } 32 | 33 | public ConfigBuilder setCacheDirPath(String path) { 34 | mCacheDirPath = path; 35 | return this; 36 | } 37 | 38 | public ConfigBuilder setManifestDirPath(String path) { 39 | mManifestDirPath = path; 40 | return this; 41 | } 42 | 43 | public ConfigBuilder setMemCacheSize(int szBytes) { 44 | mMemCacheSize = szBytes; 45 | return this; 46 | } 47 | 48 | public ConfigBuilder setUncachedFileTypes(List uncachedFileType) { 49 | mUncachedFileType = uncachedFileType; 50 | return this; 51 | } 52 | 53 | public ConfigBuilder setDefaultDomains(List domains) { 54 | mDefaultDomains = domains; 55 | return this; 56 | } 57 | 58 | public CacheConfig build() { 59 | CacheConfig cacheConfig = new CacheConfig(); 60 | cacheConfig.mUpdateCheckCycle = mUpdateCheckCycle; 61 | cacheConfig.mCacheDirPath = mCacheDirPath; 62 | cacheConfig.mManifestDirPath = mManifestDirPath; 63 | cacheConfig.mMemCacheSize = mMemCacheSize; 64 | if (mUncachedFileType != null && mUncachedFileType.size() > 0) { 65 | cacheConfig.mUncachedFileType = new ArrayList<>(mUncachedFileType); 66 | } 67 | if (mDefaultDomains != null && mDefaultDomains.size() > 0) { 68 | cacheConfig.mDefaultDomains = new ArrayList<>(mDefaultDomains); 69 | } 70 | return cacheConfig; 71 | } 72 | } 73 | 74 | private CacheConfig() { 75 | 76 | } 77 | 78 | public static ConfigBuilder createCofigBuilder() { 79 | ConfigBuilder configBuilder = new ConfigBuilder(); 80 | return configBuilder; 81 | } 82 | 83 | public long getUpdateCheckCycle() { 84 | return mUpdateCheckCycle; 85 | } 86 | 87 | public String getCacheDirPath() { 88 | return mCacheDirPath; 89 | } 90 | 91 | public String getManifestDirPath() { 92 | return mManifestDirPath; 93 | } 94 | 95 | public int getMemCacheSize() { 96 | return mMemCacheSize; 97 | } 98 | 99 | public List getUncachedFileType() { 100 | return mUncachedFileType; 101 | } 102 | 103 | public List getDefaultDomains() { 104 | return mDefaultDomains; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/CacheError.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache; 2 | 3 | /** 4 | * Created by netease on 16/6/3. 5 | */ 6 | public class CacheError extends Exception { 7 | public CacheError() { 8 | 9 | } 10 | 11 | public CacheError(String detailMessage) { 12 | super(detailMessage); 13 | } 14 | 15 | public CacheError(String detailMessage, Throwable throwable) { 16 | super(detailMessage, throwable); 17 | } 18 | 19 | public CacheError(Throwable throwable) { 20 | super(throwable); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/HybridWebviewClient.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache; 2 | 3 | import android.webkit.WebResourceRequest; 4 | import android.webkit.WebResourceResponse; 5 | import android.webkit.WebView; 6 | import android.webkit.WebViewClient; 7 | 8 | /** 9 | * Created by netease on 16/7/7. 10 | */ 11 | public class HybridWebviewClient extends WebViewClient { 12 | @Override 13 | public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { 14 | return CandyWebCache.getsInstance().getResponse(view, request); 15 | } 16 | 17 | @Override 18 | public WebResourceResponse shouldInterceptRequest(WebView view, String url) { 19 | return CandyWebCache.getsInstance().getResponse(view, url); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/WebViewManager.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.webkit.WebView; 7 | 8 | import java.util.LinkedList; 9 | 10 | /** 11 | * Created by netease on 16/6/6. 12 | */ 13 | public class WebViewManager { 14 | public interface WebViewFactory { 15 | WebView createWebView(Context context); 16 | } 17 | 18 | private static WebViewManager sInstance; 19 | 20 | private WebViewFactory mDefaultWebViewFactory; 21 | private WebViewFactory mWebViewFactory; 22 | 23 | private Context mContext; 24 | private LinkedList mWebViewCache; 25 | private int mMaxWebViewCount; 26 | 27 | private WebViewManager() { 28 | } 29 | 30 | public static synchronized WebViewManager getsInstance() { 31 | if (sInstance == null) { 32 | sInstance = new WebViewManager(); 33 | } 34 | return sInstance; 35 | } 36 | 37 | public synchronized void init(int maxCount) { 38 | mMaxWebViewCount = maxCount; 39 | mDefaultWebViewFactory = new DefaultWebviewFactory(); 40 | mWebViewFactory = mDefaultWebViewFactory; 41 | mWebViewCache = new LinkedList<>(); 42 | } 43 | 44 | public synchronized void setsWebViewFactory(WebViewFactory factory) { 45 | mWebViewFactory = factory; 46 | } 47 | 48 | private class WebViewCreationTask implements Runnable { 49 | private Context mContext; 50 | 51 | public WebViewCreationTask(Context context) { 52 | mContext = context; 53 | } 54 | 55 | @Override 56 | public void run() { 57 | synchronized (WebViewManager.this) { 58 | while (mWebViewCache.size() < mMaxWebViewCount) { 59 | WebView view; 60 | if (mWebViewFactory != null) { 61 | view = mWebViewFactory.createWebView(mContext); 62 | } else { 63 | view = new WebView(mContext); 64 | } 65 | mWebViewCache.add(view); 66 | } 67 | } 68 | } 69 | } 70 | 71 | public synchronized WebView getWebView(Context context) { 72 | WebView view = null; 73 | if (mContext != context) { 74 | mWebViewCache.clear(); 75 | mContext = context; 76 | Handler handler = new Handler(Looper.getMainLooper()); 77 | WebViewCreationTask task = new WebViewCreationTask(context); 78 | handler.post(task); 79 | } else { 80 | if (mWebViewCache.size() > 0) { 81 | view = mWebViewCache.remove(); 82 | } 83 | } 84 | if (view == null) { 85 | if (mWebViewFactory != null) { 86 | view = mWebViewFactory.createWebView(context); 87 | } else { 88 | view = new WebView(context); 89 | } 90 | } 91 | return view; 92 | } 93 | 94 | private static class DefaultWebviewFactory implements WebViewFactory { 95 | @Override 96 | public WebView createWebView(Context context) { 97 | WebView webView = new WebView(context); 98 | return webView; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/WebcacheLog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.netease.hearttouch.candywebcache; 18 | 19 | import android.os.SystemClock; 20 | import android.util.Log; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | import java.util.Locale; 25 | 26 | /** 27 | * Logging helper class. 28 | *

29 | * to see Volley logs call:
30 | * {@code /platform-tools/adb shell setprop log.tag.Volley VERBOSE} 31 | */ 32 | public class WebcacheLog { 33 | public static String TAG = "Webcache"; 34 | 35 | public static boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 36 | 37 | /** 38 | * Customize the log tag for your application, so that other apps 39 | * using Volley don't mix their logs with yours. 40 | *
41 | * Enable the log property for your tag before starting your app: 42 | *
43 | * {@code adb shell setprop log.tag.<tag>} 44 | */ 45 | public static void setTag(String tag) { 46 | d("Changing log tag to %s", tag); 47 | TAG = tag; 48 | 49 | // Reinitialize the DEBUG "constant" 50 | DEBUG = Log.isLoggable(TAG, Log.VERBOSE); 51 | } 52 | 53 | public static void v(String format, Object... args) { 54 | if (DEBUG) { 55 | Log.v(TAG, buildMessage(format, args)); 56 | } 57 | } 58 | 59 | public static void d(String format, Object... args) { 60 | if (DEBUG) { 61 | Log.d(TAG, buildMessage(format, args)); 62 | } 63 | } 64 | 65 | public static void i(String format, Object... args) { 66 | Log.i(TAG, buildMessage(format, args)); 67 | } 68 | 69 | public static void w(String format, Object... args) { 70 | Log.w(TAG, buildMessage(format, args)); 71 | } 72 | 73 | public static void e(String format, Object... args) { 74 | Log.e(TAG, buildMessage(format, args)); 75 | } 76 | 77 | public static void e(Throwable tr, String format, Object... args) { 78 | Log.e(TAG, buildMessage(format, args), tr); 79 | } 80 | 81 | public static void wtf(String format, Object... args) { 82 | Log.wtf(TAG, buildMessage(format, args)); 83 | } 84 | 85 | public static void wtf(Throwable tr, String format, Object... args) { 86 | Log.wtf(TAG, buildMessage(format, args), tr); 87 | } 88 | 89 | /** 90 | * Formats the caller's provided message and prepends useful info like 91 | * calling thread ID and method name. 92 | */ 93 | private static String buildMessage(String format, Object... args) { 94 | String msg = (args == null) ? format : String.format(Locale.US, format, args); 95 | if (false) { 96 | StackTraceElement[] trace = new Throwable().fillInStackTrace().getStackTrace(); 97 | 98 | String caller = ""; 99 | // Walk up the stack looking for the first caller outside of WebcacheLog. 100 | // It will be at least two frames up, so start there. 101 | for (int i = 2; i < trace.length; i++) { 102 | Class clazz = trace[i].getClass(); 103 | if (!clazz.equals(WebcacheLog.class)) { 104 | String callingClass = trace[i].getClassName(); 105 | callingClass = callingClass.substring(callingClass.lastIndexOf('.') + 1); 106 | callingClass = callingClass.substring(callingClass.lastIndexOf('$') + 1); 107 | 108 | caller = callingClass + "." + trace[i].getMethodName(); 109 | break; 110 | } 111 | } 112 | return String.format(Locale.US, "[%d] %s: %s", 113 | Thread.currentThread().getId(), caller, msg); 114 | } else { 115 | return msg; 116 | } 117 | } 118 | 119 | /** 120 | * A simple event log with records containing a name, thread ID, and timestamp. 121 | */ 122 | static class MarkerLog { 123 | public static final boolean ENABLED = WebcacheLog.DEBUG; 124 | 125 | /** Minimum duration from first marker to last in an marker log to warrant logging. */ 126 | private static final long MIN_DURATION_FOR_LOGGING_MS = 0; 127 | 128 | private static class Marker { 129 | public final String name; 130 | public final long thread; 131 | public final long time; 132 | 133 | public Marker(String name, long thread, long time) { 134 | this.name = name; 135 | this.thread = thread; 136 | this.time = time; 137 | } 138 | } 139 | 140 | private final List mMarkers = new ArrayList(); 141 | private boolean mFinished = false; 142 | 143 | /** Adds a marker to this log with the specified name. */ 144 | public synchronized void add(String name, long threadId) { 145 | if (mFinished) { 146 | throw new IllegalStateException("Marker added to finished log"); 147 | } 148 | 149 | mMarkers.add(new Marker(name, threadId, SystemClock.elapsedRealtime())); 150 | } 151 | 152 | /** 153 | * Closes the log, dumping it to logcat if the time difference between 154 | * the first and last markers is greater than {@link #MIN_DURATION_FOR_LOGGING_MS}. 155 | * @param header Header string to print above the marker log. 156 | */ 157 | public synchronized void finish(String header) { 158 | mFinished = true; 159 | 160 | long duration = getTotalDuration(); 161 | if (duration <= MIN_DURATION_FOR_LOGGING_MS) { 162 | return; 163 | } 164 | 165 | long prevTime = mMarkers.get(0).time; 166 | d("(%-4d ms) %s", duration, header); 167 | for (Marker marker : mMarkers) { 168 | long thisTime = marker.time; 169 | d("(+%-4d) [%2d] %s", (thisTime - prevTime), marker.thread, marker.name); 170 | prevTime = thisTime; 171 | } 172 | } 173 | 174 | @Override 175 | protected void finalize() throws Throwable { 176 | // Catch requests that have been collected (and hence end-of-lifed) 177 | // but had no debugging output printed for them. 178 | if (!mFinished) { 179 | finish("Request on the loose"); 180 | e("Marker log finalized without finish() - uncaught exit point for request"); 181 | } 182 | } 183 | 184 | /** Returns the time difference between the first and last events in this log. */ 185 | private long getTotalDuration() { 186 | if (mMarkers.size() == 0) { 187 | return 0; 188 | } 189 | 190 | long first = mMarkers.get(0).time; 191 | long last = mMarkers.get(mMarkers.size() - 1).time; 192 | return last - first; 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/BsdiffPatcher.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | /** 4 | * Created by netease on 16/6/6. 5 | */ 6 | public class BsdiffPatcher implements Patcher { 7 | @Override 8 | public String applyPatch(String oldFilePath, String patchFilePath, String outFilePath) { 9 | if (nativeApplyPatch(oldFilePath, patchFilePath, outFilePath)) { 10 | return outFilePath; 11 | } 12 | return null; 13 | } 14 | 15 | private native boolean nativeApplyPatch(String oldFilePath, String patchFilePath, String outFilePath); 16 | } 17 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/Cache.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | /** 4 | * Created by netease on 16/6/3. 5 | */ 6 | public interface Cache { 7 | /** 8 | * Retrieves an entry from the cache. 9 | * @param key Cache key 10 | * @return An {@link Entry} or null in the event of a cache miss 11 | */ 12 | public Entry get(String key); 13 | 14 | /** 15 | * Adds or replaces an entry to the cache. 16 | * @param key Cache key 17 | * @param entry Data to store and metadata for cache coherency, TTL, etc. 18 | */ 19 | public void put(String key, Entry entry); 20 | 21 | /** 22 | * Performs any potentially long-running actions needed to initialize the cache; 23 | * will be called from a worker thread. 24 | */ 25 | public void initialize(); 26 | 27 | /** 28 | * Invalidates an entry in the cache. 29 | * @param key Cache key 30 | * @param fullExpire True to fully expire the entry, false to soft expire 31 | */ 32 | public void invalidate(String key, boolean fullExpire); 33 | 34 | /** 35 | * Removes an entry from the cache. 36 | * @param key Cache key 37 | */ 38 | public void remove(String key); 39 | 40 | /** 41 | * Empties the cache. 42 | */ 43 | public void clear(); 44 | 45 | /** 46 | * Data and metadata for an entry returned by the cache. 47 | */ 48 | public static class Entry { 49 | /** The data returned from cache. */ 50 | public byte[] data; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/CacheDatabaseHelper.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import android.database.sqlite.SQLiteOpenHelper; 6 | 7 | import java.io.File; 8 | 9 | /** 10 | * Created by netease on 16/6/12. 11 | */ 12 | public class CacheDatabaseHelper extends SQLiteOpenHelper { 13 | public static final String WEBAPP_INFO_TABLE_NAME = "webappinfo"; 14 | public static final String FILE_INFO_TABLE_NAME = "fileinfo"; 15 | private static final String DATABASE_NAME = "cache_info.db"; 16 | private static final int DATABASE_VERSION = 1; 17 | 18 | private final String mDatabaseFilePath; 19 | 20 | public CacheDatabaseHelper(Context context, String databasePath) { 21 | super(context, databasePath + File.separator + DATABASE_NAME, null, DATABASE_VERSION); 22 | mDatabaseFilePath = databasePath + File.separator + DATABASE_NAME; 23 | } 24 | 25 | @Override 26 | public void onCreate(SQLiteDatabase db) { 27 | db.execSQL("DROP TABLE IF EXISTS webappinfo"); 28 | db.execSQL("CREATE TABLE IF NOT EXISTS webappinfo" + 29 | "(_id INTEGER PRIMARY KEY AUTOINCREMENT, domain VARCHAR, name VARCHAR, " + 30 | "local_version VARCHAR, md5 VARCHAR, local_path VARCHAR, pkg_path VARCHAR, status INTEGER, " + 31 | "full_url VARCHAR, update_percent INTEGER, disk_size INTEGER)"); 32 | 33 | db.execSQL("DROP TABLE IF EXISTS fileinfo"); 34 | db.execSQL("CREATE TABLE IF NOT EXISTS fileinfo" + 35 | "(_id INTEGER PRIMARY KEY AUTOINCREMENT, url VARCHAR, appname VARCHAR, " + 36 | "md5 VARCHAR, local_path VARCHAR, status INTEGER, accessCount INTEGER)"); 37 | } 38 | 39 | @Override 40 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 41 | 42 | } 43 | 44 | boolean checkDatabaseValidation() { 45 | File databaseFile = new File(mDatabaseFilePath); 46 | return databaseFile.exists(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/CourgettePatcher.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | /** 4 | * Created by netease on 16/6/6. 5 | */ 6 | public class CourgettePatcher implements Patcher { 7 | @Override 8 | public String applyPatch(String oldFilePath, String patchFilePath, String outFilePath) { 9 | if (nativeApplyPatch(oldFilePath, patchFilePath, outFilePath)) { 10 | return outFilePath; 11 | } 12 | return null; 13 | } 14 | 15 | private native boolean nativeApplyPatch(String oldFilePath, String patchFilePath, String outFilePath); 16 | } 17 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/DESUtils.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | import java.security.InvalidKeyException; 4 | import java.security.NoSuchAlgorithmException; 5 | import java.security.SecureRandom; 6 | import java.security.spec.InvalidKeySpecException; 7 | 8 | import javax.crypto.BadPaddingException; 9 | import javax.crypto.Cipher; 10 | import javax.crypto.IllegalBlockSizeException; 11 | import javax.crypto.NoSuchPaddingException; 12 | import javax.crypto.SecretKey; 13 | import javax.crypto.SecretKeyFactory; 14 | import javax.crypto.spec.DESKeySpec; 15 | 16 | /** 17 | * Created by netease on 16/6/27. 18 | */ 19 | public class DESUtils { 20 | private final static String DES = "DES"; 21 | 22 | private static SecretKey generateKey(byte[] passwd) { 23 | try { 24 | DESKeySpec desKeySpec = new DESKeySpec(passwd); 25 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); 26 | SecretKey secretKey = keyFactory.generateSecret(desKeySpec); 27 | return secretKey; 28 | } catch (InvalidKeyException e) { 29 | e.printStackTrace(); 30 | } catch (NoSuchAlgorithmException e) { 31 | e.printStackTrace(); 32 | } catch (InvalidKeySpecException e) { 33 | e.printStackTrace(); 34 | } 35 | return null; 36 | } 37 | 38 | public static byte[] encrypt(byte[] dataSrc, byte[] passwd) { 39 | Cipher cipher = null; 40 | try { 41 | SecureRandom random = new SecureRandom(); 42 | cipher = Cipher.getInstance(DES); 43 | cipher.init(Cipher.ENCRYPT_MODE, generateKey(passwd), random); 44 | return cipher.doFinal(dataSrc); 45 | } catch (NoSuchAlgorithmException e) { 46 | e.printStackTrace(); 47 | } catch (NoSuchPaddingException e) { 48 | e.printStackTrace(); 49 | } catch (InvalidKeyException e) { 50 | e.printStackTrace(); 51 | } catch (IllegalBlockSizeException e) { 52 | e.printStackTrace(); 53 | } catch (BadPaddingException e) { 54 | e.printStackTrace(); 55 | } 56 | return null; 57 | } 58 | 59 | /** 60 | * 61 | * @param dataSrc 密码 62 | * @param passwd 加密字符串 63 | * @return 64 | */ 65 | public final static String encrypt(String dataSrc, String passwd) { 66 | try { 67 | return byte2String(encrypt(dataSrc.getBytes(), passwd.getBytes())); 68 | } catch (Exception e) { 69 | } 70 | return null; 71 | } 72 | 73 | private static String byte2String(byte[] b) { 74 | String hs = ""; 75 | String stmp = ""; 76 | for (int n = 0; n < b.length; n++) { 77 | stmp = (java.lang.Integer.toHexString(b[n] & 0XFF)); 78 | if (stmp.length() == 1) 79 | hs = hs + "0" + stmp; 80 | else 81 | hs = hs + stmp; 82 | } 83 | return hs.toUpperCase(); 84 | } 85 | 86 | /** 87 | * 88 | * @param dataSrc 数据源 89 | * @param passwd 密钥,长度必须是8的倍数 90 | * @return 91 | * @throws Exception 92 | */ 93 | public static byte[] decrypt(byte[] dataSrc, byte[] passwd) { 94 | Cipher cipher = null; 95 | try { 96 | cipher = Cipher.getInstance(DES); 97 | cipher.init(Cipher.DECRYPT_MODE, generateKey(passwd)); 98 | return cipher.doFinal(dataSrc); 99 | } catch (NoSuchAlgorithmException e) { 100 | e.printStackTrace(); 101 | } catch (NoSuchPaddingException e) { 102 | e.printStackTrace(); 103 | } catch (InvalidKeyException e) { 104 | e.printStackTrace(); 105 | } catch (IllegalBlockSizeException e) { 106 | e.printStackTrace(); 107 | } catch (BadPaddingException e) { 108 | e.printStackTrace(); 109 | } 110 | return null; 111 | } 112 | 113 | public final static String decrypt(String dataSrc, String passwd) { 114 | try { 115 | return new String(decrypt(String2byte(dataSrc.getBytes()), passwd.getBytes())); 116 | } catch (Exception e) { 117 | e.printStackTrace(); 118 | } 119 | return null; 120 | } 121 | 122 | private static byte[] String2byte(byte[] b) { 123 | if ((b.length % 2) != 0) 124 | throw new IllegalArgumentException("长度不是偶数"); 125 | byte[] b2 = new byte[b.length / 2]; 126 | for (int n = 0; n < b.length; n += 2) { 127 | String item = new String(b, n, 2); 128 | b2[n / 2] = (byte) Integer.parseInt(item, 16); 129 | } 130 | return b2; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/EnDecryptionUtils.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | 5 | /** 6 | * Created by netease on 16/6/28. 7 | */ 8 | public class EnDecryptionUtils { 9 | private static final String PASSWORD = "12344321"; 10 | public static String encode(String dataSrc) { 11 | String encryptedStr = null; 12 | try { 13 | encryptedStr = Base64.encode(DESUtils.encrypt(dataSrc.getBytes(), PASSWORD.getBytes())); 14 | } catch (UnsupportedEncodingException e) { 15 | } 16 | return encryptedStr; 17 | } 18 | 19 | public static String decode(String encryptedStr) { 20 | String decryptedStr = ""; 21 | try { 22 | byte[] decryptedData = Base64.decode(encryptedStr); 23 | decryptedStr = new String(DESUtils.decrypt(decryptedData, PASSWORD.getBytes()), "UTF-8"); 24 | } catch (UnsupportedEncodingException e) { 25 | } catch (Exception e) { 26 | e.printStackTrace(); 27 | } 28 | return decryptedStr; 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/FileInfo.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | /** 4 | * Created by netease on 16/6/15. 5 | */ 6 | public class FileInfo { 7 | public static final int FILE_STATUS_GOOD = 1; 8 | public static final int FILE_STATUS_BROKEN = 2; 9 | 10 | public final String mMd5; 11 | public final String mLocalPath; 12 | public final String mAppname; 13 | public final String mUrl; 14 | 15 | private int mAccessCount; 16 | private int mStatus; 17 | 18 | public FileInfo(String md5, String localPath, String appname, String url, int accessCount, int status) { 19 | mMd5 = md5; 20 | mLocalPath = localPath; 21 | mAppname = appname; 22 | mUrl = url; 23 | mAccessCount = accessCount; 24 | mStatus = status; 25 | } 26 | 27 | public void setStatus(int status) { 28 | mStatus = status; 29 | } 30 | 31 | public int getStatus() { 32 | return mStatus; 33 | } 34 | 35 | public void increaseAccessCount() { 36 | ++ mAccessCount; 37 | } 38 | 39 | public int getmAccessCount() { 40 | return mAccessCount; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/Md5Utils.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.security.MessageDigest; 9 | import java.security.NoSuchAlgorithmException; 10 | 11 | /** 12 | * Created by netease on 16/6/16. 13 | */ 14 | public class Md5Utils { 15 | private static char[] sHexChar = { '0', '1', '2', '3', '4', '5', '6', '7', 16 | '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 17 | 18 | public static String toHexString(byte[] b) { 19 | StringBuilder sb = new StringBuilder(b.length * 2); 20 | for (int i = 0; i < b.length; i++) { 21 | sb.append(sHexChar[(b[i] & 0xf0) >>> 4]); 22 | sb.append(sHexChar[b[i] & 0x0f]); 23 | } 24 | return sb.toString(); 25 | } 26 | 27 | public static String calculateMd5(InputStream is) { 28 | String md5 = ""; 29 | try { 30 | MessageDigest md5Digest = MessageDigest.getInstance("MD5"); 31 | 32 | byte[] buffer = new byte[4096]; 33 | int numRead; 34 | 35 | while ((numRead = is.read(buffer)) > 0) { 36 | md5Digest.update(buffer, 0, numRead); 37 | } 38 | byte[] digest = md5Digest.digest(); 39 | md5 = toHexString(digest); 40 | } catch (NoSuchAlgorithmException e) { 41 | } catch (IOException e) { 42 | } finally { 43 | try { 44 | is.close(); 45 | } catch (IOException e) { 46 | } 47 | } 48 | return md5; 49 | } 50 | 51 | public static String calculateMd5(File file) { 52 | FileInputStream fis = null; 53 | String md5 = ""; 54 | try { 55 | fis = new FileInputStream(file); 56 | md5 = calculateMd5(fis); 57 | } catch (FileNotFoundException e) { 58 | } finally { 59 | if (fis != null) { 60 | try { 61 | fis.close(); 62 | } catch (IOException e) { 63 | } 64 | } 65 | } 66 | return md5; 67 | } 68 | 69 | public static String calculateMd5(String filePath) { 70 | File file = new File(filePath); 71 | return calculateMd5(file); 72 | } 73 | 74 | public static boolean checkFileValidation(String filePath, String md5) { 75 | String strDigest = calculateMd5(filePath); 76 | if (strDigest.equalsIgnoreCase(md5)) { 77 | return true; 78 | } 79 | return false; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/MemBasedCache.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | import java.util.Iterator; 4 | import java.util.LinkedHashMap; 5 | import java.util.Map; 6 | 7 | /** 8 | * Created by netease on 16/6/16. 9 | */ 10 | public class MemBasedCache implements Cache { 11 | /** Default maximum memory usage in bytes. */ 12 | private static final int DEFAULT_MEMORY_USAGE_BYTES = (int)Runtime.getRuntime().maxMemory() / 8 > 0 ? 13 | (int)Runtime.getRuntime().maxMemory() / 8 : 4 * 1024 * 1024; 14 | 15 | /** High water mark percentage for the cache */ 16 | private static final float HYSTERESIS_FACTOR = 0.9f; 17 | 18 | /** Total amount of space currently used by the cache in bytes. */ 19 | private long mTotalSize = 0; 20 | 21 | /** The maximum size of the cache in bytes. */ 22 | private final int mMaxCacheSizeInBytes; 23 | 24 | private Map mDataEntries; 25 | 26 | /** 27 | * Constructs an instance of the MemBasedCache. 28 | * @param maxCacheSizeInBytes The maximum size of the cache in bytes. 29 | */ 30 | public MemBasedCache(int maxCacheSizeInBytes) { 31 | mMaxCacheSizeInBytes = maxCacheSizeInBytes; 32 | mDataEntries = new LinkedHashMap(16, .75f, true); 33 | } 34 | 35 | /** 36 | * Constructs an instance of the MemBasedCache using the default maximum cache size of 3MB. 37 | */ 38 | public MemBasedCache() { 39 | this(DEFAULT_MEMORY_USAGE_BYTES); 40 | } 41 | 42 | @Override 43 | public synchronized void initialize() { 44 | 45 | } 46 | 47 | @Override 48 | public synchronized void put(String key, Entry entry) { 49 | pruneIfNeeded(entry.data.length); 50 | CacheHeader e = new CacheHeader(key, entry); 51 | if (!mDataEntries.containsKey(key)) { 52 | mTotalSize += e.data.length; 53 | } else { 54 | CacheHeader oldEntry = mDataEntries.get(key); 55 | mTotalSize += (e.data.length - oldEntry.data.length); 56 | } 57 | mDataEntries.put(key, e); 58 | } 59 | 60 | /** 61 | * Prunes the cache to fit the amount of bytes specified. 62 | * @param neededSpace The amount of bytes we are trying to fit into the cache. 63 | */ 64 | private void pruneIfNeeded(int neededSpace) { 65 | if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes) { 66 | return; 67 | } 68 | long before = mTotalSize; 69 | int prunedFiles = 0; 70 | // long startTime = SystemClock.elapsedRealtime(); 71 | Iterator> iterator = mDataEntries.entrySet().iterator(); 72 | while (iterator.hasNext()) { 73 | Map.Entry entry = iterator.next(); 74 | CacheHeader e = entry.getValue(); 75 | mTotalSize -= e.data.length; 76 | iterator.remove(); 77 | ++ prunedFiles; 78 | if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) { 79 | break; 80 | } 81 | } 82 | 83 | // if (WebcacheLog.DEBUG) { 84 | // WebcacheLog.v("pruned %d files, %d bytes, %d ms", 85 | // prunedFiles, (mTotalSize - before), SystemClock.elapsedRealtime() - startTime); 86 | // } 87 | } 88 | 89 | @Override 90 | public synchronized Entry get(String key) { 91 | CacheHeader entry = mDataEntries.get(key); 92 | // if the entry does not exist, return. 93 | if (entry == null) { 94 | return null; 95 | } 96 | Entry e = new Entry(); 97 | e.data = entry.data; 98 | return e; 99 | } 100 | 101 | @Override 102 | public synchronized void remove(String key) { 103 | CacheHeader entry = mDataEntries.get(key); 104 | // if the entry does not exist, return. 105 | if (entry != null) { 106 | mTotalSize -= entry.data.length; 107 | mDataEntries.remove(key); 108 | } 109 | } 110 | 111 | @Override 112 | public synchronized void invalidate(String key, boolean fullExpire) { 113 | remove(key); 114 | } 115 | 116 | 117 | @Override 118 | public synchronized void clear() { 119 | mDataEntries.clear(); 120 | mTotalSize = 0; 121 | } 122 | 123 | public synchronized long totalDataSize() { 124 | return mTotalSize; 125 | } 126 | 127 | static class CacheHeader { 128 | public CacheHeader(String key, Entry entry) { 129 | this.key = key; 130 | this.data = entry.data; 131 | } 132 | 133 | public String key; 134 | 135 | public byte[] data; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/Patcher.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | /** 4 | * Created by netease on 16/6/3. 5 | */ 6 | public interface Patcher { 7 | public String applyPatch(String oldFilePath, String patchFilePath, String outDirPath); 8 | } 9 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/candywebcache/cachemanager/WebappInfo.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by netease on 16/6/3. 12 | */ 13 | public class WebappInfo { 14 | public static final int WEBAPP_STATUS_INIT = 1; 15 | public static final int WEBAPP_STATUS_LOCAL_LOAD_START = 2; 16 | public static final int WEBAPP_STATUS_LOCAL_LOAD_FAILED = 3; 17 | 18 | public static final int WEBAPP_STATUS_UPDATE_START = 4; 19 | public static final int WEBAPP_STATUS_OUT_OF_DATE = 5; 20 | 21 | public static final int WEBAPP_STATUS_DELETE_START = 6; 22 | public static final int WEBAPP_STATUS_DELETED = 7; 23 | 24 | public static final int WEBAPP_STATUS_AVAILABLE = 8; 25 | public static final int WEBAPP_STATUS_BROKEN = 9; 26 | 27 | public final String mWebappName; 28 | public final String mCachedDirPath; 29 | 30 | public final String mVerStr; 31 | public final long mVerNum; 32 | 33 | public final String mPkgFilePath; 34 | public final String mPkgFileMd5; 35 | public final String mFullUrl; 36 | 37 | public final Set mDomains; 38 | 39 | public final Map mFileInfos; 40 | public final long mCacheSize; 41 | 42 | public final int mStatus; 43 | public int mFileNumber; 44 | 45 | public WebappInfo(List domains, String fullUrl, String appName, String verStr, String cachedDirPath, 46 | long cacheSize, String pkgFilePath, String md5, int status) { 47 | mDomains = new HashSet(domains); 48 | mFullUrl = fullUrl; 49 | 50 | mWebappName = appName; 51 | mVerStr = verStr; 52 | mVerNum = Long.parseLong(mVerStr); 53 | 54 | mCachedDirPath = cachedDirPath; 55 | mCacheSize = cacheSize; 56 | 57 | mPkgFilePath = pkgFilePath; 58 | mPkgFileMd5 = md5; 59 | mFileInfos = new HashMap<>(); 60 | 61 | mStatus = status; 62 | } 63 | 64 | public WebappInfo(Set domains, String fullUrl, String appName, String verStr, String cachedDirPath, 65 | long cacheSize, String pkgFilePath, String md5, int status, Map fileInfos) { 66 | mDomains = new HashSet(domains); 67 | mFullUrl = fullUrl; 68 | 69 | mWebappName = appName; 70 | mVerStr = verStr; 71 | mVerNum = Long.parseLong(mVerStr); 72 | 73 | mCachedDirPath = cachedDirPath; 74 | mCacheSize = cacheSize; 75 | 76 | mPkgFilePath = pkgFilePath; 77 | mPkgFileMd5 = md5; 78 | mFileInfos = fileInfos; 79 | 80 | mStatus = status; 81 | } 82 | 83 | public boolean inProcessStatus() { 84 | return mStatus == WEBAPP_STATUS_LOCAL_LOAD_START || 85 | mStatus == WEBAPP_STATUS_LOCAL_LOAD_START || 86 | mStatus == WEBAPP_STATUS_LOCAL_LOAD_START; 87 | } 88 | 89 | public boolean isInvalid() { 90 | return mStatus == WebappInfo.WEBAPP_STATUS_LOCAL_LOAD_FAILED || 91 | mStatus == WebappInfo.WEBAPP_STATUS_OUT_OF_DATE || 92 | mStatus == WebappInfo.WEBAPP_STATUS_DELETED || 93 | mStatus == WebappInfo.WEBAPP_STATUS_BROKEN; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htfiledownloader/Constants.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | /** 4 | * Created by DING on 16/6/14. 5 | */ 6 | public interface Constants { 7 | int INNER_ERROR_CODE = -100; 8 | int INIT_DOWNLOAD_TASK_ID = -1; 9 | String URL_PATH_SEPERATOR = "/"; 10 | String URL_PARAMS_SERPERATOR = "?"; 11 | int DATA_BUFFER_SIZE = 8192; 12 | int READ_TIMEOUT = 8000; 13 | int CONNECT_TIMEOUT = 8000; 14 | int DOWNLOAD_SPEED_CAL_INTERVAL = 100; 15 | } 16 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htfiledownloader/DownloadDBHelper.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.database.sqlite.SQLiteDatabase; 6 | import android.database.sqlite.SQLiteOpenHelper; 7 | 8 | import java.io.File; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * Created by DING on 16/6/13. 14 | */ 15 | public class DownloadDBHelper extends SQLiteOpenHelper { 16 | private static final String DATABASE_NAME = "download_info.db"; 17 | private static final int DATABASE_VERSION = 1; 18 | //只返回一星期内的任务 19 | private static final long LATEST_TASK_TIME = 1000 * 60 * 60 * 24 * 7; 20 | 21 | private static volatile DownloadDBHelper sDownloaDBHelper; 22 | private static Context sContext; 23 | private static String sDBPath; 24 | 25 | static void init(Context context, String dbPath) { 26 | sContext = context; 27 | sDBPath = dbPath; 28 | getInstance(); 29 | try { 30 | getInstance().getReadableDatabase(); 31 | } catch (Exception e) { 32 | //吃掉异常,主要是文件被删除,下次打开应用会重建的 33 | e.printStackTrace(); 34 | } 35 | } 36 | 37 | static DownloadDBHelper getInstance() { 38 | if (sDownloaDBHelper == null) { 39 | synchronized (DownloadDBHelper.class) { 40 | if (sDownloaDBHelper == null) { 41 | sDownloaDBHelper = new DownloadDBHelper(sContext, sDBPath); 42 | } 43 | } 44 | } 45 | return sDownloaDBHelper; 46 | } 47 | 48 | private DownloadDBHelper(Context context, String databasePath) { 49 | super(context, databasePath + File.separator + DATABASE_NAME, null, DATABASE_VERSION); 50 | } 51 | 52 | 53 | @Override 54 | public void onCreate(SQLiteDatabase db) { 55 | db.execSQL("CREATE TABLE IF NOT EXISTS download_tasks (" + 56 | "task_id INTEGER PRIMARY KEY NOT NULL, " + 57 | "url TEXT NOT NULL," + 58 | "download_path TEXT NOT NULL," + 59 | "filename TEXT," + 60 | "state INTEGER NOT NULL," + 61 | "percent REAL NOT NULL," + 62 | "transferred_size INTEGER NOT NULL," + 63 | "total_size INTEGER NOT NULL," + 64 | "time INTEGER NOT NULL)"); 65 | } 66 | 67 | @Override 68 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 69 | } 70 | 71 | DownloadTask.DownloadTaskData getByTaskId(int taskId) { 72 | List result = query("SELECT * FROM download_tasks WHERE task_id=" + taskId); 73 | if (result == null || result.isEmpty()) { 74 | return null; 75 | } else { 76 | return result.get(0); 77 | } 78 | } 79 | 80 | void insertOrUpdate(DownloadTask.DownloadTaskData downloadTaskData) { 81 | try { 82 | String sql = String.format("INSERT OR REPLACE INTO download_tasks (task_id,url,download_path,filename,state,percent,transferred_size,total_size,time) " + 83 | "VALUES(%d,'%s','%s','%s',%d,%f,%d,%d,%d);", 84 | downloadTaskData.getTaskId(), 85 | downloadTaskData.getUrl(), 86 | downloadTaskData.getDownloadPath(), 87 | downloadTaskData.getFilename(), 88 | downloadTaskData.getState().ordinal(), 89 | downloadTaskData.getProgressInfo().getPercent(), 90 | downloadTaskData.getProgressInfo().getTransferredSize(), 91 | downloadTaskData.getProgressInfo().getTotalSize(), 92 | System.currentTimeMillis()); 93 | getWritableDatabase().execSQL(sql); 94 | } catch (Exception e) { 95 | //吃掉异常,主要是文件被删除,下次打开应用会重建的 96 | close(); 97 | e.printStackTrace(); 98 | } 99 | } 100 | 101 | void deleteByTaskId(int taskId) { 102 | try { 103 | String sql = String.format("DELETE FROM download_tasks WHERE task_id=%d;", taskId); 104 | getWritableDatabase().execSQL(sql); 105 | } catch (Exception e) { 106 | //吃掉异常,主要是文件被删除,下次打开应用会重建的 107 | close(); 108 | e.printStackTrace(); 109 | } 110 | } 111 | 112 | List getRemainingTasks() { 113 | String sql = String.format("SELECT * from download_tasks WHERE state<>%d AND time>=%d", 114 | DownloadTaskState.DONE.ordinal(), 115 | System.currentTimeMillis() - LATEST_TASK_TIME); 116 | return query(sql); 117 | } 118 | 119 | 120 | private List query(String sql) { 121 | Cursor cursor = null; 122 | try { 123 | cursor = getReadableDatabase().rawQuery(sql, null); 124 | if (cursor.getCount() == 0) { 125 | return null; 126 | } 127 | List resultList = new ArrayList<>(); 128 | cursor.moveToFirst(); 129 | while (!cursor.isAfterLast()) { 130 | DownloadTask.DownloadTaskData downloadTaskData = new DownloadTask.DownloadTaskData(); 131 | downloadTaskData.setTaskId(cursor.getInt(0)); 132 | downloadTaskData.setUrl(cursor.getString(1)); 133 | downloadTaskData.setDownloadPath(cursor.getString(2)); 134 | downloadTaskData.setFilename(cursor.getString(3)); 135 | downloadTaskData.setState(DownloadTaskState.valueOf(cursor.getInt(4))); 136 | downloadTaskData.getProgressInfo().setPercent(cursor.getFloat(5)); 137 | downloadTaskData.getProgressInfo().setTransferredSize(cursor.getLong(6)); 138 | downloadTaskData.getProgressInfo().setTotalSize(cursor.getLong(7)); 139 | resultList.add(downloadTaskData); 140 | cursor.moveToNext(); 141 | } 142 | return resultList; 143 | } catch (Exception e) { 144 | //吃掉异常,主要是文件被删除,下次打开应用会重建的 145 | close(); 146 | e.printStackTrace(); 147 | return null; 148 | } finally { 149 | //为了防止上面提前返回导致的cursor泄露 150 | if (cursor != null) { 151 | cursor.close(); 152 | } 153 | } 154 | } 155 | 156 | public boolean isDbValid() { 157 | File dbFile = new File(sDBPath + File.separator + DATABASE_NAME); 158 | return dbFile.exists(); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htfiledownloader/DownloadTaskState.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | /** 4 | * Created by DING on 16/6/4. 5 | */ 6 | public enum DownloadTaskState { 7 | READY, DOWNLOADING, PAUSING, CANCELLED, DONE, FAILED; 8 | 9 | public static DownloadTaskState valueOf(int ordinal) { 10 | if (ordinal < 0 || ordinal >= values().length) { 11 | throw new IndexOutOfBoundsException("Invalid ordinal"); 12 | } 13 | return values()[ordinal]; 14 | } 15 | } -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htfiledownloader/FileDownloaderUtil.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | 7 | /** 8 | * Created by DING on 16/6/14. 9 | */ 10 | public class FileDownloaderUtil { 11 | public static String md5(String string) { 12 | byte[] hash; 13 | try { 14 | hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8")); 15 | } catch (NoSuchAlgorithmException e) { 16 | throw new RuntimeException("Huh, MD5 should be supported?", e); 17 | } catch (UnsupportedEncodingException e) { 18 | throw new RuntimeException("Huh, UTF-8 should be supported?", e); 19 | } 20 | 21 | StringBuilder hex = new StringBuilder(hash.length * 2); 22 | for (byte b : hash) { 23 | if ((b & 0xFF) < 0x10) hex.append("0"); 24 | hex.append(Integer.toHexString(b & 0xFF)); 25 | } 26 | return hex.toString(); 27 | } 28 | 29 | public static int generateTaskId(String url, String path) { 30 | return md5(url + path).hashCode(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htfiledownloader/InnerStateChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | /** 4 | * Created by DING on 16/6/12. 5 | */ 6 | interface InnerStateChangeListener { 7 | void onProgressChanged(DownloadTask downloadTask, ProgressInfo progressInfo); 8 | 9 | void onStateChanged(DownloadTask downloadTask, DownloadTaskState state); 10 | } 11 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htfiledownloader/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Created by DING on 16/6/29. 7 | */ 8 | 9 | public class LogUtil { 10 | private static final String TAG = LogUtil.class.getSimpleName(); 11 | public static final int VERBOSE = Log.VERBOSE; 12 | public static final int DEBUG = Log.DEBUG; 13 | public static final int INFO = Log.INFO; 14 | public static final int WARN = Log.WARN; 15 | public static final int ERROR = Log.ERROR; 16 | public static final int ASSERT = Log.ASSERT; 17 | 18 | //默认level Error 19 | private static int level = DEBUG; 20 | private static boolean enable = true; 21 | 22 | public static void setLevel(int level) { 23 | LogUtil.level = level; 24 | } 25 | 26 | public static void enableLog(boolean enable) { 27 | LogUtil.enable = enable; 28 | } 29 | 30 | /** 31 | * debug level 32 | * 33 | * @param tag 调试信息标签 34 | * @param info 信息 35 | * @return void 36 | */ 37 | public static void d(String tag, String info) { 38 | if (enable && DEBUG >= level) { 39 | Log.d(tag, info); 40 | } 41 | } 42 | 43 | /** 44 | * information level 45 | * 46 | * @param tag 提示信息标签 47 | * @param info 信息 48 | * @return void 49 | */ 50 | public static void i(String tag, String info) { 51 | if (enable && INFO >= level) { 52 | Log.i(tag, info); 53 | } 54 | } 55 | 56 | /** 57 | * error level 58 | * 59 | * @param tag 错误信息标签 60 | * @param info 信息 61 | * @return void 62 | */ 63 | public static void e(String tag, String info) { 64 | if (enable && ERROR >= level) { 65 | Log.e(tag, info); 66 | } 67 | } 68 | 69 | /** 70 | * warning level 71 | * 72 | * @param tag 警告信息标签 73 | * @param info 信息 74 | * @return void 75 | */ 76 | public static void w(String tag, String info) { 77 | if (enable && WARN >= level) { 78 | Log.w(tag, info); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htfiledownloader/ProgressInfo.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | /** 4 | * Created by DING on 16/6/4. 5 | */ 6 | public class ProgressInfo { 7 | private float percent; 8 | private long transferredSize; 9 | private long totalSize; 10 | private float transferSpeed; 11 | 12 | public ProgressInfo() { 13 | } 14 | 15 | public ProgressInfo(ProgressInfo progressInfo) { 16 | copyFrom(progressInfo); 17 | } 18 | 19 | void reset() { 20 | percent = 0f; 21 | transferredSize = 0; 22 | totalSize = 0; 23 | transferSpeed = 0f; 24 | } 25 | 26 | 27 | void copyFrom(ProgressInfo progressInfo) { 28 | percent = progressInfo.percent; 29 | transferredSize = progressInfo.transferredSize; 30 | totalSize = progressInfo.totalSize; 31 | transferSpeed = progressInfo.transferSpeed; 32 | } 33 | 34 | public float getPercent() { 35 | return percent; 36 | } 37 | 38 | void setPercent(float percent) { 39 | this.percent = percent; 40 | } 41 | 42 | public long getTransferredSize() { 43 | return transferredSize; 44 | } 45 | 46 | void setTransferredSize(long transferredSize) { 47 | this.transferredSize = transferredSize; 48 | } 49 | 50 | public long getTotalSize() { 51 | return totalSize; 52 | } 53 | 54 | void setTotalSize(long totalSize) { 55 | this.totalSize = totalSize; 56 | } 57 | 58 | public float getTransferSpeed() { 59 | return transferSpeed; 60 | } 61 | 62 | void setTransferSpeed(float transferSpeed) { 63 | this.transferSpeed = transferSpeed; 64 | } 65 | 66 | public String toString() { 67 | StringBuilder sb = new StringBuilder(); 68 | sb.append("percent:").append(percent) 69 | .append(",transferred_size:").append(transferredSize) 70 | .append(",total_size:").append(totalSize) 71 | .append(",speed:").append(transferSpeed); 72 | return sb.toString(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htfiledownloader/StateChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | /** 4 | * Created by DING on 16/6/4. 5 | */ 6 | public interface StateChangeListener { 7 | void onProgressChanged(DownloadTask downloadTask, ProgressInfo progressInfo); 8 | 9 | void onStateChanged(DownloadTask downloadTask, DownloadTaskState state); 10 | } 11 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htresourceversionchecker/Constants.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker; 2 | 3 | /** 4 | * Created by DING on 16/7/7. 5 | */ 6 | public interface Constants { 7 | int DATA_BUFFER_SIZE = 1024; 8 | int CONNECT_TIMEOUT = 8000; 9 | int READ_TIMEOUT = 8000; 10 | 11 | String PROTOCOL_VERSION_0_1 = "0.1"; 12 | String PROTOCOL_VERSION_0_2 = "0.2"; 13 | } 14 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htresourceversionchecker/OnResponseListener.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker; 2 | 3 | /** 4 | * Created by DING on 16/6/8. 5 | */ 6 | public interface OnResponseListener { 7 | byte[] onResponse(byte[] result); 8 | } 9 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htresourceversionchecker/VersionChecker.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker; 2 | 3 | import android.text.TextUtils; 4 | import android.util.Log; 5 | 6 | import com.netease.hearttouch.htresourceversionchecker.model.AppInfo; 7 | import com.netease.hearttouch.htresourceversionchecker.model.ResponseResInfo; 8 | import com.netease.hearttouch.htresourceversionchecker.model.VersionCheckResponseData; 9 | import com.netease.hearttouch.htresourceversionchecker.model.VersionCheckResponseModel; 10 | 11 | import org.json.JSONArray; 12 | import org.json.JSONException; 13 | 14 | import java.io.BufferedInputStream; 15 | import java.io.ByteArrayOutputStream; 16 | import java.io.IOException; 17 | import java.io.PrintWriter; 18 | import java.io.UnsupportedEncodingException; 19 | import java.net.HttpURLConnection; 20 | import java.net.SocketTimeoutException; 21 | import java.net.URL; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | /** 26 | * Created by DING on 16/6/8. 27 | */ 28 | public class VersionChecker { 29 | public static final String PACKAGE_MODE_ZIP = "zip"; 30 | public static final String PACKAGE_MODE_DEFAULT = PACKAGE_MODE_ZIP; 31 | 32 | public static final String COMPRESS_MODE_NONE = "none"; 33 | public static final String COMPRESS_MODE_GZIP = "gzip"; 34 | public static final String COMPRESS_MODE_BRO = "bro"; 35 | public static final String COMPRESS_MODE_DEFAULT = COMPRESS_MODE_NONE; 36 | 37 | public static final String DIFF_MDOE_BSDIFF = "bsdiff"; 38 | public static final String DIFF_MODE_COURGETTE = "courgette"; 39 | public static final String DIFF_MODE_DEFAULT = DIFF_MDOE_BSDIFF; 40 | 41 | 42 | /** 43 | * 进行版本检测,同步接口 44 | * 45 | * @param url 检测的目标url 46 | * @param appInfo 检测的AppInfo信息 47 | * @param extraHeaders 额外的Header数据 可以为{@code null} 48 | * @param onResponseListener 响应的监听,可以进行数据的解密等操作 可以为{@code null} 49 | * @return 检测的结果,如果有错误,也包含在返回的{@link VersionCheckResponseModel}中 50 | */ 51 | static public VersionCheckResponseModel checkVersion(String url, AppInfo appInfo, Map extraHeaders, OnResponseListener onResponseListener) { 52 | if (TextUtils.isEmpty(url) || appInfo == null 53 | || TextUtils.isEmpty(appInfo.getAppID()) 54 | || TextUtils.isEmpty(appInfo.getAppVersion()) 55 | || TextUtils.isEmpty(appInfo.getPlatform())) { 56 | return new VersionCheckResponseModel(ResultCode.PARAMS_ERROR, "please check params..."); 57 | } 58 | 59 | String body = null; 60 | try { 61 | body = appInfo.toJsonString(); 62 | Log.d("%s", "Request body: " + body); 63 | } catch (JSONException e) { 64 | e.printStackTrace(); 65 | return new VersionCheckResponseModel(ResultCode.JSON_EXCEPTION, "parse request json string error..."); 66 | } 67 | 68 | BufferedInputStream bis = null; 69 | ByteArrayOutputStream baos = null; 70 | 71 | try { 72 | HttpURLConnection httpConnection; 73 | URL requestUrl = new URL(url); 74 | httpConnection = (HttpURLConnection) requestUrl.openConnection(); 75 | httpConnection.setRequestMethod("POST"); 76 | httpConnection.setConnectTimeout(Constants.CONNECT_TIMEOUT); 77 | httpConnection.setReadTimeout(Constants.READ_TIMEOUT); 78 | httpConnection.setUseCaches(false); 79 | 80 | //加入header 81 | if (extraHeaders != null && !extraHeaders.isEmpty()) { 82 | for (String key : extraHeaders.keySet()) { 83 | httpConnection.setRequestProperty(key, extraHeaders.get(key)); 84 | } 85 | } 86 | httpConnection.setRequestProperty("Content-Type", "application/json"); 87 | 88 | // 发送POST请求必须设置如下两行 89 | httpConnection.setDoOutput(true); 90 | httpConnection.setDoInput(true); 91 | // 获取URLConnection对象对应的输出流 92 | PrintWriter printWriter = new PrintWriter(httpConnection.getOutputStream()); 93 | // 发送请求参数 94 | printWriter.write(body); 95 | // flush输出流的缓冲 96 | printWriter.flush(); 97 | printWriter.close(); 98 | 99 | final int responseCode = httpConnection.getResponseCode(); 100 | if (responseCode == HttpURLConnection.HTTP_OK) { 101 | bis = new BufferedInputStream(httpConnection.getInputStream()); 102 | //按行读取数据,拼接到结果字符串中 103 | baos = new ByteArrayOutputStream(); 104 | byte[] data = new byte[Constants.DATA_BUFFER_SIZE]; 105 | int size = 0; 106 | while ((size = bis.read(data)) != -1) { 107 | baos.write(data, 0, size); 108 | } 109 | byte[] result = baos.toByteArray(); 110 | if (result != null && result.length > 0) { 111 | Log.d("%s", "Response result = " + baos.toString()); 112 | if (onResponseListener != null) { 113 | result = onResponseListener.onResponse(result); 114 | } 115 | //解析字符串 116 | try { 117 | return VersionCheckResponseModel.fromJsonString(new String(result, "UTF-8")); 118 | } catch (JSONException e) { 119 | e.printStackTrace(); 120 | return new VersionCheckResponseModel(ResultCode.JSON_EXCEPTION, "parse response json string error..."); 121 | } catch (UnsupportedEncodingException e) { 122 | e.printStackTrace(); 123 | return new VersionCheckResponseModel(ResultCode.INNER_ERROR_UNSUPPORT_CHARSET, "unsupported charset..."); 124 | } 125 | } else { 126 | return new VersionCheckResponseModel(ResultCode.HTTP_ERROR_NOTHING_READ, "read nothing from network..."); 127 | } 128 | } else { 129 | //其他的错误的response code 130 | return new VersionCheckResponseModel(responseCode, httpConnection.getResponseMessage()); 131 | } 132 | } catch (SocketTimeoutException e) { 133 | e.printStackTrace(); 134 | return new VersionCheckResponseModel(ResultCode.HTTP_ERROR_TIMEOUT, "socket timeout..."); 135 | } catch (IOException e) { 136 | e.printStackTrace(); 137 | return new VersionCheckResponseModel(ResultCode.INNER_ERROR_IO, "io exception..."); 138 | } finally { 139 | if (bis != null) { 140 | try { 141 | bis.close(); 142 | } catch (IOException e) { 143 | e.printStackTrace(); 144 | Log.w("VersionChecker", e.toString()); 145 | } 146 | } 147 | if (baos != null) { 148 | try { 149 | baos.close(); 150 | } catch (IOException e) { 151 | e.printStackTrace(); 152 | Log.w("VersionChecker", e.toString()); 153 | } 154 | } 155 | } 156 | } 157 | 158 | /** 159 | * 根据输入的版本信息,解析出对应的版本检测结果信息数据 160 | * 输入的应该是List变成json的字符串,否则解析出错 161 | * 162 | * @param jsonStr 客户端自行获取到的版本信息的json字符串 163 | * @return 根据输入解析出的版本检测结果信息数据 164 | */ 165 | static public List getVersionInfo(String jsonStr) { 166 | try { 167 | VersionCheckResponseData versionCheckResponseData = VersionCheckResponseData.fromJsonArray(new JSONArray(jsonStr)); 168 | return versionCheckResponseData.getResInfos(); 169 | } catch (JSONException e) { 170 | e.printStackTrace(); 171 | return null; 172 | } 173 | } 174 | 175 | public interface ResultCode { 176 | //http错误或者内部错误 177 | /** 内部IO错误 */ 178 | int INNER_ERROR_IO = -100; 179 | /** 内部无法解析的字符集 */ 180 | int INNER_ERROR_UNSUPPORT_CHARSET = -101; 181 | /** 网络请求超时 */ 182 | int HTTP_ERROR_TIMEOUT = -102; 183 | /** 网络请求没有读取到数据 */ 184 | int HTTP_ERROR_NOTHING_READ = -103; 185 | /** 参数设置错误 */ 186 | int PARAMS_ERROR = -104; 187 | /** JSON解析或序列化错误 */ 188 | int JSON_EXCEPTION = -105; 189 | 190 | //服务器的返回码,默认从0开始 191 | /** 请求成功返回 */ 192 | int SUCCESS = 200; 193 | /** 协议版本不支持 */ 194 | int ERR_PROTOCOL_VERSION_NOT_SUPPORT = 401; 195 | /** appID不支持 */ 196 | int ERR_APPID = 402; 197 | /** 服务端错误 */ 198 | int ERR_SERVER = 501; 199 | /** 表示native id在服务器检索不到错误 */ 200 | int ERR_UNKNOWN = 601; 201 | } 202 | 203 | public interface StatusCode { 204 | /** 资源包最新 */ 205 | int LATEST = 0; 206 | /** 资源包有更新 */ 207 | int NEED_UPDATE = 1; 208 | /** 资源包在服务器不存在 */ 209 | int RESOURCE_NOT_EXIST = 2; 210 | /** 自动补全的资源信息 */ 211 | int RESOURCE_AUTO_FILL = 3; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htresourceversionchecker/model/AppInfo.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker.model; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.netease.hearttouch.htresourceversionchecker.Constants; 6 | 7 | import org.json.JSONArray; 8 | import org.json.JSONException; 9 | import org.json.JSONObject; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Created by DING on 16/6/8. 15 | */ 16 | public class AppInfo { 17 | private String version = Constants.PROTOCOL_VERSION_0_2; 18 | private String appID; 19 | private String appVersion; 20 | private String platform; 21 | private boolean isDiff = false; 22 | private boolean autoFill = false; 23 | private List resInfos; 24 | private String userData; 25 | 26 | public String getVersion() { 27 | return version; 28 | } 29 | 30 | public void setVersion(String version) { 31 | this.version = version; 32 | } 33 | 34 | public String getAppID() { 35 | return appID; 36 | } 37 | 38 | public void setAppID(String appID) { 39 | this.appID = appID; 40 | } 41 | 42 | public String getAppVersion() { 43 | return appVersion; 44 | } 45 | 46 | public void setAppVersion(String appVersion) { 47 | this.appVersion = appVersion; 48 | } 49 | 50 | public String getPlatform() { 51 | return platform; 52 | } 53 | 54 | public void setPlatform(String platform) { 55 | this.platform = platform; 56 | } 57 | 58 | public boolean isDiff() { 59 | return isDiff; 60 | } 61 | 62 | public void setIsDiff(boolean isDiff) { 63 | this.isDiff = isDiff; 64 | } 65 | 66 | public boolean isAutoFill() { 67 | return autoFill; 68 | } 69 | 70 | public void setAutoFill(boolean autoFill) { 71 | this.autoFill = autoFill; 72 | } 73 | 74 | public List getResInfos() { 75 | return resInfos; 76 | } 77 | 78 | public void setResInfos(List resInfos) { 79 | this.resInfos = resInfos; 80 | } 81 | 82 | public String getUserData() { 83 | return userData; 84 | } 85 | 86 | public void setUserData(String userData) { 87 | this.userData = userData; 88 | } 89 | 90 | public String toJsonString() throws JSONException { 91 | JSONObject jsonObject = new JSONObject(); 92 | jsonObject.put("version", version); 93 | jsonObject.put("appID", appID); 94 | jsonObject.put("appVersion", appVersion); 95 | jsonObject.put("platform", platform); 96 | jsonObject.put("isDiff", isDiff); 97 | jsonObject.put("autoFill", autoFill); 98 | 99 | if (resInfos != null && !resInfos.isEmpty()) { 100 | JSONArray appInfosJsonArray = new JSONArray(); 101 | for (RequestResInfo requestResInfo : resInfos) { 102 | appInfosJsonArray.put(requestResInfo.toJsonObject()); 103 | } 104 | jsonObject.put("resInfos", appInfosJsonArray); 105 | } 106 | 107 | if (!TextUtils.isEmpty(userData)) { 108 | jsonObject.put("userData", userData); 109 | } 110 | return jsonObject.toString(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htresourceversionchecker/model/RequestResInfo.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker.model; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | /** 7 | * Created by DING on 16/6/8. 8 | */ 9 | public class RequestResInfo { 10 | private String resID; 11 | private String resVersion; 12 | 13 | public String getResID() { 14 | return resID; 15 | } 16 | 17 | public void setResID(String resID) { 18 | this.resID = resID; 19 | } 20 | 21 | public String getResVersion() { 22 | return resVersion; 23 | } 24 | 25 | public void setResVersion(String resVersion) { 26 | this.resVersion = resVersion; 27 | } 28 | 29 | public JSONObject toJsonObject() throws JSONException { 30 | JSONObject jsonObject = new JSONObject(); 31 | jsonObject.put("resID", resID); 32 | jsonObject.put("resVersion", resVersion); 33 | return jsonObject; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htresourceversionchecker/model/ResponseResInfo.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker.model; 2 | 3 | import com.netease.hearttouch.htresourceversionchecker.VersionChecker; 4 | 5 | import org.json.JSONException; 6 | import org.json.JSONObject; 7 | 8 | /** 9 | * Created by DING on 16/6/8. 10 | */ 11 | public class ResponseResInfo { 12 | private String resID; 13 | private int state; 14 | private String resVersion; 15 | private String diffUrl; 16 | private String diffMd5; 17 | private String fullUrl; 18 | private String fullMd5; 19 | 20 | private String packageMode = VersionChecker.PACKAGE_MODE_DEFAULT; 21 | private String compressMode = VersionChecker.COMPRESS_MODE_DEFAULT; 22 | private String diffMode = VersionChecker.DIFF_MODE_DEFAULT; 23 | 24 | private String userData; 25 | 26 | public String getResID() { 27 | return resID; 28 | } 29 | 30 | public void setResID(String resID) { 31 | this.resID = resID; 32 | } 33 | 34 | public String getResVersion() { 35 | return resVersion; 36 | } 37 | 38 | public void setResVersion(String resVersion) { 39 | this.resVersion = resVersion; 40 | } 41 | 42 | public String getDiffUrl() { 43 | return diffUrl; 44 | } 45 | 46 | public void setDiffUrl(String diffUrl) { 47 | this.diffUrl = diffUrl; 48 | } 49 | 50 | public String getDiffMd5() { 51 | return diffMd5; 52 | } 53 | 54 | public void setDiffMd5(String diffMd5) { 55 | this.diffMd5 = diffMd5; 56 | } 57 | 58 | public String getFullUrl() { 59 | return fullUrl; 60 | } 61 | 62 | public void setFullUrl(String fullUrl) { 63 | this.fullUrl = fullUrl; 64 | } 65 | 66 | public String getFullMd5() { 67 | return fullMd5; 68 | } 69 | 70 | public void setFullMd5(String fullMd5) { 71 | this.fullMd5 = fullMd5; 72 | } 73 | 74 | public void setPackageMode(String packageMode) { 75 | this.packageMode = packageMode; 76 | } 77 | 78 | public String getPackageMode() { 79 | return packageMode; 80 | } 81 | 82 | public void setCompressMode(String compressMode) { 83 | this.compressMode = compressMode; 84 | } 85 | 86 | public String getCompressMode() { 87 | return compressMode; 88 | } 89 | 90 | public void setDiffMode(String diffMode) { 91 | this.diffMode = diffMode; 92 | } 93 | 94 | public String getDiffMode() { 95 | return diffMode; 96 | } 97 | 98 | public int getState() { 99 | return state; 100 | } 101 | 102 | public void setState(int state) { 103 | this.state = state; 104 | } 105 | 106 | public String getUserData() { 107 | return userData; 108 | } 109 | 110 | public void setUserData(String userData) { 111 | this.userData = userData; 112 | } 113 | 114 | public static ResponseResInfo fromJsonString(String jsonStr) throws JSONException { 115 | return fromJsonObject(new JSONObject(jsonStr)); 116 | } 117 | 118 | public static ResponseResInfo fromJsonObject(JSONObject jsonObject) throws JSONException { 119 | if (jsonObject == null) { 120 | return null; 121 | } 122 | ResponseResInfo result = new ResponseResInfo(); 123 | 124 | //必须有的字段 125 | result.resID = jsonObject.getString("resID"); 126 | //必须有的字段 127 | result.state = jsonObject.getInt("state"); 128 | 129 | if (jsonObject.has("resVersion")) { 130 | result.resVersion = jsonObject.getString("resVersion"); 131 | } 132 | if (jsonObject.has("diffUrl")) { 133 | result.diffUrl = jsonObject.getString("diffUrl"); 134 | } 135 | if (jsonObject.has("diffMd5")) { 136 | result.diffMd5 = jsonObject.getString("diffMd5"); 137 | } 138 | if (jsonObject.has("fullUrl")) { 139 | result.fullUrl = jsonObject.getString("fullUrl"); 140 | } 141 | if (jsonObject.has("fullMd5")) { 142 | result.fullMd5 = jsonObject.getString("fullMd5"); 143 | } 144 | if (jsonObject.has("userData")) { 145 | result.userData = jsonObject.getString("userData"); 146 | } 147 | if (jsonObject.has("packageMode")) { 148 | result.packageMode = jsonObject.getString("packageMode"); 149 | } 150 | if (jsonObject.has("compressMode")) { 151 | result.compressMode = jsonObject.getString("compressMode"); 152 | } 153 | if (jsonObject.has("diffMode")) { 154 | result.diffMode = jsonObject.getString("diffMode"); 155 | } 156 | return result; 157 | } 158 | 159 | public String toString() { 160 | StringBuilder sb = new StringBuilder(); 161 | sb.append("resID:").append(resID != null ? resID : "null").append(',') 162 | .append("resVersion:").append(resVersion != null ? resVersion : "null").append(',') 163 | .append("diffUrl:").append(diffUrl != null ? diffUrl : "null").append(',') 164 | .append("diffMd5:").append(diffMd5 != null ? diffMd5 : "null").append(',') 165 | .append("fullUrl:").append(fullUrl != null ? fullUrl : "null").append(',') 166 | .append("fullMd5:").append(fullMd5 != null ? fullMd5 : "null").append(',') 167 | .append("state:").append(state).append(',') 168 | .append("packageMode").append(packageMode).append(",") 169 | .append("compressMode").append(compressMode).append(",") 170 | .append("diffMode").append(diffMode).append(",") 171 | .append("userData:").append(userData != null ? userData : "null"); 172 | return sb.toString(); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htresourceversionchecker/model/VersionCheckResponseData.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker.model; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONException; 5 | import org.json.JSONObject; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * Created by DING on 16/6/8. 12 | */ 13 | public class VersionCheckResponseData { 14 | private List resInfos; 15 | 16 | public List getResInfos() { 17 | return resInfos; 18 | } 19 | 20 | public void setResInfos(List resInfos) { 21 | this.resInfos = resInfos; 22 | } 23 | 24 | public static VersionCheckResponseData fromJsonString(String jsonStr) throws JSONException { 25 | return fromJsonObject(new JSONObject(jsonStr)); 26 | } 27 | 28 | public static VersionCheckResponseData fromJsonObject(JSONObject jsonObject) throws JSONException { 29 | if (jsonObject == null) { 30 | return null; 31 | } 32 | JSONArray appVersionInfosJsonArray = jsonObject.getJSONArray("resInfos"); 33 | return fromJsonArray(appVersionInfosJsonArray); 34 | } 35 | 36 | public static VersionCheckResponseData fromJsonArray(JSONArray jsonArray) throws JSONException { 37 | VersionCheckResponseData versionCheckResponseData = new VersionCheckResponseData(); 38 | if (jsonArray != null) { 39 | List resInfosList = new ArrayList<>(); 40 | for (int i = 0; i < jsonArray.length(); i++) { 41 | JSONObject object = jsonArray.getJSONObject(i); 42 | ResponseResInfo responseResInfo = ResponseResInfo.fromJsonObject(object); 43 | resInfosList.add(responseResInfo); 44 | } 45 | versionCheckResponseData.resInfos = resInfosList; 46 | } 47 | return versionCheckResponseData; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /candywebcache/src/main/java/com/netease/hearttouch/htresourceversionchecker/model/VersionCheckResponseModel.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker.model; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | /** 7 | * Created by DING on 16/6/8. 8 | */ 9 | public class VersionCheckResponseModel { 10 | private int code; 11 | private VersionCheckResponseData data; 12 | private String errMsg; 13 | 14 | public VersionCheckResponseModel() { 15 | 16 | } 17 | 18 | public VersionCheckResponseModel(int code, String errMsg) { 19 | this.code = code; 20 | this.errMsg = errMsg; 21 | data = null; 22 | } 23 | 24 | public int getCode() { 25 | return code; 26 | } 27 | 28 | public void setCode(int code) { 29 | this.code = code; 30 | } 31 | 32 | public VersionCheckResponseData getData() { 33 | return data; 34 | } 35 | 36 | public void setData(VersionCheckResponseData data) { 37 | this.data = data; 38 | } 39 | 40 | public String getErrMsg() { 41 | return errMsg; 42 | } 43 | 44 | public void setErrMsg(String errMsg) { 45 | this.errMsg = errMsg; 46 | } 47 | 48 | public static VersionCheckResponseModel fromJsonString(String jsonStr) throws JSONException { 49 | JSONObject jsonObject = new JSONObject(jsonStr); 50 | VersionCheckResponseModel result = new VersionCheckResponseModel(); 51 | result.code = jsonObject.getInt("code"); 52 | if (jsonObject.has("data")) { 53 | result.data = VersionCheckResponseData.fromJsonObject(jsonObject.getJSONObject("data")); 54 | } 55 | if (jsonObject.has("errMsg")) { 56 | result.errMsg = jsonObject.getString("errMsg"); 57 | } 58 | return result; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /candywebcache/src/main/jni/3rd/bsdiff/bsdiff.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * Copyright 2012 Matthew Endsley 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef BSDIFF_H 29 | # define BSDIFF_H 30 | 31 | # include 32 | # include 33 | 34 | struct bsdiff_stream 35 | { 36 | void* opaque; 37 | 38 | void* (*malloc)(size_t size); 39 | void (*free)(void* ptr); 40 | int (*write)(struct bsdiff_stream* stream, const void* buffer, int size); 41 | }; 42 | 43 | int bsdiff(const uint8_t* old, int64_t oldsize, const uint8_t* new, int64_t newsize, struct bsdiff_stream* stream); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /candywebcache/src/main/jni/3rd/bsdiff/bspatch.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #if 0 28 | __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:06 cperciva Exp $"); 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | //#include 36 | #include 37 | #include 38 | 39 | static off_t offtin(u_char *buf) 40 | { 41 | off_t y; 42 | 43 | y=buf[7]&0x7F; 44 | y=y*256;y+=buf[6]; 45 | y=y*256;y+=buf[5]; 46 | y=y*256;y+=buf[4]; 47 | y=y*256;y+=buf[3]; 48 | y=y*256;y+=buf[2]; 49 | y=y*256;y+=buf[1]; 50 | y=y*256;y+=buf[0]; 51 | 52 | if(buf[7]&0x80) y=-y; 53 | 54 | return y; 55 | } 56 | 57 | int bspatch_main(int argc,char * argv[]) { 58 | FILE *f, *cpf, *dpf, *epf; 59 | BZFILE *cpfbz2, *dpfbz2, *epfbz2; 60 | int cbz2err, dbz2err, ebz2err; 61 | int fd; 62 | ssize_t oldsize, newsize; 63 | ssize_t bzctrllen, bzdatalen; 64 | u_char header[32], buf[8]; 65 | u_char *old, *new; 66 | off_t oldpos, newpos; 67 | off_t ctrl[3]; 68 | off_t lenread; 69 | off_t i; 70 | 71 | if (argc != 4) { 72 | return 1; 73 | // errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); 74 | } 75 | 76 | /* Open patch file */ 77 | if ((f = fopen(argv[3], "r")) == NULL) { 78 | return 1; 79 | // err(1, "fopen(%s)", argv[3]); 80 | } 81 | 82 | /* 83 | File format: 84 | 0 8 "BSDIFF40" 85 | 8 8 X 86 | 16 8 Y 87 | 24 8 sizeof(newfile) 88 | 32 X bzip2(control block) 89 | 32+X Y bzip2(diff block) 90 | 32+X+Y ??? bzip2(extra block) 91 | with control block a set of triples (x,y,z) meaning "add x bytes 92 | from oldfile to x bytes from the diff block; copy y bytes from the 93 | extra block; seek forwards in oldfile by z bytes". 94 | */ 95 | 96 | /* Read header */ 97 | if (fread(header, 1, 32, f) < 32) { 98 | return 1; 99 | // if (feof(f)) 100 | // errx(1, "Corrupt patch\n"); 101 | // err(1, "fread(%s)", argv[3]); 102 | } 103 | 104 | /* Check for appropriate magic */ 105 | if (memcmp(header, "BSDIFF40", 8) != 0) { 106 | return 1; 107 | // errx(1, "Corrupt patch\n"); 108 | } 109 | 110 | /* Read lengths from header */ 111 | bzctrllen = offtin(header + 8); 112 | bzdatalen = offtin(header + 16); 113 | newsize = offtin(header + 24); 114 | if ((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0)) { 115 | return 1; 116 | // errx(1, "Corrupt patch\n"); 117 | } 118 | 119 | /* Close patch file and re-open it via libbzip2 at the right places */ 120 | if (fclose(f)) { 121 | return 1; 122 | // err(1, "fclose(%s)", argv[3]); 123 | } 124 | if ((cpf = fopen(argv[3], "r")) == NULL) { 125 | return 1; 126 | // err(1, "fopen(%s)", argv[3]); 127 | } 128 | if (fseeko(cpf, 32, SEEK_SET)) { 129 | return 1; 130 | // err(1, "fseeko(%s, %lld)", argv[3], 131 | // (long long) 32); 132 | } 133 | if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL) { 134 | return 1; 135 | // errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err); 136 | } 137 | if ((dpf = fopen(argv[3], "r")) == NULL) { 138 | return 1; 139 | // err(1, "fopen(%s)", argv[3]); 140 | } 141 | if (fseeko(dpf, 32 + bzctrllen, SEEK_SET)) { 142 | return 1; 143 | // err(1, "fseeko(%s, %lld)", argv[3], 144 | // (long long) (32 + bzctrllen)); 145 | } 146 | if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL) { 147 | return 1; 148 | // errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err); 149 | } 150 | if ((epf = fopen(argv[3], "r")) == NULL) { 151 | return 1; 152 | // err(1, "fopen(%s)", argv[3]); 153 | } 154 | if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET)) { 155 | return 1; 156 | // err(1, "fseeko(%s, %lld)", argv[3], 157 | // (long long) (32 + bzctrllen + bzdatalen)); 158 | } 159 | if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL) { 160 | return 1; 161 | // errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err); 162 | } 163 | 164 | if (((fd = open(argv[1], O_RDONLY, 0)) < 0) || 165 | ((oldsize = lseek(fd, 0, SEEK_END)) == -1) || 166 | ((old = malloc(oldsize + 1)) == NULL) || 167 | (lseek(fd, 0, SEEK_SET) != 0) || 168 | (read(fd, old, oldsize) != oldsize) || 169 | (close(fd) == -1)) { 170 | return 1; 171 | // err(1,"%s",argv[1]); 172 | } 173 | if ((new = malloc(newsize + 1)) == NULL) { 174 | return 1; 175 | // err(1,NULL); 176 | } 177 | 178 | oldpos = 0; 179 | newpos = 0; 180 | while (newpos < newsize) { 181 | /* Read control data */ 182 | for (i = 0; i <= 2; i++) { 183 | lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8); 184 | if ((lenread < 8) || ((cbz2err != BZ_OK) && 185 | (cbz2err != BZ_STREAM_END))) { 186 | return 1; 187 | // errx(1, "Corrupt patch\n"); 188 | } 189 | ctrl[i] = offtin(buf); 190 | }; 191 | 192 | /* Sanity-check */ 193 | if (newpos + ctrl[0] > newsize) { 194 | return 1; 195 | // errx(1, "Corrupt patch\n"); 196 | } 197 | 198 | /* Read diff string */ 199 | lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]); 200 | if ((lenread < ctrl[0]) || 201 | ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END))) { 202 | return 1; 203 | // errx(1, "Corrupt patch\n"); 204 | } 205 | 206 | /* Add old data to diff string */ 207 | for (i = 0; i < ctrl[0]; i++) 208 | if ((oldpos + i >= 0) && (oldpos + i < oldsize)) 209 | new[newpos + i] += old[oldpos + i]; 210 | 211 | /* Adjust pointers */ 212 | newpos += ctrl[0]; 213 | oldpos += ctrl[0]; 214 | 215 | /* Sanity-check */ 216 | if (newpos + ctrl[1] > newsize) { 217 | return 1; 218 | // errx(1, "Corrupt patch\n"); 219 | } 220 | 221 | /* Read extra string */ 222 | lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]); 223 | if ((lenread < ctrl[1]) || 224 | ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END))) { 225 | return 1; 226 | // errx(1, "Corrupt patch\n"); 227 | } 228 | 229 | /* Adjust pointers */ 230 | newpos += ctrl[1]; 231 | oldpos += ctrl[2]; 232 | }; 233 | 234 | /* Clean up the bzip2 reads */ 235 | BZ2_bzReadClose(&cbz2err, cpfbz2); 236 | BZ2_bzReadClose(&dbz2err, dpfbz2); 237 | BZ2_bzReadClose(&ebz2err, epfbz2); 238 | if (fclose(cpf) || fclose(dpf) || fclose(epf)) { 239 | return 1; 240 | // err(1, "fclose(%s)", argv[3]); 241 | } 242 | 243 | 244 | /* Write the new file */ 245 | if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) || 246 | (write(fd,new,newsize)!=newsize) || (close(fd)==-1)) { 247 | return 1; 248 | // err(1, "%s", argv[2]); 249 | } 250 | 251 | free(new); 252 | free(old); 253 | 254 | return 0; 255 | } 256 | -------------------------------------------------------------------------------- /candywebcache/src/main/jni/3rd/bsdiff/bspatch.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * Copyright 2012 Matthew Endsley 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef BSPATCH_H 29 | # define BSPATCH_H 30 | 31 | # include 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | struct bspatch_stream 38 | { 39 | void* opaque; 40 | int (*read)(const struct bspatch_stream* stream, void* buffer, int length); 41 | }; 42 | 43 | int bspatch(const uint8_t* old, int64_t oldsize, uint8_t* newfile, int64_t newsize, struct bspatch_stream* stream); 44 | 45 | int bspatch_main(int argc, char * argv[]); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | 53 | -------------------------------------------------------------------------------- /candywebcache/src/main/jni/3rd/bsdiff/config.h: -------------------------------------------------------------------------------- 1 | /* config.h. Generated from config.h.in by configure. */ 2 | /* config.h.in. Generated from configure.ac by autoheader. */ 3 | 4 | /* Define to 1 if you have the header file. */ 5 | #define HAVE_FCNTL_H 1 6 | 7 | /* Define to 1 if you have the header file. */ 8 | #define HAVE_INTTYPES_H 1 9 | 10 | /* Define to 1 if you have the `bz2' library (-lbz2). */ 11 | #define HAVE_LIBBZ2 1 12 | 13 | /* Define to 1 if you have the header file. */ 14 | #define HAVE_LIMITS_H 1 15 | 16 | /* Define to 1 if your system has a GNU libc compatible `malloc' function, and 17 | to 0 otherwise. */ 18 | #define HAVE_MALLOC 1 19 | 20 | /* Define to 1 if you have the header file. */ 21 | #define HAVE_MEMORY_H 1 22 | 23 | /* Define to 1 if you have the `memset' function. */ 24 | #define HAVE_MEMSET 1 25 | 26 | /* Define to 1 if you have the header file. */ 27 | #define HAVE_STDDEF_H 1 28 | 29 | /* Define to 1 if you have the header file. */ 30 | #define HAVE_STDINT_H 1 31 | 32 | /* Define to 1 if you have the header file. */ 33 | #define HAVE_STDLIB_H 1 34 | 35 | /* Define to 1 if you have the header file. */ 36 | #define HAVE_STRINGS_H 1 37 | 38 | /* Define to 1 if you have the header file. */ 39 | #define HAVE_STRING_H 1 40 | 41 | /* Define to 1 if you have the header file. */ 42 | #define HAVE_SYS_STAT_H 1 43 | 44 | /* Define to 1 if you have the header file. */ 45 | #define HAVE_SYS_TYPES_H 1 46 | 47 | /* Define to 1 if you have the header file. */ 48 | #define HAVE_UNISTD_H 1 49 | 50 | /* Name of package */ 51 | #define PACKAGE "bsdiff" 52 | 53 | /* Define to the address where bug reports for this package should be sent. */ 54 | #define PACKAGE_BUGREPORT "" 55 | 56 | /* Define to the full name of this package. */ 57 | #define PACKAGE_NAME "bsdiff" 58 | 59 | /* Define to the full name and version of this package. */ 60 | #define PACKAGE_STRING "bsdiff 0.1" 61 | 62 | /* Define to the one symbol short name of this package. */ 63 | #define PACKAGE_TARNAME "bsdiff" 64 | 65 | /* Define to the home page for this package. */ 66 | #define PACKAGE_URL "" 67 | 68 | /* Define to the version of this package. */ 69 | #define PACKAGE_VERSION "0.1" 70 | 71 | /* Define to 1 if you have the ANSI C header files. */ 72 | #define STDC_HEADERS 1 73 | 74 | /* Version number of package */ 75 | #define VERSION "0.1" 76 | 77 | /* Define for Solaris 2.5.1 so the uint8_t typedef from , 78 | , or is not used. If the typedef were allowed, the 79 | #define below would cause a syntax error. */ 80 | /* #undef _UINT8_T */ 81 | 82 | /* Define to the type of a signed integer type of width exactly 64 bits if 83 | such a type exists and the standard includes do not define it. */ 84 | /* #undef int64_t */ 85 | 86 | /* Define to rpl_malloc if the replacement function should be used. */ 87 | /* #undef malloc */ 88 | 89 | /* Define to `long int' if does not define. */ 90 | /* #undef off_t */ 91 | 92 | /* Define to `unsigned int' if does not define. */ 93 | /* #undef size_t */ 94 | 95 | /* Define to the type of an unsigned integer type of width exactly 8 bits if 96 | such a type exists and the standard includes do not define it. */ 97 | /* #undef uint8_t */ 98 | -------------------------------------------------------------------------------- /candywebcache/src/main/jni/3rd/bzip2/bzlib.h: -------------------------------------------------------------------------------- 1 | 2 | /*-------------------------------------------------------------*/ 3 | /*--- Public header file for the library. ---*/ 4 | /*--- bzlib.h ---*/ 5 | /*-------------------------------------------------------------*/ 6 | 7 | /* ------------------------------------------------------------------ 8 | This file is part of bzip2/libbzip2, a program and library for 9 | lossless, block-sorting data compression. 10 | 11 | bzip2/libbzip2 version 1.0.5 of 10 December 2007 12 | Copyright (C) 1996-2007 Julian Seward 13 | 14 | Please read the WARNING, DISCLAIMER and PATENTS sections in the 15 | README file. 16 | 17 | This program is released under the terms of the license contained 18 | in the file LICENSE. 19 | ------------------------------------------------------------------ */ 20 | 21 | 22 | #ifndef _BZLIB_H 23 | #define _BZLIB_H 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #define BZ_RUN 0 30 | #define BZ_FLUSH 1 31 | #define BZ_FINISH 2 32 | 33 | #define BZ_OK 0 34 | #define BZ_RUN_OK 1 35 | #define BZ_FLUSH_OK 2 36 | #define BZ_FINISH_OK 3 37 | #define BZ_STREAM_END 4 38 | #define BZ_SEQUENCE_ERROR (-1) 39 | #define BZ_PARAM_ERROR (-2) 40 | #define BZ_MEM_ERROR (-3) 41 | #define BZ_DATA_ERROR (-4) 42 | #define BZ_DATA_ERROR_MAGIC (-5) 43 | #define BZ_IO_ERROR (-6) 44 | #define BZ_UNEXPECTED_EOF (-7) 45 | #define BZ_OUTBUFF_FULL (-8) 46 | #define BZ_CONFIG_ERROR (-9) 47 | 48 | typedef 49 | struct { 50 | char *next_in; 51 | unsigned int avail_in; 52 | unsigned int total_in_lo32; 53 | unsigned int total_in_hi32; 54 | 55 | char *next_out; 56 | unsigned int avail_out; 57 | unsigned int total_out_lo32; 58 | unsigned int total_out_hi32; 59 | 60 | void *state; 61 | 62 | void *(*bzalloc)(void *,int,int); 63 | void (*bzfree)(void *,void *); 64 | void *opaque; 65 | } 66 | bz_stream; 67 | 68 | 69 | #ifndef BZ_IMPORT 70 | #define BZ_EXPORT 71 | #endif 72 | 73 | #ifndef BZ_NO_STDIO 74 | /* Need a definitition for FILE */ 75 | #include 76 | #endif 77 | 78 | #ifdef _WIN32 79 | # include 80 | # ifdef small 81 | /* windows.h define small to char */ 82 | # undef small 83 | # endif 84 | # ifdef BZ_EXPORT 85 | # define BZ_API(func) WINAPI func 86 | # define BZ_EXTERN extern 87 | # else 88 | /* import windows dll dynamically */ 89 | # define BZ_API(func) (WINAPI * func) 90 | # define BZ_EXTERN 91 | # endif 92 | #else 93 | # define BZ_API(func) func 94 | # define BZ_EXTERN extern 95 | #endif 96 | 97 | 98 | /*-- Core (low-level) library functions --*/ 99 | 100 | // !!! CHANGE !!! 101 | 102 | BZ_EXTERN int testBZLib(int value); 103 | 104 | // !!! CHANGE !!! 105 | 106 | BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( 107 | bz_stream* strm, 108 | int blockSize100k, 109 | int verbosity, 110 | int workFactor 111 | ); 112 | 113 | BZ_EXTERN int BZ_API(BZ2_bzCompress) ( 114 | bz_stream* strm, 115 | int action 116 | ); 117 | 118 | BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( 119 | bz_stream* strm 120 | ); 121 | 122 | BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( 123 | bz_stream *strm, 124 | int verbosity, 125 | int small 126 | ); 127 | 128 | BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( 129 | bz_stream* strm 130 | ); 131 | 132 | BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( 133 | bz_stream *strm 134 | ); 135 | 136 | 137 | 138 | /*-- High(er) level library functions --*/ 139 | 140 | #ifndef BZ_NO_STDIO 141 | #define BZ_MAX_UNUSED 5000 142 | 143 | typedef void BZFILE; 144 | 145 | BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( 146 | int* bzerror, 147 | FILE* f, 148 | int verbosity, 149 | int small, 150 | void* unused, 151 | int nUnused 152 | ); 153 | 154 | BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( 155 | int* bzerror, 156 | BZFILE* b 157 | ); 158 | 159 | BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( 160 | int* bzerror, 161 | BZFILE* b, 162 | void** unused, 163 | int* nUnused 164 | ); 165 | 166 | BZ_EXTERN int BZ_API(BZ2_bzRead) ( 167 | int* bzerror, 168 | BZFILE* b, 169 | void* buf, 170 | int len 171 | ); 172 | 173 | BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( 174 | int* bzerror, 175 | FILE* f, 176 | int blockSize100k, 177 | int verbosity, 178 | int workFactor 179 | ); 180 | 181 | BZ_EXTERN void BZ_API(BZ2_bzWrite) ( 182 | int* bzerror, 183 | BZFILE* b, 184 | void* buf, 185 | int len 186 | ); 187 | 188 | BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( 189 | int* bzerror, 190 | BZFILE* b, 191 | int abandon, 192 | unsigned int* nbytes_in, 193 | unsigned int* nbytes_out 194 | ); 195 | 196 | BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( 197 | int* bzerror, 198 | BZFILE* b, 199 | int abandon, 200 | unsigned int* nbytes_in_lo32, 201 | unsigned int* nbytes_in_hi32, 202 | unsigned int* nbytes_out_lo32, 203 | unsigned int* nbytes_out_hi32 204 | ); 205 | #endif 206 | 207 | 208 | /*-- Utility functions --*/ 209 | 210 | BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( 211 | char* dest, 212 | unsigned int* destLen, 213 | char* source, 214 | unsigned int sourceLen, 215 | int blockSize100k, 216 | int verbosity, 217 | int workFactor 218 | ); 219 | 220 | BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( 221 | char* dest, 222 | unsigned int* destLen, 223 | char* source, 224 | unsigned int sourceLen, 225 | int small, 226 | int verbosity 227 | ); 228 | 229 | 230 | /*-- 231 | Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) 232 | to support better zlib compatibility. 233 | This code is not _officially_ part of libbzip2 (yet); 234 | I haven't tested it, documented it, or considered the 235 | threading-safeness of it. 236 | If this code breaks, please contact both Yoshioka and me. 237 | --*/ 238 | 239 | BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( 240 | void 241 | ); 242 | 243 | #ifndef BZ_NO_STDIO 244 | BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( 245 | const char *path, 246 | const char *mode 247 | ); 248 | 249 | BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( 250 | int fd, 251 | const char *mode 252 | ); 253 | 254 | BZ_EXTERN int BZ_API(BZ2_bzread) ( 255 | BZFILE* b, 256 | void* buf, 257 | int len 258 | ); 259 | 260 | BZ_EXTERN int BZ_API(BZ2_bzwrite) ( 261 | BZFILE* b, 262 | void* buf, 263 | int len 264 | ); 265 | 266 | BZ_EXTERN int BZ_API(BZ2_bzflush) ( 267 | BZFILE* b 268 | ); 269 | 270 | BZ_EXTERN void BZ_API(BZ2_bzclose) ( 271 | BZFILE* b 272 | ); 273 | 274 | BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( 275 | BZFILE *b, 276 | int *errnum 277 | ); 278 | #endif 279 | 280 | #ifdef __cplusplus 281 | } 282 | #endif 283 | 284 | #endif 285 | 286 | /*-------------------------------------------------------------*/ 287 | /*--- end bzlib.h ---*/ 288 | /*-------------------------------------------------------------*/ 289 | -------------------------------------------------------------------------------- /candywebcache/src/main/jni/3rd/bzip2/crctable.c: -------------------------------------------------------------------------------- 1 | 2 | /*-------------------------------------------------------------*/ 3 | /*--- Table for doing CRCs ---*/ 4 | /*--- crctable.c ---*/ 5 | /*-------------------------------------------------------------*/ 6 | 7 | /* ------------------------------------------------------------------ 8 | This file is part of bzip2/libbzip2, a program and library for 9 | lossless, block-sorting data compression. 10 | 11 | bzip2/libbzip2 version 1.0.5 of 10 December 2007 12 | Copyright (C) 1996-2007 Julian Seward 13 | 14 | Please read the WARNING, DISCLAIMER and PATENTS sections in the 15 | README file. 16 | 17 | This program is released under the terms of the license contained 18 | in the file LICENSE. 19 | ------------------------------------------------------------------ */ 20 | 21 | 22 | #include "bzlib_private.h" 23 | 24 | /*-- 25 | I think this is an implementation of the AUTODIN-II, 26 | Ethernet & FDDI 32-bit CRC standard. Vaguely derived 27 | from code by Rob Warnock, in Section 51 of the 28 | comp.compression FAQ. 29 | --*/ 30 | 31 | UInt32 BZ2_crc32Table[256] = { 32 | 33 | /*-- Ugly, innit? --*/ 34 | 35 | 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, 36 | 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, 37 | 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, 38 | 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, 39 | 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, 40 | 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, 41 | 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, 42 | 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, 43 | 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, 44 | 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, 45 | 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, 46 | 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, 47 | 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, 48 | 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, 49 | 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, 50 | 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, 51 | 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, 52 | 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, 53 | 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, 54 | 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, 55 | 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, 56 | 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, 57 | 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, 58 | 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, 59 | 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, 60 | 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, 61 | 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, 62 | 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, 63 | 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, 64 | 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, 65 | 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, 66 | 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, 67 | 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, 68 | 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, 69 | 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, 70 | 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, 71 | 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, 72 | 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, 73 | 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, 74 | 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, 75 | 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, 76 | 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, 77 | 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, 78 | 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, 79 | 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, 80 | 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, 81 | 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, 82 | 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, 83 | 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, 84 | 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, 85 | 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, 86 | 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, 87 | 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, 88 | 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, 89 | 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, 90 | 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, 91 | 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, 92 | 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, 93 | 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, 94 | 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, 95 | 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, 96 | 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, 97 | 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, 98 | 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L 99 | }; 100 | 101 | 102 | /*-------------------------------------------------------------*/ 103 | /*--- end crctable.c ---*/ 104 | /*-------------------------------------------------------------*/ 105 | -------------------------------------------------------------------------------- /candywebcache/src/main/jni/3rd/bzip2/huffman.c: -------------------------------------------------------------------------------- 1 | 2 | /*-------------------------------------------------------------*/ 3 | /*--- Huffman coding low-level stuff ---*/ 4 | /*--- huffman.c ---*/ 5 | /*-------------------------------------------------------------*/ 6 | 7 | /* ------------------------------------------------------------------ 8 | This file is part of bzip2/libbzip2, a program and library for 9 | lossless, block-sorting data compression. 10 | 11 | bzip2/libbzip2 version 1.0.5 of 10 December 2007 12 | Copyright (C) 1996-2007 Julian Seward 13 | 14 | Please read the WARNING, DISCLAIMER and PATENTS sections in the 15 | README file. 16 | 17 | This program is released under the terms of the license contained 18 | in the file LICENSE. 19 | ------------------------------------------------------------------ */ 20 | 21 | 22 | #include "bzlib_private.h" 23 | 24 | /*---------------------------------------------------*/ 25 | #define WEIGHTOF(zz0) ((zz0) & 0xffffff00) 26 | #define DEPTHOF(zz1) ((zz1) & 0x000000ff) 27 | #define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) 28 | 29 | #define ADDWEIGHTS(zw1,zw2) \ 30 | (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ 31 | (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) 32 | 33 | #define UPHEAP(z) \ 34 | { \ 35 | Int32 zz, tmp; \ 36 | zz = z; tmp = heap[zz]; \ 37 | while (weight[tmp] < weight[heap[zz >> 1]]) { \ 38 | heap[zz] = heap[zz >> 1]; \ 39 | zz >>= 1; \ 40 | } \ 41 | heap[zz] = tmp; \ 42 | } 43 | 44 | #define DOWNHEAP(z) \ 45 | { \ 46 | Int32 zz, yy, tmp; \ 47 | zz = z; tmp = heap[zz]; \ 48 | while (True) { \ 49 | yy = zz << 1; \ 50 | if (yy > nHeap) break; \ 51 | if (yy < nHeap && \ 52 | weight[heap[yy+1]] < weight[heap[yy]]) \ 53 | yy++; \ 54 | if (weight[tmp] < weight[heap[yy]]) break; \ 55 | heap[zz] = heap[yy]; \ 56 | zz = yy; \ 57 | } \ 58 | heap[zz] = tmp; \ 59 | } 60 | 61 | 62 | /*---------------------------------------------------*/ 63 | void BZ2_hbMakeCodeLengths ( UChar *len, 64 | Int32 *freq, 65 | Int32 alphaSize, 66 | Int32 maxLen ) 67 | { 68 | /*-- 69 | Nodes and heap entries run from 1. Entry 0 70 | for both the heap and nodes is a sentinel. 71 | --*/ 72 | Int32 nNodes, nHeap, n1, n2, i, j, k; 73 | Bool tooLong; 74 | 75 | Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; 76 | Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; 77 | Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; 78 | 79 | for (i = 0; i < alphaSize; i++) 80 | weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; 81 | 82 | while (True) { 83 | 84 | nNodes = alphaSize; 85 | nHeap = 0; 86 | 87 | heap[0] = 0; 88 | weight[0] = 0; 89 | parent[0] = -2; 90 | 91 | for (i = 1; i <= alphaSize; i++) { 92 | parent[i] = -1; 93 | nHeap++; 94 | heap[nHeap] = i; 95 | UPHEAP(nHeap); 96 | } 97 | 98 | AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); 99 | 100 | while (nHeap > 1) { 101 | n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); 102 | n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); 103 | nNodes++; 104 | parent[n1] = parent[n2] = nNodes; 105 | weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); 106 | parent[nNodes] = -1; 107 | nHeap++; 108 | heap[nHeap] = nNodes; 109 | UPHEAP(nHeap); 110 | } 111 | 112 | AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); 113 | 114 | tooLong = False; 115 | for (i = 1; i <= alphaSize; i++) { 116 | j = 0; 117 | k = i; 118 | while (parent[k] >= 0) { k = parent[k]; j++; } 119 | len[i-1] = j; 120 | if (j > maxLen) tooLong = True; 121 | } 122 | 123 | if (! tooLong) break; 124 | 125 | /* 17 Oct 04: keep-going condition for the following loop used 126 | to be 'i < alphaSize', which missed the last element, 127 | theoretically leading to the possibility of the compressor 128 | looping. However, this count-scaling step is only needed if 129 | one of the generated Huffman code words is longer than 130 | maxLen, which up to and including version 1.0.2 was 20 bits, 131 | which is extremely unlikely. In version 1.0.3 maxLen was 132 | changed to 17 bits, which has minimal effect on compression 133 | ratio, but does mean this scaling step is used from time to 134 | time, enough to verify that it works. 135 | 136 | This means that bzip2-1.0.3 and later will only produce 137 | Huffman codes with a maximum length of 17 bits. However, in 138 | order to preserve backwards compatibility with bitstreams 139 | produced by versions pre-1.0.3, the decompressor must still 140 | handle lengths of up to 20. */ 141 | 142 | for (i = 1; i <= alphaSize; i++) { 143 | j = weight[i] >> 8; 144 | j = 1 + (j / 2); 145 | weight[i] = j << 8; 146 | } 147 | } 148 | } 149 | 150 | 151 | /*---------------------------------------------------*/ 152 | void BZ2_hbAssignCodes ( Int32 *code, 153 | UChar *length, 154 | Int32 minLen, 155 | Int32 maxLen, 156 | Int32 alphaSize ) 157 | { 158 | Int32 n, vec, i; 159 | 160 | vec = 0; 161 | for (n = minLen; n <= maxLen; n++) { 162 | for (i = 0; i < alphaSize; i++) 163 | if (length[i] == n) { code[i] = vec; vec++; }; 164 | vec <<= 1; 165 | } 166 | } 167 | 168 | 169 | /*---------------------------------------------------*/ 170 | void BZ2_hbCreateDecodeTables ( Int32 *limit, 171 | Int32 *base, 172 | Int32 *perm, 173 | UChar *length, 174 | Int32 minLen, 175 | Int32 maxLen, 176 | Int32 alphaSize ) 177 | { 178 | Int32 pp, i, j, vec; 179 | 180 | pp = 0; 181 | for (i = minLen; i <= maxLen; i++) 182 | for (j = 0; j < alphaSize; j++) 183 | if (length[j] == i) { perm[pp] = j; pp++; }; 184 | 185 | for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; 186 | for (i = 0; i < alphaSize; i++) base[length[i]+1]++; 187 | 188 | for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; 189 | 190 | for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; 191 | vec = 0; 192 | 193 | for (i = minLen; i <= maxLen; i++) { 194 | vec += (base[i+1] - base[i]); 195 | limit[i] = vec-1; 196 | vec <<= 1; 197 | } 198 | for (i = minLen + 1; i <= maxLen; i++) 199 | base[i] = ((limit[i-1] + 1) << 1) - base[i]; 200 | } 201 | 202 | 203 | /*-------------------------------------------------------------*/ 204 | /*--- end huffman.c ---*/ 205 | /*-------------------------------------------------------------*/ 206 | -------------------------------------------------------------------------------- /candywebcache/src/main/jni/3rd/bzip2/randtable.c: -------------------------------------------------------------------------------- 1 | 2 | /*-------------------------------------------------------------*/ 3 | /*--- Table for randomising repetitive blocks ---*/ 4 | /*--- randtable.c ---*/ 5 | /*-------------------------------------------------------------*/ 6 | 7 | /* ------------------------------------------------------------------ 8 | This file is part of bzip2/libbzip2, a program and library for 9 | lossless, block-sorting data compression. 10 | 11 | bzip2/libbzip2 version 1.0.5 of 10 December 2007 12 | Copyright (C) 1996-2007 Julian Seward 13 | 14 | Please read the WARNING, DISCLAIMER and PATENTS sections in the 15 | README file. 16 | 17 | This program is released under the terms of the license contained 18 | in the file LICENSE. 19 | ------------------------------------------------------------------ */ 20 | 21 | 22 | #include "bzlib_private.h" 23 | 24 | 25 | /*---------------------------------------------*/ 26 | Int32 BZ2_rNums[512] = { 27 | 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 28 | 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 29 | 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 30 | 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 31 | 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 32 | 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 33 | 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 34 | 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 35 | 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 36 | 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 37 | 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 38 | 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 39 | 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 40 | 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 41 | 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 42 | 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 43 | 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 44 | 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 45 | 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 46 | 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 47 | 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 48 | 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 49 | 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 50 | 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 51 | 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 52 | 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 53 | 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 54 | 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 55 | 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 56 | 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 57 | 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 58 | 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 59 | 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 60 | 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 61 | 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 62 | 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 63 | 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 64 | 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 65 | 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 66 | 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 67 | 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 68 | 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 69 | 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 70 | 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 71 | 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 72 | 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 73 | 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 74 | 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 75 | 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 76 | 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 77 | 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 78 | 936, 638 79 | }; 80 | 81 | 82 | /*-------------------------------------------------------------*/ 83 | /*--- end randtable.c ---*/ 84 | /*-------------------------------------------------------------*/ 85 | -------------------------------------------------------------------------------- /candywebcache/src/main/jni/Android.mk: -------------------------------------------------------------------------------- 1 | include $(call all-subdir-makefiles) 2 | 3 | LOCAL_PATH := $(call my-dir) 4 | 5 | include $(CLEAR_VARS) 6 | 7 | #source code 8 | LOCAL_SRC_FILES = $(LOCAL_PATH)/3rd/bsdiff/bsdiff.c \ 9 | $(LOCAL_PATH)/3rd/bsdiff/bspatch.c \ 10 | $(LOCAL_PATH)/3rd/bzip2/blocksort.c \ 11 | $(LOCAL_PATH)/3rd/bzip2/bzlib.c \ 12 | $(LOCAL_PATH)/3rd/bzip2/compress.c \ 13 | $(LOCAL_PATH)/3rd/bzip2/crctable.c \ 14 | $(LOCAL_PATH)/3rd/bzip2/decompress.c \ 15 | $(LOCAL_PATH)/3rd/bzip2/huffman.c \ 16 | $(LOCAL_PATH)/3rd/bzip2/randtable.c 17 | 18 | LOCAL_SRC_FILES += $(LOCAL_PATH)/PatcherJni.cpp 19 | 20 | LOCAL_CFLAGS := -DDEBUG 21 | 22 | # LOCAL_CPPFLAGS := 23 | 24 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/3rd/bsdiff \ 25 | $(LOCAL_PATH)/3rd/bzip2 \ 26 | $(LOCAL_PATH)/ 27 | 28 | LOCAL_LDLIBS := -llog -landroid -lz 29 | 30 | LOCAL_SHARED_LIBRARIES := 31 | 32 | LOCAL_MODULE:= patcher 33 | 34 | include $(BUILD_SHARED_LIBRARY) -------------------------------------------------------------------------------- /candywebcache/src/main/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi armeabi-v7a x86 -------------------------------------------------------------------------------- /candywebcache/src/main/jni/JNIHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by NetEase on 16/6/7. 3 | // 4 | 5 | #ifndef CANDYWEBCACHE_JNIHELPER_H 6 | #define CANDYWEBCACHE_JNIHELPER_H 7 | 8 | #include 9 | 10 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) 11 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) 12 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) 13 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) 14 | #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) 15 | 16 | #ifndef NELEM 17 | # define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) 18 | #endif 19 | 20 | #define NATIVE_METHOD(className, functionName, signature) \ 21 | { #functionName, signature, reinterpret_cast(className ## _ ## functionName) } 22 | 23 | #endif //CANDYWEBCACHE_JNIHELPER_H 24 | -------------------------------------------------------------------------------- /candywebcache/src/main/jni/PatcherJni.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by NetEase on 16/6/6. 3 | // 4 | 5 | #include 6 | #include "jni.h" 7 | 8 | #include "bspatch.h" 9 | 10 | #include "JNIHelper.h" 11 | 12 | #define TAG "CandyWebCache" 13 | 14 | static jboolean CourgettePatcher_nativeApplyPatch(JNIEnv* env, jclass, jstring javaOldFilePath, 15 | jstring javaPatchFilePath, jstring javaOutFilePath) { 16 | return JNI_TRUE; 17 | } 18 | 19 | static JNINativeMethod gCourgettePatcherMethods[] = { 20 | NATIVE_METHOD(CourgettePatcher, nativeApplyPatch, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z"), 21 | }; 22 | 23 | 24 | static jboolean BsdiffPatcher_nativeApplyPatch(JNIEnv* env, jclass, jstring javaOldFilePath, 25 | jstring javaPatchFilePath, jstring javaOutFilePath) { 26 | const char* oldFilePath = env->GetStringUTFChars(javaOldFilePath, NULL); 27 | const char* patchFilePath = env->GetStringUTFChars(javaPatchFilePath, NULL); 28 | const char* outFilePath = env->GetStringUTFChars(javaOutFilePath, NULL); 29 | 30 | char **argv = (char **)malloc(sizeof(char *) * 5); 31 | argv[0] = "bspatch"; 32 | argv[1] = const_cast(oldFilePath); 33 | argv[2] = const_cast(outFilePath); 34 | argv[3] = const_cast(patchFilePath); 35 | argv[4] = NULL; 36 | 37 | int ret = bspatch_main(4, argv); 38 | free(argv); 39 | 40 | env->ReleaseStringUTFChars(javaOutFilePath, outFilePath); 41 | env->ReleaseStringUTFChars(javaPatchFilePath, patchFilePath); 42 | env->ReleaseStringUTFChars(javaOldFilePath, oldFilePath); 43 | 44 | if (ret == 0) { 45 | return JNI_TRUE; 46 | } 47 | return JNI_FALSE; 48 | } 49 | 50 | static JNINativeMethod gBsdiffPatcherMethods[] = { 51 | NATIVE_METHOD(BsdiffPatcher, nativeApplyPatch, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z"), 52 | }; 53 | 54 | static int jniRegisterNativeMethods(JNIEnv* env, const char *classPathName, JNINativeMethod *nativeMethods, jint nMethods) { 55 | jclass clazz; 56 | clazz = env->FindClass(classPathName); 57 | if (clazz == NULL) { 58 | LOGW("Native registration unable to find class '%s'", classPathName); 59 | return JNI_FALSE; 60 | } 61 | if (env->RegisterNatives(clazz, nativeMethods, nMethods) < 0) { 62 | LOGW("RegisterNatives failed for '%s'", classPathName); 63 | return JNI_FALSE; 64 | } 65 | return JNI_TRUE; 66 | } 67 | 68 | void register_com_netease_hearttouch_candywebcache_cachemanager_CourgettePatcher(JNIEnv* env) { 69 | jniRegisterNativeMethods(env, "com/netease/hearttouch/candywebcache/cachemanager/CourgettePatcher", 70 | gCourgettePatcherMethods, NELEM(gCourgettePatcherMethods)); 71 | } 72 | 73 | void register_com_netease_hearttouch_candywebcache_cachemanager_BsdiffPatcher(JNIEnv* env) { 74 | jniRegisterNativeMethods(env, "com/netease/hearttouch/candywebcache/cachemanager/BsdiffPatcher", 75 | gBsdiffPatcherMethods, NELEM(gBsdiffPatcherMethods)); 76 | } 77 | 78 | // DalvikVM calls this on startup, so we can statically register all our native methods. 79 | jint JNI_OnLoad(JavaVM* vm, void*) { 80 | JNIEnv* env; 81 | if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { 82 | LOGE("JavaVM::GetEnv() failed"); 83 | abort(); 84 | } 85 | // register_com_netease_hearttouch_candywebcache_cachemanager_CourgettePatcher(env); 86 | register_com_netease_hearttouch_candywebcache_cachemanager_BsdiffPatcher(env); 87 | return JNI_VERSION_1_6; 88 | } -------------------------------------------------------------------------------- /candywebcache/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | candywebcache 3 | 4 | -------------------------------------------------------------------------------- /candywebcache/src/test/java/com/netease/hearttouch/candywebcache/CacheConfigTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import static org.junit.Assert.*; 10 | 11 | /** 12 | * Created by netease on 16/6/12. 13 | */ 14 | public class CacheConfigTest { 15 | private CacheConfig.ConfigBuilder mConfigBuilder; 16 | 17 | @Before 18 | public void setUp() throws Exception { 19 | mConfigBuilder = CacheConfig.createCofigBuilder(); 20 | } 21 | 22 | @After 23 | public void tearDown() throws Exception { 24 | 25 | } 26 | 27 | @org.junit.Test 28 | public void testCreateCofigBuilder() throws Exception { 29 | assertNotNull(mConfigBuilder); 30 | } 31 | 32 | @org.junit.Test 33 | public void testGetUpdateCheckCycle() throws Exception { 34 | mConfigBuilder.setUpdateCycle(1000); 35 | CacheConfig cacheConfig = mConfigBuilder.build(); 36 | assertNotNull(cacheConfig); 37 | assertEquals(1000, cacheConfig.getUpdateCheckCycle()); 38 | } 39 | 40 | @org.junit.Test 41 | public void testGetCacheDirPath() throws Exception { 42 | mConfigBuilder.setCacheDirPath("/sdcard/netease/webcache/webapp"); 43 | CacheConfig cacheConfig = mConfigBuilder.build(); 44 | assertNotNull(cacheConfig); 45 | assertEquals("/sdcard/netease/webcache/webapp", cacheConfig.getCacheDirPath()); 46 | } 47 | 48 | @org.junit.Test 49 | public void testGetManifestDirPath() throws Exception { 50 | mConfigBuilder.setManifestDirPath("/sdcard/netease/webcache/manifest"); 51 | CacheConfig cacheConfig = mConfigBuilder.build(); 52 | assertNotNull(cacheConfig); 53 | assertEquals("/sdcard/netease/webcache/manifest", cacheConfig.getManifestDirPath()); 54 | } 55 | 56 | @org.junit.Test 57 | public void testGetMemCacheSize() throws Exception { 58 | mConfigBuilder.setMemCacheSize(5 * 1024 * 1024); 59 | CacheConfig cacheConfig = mConfigBuilder.build(); 60 | assertNotNull(cacheConfig); 61 | assertEquals(5 * 1024 * 1024, cacheConfig.getMemCacheSize()); 62 | } 63 | 64 | @org.junit.Test 65 | public void testGetUncachedFileType() throws Exception { 66 | ArrayList uncachedFileTypes = new ArrayList(); 67 | uncachedFileTypes.add(".index"); 68 | uncachedFileTypes.add(".css"); 69 | mConfigBuilder.setUncachedFileTypes(uncachedFileTypes); 70 | CacheConfig cacheConfig = mConfigBuilder.build(); 71 | assertNotNull(cacheConfig); 72 | List fileTypes = cacheConfig.getUncachedFileType(); 73 | assertTrue(fileTypes.contains(".index")); 74 | assertTrue(fileTypes.contains(".css")); 75 | assertFalse(fileTypes.contains(".js")); 76 | } 77 | } -------------------------------------------------------------------------------- /candywebcache/src/test/java/com/netease/hearttouch/candywebcache/cachemanager/EnDecryptTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | /** 10 | * Created by netease on 16/6/27. 11 | */ 12 | public class EnDecryptTest { 13 | @Before 14 | public void setUp() throws Exception { 15 | 16 | } 17 | 18 | @After 19 | public void tearDown() throws Exception { 20 | 21 | } 22 | 23 | @Test 24 | public void testEnDecrypt() throws Exception { 25 | String dataSrc = "20398415cf372481131278f074119188"; 26 | String passwd = "12344321"; 27 | 28 | assertEquals("E13F4ECDDBB54551664F74AC76634BBAD8F5ACB35DFF99CA711C05169E990064996A020A8336A5E0", DESUtils.encrypt(dataSrc, passwd)); 29 | assertEquals("4T9Ozdu1RVFmT3SsdmNLutj1rLNd/5nKcRwFFp6ZAGSZagIKgzal4A==", Base64.encode(DESUtils.encrypt(dataSrc.getBytes(), passwd.getBytes()))); 30 | assertEquals("4T9Ozdu1RVFmT3SsdmNLutj1rLNd/5nKcRwFFp6ZAGSZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 31 | 32 | dataSrc = "cbc2d2376ef405c6c49088706b294275"; 33 | assertEquals("rjNJ5lUmD06tE4rWnohvd3ifijh9lXDkRTGRDzNwrn+ZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 34 | assertEquals(dataSrc, EnDecryptionUtils.decode("rjNJ5lUmD06tE4rWnohvd3ifijh9lXDkRTGRDzNwrn+ZagIKgzal4A==")); 35 | 36 | dataSrc = "a2e4c9b7ae6beb31e68daca9d7ad6f4e"; 37 | assertEquals("lQdR6sBdy+AIakJz7Pi53ZlIPWGEj1IDybvPm0RfGsKZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 38 | assertEquals(dataSrc, EnDecryptionUtils.decode("lQdR6sBdy+AIakJz7Pi53ZlIPWGEj1IDybvPm0RfGsKZagIKgzal4A==")); 39 | 40 | dataSrc = "6e3ace2638be9fc855e7672964cf4d4c"; 41 | assertEquals("kC/KhxC55iM83nDOCXxvtaSeEQ0Qf99pCDYD6+ZUVp+ZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 42 | assertEquals(dataSrc, EnDecryptionUtils.decode("kC/KhxC55iM83nDOCXxvtaSeEQ0Qf99pCDYD6+ZUVp+ZagIKgzal4A==")); 43 | 44 | dataSrc = "836a47fe852fa5352322dbd6f2c9a813"; 45 | assertEquals("ZuIMHTf3d+sS3C3dOK9UepD96EsChggc3XmVZhIn3MKZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 46 | assertEquals(dataSrc, EnDecryptionUtils.decode("ZuIMHTf3d+sS3C3dOK9UepD96EsChggc3XmVZhIn3MKZagIKgzal4A==")); 47 | 48 | dataSrc = "32d32a0700b8067d0cc98a770a8a1c61"; 49 | assertEquals("+a8HfZHo5447sQc3uhcGSTa6ZLa+LwXs4DzONPSTNz2ZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 50 | assertEquals(dataSrc, EnDecryptionUtils.decode("+a8HfZHo5447sQc3uhcGSTa6ZLa+LwXs4DzONPSTNz2ZagIKgzal4A==")); 51 | 52 | dataSrc = "3244787f9fe856920a77a807a285e6b5"; 53 | assertEquals("S1zVHQTTe5gDJphM1w9xS7RK+NRoaR42nJsE9o8jkzeZagIKgzal4A==", EnDecryptionUtils.encode(dataSrc)); 54 | assertEquals(dataSrc, EnDecryptionUtils.decode("S1zVHQTTe5gDJphM1w9xS7RK+NRoaR42nJsE9o8jkzeZagIKgzal4A==")); 55 | 56 | String encryptedStr = "4T9Ozdu1RVFmT3SsdmNLutj1rLNd/5nKcRwFFp6ZAGSZagIKgzal4A=="; 57 | assertEquals("e13f4ecddbb54551664f74ac76634bbad8f5acb35dff99ca711c05169e990064996a020a8336a5e0", Md5Utils.toHexString(Base64.decode(encryptedStr))); 58 | byte[] decryptedData = Base64.decode(encryptedStr); 59 | String md5 = new String(DESUtils.decrypt(decryptedData, passwd.getBytes()), "UTF-8"); 60 | assertEquals("20398415cf372481131278f074119188", new String(DESUtils.decrypt(decryptedData, passwd.getBytes()), "UTF-8")); 61 | } 62 | } -------------------------------------------------------------------------------- /candywebcache/src/test/java/com/netease/hearttouch/candywebcache/cachemanager/Md5UtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.cachemanager; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Created by netease on 16/6/16. 9 | */ 10 | public class Md5UtilsTest { 11 | 12 | @Test 13 | public void testCalculateMd5() throws Exception { 14 | String filePath1 = "/Users/netease/webcacheunittestfiles/web_app_old.zip"; 15 | String md5_1 = "1ab73685e5fbb4269d5c1432c232a574"; 16 | assertEquals(md5_1, Md5Utils.calculateMd5(filePath1)); 17 | 18 | String filePath2 = "/Users/netease/webcacheunittestfiles/web_app_new.zip"; 19 | String md5_2 = "dd859ff9180e292ada81e53da5b46e71"; 20 | assertEquals(md5_2, Md5Utils.calculateMd5(filePath2)); 21 | } 22 | 23 | @Test 24 | public void testCheckFileValidation() throws Exception { 25 | String filePath1 = "/Users/netease/webcacheunittestfiles/web_app_old.zip"; 26 | String md5_1 = "1ab73685e5fbb4269d5c1432c232a574"; 27 | assertTrue(Md5Utils.checkFileValidation(filePath1, md5_1)); 28 | 29 | String filePath2 = "/Users/netease/webcacheunittestfiles/web_app_new.zip"; 30 | String md5_2 = "dd859ff9180e292ada81e53da5b46e71"; 31 | assertTrue(Md5Utils.checkFileValidation(filePath2, md5_2)); 32 | } 33 | } -------------------------------------------------------------------------------- /candywebcache/src/test/java/com/netease/hearttouch/htfiledownloader/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htfiledownloader; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /candywebcache/src/test/java/com/netease/hearttouch/htresourceversionchecker/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.htresourceversionchecker; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /candywebcacheplugin/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /plugin -------------------------------------------------------------------------------- /candywebcacheplugin/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'groovy' 2 | apply plugin: 'maven-publish' 3 | 4 | dependencies { 5 | compile gradleApi() 6 | compile localGroovy() 7 | } 8 | 9 | 10 | publishing{ 11 | publications { 12 | mavenJava(MavenPublication) { 13 | from components.java 14 | artifact sourcesJar 15 | artifact javadocJar 16 | 17 | groupId 'com.netease.hearttouch' 18 | artifactId 'candywebcache-plugin' 19 | 20 | version '0.0.7-SNAPSHOT' 21 | } 22 | } 23 | 24 | repositories { 25 | maven { 26 | } 27 | } 28 | } 29 | 30 | 31 | task javadocJar(type: Jar, dependsOn: groovydoc) { 32 | classifier = 'javadoc' 33 | from "${buildDir}/javadoc" 34 | } 35 | 36 | task sourcesJar(type: Jar) { 37 | from sourceSets.main.allSource 38 | classifier = 'sources' 39 | } -------------------------------------------------------------------------------- /candywebcacheplugin/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Volumes/Documents/android_env/android-sdk-macosx/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /candywebcacheplugin/readme.md: -------------------------------------------------------------------------------- 1 | ### 插件使用方法 2 | 3 | * 在主`module`的`build.gradle`中加入 4 | ```apply plugin: 'com.netease.hearttouch.PresetResourcePlugin'``` 5 | 6 | * 在主`module`的`build.gradle`中加入 7 | 8 | ``` 9 | buildscript { 10 | //目前先发布在本地,后面会通过maven进行引用 11 | repositories { 12 | // maven { 13 | // url "http://mvn.hz.netease.com/artifactory/libs-releases/" 14 | // } 15 | // maven { 16 | // url "http://mvn.hz.netease.com/artifactory/libs-snapshots/" 17 | // } 18 | maven { 19 | url "./plugin" 20 | } 21 | } 22 | dependencies { 23 | classpath 'com.netease.hearttouch:candywebcache-plugin:0.0.1-SNAPSHOT' //添加依赖,后续发布后版本号会变 24 | } 25 | } 26 | ``` 27 | * 在主`module`的`build.gradle`中加入 28 | 29 | - `url`:检测版本的`http`请求地址 30 | - `appID `:本应用注册在`CandyWebcache`的`native`应用标识 31 | - `appVersion `:本应用当前的版本号 32 | - `needDownload`:是否需要下载,默认设置为true,如果确定在`assembleRelease`的时候资源包没有更新,可以设置为false,加速打包过程 33 | 34 | ``` 35 | presetExt{ 36 | url 'http://10.242.27.37:9001/api/version_check' 37 | appID 'KaoLa' 38 | appVersion '1.2.3' 39 | needDownload true 40 | } 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /candywebcacheplugin/src/main/groovy/com/netease/hearttouch/PresetExt.groovy: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch 2 | 3 | public class PresetExt { 4 | String url; 5 | String appID; 6 | String appVersion; 7 | String downloadPath; 8 | boolean needDownload = true; 9 | } 10 | -------------------------------------------------------------------------------- /candywebcacheplugin/src/main/groovy/com/netease/hearttouch/PresetResourcePlugin.groovy: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch 2 | 3 | import groovy.json.JsonBuilder 4 | import groovy.json.JsonSlurper 5 | import groovy.xml.MarkupBuilder 6 | import org.gradle.api.Plugin 7 | import org.gradle.api.Project 8 | import org.gradle.api.Task 9 | 10 | import java.util.regex.Pattern 11 | 12 | class PresetResourcePlugin implements Plugin { 13 | private String PROTOCOL_VERSION = "0.1"; 14 | 15 | @Override 16 | void apply(Project project) { 17 | project.extensions.add("presetExt", PresetExt) 18 | 19 | project.task('presetResourceTask') { 20 | //task的group 21 | group 'hearttouch' 22 | 23 | doLast { 24 | PresetExt ext = project.presetExt 25 | if (!ext.needDownload) { 26 | println "user setting: No need to redownload..." 27 | return 28 | } 29 | //清除旧文件,如果下载失败等原因,下次重新打包的时候会再清理的 30 | File projectDir = project.getProjectDir() 31 | String targetPath = "src/main/assets/webapps" 32 | if (ext.downloadPath != null && ext.downloadPath != "") { 33 | targetPath = ext.downloadPath + "/webapps"; 34 | } 35 | File dirFile = new File(projectDir, targetPath) 36 | if (dirFile.exists()) { 37 | dirFile.deleteDir() 38 | } 39 | println dirFile.getAbsolutePath() 40 | dirFile.mkdirs() 41 | 42 | def json = new JsonBuilder() 43 | json { 44 | version PROTOCOL_VERSION 45 | appID ext.appID 46 | appVersion ext.appVersion 47 | platform "android" 48 | autoFill true 49 | isDiff false 50 | } 51 | println "request data:" + json 52 | 53 | def connection = new URL(ext.url).openConnection() 54 | connection.setRequestMethod('POST') 55 | connection.useCaches = false 56 | connection.doOutput = true 57 | connection.readTimeout = 10000 58 | connection.connectTimeout = 10000 59 | connection.setRequestProperty("Content-Type", "application/json") 60 | 61 | def writer = new OutputStreamWriter(connection.outputStream) 62 | 63 | 64 | writer.write(json.toString()) 65 | writer.flush() 66 | writer.close() 67 | connection.connect() 68 | def responseText = connection.content.text 69 | println "response data:" + responseText 70 | 71 | def jsonSlurper = new JsonSlurper() 72 | def responseData = jsonSlurper.parseText(responseText) 73 | if (responseData.code != 200) { 74 | throw new RuntimeException("code in data return from server is " + responseData.code + "! errMsg:" + responseData.errMsg) 75 | } 76 | //下面发生找不到字段的错误让他自己报错就行了 77 | def resInfos = responseData.data.resInfos 78 | File xmlFile = new File(dirFile, "webapps.xml") 79 | def xmlWriter = new FileWriter(xmlFile) 80 | 81 | def xmlBuilder = new MarkupBuilder(xmlWriter) 82 | xmlBuilder.getMkp().pi(xml: [version: '1.0', encoding: 'UTF-8']) 83 | 84 | RandomAccessFile raFile = null 85 | BufferedInputStream bis = null 86 | try { 87 | xmlBuilder.webappinfos { 88 | resInfos.each { 89 | // if (it.state != 1 || it.state != 3) { 90 | // throw new RuntimeException("state is " + it.state + " for " + it.resID); 91 | // } 92 | if(it.userData != null && !it.userData.equals("")){ 93 | def userData = jsonSlurper.parseText(it.userData) 94 | def domains = userData.domains 95 | webapp(name: it.resID, md5: it.fullMd5, version: it.resVersion) { 96 | for (d in domains) { 97 | domain d 98 | } 99 | } 100 | } 101 | def downloadConnection = new URL(it.fullUrl).openConnection() 102 | downloadConnection.setRequestMethod('GET') 103 | downloadConnection.useCaches = false 104 | downloadConnection.doOutput = true 105 | downloadConnection.readTimeout = 10000 106 | downloadConnection.connectTimeout = 10000 107 | 108 | def extension = getFileExtensionFromUrl(it.fullUrl); 109 | if (extension == null || extension.equals("")) { 110 | extension = "zip" 111 | } 112 | extension = "." + extension 113 | println "downloading " + it.resID + extension 114 | 115 | File file = new File(dirFile, it.resID + extension); 116 | raFile = new RandomAccessFile(file, "rw") 117 | 118 | byte[] buf = new byte[8192]; 119 | bis = new BufferedInputStream(downloadConnection.inputStream) 120 | int size = 0 121 | while ((size = bis.read(buf)) != -1) { 122 | raFile.write(buf, 0, size); 123 | } 124 | bis.close() 125 | raFile.close() 126 | } 127 | println "download completed, find files in " + dirFile.getAbsolutePath() 128 | } 129 | } catch (Exception e) { 130 | if (bis != null) { 131 | bis.close() 132 | } 133 | if (raFile != null) { 134 | bis.close() 135 | } 136 | if (xmlWriter != null) { 137 | xmlWriter.close() 138 | } 139 | dirFile.deleteDir() 140 | 141 | //丢出去 142 | throw e 143 | } 144 | } 145 | } 146 | 147 | 148 | project.afterEvaluate { 149 | project.tasks.findByName("assembleRelease") 150 | } 151 | 152 | project.afterEvaluate { 153 | for (Task task : project.tasks) { 154 | if(task.name.startsWith("assemble") && task.name.endsWith("Release")) { 155 | task.dependsOn 'presetResourceTask' 156 | } 157 | } 158 | } 159 | } 160 | 161 | private String getFileExtensionFromUrl(String url) { 162 | if (url != null && !url.equals("")) { 163 | int fragment = url.lastIndexOf('#'); 164 | if (fragment > 0) { 165 | url = url.substring(0, fragment); 166 | } 167 | 168 | int query = url.lastIndexOf('?'); 169 | if (query > 0) { 170 | url = url.substring(0, query); 171 | } 172 | 173 | int filenamePos = url.lastIndexOf('/'); 174 | String filename = 175 | 0 <= filenamePos ? url.substring(filenamePos + 1) : url; 176 | 177 | // if the filename contains special characters, we don't 178 | // consider it valid for our matching purposes: 179 | if (!filename.isEmpty() && 180 | Pattern.matches("[a-zA-Z_0-9\\.\\-\\(\\)\\%]+", filename)) { 181 | int dotPos = filename.lastIndexOf('.'); 182 | if (0 <= dotPos) { 183 | return filename.substring(dotPos + 1); 184 | } 185 | } 186 | } 187 | 188 | return ""; 189 | } 190 | } -------------------------------------------------------------------------------- /candywebcacheplugin/src/main/resources/META-INF/gradle-plugins/com.netease.hearttouch.PresetResourcePlugin.properties: -------------------------------------------------------------------------------- 1 | implementation-class=com.netease.hearttouch.PresetResourcePlugin -------------------------------------------------------------------------------- /demoapp/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .idea/ 3 | build/ 4 | .gradle/ 5 | *.iml -------------------------------------------------------------------------------- /demoapp/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 21 5 | buildToolsVersion "21.1.2" 6 | 7 | defaultConfig { 8 | applicationId "com.netease.hearttouch.candywebcache.demoapp" 9 | minSdkVersion 14 10 | targetSdkVersion 21 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles.add(file("proguard-rules.pro")) 19 | } 20 | } 21 | } 22 | 23 | buildscript { 24 | repositories { 25 | jcenter() 26 | } 27 | dependencies { 28 | classpath 'com.netease.hearttouch:ht-candywebcacheplugin:0.1.0' 29 | } 30 | } 31 | 32 | apply plugin: 'com.netease.hearttouch.PresetResourcePlugin' 33 | 34 | presetExt { 35 | url 'http://webcache-sp.kaola.com/api/version_check/webapp' 36 | appID 'kaola' 37 | appVersion '20166666' 38 | needDownload true 39 | } 40 | 41 | dependencies { 42 | compile project(":candywebcache") 43 | // compile 'com.netease.hearttouch:ht-candywebcache:0.2.0' 44 | 45 | compile fileTree(dir: 'libs', include: ['*.jar']) 46 | testCompile 'junit:junit:4.12' 47 | compile 'com.android.support:appcompat-v7:21.+' 48 | } 49 | -------------------------------------------------------------------------------- /demoapp/plugins/candywebcacheplugin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-android/43a30bbced51bddab2dd21477b2043f0b9506722/demoapp/plugins/candywebcacheplugin.jar -------------------------------------------------------------------------------- /demoapp/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/netease/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /demoapp/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /demoapp/src/main/java/com/netease/hearttouch/candywebcache/demoapp/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.demoapp; 2 | 3 | import android.app.Application; 4 | 5 | import com.netease.hearttouch.candywebcache.CacheConfig; 6 | import com.netease.hearttouch.candywebcache.CandyWebCache; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * Created by DING on 16/6/30. 13 | */ 14 | public class DemoApplication extends Application{ 15 | @Override 16 | public void onCreate() { 17 | super.onCreate(); 18 | CacheConfig config = buildCacheConfig(); 19 | // String versionCheckUrl = "http://10.242.27.37:9001/api/version_check"; 20 | String versionCheckUrl = "http://webcache-sp.kaola.com/api/version_check/webapp"; 21 | String statisticsDataUploadUrl = "http://webcache-sp.kaola.com/api/statistics/webapp"; 22 | CandyWebCache.getsInstance().setWebcacheEnabled(true); 23 | CandyWebCache.getsInstance().setDebugEnabled(true); 24 | CandyWebCache.getsInstance().init(this, config, null, "kaola", "1.0.1", 25 | versionCheckUrl, statisticsDataUploadUrl); 26 | CandyWebCache.getsInstance().setStatisticUploadUrl(statisticsDataUploadUrl); 27 | CandyWebCache.getsInstance().setUserId("hanpfei"); 28 | } 29 | 30 | private CacheConfig buildCacheConfig() { 31 | CacheConfig.ConfigBuilder builder = CacheConfig.createCofigBuilder(); 32 | List uncachedType = new ArrayList<>(); 33 | // uncachedType.add(".html"); 34 | builder.setUncachedFileTypes(uncachedType); 35 | builder.setMemCacheSize(5 * 1025 * 1024); 36 | 37 | List defaultDomains = new ArrayList<>(); 38 | defaultDomains.add("w.kl.126.net/"); 39 | builder.setDefaultDomains(defaultDomains); 40 | return builder.build(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /demoapp/src/main/java/com/netease/hearttouch/candywebcache/demoapp/InfomationActivity.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.demoapp; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.TextView; 9 | 10 | import com.netease.hearttouch.candywebcache.CandyWebCache; 11 | import com.netease.hearttouch.candywebcache.cachemanager.FileInfo; 12 | import com.netease.hearttouch.candywebcache.cachemanager.WebappInfo; 13 | 14 | import java.util.List; 15 | 16 | public class InfomationActivity extends Activity { 17 | private TextView mTvInformation; 18 | private boolean needAll = false; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_infomation); 24 | final Button btnSwitch = (Button) findViewById(R.id.btn_switch); 25 | btnSwitch.setOnClickListener(new View.OnClickListener() { 26 | @Override 27 | public void onClick(View v) { 28 | needAll = !needAll; 29 | if (needAll) { 30 | btnSwitch.setText("不显示文件信息"); 31 | print(); 32 | } else { 33 | btnSwitch.setText("显示全部信息"); 34 | print(); 35 | } 36 | } 37 | }); 38 | mTvInformation = (TextView) findViewById(R.id.tv_information); 39 | print(); 40 | } 41 | 42 | private void print() { 43 | mTvInformation.setText(""); 44 | List webappInfos = CandyWebCache.getsInstance().getAllWebappInfo(); 45 | if (webappInfos != null && !webappInfos.isEmpty()) { 46 | for (WebappInfo webappInfo : webappInfos) { 47 | print(webappInfo); 48 | } 49 | } else { 50 | mTvInformation.setText("nothing found!!!"); 51 | } 52 | } 53 | 54 | private void print(WebappInfo webappInfo) { 55 | StringBuilder sb = new StringBuilder(); 56 | sb.append("=====").append(webappInfo.mWebappName).append("=====\n") 57 | .append(webappInfo.mVerStr).append('\n') 58 | .append(webappInfo.mCachedDirPath).append('\n') 59 | .append(webappInfo.mCacheSize).append('\n') 60 | .append(webappInfo.mPkgFilePath).append('\n') 61 | .append(webappInfo.mPkgFileMd5).append('\n') 62 | .append(webappInfo.mFullUrl).append('\n') 63 | .append(webappInfo.mStatus).append('\n') 64 | .append(webappInfo.mDomains).append('\n'); 65 | Log.d("WebAppInformation", sb.toString()); 66 | mTvInformation.append(sb.toString()); 67 | if (needAll) { 68 | if (webappInfo.mFileInfos != null && !webappInfo.mFileInfos.isEmpty()) { 69 | Log.d("WebAppInformation", "*****FileInfo*****\n"); 70 | mTvInformation.append("*****FileInfo*****\n"); 71 | for (String key : webappInfo.mFileInfos.keySet()) { 72 | StringBuilder fileInfoSb = new StringBuilder(); 73 | fileInfoSb.append("#####").append(key).append("#####\n").append(toString(webappInfo.mFileInfos.get(key))).append('\n'); 74 | Log.d("WebAppInformation", fileInfoSb.toString()); 75 | mTvInformation.append(fileInfoSb.toString()); 76 | } 77 | } 78 | } 79 | } 80 | 81 | private String toString(FileInfo fileInfo) { 82 | StringBuilder sb = new StringBuilder(); 83 | sb.append(fileInfo.mAppname).append('\n') 84 | .append(fileInfo.mUrl).append('\n') 85 | .append(fileInfo.mLocalPath).append('\n') 86 | .append(fileInfo.mMd5).append('\n') 87 | .append(fileInfo.getStatus()).append('\n') 88 | .append(fileInfo.getmAccessCount()).append('\n'); 89 | return sb.toString(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /demoapp/src/main/java/com/netease/hearttouch/candywebcache/demoapp/LoadResourceActivity.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.demoapp; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.webkit.WebResourceRequest; 7 | import android.webkit.WebResourceResponse; 8 | import android.webkit.WebView; 9 | import android.webkit.WebViewClient; 10 | import android.widget.EditText; 11 | 12 | import com.netease.hearttouch.candywebcache.CandyWebCache; 13 | import com.netease.hearttouch.candywebcache.HybridWebviewClient; 14 | 15 | public class LoadResourceActivity extends Activity implements View.OnClickListener{ 16 | private WebView mWebview; 17 | private EditText mUrlEditText; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_load_resource); 23 | mWebview = (WebView) findViewById(R.id.webview); 24 | if (mWebview != null) { 25 | mWebview.getSettings().setJavaScriptEnabled(true); 26 | mWebview.setWebViewClient(new HybridWebviewClient()); 27 | } 28 | mUrlEditText = (EditText) findViewById(R.id.et_url); 29 | findViewById(R.id.btn_load).setOnClickListener(this); 30 | } 31 | 32 | @Override 33 | public void onClick(View v) { 34 | switch (v.getId()) { 35 | case R.id.btn_load: 36 | mWebview.clearCache(true); 37 | mWebview.loadUrl(mUrlEditText.getText().toString()); 38 | break; 39 | default: 40 | break; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /demoapp/src/main/java/com/netease/hearttouch/candywebcache/demoapp/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.netease.hearttouch.candywebcache.demoapp; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.Toast; 8 | 9 | import com.netease.hearttouch.candywebcache.CandyWebCache; 10 | import com.netease.hearttouch.candywebcache.cachemanager.WebappInfo; 11 | 12 | import java.util.List; 13 | 14 | public class MainActivity extends Activity implements View.OnClickListener { 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | findViewById(R.id.btn_check_update).setOnClickListener(this); 21 | findViewById(R.id.btn_load_resource).setOnClickListener(this); 22 | findViewById(R.id.btn_clear).setOnClickListener(this); 23 | findViewById(R.id.btn_log_info).setOnClickListener(this); 24 | findViewById(R.id.upload_statistics).setOnClickListener(this); 25 | } 26 | 27 | @Override 28 | public void onClick(View v) { 29 | Intent intent = null; 30 | switch (v.getId()) { 31 | case R.id.btn_check_update: 32 | CandyWebCache.getsInstance().startCheckAndUpdate(1); 33 | Toast.makeText(MainActivity.this, "check update!", Toast.LENGTH_SHORT).show(); 34 | break; 35 | case R.id.btn_load_resource: 36 | intent = new Intent(MainActivity.this, LoadResourceActivity.class); 37 | startActivity(intent); 38 | break; 39 | case R.id.btn_clear: 40 | deleteAllCache(); 41 | Toast.makeText(MainActivity.this, "clear cache!", Toast.LENGTH_SHORT).show(); 42 | break; 43 | case R.id.btn_log_info: 44 | intent = new Intent(MainActivity.this, InfomationActivity.class); 45 | startActivity(intent); 46 | break; 47 | case R.id.upload_statistics: 48 | CandyWebCache.getsInstance().updateStatisticsStub(); 49 | break; 50 | default: 51 | break; 52 | } 53 | } 54 | 55 | private void deleteAllCache() { 56 | final List webAppInfos = CandyWebCache.getsInstance().getAllWebappInfo(); 57 | if (webAppInfos != null && !webAppInfos.isEmpty()) { 58 | new Thread(new Runnable() { 59 | @Override 60 | public void run() { 61 | for (WebappInfo webappInfo : webAppInfos) { 62 | CandyWebCache.getsInstance().deleteCache(webappInfo.mWebappName); 63 | } 64 | } 65 | }).start(); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /demoapp/src/main/res/layout/activity_infomation.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 13 |